Sine/Cosine Problem

Blitz3D Forums/Blitz3D Programming/Sine/Cosine Problem

Nexic(Posted 2005) [#1]
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.


_PJ_(Posted 2005) [#2]
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.


semar(Posted 2005) [#3]
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.


DH(Posted 2005) [#4]
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..


_PJ_(Posted 2005) [#5]

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!


HappyCat(Posted 2005) [#6]
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



Nexic(Posted 2005) [#7]
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



Stevie G(Posted 2005) [#8]
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?


Nexic(Posted 2005) [#9]
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.


Stevie G(Posted 2005) [#10]
So what is you're FL\speedfactor and I'll have a piss around?


Stevie G(Posted 2005) [#11]
.... frame limiting update rate I presume.


Nexic(Posted 2005) [#12]
sorry, its framerate handling.

IE. at 30 fps it = 2
at 60fps it = 1
at 120 fps it = 0.5


Stevie G(Posted 2005) [#13]
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





DH(Posted 2005) [#14]
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.


Nexic(Posted 2005) [#15]
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!


Stevie G(Posted 2005) [#16]
No worries mate ... give me a shout if you need any more help.