Sine/Cosine Problem
Blitz3D Forums/Blitz3D Programming/Sine/Cosine Problem
| ||
At the moment I have some basic acceleration code for an asteroids style game. Here is what I have for accelerating forwards.Player(pnum)\SpeedX# = NewXValue#(Player(pnum)\SpeedX#, 100 * FL\SpeedFactor#,Player(pnum)\AngleZ#) Player(pnum)\SpeedY# = NewYValue#(Player(pnum)\SpeedY#, 100 * FL\SpeedFactor#,Player(pnum)\AngleZ#) And here are the functions the above code calls. Function NewXValue#(oldX#, amount#, Angle#) TempAngle# = Angle# cosine# = Cos#(TempAngle#) cosine# = Cosine# * amount# Newx# = oldx# + cosine# Return Newx# End Function Function NewYValue#(oldY#, amount#, Angle#) TempAngle# = Angle# sine# = Sin#(TempAngle#) sine# = sine# * amount# Newy# = (oldy# + sine#) Return Newy# End Function The problem is that instead of the player being able to move along any angle, it seems as if the angle is being rounded into 4 directions. The directions are 45 degrees, 135 degrees, 225 degrees and 315 degrees (so can basically only go in a diamond shap) Anyone got any ideas? Thanks in advance. |
| ||
There's some useful code here: http://www.blitzbasic.com/Community/posts.php?topic=17097 ------------ The maths looks a little complicated to me, so Im not sure ho else I can help. |
| ||
1) get rid of all that # symbols. You only need when: - you declare a variable or a type field - you declare a function which should return a float. So, once you declared: Global x# just use it without # when you refer to it x = x + 0.1 Same for Function return: function myfloat#(x#) x = x + 0.5 Return x is correct Return x# # is not required end function This will improve the readability of your code. More, Sin and Cos does not require any #, so: Sin(angle) is correct Sin#(angle) the # is not required 2) your two functions NewXValue and NewYValue are quite the same. Just merge both in a single function like GetNewValue, and use a flag to select a sin or a cos function: GetNewValue(a,b,c,true) will use sin GetNewValue(a,b,c,false) will use cos Function GetNewValue#(oldval#, amount#, Angle#, sinus) ;if sinus = true then use sin, else use cos local tempval# if sinus then tempval = sin(tempangle) * amount else tempval = cos(tempangle) * amount endif Return (oldval + tempval) End Function 3) Check how you have declared the fields in the type structure. If a field should be float, then you should declare it in the type declaration: type mytype field x# ;will be a float field angle ;will be an integer end type Later, if you do: temp.mytype = new mytype temp\x = 1.5 temp\angle# = 1.2 --> note the # here, it can confuse you because it will not affect the nature of the field, since angle has been declared as integer in the type structure. So if you give it a float value, and expect to get it, you will have an integer instead: print temp\x print temp\angle will print: 1.5 1 That's why I suggest you to use the # only when you declare a variable or a type field. 4) be careful with floats, since the approximation may differ on different pc and processors - use integers instead ! Bare in mind that floats can put you in troubles, for example: Global x# x = 10/3 Print x What do you expect to be printed ? You will be surprised from the result. Try this instead: Global x# x = 10.0/3 Print x See ? Floats can give unexpected behaviours... Again, use integers when possible !!! ;-) Hope it helps, Sergio. |
| ||
Personally I use # where-ever I use a float value, regardless of whether I am not required to or so.. Same as strings, the $ follows every declared Var throughout the program. I prefer this because it's easier to see what is doing what and debugging is much simpler that way.. |
| ||
Personally I use # where-ever I use a float value, regardless of whether I am not required to or so.. Same as strings, the $ follows every declared Var throughout the program. I prefer this because it's easier to see what is doing what and debugging is much simpler that way.. Im the same except I dont bother for % integer variables! |
| ||
Dark Half - me too. And, not meaning to be rude Semar, but to spend so long criticising someones code without actually trying to help them with their stated problem just seems ... well, a bit unnecessary really. I could see the point if the guys code was actually broken, but it's not (see below). Having said that, I'm not sure I can help either :-) The following (which is based on your code Nexic) seems to work fine so I'd suggest that it's something outwith what you've posted that's causing the problem. One thing that I did wrong at first when copying and pasting the code was to add SpeedX to the players Y coordinate (instead of SpeedY) - that produces the effect you describe. Graphics 640, 480, 0, 2 Type PlayerType Field X, Y Field SpeedX# Field SpeedY# Field AngleZ# End Type Player.PlayerType = New PlayerType Player\X = 320 Player\Y = 240 Player\AngleZ# = 10 FLSpeedFactor# = 0.05 Repeat Plot Player\X, Player\Y WaitKey() Player\SpeedX# = NewXValue#(Player\SpeedX#, 100 * FLSpeedFactor#,Player\AngleZ#) Player\SpeedY# = NewYValue#(Player\SpeedY#, 100 * FLSpeedFactor#,Player\AngleZ#) Player\X = Player\X + Player\SpeedX# Player\Y = Player\Y + Player\SpeedY# Until KeyHit(1) Function NewXValue#(oldX#, amount#, Angle#) TempAngle# = Angle# cosine# = Cos#(TempAngle#) cosine# = Cosine# * amount# Newx# = oldx# + cosine# Return Newx# End Function Function NewYValue#(oldY#, amount#, Angle#) TempAngle# = Angle# sine# = Sin#(TempAngle#) sine# = sine# * amount# Newy# = (oldy# + sine#) Return Newy# End Function |
| ||
Im afraid I'm still stuck with this, despite your help. I really can't see what I'm doing wrong. Below is the entire code im using for this. If anyone can be bothered to take a look please do, I'd greatly appreciate it.Type TypePlayer Field Model Field x# Field y# Field z# Field AngleX# Field AngleY# Field AngleZ# Field SpeedX# Field SpeedY# Field TurnSpeed# Field MaxSpeedX# Field MaxSpeedY# Field MaxTurnSpeed# Field AccelSpeed# Field AccelTurn# Field DeccelSpeed# End Type Dim Player.TypePlayer(10) For i = 1 To 10 Player(i) = New TypePlayer Next Function LoadPlayer() For i = 1 To 10 Player(i)\x# = 0 Player(i)\y# = 0 Player(i)\z# = 0 Player(i)\AngleX# = 0 Player(i)\AngleY# = 0 Player(i)\AngleZ# = 0 Player(i)\SpeedX# = 0 Player(i)\SpeedY# = 0 Player(i)\TurnSpeed# = 0 Player(i)\MaxSpeedX# = 0.5 Player(i)\MaxSpeedY# = 0.5 Player(i)\MaxTurnSpeed# = 0.8 Player(i)\AccelTurn# = 0.03 Player(i)\AccelSpeed# = 0.3 Player(i)\DeccelSpeed# = 0.5 Player(i)\Model = CreateCube() ScaleEntity(Player(i)\Model, 10, 10,10) HideEntity(Player(i)\Model) Next ShowEntity(Player(1)\model) End Function Function DoPlayer() For i = 1 To 10 DoPlayerMovement(i) UpdatePlayer(i) Next End Function Function DoPlayerMovement(pnum) WentRight = 0 WentLeft = 0 WentForward = 0 WentBackward = 0 If (KeyDown(UpKey)) WentForward = 1 Player(pnum)\SpeedX# = NewXValue#(Player(pnum)\SpeedX#, 100.0 * FL\SpeedFactor#,WrapAngle(Player(pnum)\AngleZ#)) Player(pnum)\SpeedY# = NewYValue#(Player(pnum)\SpeedY#, 100.0 * FL\SpeedFactor#,WrapAngle(Player(pnum)\AngleZ#)) EndIf If (KeyDown(DownKey)) WentBackward = 1 Player(pnum)\SpeedX# = NewXValue#(Player(pnum)\SpeedX#, (-1.0*100.0) * FL\SpeedFactor#,WrapAngle(Player(pnum)\AngleZ#)) Player(pnum)\SpeedY# = NewYValue#(Player(pnum)\SpeedY#, (-1.0*100.0) * FL\SpeedFactor#,WrapAngle(Player(pnum)\AngleZ#)) EndIf If (KeyDown(LeftKey)) WentLeft = 1 Player(pnum)\TurnSpeed# = Player(pnum)\TurnSpeed# - (Player(pnum)\AccelTurn# * FL\SpeedFactor#) EndIf If (KeyDown(RightKey)) WentRight = 1 Player(pnum)\TurnSpeed# = Player(pnum)\TurnSpeed# + (Player(pnum)\AccelTurn# * FL\SpeedFactor#) EndIf If (Player(pnum)\SpeedX# > Player(pnum)\MaxSpeedX#) Then Player(pnum)\SpeedX# = Player(pnum)\MaxSpeedX# If (Player(pnum)\SpeedX# < (-1.0*Player(pnum)\MaxSpeedX#)) Then Player(pnum)\SpeedX# = (-1.0*Player(pnum)\MaxSpeedX#) If (Player(pnum)\SpeedY# > Player(pnum)\MaxSpeedY#) Then Player(pnum)\SpeedY# = Player(pnum)\MaxSpeedY# If (Player(pnum)\SpeedY# < (-1.0*Player(pnum)\MaxSpeedY#)) Then Player(pnum)\SpeedY# = (-1.0*Player(pnum)\MaxSpeedY#) If (Player(pnum)\TurnSpeed# > Player(pnum)\MaxTurnSpeed#) Then Player(pnum)\TurnSpeed# = Player(pnum)\MaxTurnSpeed# If (Player(pnum)\TurnSpeed# < (-1.0*Player(pnum)\MaxTurnSpeed#)) Then Player(pnum)\TurnSpeed# = (-1.0*Player(pnum)\MaxTurnSpeed#) If (Player(pnum)\SpeedX# > 0) And WentForward = 0 And WentBackward = 0 Player(pnum)\SpeedX# = Player(pnum)\SpeedX# - (0.05*FL\SpeedFactor) If (Player(pnum)\SpeedX# < 0.25) Then Player(pnum)\SpeedX# = 0 EndIf If (Player(pnum)\SpeedX# < 0) And WentForward = 0 And WentBackward = 0 Player(pnum)\SpeedX# = Player(pnum)\SpeedX# + (0.05*FL\SpeedFactor) If (Player(pnum)\SpeedX# > -0.25) Then Player(pnum)\SpeedX# = 0 EndIf If (Player(pnum)\SpeedY# > 0) And WentForward = 0 And WentBackward = 0 Player(pnum)\SpeedY# = Player(pnum)\SpeedY# - (0.05*FL\SpeedFactor) If (Player(pnum)\SpeedY# < 0.25) Then Player(pnum)\SpeedY# = 0 EndIf If (Player(pnum)\SpeedY# < 0) And WentForward = 0 And WentBackward = 0 Player(pnum)\SpeedY# = Player(pnum)\SpeedY# + (0.05*FL\SpeedFactor) If (Player(pnum)\SpeedY# > -0.25) Then Player(pnum)\SpeedY# = 0 EndIf If (Player(pnum)\TurnSpeed# > 0) And WentLeft = 0 And WentRight = 0 Player(pnum)\TurnSpeed# = Player(pnum)\TurnSpeed# - (0.01*FL\SpeedFactor) If (Player(pnum)\TurnSpeed# < 0.01) Then Player(pnum)\TurnSpeed# = 0 EndIf If (Player(pnum)\TurnSpeed# < 0) And WentLeft = 0 And WentRight = 0 Player(pnum)\TurnSpeed# = Player(pnum)\TurnSpeed# + (0.01*FL\SpeedFactor) If (Player(pnum)\TurnSpeed# > -0.01) Then Player(pnum)\TurnSpeed# = 0 EndIf Player(pnum)\AngleZ# = Player(pnum)\AngleZ# + (Player(pnum)\TurnSpeed#*FL\SpeedFactor) Player(pnum)\x# = Player(pnum)\x# + (Player(pnum)\SpeedX# * FL\SpeedFactor) Player(pnum)\y# = Player(pnum)\y# + (Player(pnum)\SpeedY# * FL\SpeedFactor) End Function Function UpdatePlayer(pnum) PositionEntity(Player(pnum)\model,Player(pnum)\x#,Player(pnum)\y#,0) RotateEntity(Player(pnum)\Model, 0,0,Player(pnum)\AngleZ#) End Function |
| ||
Nexic, I'm not 100% sure what you're looking for ... do you just want an asteroids ship moving around with rotational momentum as well as directional? I think this is a longwinded approach and could be reduced to around a few lines depending on what you're after. Let me know. I assume FL\Speedfactor is a float .. it's not declared anywhere in this code? |
| ||
Yes that is pretty much what I want. I'm sure there may be other ways to do it, but I'd really like to know what I'm doing wrong here. It frustrates me when something that should work, doesnt. |
| ||
So what is you're FL\speedfactor and I'll have a piss around? |
| ||
.... frame limiting update rate I presume. |
| ||
sorry, its framerate handling. IE. at 30 fps it = 2 at 60fps it = 1 at 120 fps it = 0.5 |
| ||
Ok, I had to tidy this up and strip half of it out - most of it was longwinded and not really necessary ... ( sorry I just couldn't follow it very well ) Note that the MaxTurnSpeed and MaxMoveSpeed are determined by the drag and acceleration forces .. see the function for estimated values ... saves you having to store them. Hope this helps you out .. Graphics3D 640,480,16,1 Const Upkey = 200 Const DownKey = 208 Const LeftKey = 203 Const Rightkey = 205 Global Camera = CreateCamera() PositionEntity Camera,0,0,-150 Type TypePlayer Field Model Field SpeedX# Field SpeedY# Field TurnSpeed# Field TurnDrag# Field TurnAcceleration# Field MoveDrag# Field MoveAcceleration# Field MoveDeceleration# End Type Type Frame Field SpeedFactor# End Type Global FL.Frame = New Frame FL\Speedfactor = 1 ;60fps Dim Player.TypePlayer(10) ;main program LoadPlayer() While Not KeyDown(1) DoPlayer() RenderWorld() Flip Wend ;=============================================== ;=============================================== ;=============================================== Function LoadPlayer() For i = 1 To 10 Player(i) = New TypePlayer Player(i)\SpeedX# = 0 Player(i)\SpeedY# = 0 Player(i)\TurnSpeed# = 0 Player(i)\TurnAcceleration# = 0.03 Player(i)\TurnDrag# = .99 Player(i)\MoveAcceleration# = 0.05 Player(i)\MoveDeceleration# = 0.05 Player(i)\MoveDrag = .99 ;MaxSpeed = .03 / ( 1.0 -.99 ) = 3 ;MaxTurnSpeed = .05 / ( 1.0 - .99 ) = 5 Player(i)\Model = CreateCone() ScaleEntity(Player(i)\Model, 10, 10,10) HideEntity(Player(i)\Model) Next ShowEntity(Player(1)\model) End Function ;=============================================== ;=============================================== ;=============================================== Function DoPlayer() For i = 1 To 10 DoPlayerMovement( Player( i ) ) Next End Function ;=============================================== ;=============================================== ;=============================================== Function DoPlayerMovement( p.TypePlayer ) ;turning Turn# = KeyDown (LeftKey) - KeyDown(RightKey) p\TurnSpeed# = p\TurnSpeed# *p\TurnDrag + Turn * p\TurnAcceleration * FL\SpeedFactor TurnEntity p\Model , 0,0, p\TurnSpeed * FL\SpeedFactor ;moving Direction# = KeyDown(UpKey) - KeyDown(DownKey) TFormNormal 0,1,0, p\Model, 0 Thrust# = ( Direction = 1 ) * p\MoveAcceleration - ( Direction = -1 ) * p\MoveDeceleration p\SpeedX = p\SpeedX * p\MoveDrag + Thrust * FL\SpeedFactor * TFormedX() p\SpeedY = p\SpeedY * p\MoveDrag + Thrust * FL\SpeedFactor * TFormedY() TranslateEntity p\Model, p\SpeedX , p\SpeedY , 0 End Function |
| ||
Im the same except I dont bother for % integer variables! Same here. I personally just consider it good programming practice to keep identifying symbols on variables just for readability. It gets frustrating trying to look at someone elses code when they strip those symbols off and I have to trace each var back and create a hardcopy list of what each is just so I can follow the program smoother whereas if they had just kept those symbols, I can just continue reading the code and following along. |
| ||
Thanks a lot for that Steve G! I've used that code for my program now instead of what I had before, but I still can't understand what I was doing wrong, oh well :) Thanks again! |
| ||
No worries mate ... give me a shout if you need any more help. |