Lap counting examples for racing games.

Started by kevin, June 08, 2012, 02:09:54 AM

Previous topic - Next topic

kevin

 Lap counting examples for racing games.

   This is one of the little things that's often required when developing a racing games.  Where the game needs to keep track of the player so they can't cheat and go backwards around a track to win.   There's a number of ways of doing this, but a perhaps the simplest that comes to mind would be quadrant tracking.    

   This example is going to build a mask of the quadrants the player has pasted through.  The moving character is simulated to be moving in an elliptical path.   To map the quadrants  we working out the angle between the center of the screen and the player.   We then divide this by 90 to give us a value that's in 0 to 3 ranges,  that i'm calling a sector.  So we're cutting the screen up into four 90 degree quadrants, or sectors.  

   To map the players progress around the track, we simply build a (power of two) mask from the sector.  So the four sectors become four bit switches merged together.  So we know when the character has completed a lap (by passing though all sectors) when the mask equals 15..  

Example #1 - Quadrant

PlayBASIC Code: [Select]
   RadiusX=350
RadiusY=200


CurrentSector =-1

Dim Colours(1)
Colours(0)=$334455
Colours(1)=$55455

Setfps 100

Do


; Draw the backdrop
DrawBackDrop()



; plot a mock path that our game character is moving around the track
x#=400+Cos(ObjectAngle#)*RadiusX
y#=300+Sin(ObjectAngle#)*RadiusY
Circle x#,y#,30,true
ObjectAngle#=wrapangle(ObjectAngle#+1)


; get the angle from the center of the track to the character
SectorAngle#=GetAngle2d(400,300,x#,y#)

; divide this angle by 90 to split the screen up into four 90degree sectors
Sector=floor(SectorAngle#)/90


; check if the sector we're currently in, is equal to the next sector
if mod(CurrentSector+1,4)=Sector

; Set the current sector
CurrentSector=Sector

; Use Sector of power of 2, a binary switch in other words
; So we can merge the 4 sector values into one flag
LapMask =LapMask or (2 ^ Sector)

; in order for the character to complete a lap it must pass through all sectors
; when this occurs the Lap Mask will equal 15
if LapMask = 15
LapCount++
LapMask=0
CurrentSector =-1

endif
endif

print "Angle#:"+Str$(SectorAngle#)
print "Sector:"+Str$(Sector)
print "LapMask %"+Right$(bin$(LapMask),4)
print "LapCount:"+Str$(LapCount)

Sync
loop




Psub DrawBackDrop()

Cls

; --------------------------------------------
; draw the backdrop to show the sectors
; --------------------------------------------
For lp=0 to 4
angle#=lp*90
x2#=400+cos(angle#)*600
y2#=300+sin(angle#)*600
if lp>0
c=Colours((lp and 1))
tric x1#,y1#,x2#,y2#,400,300,c
endif

x1#=x2#
y1#=y2#

next

; draw a starting line thing
linec 400,0,400,300,$ff0000

EndPsub





Example #2 - Gates

  in this example we're using a series of gates placed around the track that the player is required to pass through in order to complete a lap around the circuit (shown here as an oval).  The gates are just line fragments.   To detect if the player has moved through a gate, we're using line intersection against a circle.  The circle is representing the game character in this example.   Each time we pass through a gate the program bumps the NextGate counter forward to the next gate.   So the player is required to pass through the gates in order to complete a lap.   Obviously in a real game we've got make sure that the game keeps the player inside the track.  As if they can skip around a gate, it'd lose track of the lap.  

PlayBASIC Code: [Select]
   RadiusX=350
RadiusY=200

CurrentSector =-1

Dim Colours(1)
Colours(0)=$334455
Colours(1)=$55455



; Create a list of gates that the character will need to pass through
Type tGate
x1#,y1#
x2#,y2#
EndType

Dim Gate(7) as tGate

Init_Gates()



Setfps 100

Do


; Draw the backdrop
DrawBackDrop()

; draw the gates
Draw_Gates(NextGate)


; plot a mock path that our game character is moving around the track
x#=400+Cos(ObjectAngle#)*RadiusX
y#=300+Sin(ObjectAngle#)*RadiusY
Circle x#,y#,30,true
ObjectAngle#=wrapangle(ObjectAngle#+1)

; Check if the player hit the next gate
if player_Hit_Next_Gate(x#,y#,30,NextGate)

; bump the next gate through the set
NextGate=mod(nextGate+1,GetArrayElements(Gate())+1)

; The next gate will roll over to zero when we're
; gone all the way through them
if NextGate=0
; bump the lap counter
LapCount++
endif

endif

; Display info
print "Next Gate:"+Str$(NextGate)
print "LapCount:"+Str$(LapCount)

Sync
loop



Psub Init_Gates()

size=Getarrayelements(Gate())

For lp=0 to size
angle#=(360/(Size+1))*lp

Gate(lp) = New tGate
Gate(lp).x1#=400+cos(angle#)*100
Gate(lp).y1#=300+sin(angle#)*100
Gate(lp).x2#=400+cos(angle#)*600
Gate(lp).y2#=300+sin(angle#)*600
next

EndPsub



Psub Draw_Gates(NextGate)
size=Getarrayelements(Gate())
For lp=0 to size
angle#=(360/(Size+1))*lp
c=$00ff00
if (lp=NextGate)
c=$ff0000
endif
linec Gate(lp).x1#,Gate(lp).y1#,_
Gate(lp).x2#,Gate(lp).y2#,c
next

EndPsub




Psub player_Hit_Next_Gate(Playerx#,playery#,Playerradius,NextGate)
x1#=Gate(NextGate).x1#
y1#=Gate(NextGate).y1#
x2#=Gate(NextGate).x2#
y2#=Gate(NextGate).y2#
Status=lineIntersectCircle(x1#,y1#,x2#,y2#,playerx#,playery#,PlayerRadius)
EndPsub Status





Psub DrawBackDrop()

Cls

; --------------------------------------------
; draw the backdrop to show the sectors
; --------------------------------------------
For lp=0 to 4
angle#=lp*90
x2#=400+cos(angle#)*600
y2#=300+sin(angle#)*600
if lp>0
c=Colours((lp and 1))
tric x1#,y1#,x2#,y2#,400,300,c
endif

x1#=x2#
y1#=y2#

next


EndPsub







Related Examples

   * Sliding Collision Around A Track

 


Video

   



   Music:  The Wish by Devon Church
   https://www.youtube.com/audiolibrary/music