Sonic Maths?

BlitzPlus Forums/BlitzPlus Programming/Sonic Maths?

WillKoh(Posted 2003) [#1]
Can someone help me with the maths involved in making a game like sonic? I suppose it involves pi and gravity..

Just don't refer to the "sonicblitz" please, I don't get anything of that code...


WillKoh(Posted 2003) [#2]
Maybe I should be more specific: I was thinking about the loops in particular...


WillKoh(Posted 2003) [#3]
...And the Sonic game I refer to is that of a certain hedgehog...


Paul "Taiphoz"(Posted 2003) [#4]
loops ?

your going to have to give us more to go on than that. how about you tell us what sort of coding level your at then we can help better, also let us know exactly what it is your asking.

Help with loops could be anything . as there will be millions of code iterations in any game.


WolRon(Posted 2003) [#5]
Pretty simple.

Increase speed if button pressed (unless at max speed) but only if Sonic is touching 'ground'.
Decrease speed if button not pressed (unless at zero speed) or if Sonic is NOT touching 'ground'.
Move forward an amount relative to speed (following contour of environment).
Apply gravity.

Should do it for ya.


WillKoh(Posted 2003) [#6]
>>Following contour of environment>> That's the tricky part - in a loop that sonic should run (being upside down and so, with a certain generosity to actual gravity rules though)


Réno(Posted 2003) [#7]
speed move :

;#1
SonicY=(SonicY+1)
If ImagesOverlap (TileOfSonic,TileOfGroundY);bla bla, change it
SonicY=(TileOfGroundY-TileOfSonic)

;#2
SonicX=(SonicX+SonicSpeed)
Select SonicScript
Case 0;Sonic doesn't move
   SonicSpeed=(SonicSpeed-1)
   If SonicSpeed<0 SonicSpeed=0
case 1;sonic script left
   SonicSpeed=(SonicSpeed+1)
   If SonicSpeed>8 SonicSpeed=8
endif



WillKoh(Posted 2003) [#8]
What is the issue is not movement across common ground but on the inside of a looping, where he tilts to match the part of the loop-road he is stepping on, pointing head to ground when he is in the very roof of the loop.

Can someone help me with the maths to do that?


Warren(Posted 2003) [#9]
One idea would be to use his speed as a countering force against gravity. So do a linepick from his head towards his feet. Whatever the surface normal is that you hit, apply the countering force in the opposite direction of that normal. If he's going fast enough, that should make him stick to the top of loops and such.

As for moving him forward, you'll have to do that same check but probably bust out a cross product to get the "forward" vector in relation to whatever surface he's on at any given moment.


Todd(Posted 2003) [#10]
The only problem with that is that I assume he's trying to do this in 2d, not 3d. So there's no linepicks or surface normals. You could still do that using the same principal though. If you're using a tile map, just store collision data in the form of a line for each tile. When your character collides with the line, you can get the normal of the line by taking the line vector, diving 1 by it, and switching the sign. Then you can convert the normal into degrees usins Sin() and Cos(). You can then use that angle to draw your character pointing in the right direction. That probably didn't make any sense, so if you want me to explain a little more, I might consider writing a tutorial on doing this.


WillKoh(Posted 2003) [#11]
Please do that, that would be very kind of you. You would need to explain even things like normals and tilemaps though.


Rob(Posted 2003) [#12]
Since this is 2D, the most important thing to learn is pinball physics.

If you use a black and white mask and get a ball working on a pinball table, you will have the required physics for use in a sonic game.


WillKoh(Posted 2003) [#13]
>>Since this is 2D, the most important thing to learn is pinball physics>> I guess so. Any help on that? I can't help but think it should be quite simple in terms of the code size?


Rob Farley(Posted 2004) [#14]
The yellow lines are the normals.

Graphics 640,480,0,2

For n=0 To 359 Step 10

x=Sin(n)*200+320
y=Cos(n)*200+240

Color 0,255,0
Line x+(Sin(n-90)*15),y+(Cos(n-90)*15),x+(Sin(n+90)*15),y+(Cos(n+90)*15)
Color 255,255,0
Line x,y,x+(Sin(n+180)*15),y+(Cos(n+180)*15)

Next

WaitKey



tonyg(Posted 2004) [#15]
If this is 2D and your play area is larger than a single screen then you'll need tilemaps.
Would it be possible to use pre-calculated waypoints (connected using Bezier curves or sin/cos table?)around the inside of the loops and a min speed threshold. If you duck below that speed you branch to a 'start_dropping' function?


Rob Farley(Posted 2004) [#16]
Tony, that seems like a terrible way of handling the game.

Basically you'll need a real basic physics engine that holds your xspeed and yspeed.

xspeed increases and decreases as you press left and right
if keydown(right) then xspeed=xspeed+1 (where 1 is an acceleration speed)
if keydown(left) then xspeed=xspeed-1

xspeed gets dampened by friction
xspeed=xspeed*friction (where 1 would be no friction and 0 would make you stop immediately)

yspeed always accelerates downwards at the force of gravity
yspeed=yspeed+gravity_constant

yspeed gets adjusted by height differences upwards that the player has made.
if oldy<y then yspeed=yspeed-((currenty-oldy)*lift_constant)

Adjust x and y positions based on the x and y speeds
x=x+xspeed
y=y+yspeed

Make sure player hasn't fallen through the ground or through the ceiling and adjust the y accordingly.

If you hit the jump key then you make yspeed = -5 (or something similar) and everything will work fine.

Anyway... that's how I'd do it.


Rob Farley(Posted 2004) [#17]
Just knocked this up... it might help a bit...

; =======================================================================
;  Basic physics engine                                  Rob Farley 2004
; 
;  http://www.mentalillusion.co.uk              rob@...
; =======================================================================



Graphics 640,480,0,2
SetBuffer BackBuffer()

Dim ground(639)
createground()

Const keyRht=205
Const keyLft=203
Const keyUp =200
Const KeyDwn=208


Const accel#=0.5
Const friction#=0.9
Const gravity#=0.5


x#=320.0
y#=240.0
oldy#=y

xs#=0.0
ys#=0.0

ontheground=False

Repeat

Cls

; draw ground
Color 0,255,0
For n=0 To 639
Plot n,ground(n)
Next

; draw player
Color 255,255,255
Oval x-5,y-11,11,11,True

oldy=y

; get user input
If ontheground
If KeyDown(keyrht) Then xs=xs+accel
If KeyDown(keylft) Then xs=xs-accel
If KeyDown(keyup)  Then ys=ys-5 	; jump
xs=xs*friction				; add friction
EndIf


x=x+xs		; update x position

ys=ys+gravity	; add gravity
y=y+ys		; add the y speed to the y position

; wrap x
If x>639 Then x=0
If x<0 Then x=639

; hit the ground
If y<ground(x) Then ontheground=False Else ontheground=True ; are you on the ground
If y>ground(x) Then y=ground(x):ys=-ys/5 ;bounce
If ontheground	; things to deal with when on the ground:

	If y<oldy Then ys=ys-(oldy-y)	; lift from hills
	hl#=ground(wrap(x-1,0,639))
	hr#=ground(wrap(x+1,0,639))
	xs=xs+((hr-hl)/10)		; the /10 reduces the amount of affect the ground has
	EndIf
	

Flip
Until KeyHit(1)


; create the ground
; this just creates a bunch of random places and cosine interpolates between them to create
; a rolling landscale.
Function createground()
steps#=50
fraction#=640/steps
gap#=640/fraction

old_random=Rand(0,100)
For x#=0 To fraction
	random=Rand(0,100)
	For n#=0 To 1 Step .001
		Color 0,255,0
		xx=Int((x*gap)+(n*gap))
		If xx>-1 And xx<640 Then ground(xx)=(cosine_interpolate(old_random,random,n))+300
		Next
	old_random=random
	Next
	
End Function
	
Function cosine_interpolate#(a#, b#, x#) 
	f#=(1-Cos(x*180))/2 
	Return a*(1-f)+(b*f) 
End Function

Function wrap(x,low,high)
	If x<low Then x=x+(high-low)
	If x>high Then x=x-(high-low)
	Return x
End Function



LarsG(Posted 2004) [#18]
Excellent little snippet you got there Rob.. :)


sswift(Posted 2004) [#19]
WillKoh:
Never look a gift horse in the mouth...

...Unless you're checking for sharp objects that might have an adverse affect on your plans for it later.


sswift(Posted 2004) [#20]
Btw, you're asking for something really complicated to do right. Hacking it though... Well you could do that. That's what Sega did.

What you need to do is detect when Sonic enters a loop, and then switch him to a mode where he'll follow the path of a circle.

First you need to know where the center of the loop is. That is Lx#, Ly#. Then you need to know the radius of the loop. That is the distance from the center to the edge. That is R#.

The equations then are:

X# = Lx# + R#*Cos(A#)
Y# = Ly# + R#*Sin(A#)

The problem is, what value should you use for A#? X# and Y# are the location to put Sonic at.

Now, when Sonic enters the loop, A# will be -90. You will need to increment that value as he goes around. At 0 he will be on the left of the loop, and at 90 he will be at the top of the loop. At 180 he is on the right, and at 270 he exits the loop.

But how much should you increment A# by each loop?

Well, that depends on two things. One, is Soncic's velocity. That is to say, how far does he move each second?

The second is, what is the distance betweem one degree and another on a circle?

The answer to that is this:
D# = (Pi#/180.0) * R#

Where pi is 3.14159265
And where R is the radius of our circle.

So now that we know how far sonic will move if he moves one degree on the circle, we can calculate how many degrees we should move him if we want to move him 10 pixels this frame, assuming the radius of our circle is in pixels.

So if V# is the number of pixels to move this frame, then A# is:

A# = V# / D#

So now we know all the variables for our first two equations. Except that you should know that A# here is just an increment for A for the above equations. In other words, add this A to the A from the last frame, using the current velocity of Sonic.

I leave the rest as an excerise for the reader. :-)