'Snake' game : type-based snake segments
Blitz3D Forums/Blitz3D Beginners Area/'Snake' game : type-based snake segments
| ||
| Okay, first off, I apologise in advance for posting the whole code. The reason for this is because I am really unsure of just where the issues may be, although it's most certainly in the movement and checkposition functions. Now, to the issue itself. As the code stands, it displays a simple menu screen wioth random snakes coiling around (set to change direction at random as well as on encounering other snakes). However, this doesn't seem to happen correctly and 'holes' appear within the snakes and eventually they seem to shrink up to just two segements. (possibly the multiple body segments' positions being equivalent to those of the head/tail.) As for the code: ; Removed (see below) "Keys.bb" is just to convert keycodes etc. for later redefining key options. The various fonts, sounds and images are not really important and can be replaced with substitutes. Again, sorry for posting so much code here, but I'm running out of ideas on how to deal with this... |
| ||
| Come on - help us help you! Make a version that runs without any media and exernal files and I'll happily take a look, otherwise forget it. Just a quick observation: your select case statement doesn't look right in the BuildSegments function. Not sure if this makes a difference - probably not. This : Select Iter Case Iter=1 Player\SegType=SEG_HEAD Case Iter=Size Player\SegType=SEG_TAIL Default Player\SegType=SEG_BODY End Select Should be : Select Iter Case 1 Player\SegType=SEG_HEAD Case Size Player\SegType=SEG_TAIL Default Player\SegType=SEG_BODY End Select |
| ||
| Thanks for taking the time to look, Stevie. I really appreciate it. Here's a version without any media/dependencies. I replaced the draw routine wit text line, so the snakes are visible on screen with their segments made from "O" characters. I changeed the case as above, but, it didnt seem to make a difference.
Graphics 800,600,32,2
SetBuffer BackBuffer()
SeedRnd MilliSecs()
;Include "keys.bb"
FlushMouse()
FlushKeys()
; Initialise
;Const Datafile_path$="Snkdat.DAT"
;Const SnakeImage_path$="Snkspr.jpg"
;Const WallImage_path$="Wllspr.jpg"
;Const FoodImage_path$="Eatspr.jpg"
Const SNAKE_TYPES=6
Const BANNER_L=5
Const BANNER_R=795
Const BANNER_T=5
Const BANNER_B=35
Const HIGHLIGHT_DIFF=1
Const HIGHLIGHT_START=2
Const HIGHLIGHT_MUS=3
Const HIGHLIGHT_SFX=4
Const HIGHLIGHT_KANT=5
Const HIGHLIGHT_KCLCK=6
Const TP_DIFF=85
Const LT_DIFF=275
Const BM_DIFF=170
Const RT_DIFF=575
Const TP_START=175
Const LT_START=300
Const BM_START=210
Const RT_START=515
Const TP_MUS=250
Const LT_MUS=295
Const BM_MUS=330
Const RT_MUS=527
Const TP_SFX=335
Const LT_SFX=215
Const BM_SFX=430
Const RT_SFX=630
Const TP_KANT=491
Const LT_KANT=173
Const BT_KANT=584
Const RT_KANT=390
Const TP_KCLCK=491
Const LT_KCLCK=526
Const BT_KCLCK=584
Const RT_KCLCK=658
Const SCREEN_TOP=40
Const SCREEN_BOTTOM=600
Const SCREEN_LEFT=0
Const SCREEN_RIGHT=800
Const TILE_MINX=0
Const TILE_MINY=0
Const TILE_MAXX=50
Const TILE_MAXY=35
Const TILE_SIZE=16
Const DIR_UP%=2
Const DIR_LEFT%=3
Const DIR_RIGHT%=0
Const DIR_DOWN%=1
Const CHG_ANTICLOCK=1
Const CHG_CLOCK=2
Const AHEAD_SAFE=0
Const AHEAD_WALL=1
Const AHEAD_FOOD=2
Const AHEAD_SNAKE=3
Const COL_GREEN=0
Const COL_BLUE=1
Const COL_PURPLE=2
Const COL_RED=3
Const COL_YELLOW=4
Const COL_MULTI=5
Const SEG_HEAD=1
Const SEG_BODY=0
Const SEG_TAIL=2
Const SNAKE_SPEED=1
Global Sfx=80
Global Music=70
Global Difficulty%=5
Global Stage=1
Global HiScore1%=250
Global HiScoreName1$="H I"
Global HiScore2%=100
Global HiScoreName2$="MUM"
Global HiScore3%=50
Global HiScoreName3$="..."
Global KeyClockWise%=25
Global KeyAntiClockWise%=16
Global CurrentScore=0;
;; Remove This!
;SaveData()
;LoadData()
;Custom Types
Type Snake
Field Reference
Field Direction%
Field Colour%
Field Length%
Field HeadX%
Field HeadY%
End Type
Type Segments
Field Reference%
Field Direction%
Field Daddy%
Field SegType%
Field X%
Field Y%
End Type
Type Changepoints
Field Daddy%
Field Direction%
Field X%
Field Y%
End Type
Dim Wall(TILE_MAXX+1,TILE_MAXY+1)
Global FoodX
Global FoodY
; Load Media
;Font = LoadFont("Year Supply Of Fairy Cakes.ttf",40,0,0,0)
;SetFont Font
;Global SegmentSprites=LoadAnimImage(SnakeImage_path$,TILE_SIZE,TILE_SIZE,0,SNAKE_TYPES)
;Global WallSprites=LoadAnimImage(WallImage_path$,TILE_SIZE,TILE_SIZE,0,1)
;Global FoodSprites=LoadAnimImage(SnakeImage_path$,TILE_SIZE,TILE_SIZE,0,2)
;Global Theme=LoadSound("Thmmus.wav")
;Global background=LoadImage("bcktile.jpg")
;Global system=LoadImage("system.bmp")
Global ticker=CreateImage(BANNER_R-BANNER_L,BANNER_B-BANNER_T)
SetBuffer ImageBuffer(ticker)
Cls
SetBuffer BackBuffer()
;Menu Setup
Global MenuOn=1
Global KeyOn=0
Global BANNER_TEXT$="WELCOME TO STARVING SNAKE 2009! "
Global Highlighted=HighlightMenuSelect(MouseX(),MouseY())
Global Bannerfeed=0
;LoopSound Theme
;Global Theme_Channel=PlaySound(Theme)
tempfloat#=Music
tempfloat#=tempfloat#/100.0
;ChannelVolume Theme_Channel,tempfloat#
For Iter=1 To Rand(5,15)
BuildSnake(Iter,Rand(3,10))
Next
For Master.Snake=Each Snake
Master\Direction=Rand(0,3)
Next
Flip
ClsColor 0,0,0
Cls
Global MoveDelay=MilliSecs()
; GO MENU!
While Not (KeyDown(KEY_ESCAPE))
; DrawImage background,0,0
Cls
For Master.Snake=Each Snake
If Rand(100) < 5 Then ChangeSnakeDirection(Master\Reference,Rand(1,2))
Next
If (MilliSecs()-MoveDelay)>333
MoveSnakes(MenuOn)
MoveDelay=MilliSecs()
End If
DrawSnakes()
; DrawImage system,0,0
DrawMenu()
Highlighted=HighlightMenuSelect(MouseX(),MouseY())
Color 255,0,255
; If KeyOn=0
; Text 327,535,ReturnKey$(KeyAntiClockWise),1,1
; Text 615,535,ReturnKey$(KeyClockWise),1,1
; End If
Text 400,138,ResolveDifficulty$(),1,1
Text 400,300,ResolveMusic$(),1,1
Text 400,393,ResolveSfx$(),1,1
If MouseDown(1)
If MilliSecs()-LastControl>100
LastControl=MilliSecs()
FlushMouse()
GetMenu()
End If
End If
Flip
Wend
;Start Game
Function StartGame()
UpdateBanner()
Stage=0;
DoNewLevel()
End Function
;Functions
Function DrawMenu()
HighlightOpt()
UpdateBanner()
DrawImageRect ticker,BanenerEdge,BANNER_T,BannerEdge-Bannerfeed,0,BANNER_R-BANNER_L,BANNER_B-BANNER_T
End Function
Function UpdateBanner()
Select Highlighted
Case HIGHLIGHT_DIFF
BANNER_TEXT="CHALLENGE LEVEL CHANGED TO "+ResolveDifficulty$()+" "
Case HIGHLIGHT_START
BANNER_TEXT="SCORE: "+CurrentScore+" HI SCORE: "+HiScore1+" STAGE: "+Stage+" "
Case HIGHLIGHT_MUS
BANNER_TEXT="MUSIC VOLUME CHANGED TO "+ResolveMusic$()+" "
Case HIGHLIGHT_SFX
BANNER_TEXT="SOUND EFFECTS VOLUME CHANGED TO "+ResolveSfx$()+" "
End Select
If KeyOn=1 Then BANNER_TEXT="PRESS A KEY FOR ANTICLOCKWISE "
If KeyOn=2 Then BANNER_TEXT="PRESS A KEY FOR CLOCKWISE "
If (BANNER_R-BannerEdge)>ImageWidth(ticker)
Bannerfeed=Bannerfeed+1
If Bannerfeed>ImageWidth(ticker)
Bannerfeed=1
BannerEdge=BANNER_R-1
End If
End If
If Highlighted<>0
SetBuffer ImageBuffer(ticker)
Cls
Color BannerFeed Mod 256,BannerFeed Mod 256,BannerFeed Mod 256
Text 0,(BANNER_B-BANNER_T)/2,BANNER_TEXT,False,True
SetBuffer BackBuffer()
End If
End Function
Function HighlightMenuSelect(X,Y)
If X<RT_DIFF And X>LT_DIFF And Y>TP_DIFF And Y<BM_DIFF Then Return HIGHLIGHT_DIFF
If X<RT_START And X>LT_START And Y>TP_START And Y<BM_START Then Return HIGHLIGHT_START
If X<RT_MUS And X>LT_MUS And Y>TP_MUS And Y<BM_MUS Then Return HIGHLIGHT_MUS
If X<RT_SFX And X>LT_SFX And Y>TP_SFX And Y<BM_SFX Then Return HIGHLIGHT_SFX
If X<RT_KANT And X>LT_KANT And Y>TP_KANT And Y<BM_KANT Then Return HIGHLIGHT_KANT
If X<RT_KCLCK And X>LT_KCLCK And Y>TP_KCLCK And Y<BM_KCLCK Then Return HIGHLIGHT_KCLCK
Return 0
End Function
Function HighlightOpt()
Color 224,224,224
Select Highlighted
Case HIGHLIGHT_DIFF
Rect LT_DIFF,TP_DIFF,RT_DIFF-LT_DIFF,BM_DIFF-TP_DIFF,0
Case HIGHLIGHT_START
Rect LT_START,TP_START,RT_START-LT_START,BM_START-TP_START,0
Case HIGHLIGHT_MUS
Rect LT_MUS,TP_MUS,RT_MUS-LT_MUS,BM_MUS-TP_MUS,0
Case HIGHLIGHT_SFX
Rect LT_SFX,TP_SFX,RT_SFX-LT_SFX,BM_SFX-TP_SFX,0
Case HIGHLIGHT_KANT
Rect LT_KANT,TP_KANT,RT_KANT-LT_KANT,BM_KANT-TP_KANT,0
Case HIGHLIGHT_KCLCK
Rect LT_KCLCK,TP_KCLCK,RT_KCLCK-LT_KCLCK,BM_KCLCK-TP_KCLCK,0
End Select
End Function
Function ResolveDifficulty$()
Select Difficulty
Case 1
Return "EASY-PEASY"
Case 2
Return "VERY EASY"
Case 3
Return "EASY"
Case 4
Return "NORMAL"
Case 5
Return "CHALLENGING"
Case 6
Return "TOUGH"
Case 7
Return "VERY TOUGH"
Case 8
Return "TAXING"
Case 9
Return "FRUSTRATING"
Case 10
Return "IMPOSSIBLE"
End Select
End Function
Function ResolveMusic$()
Val=Music/5
Select Val
Case 0 Return "SILENT"
Case 1 Return "INAUDIBLE"
Case 2 Return "WHISPER"
Case 3 Return "MOUSE"
Case 4 Return "RABBIT HUNTING"
Case 5 Return "VERY QUIET"
Case 6 Return "QUIET"
Case 7 Return "PEACEFUL"
Case 8 Return "BELOW NORMAL"
Case 9 Return "JUST BELOW NORMAL"
Case 10 Return "NORMAL"
Case 11 Return "A LITTLE LOUDER"
Case 12 Return "MORE AUDIBLE"
Case 13 Return "CLEAR"
Case 14 Return "HARD OF HEARING"
Case 15 Return "LOUD"
Case 16 Return "VERY LOUD"
Case 17 Return "SHOUT"
Case 18 Return "NOISY"
Case 19 Return "CACOPHONY"
Case 20 Return "DEAFENING"
End Select
End Function
Function ResolveSfx$()
Val=Sfx/5
Select Val
Case 0 Return "SILENT"
Case 1 Return "INAUDIBLE"
Case 2 Return "WHISPER"
Case 3 Return "MOUSE"
Case 4 Return "RABBIT HUNTING"
Case 5 Return "VERY QUIET"
Case 6 Return "QUIET"
Case 7 Return "PEACEFUL"
Case 8 Return "BELOW NORMAL"
Case 9 Return "JUST BELOW NORMAL"
Case 10 Return "NORMAL"
Case 11 Return "A LITTLE LOUDER"
Case 12 Return "MORE AUDIBLE"
Case 13 Return "CLEAR"
Case 14 Return "HARD OF HEARING"
Case 15 Return "LOUD"
Case 16 Return "VERY LOUD"
Case 17 Return "SHOUT"
Case 18 Return "NOISY"
Case 19 Return "CACOPHONY"
Case 20 Return "DEAFENING"
End Select
End Function
Function GetMenu()
Select Highlighted
Case HIGHLIGHT_DIFF
Difficulty=Difficulty+1
If Difficulty>10 Then Difficulty=1
Case HIGHLIGHT_START
StartGame()
Case HIGHLIGHT_MUS
Music=Music+5
If Music>100.0 Then Music=0
tempfloat#=Music
tempfloat#=tempfloat#/100.0
; ChannelVolume Theme_Channel,tempfloat#
Case HIGHLIGHT_SFX
Sfx=Sfx+5
If Sfx>100 Then Sfx=0
tempfloat#=Sfx
tempfloat#=tempfloat#/100.0
Case HIGHLIGHT_KANT
KeyOn=1
Case HIGHLIGHT_KCLCK
KeyOn=2
End Select
If Highlighted<>0 Then UpdateBanner()
FlushMouse()
FlushKeys()
End Function
Function AddSegmentToSnake(ReferenceNumber)
CountSegments=0
For Master.Snake=Each Snake
MasterReference=Master\Reference
If MasterReference=ReferenceNumber Then Exit
Next
SnakeLength=Master\Length
For IterSegments.Segments = Each Segments
If IterSegments\Daddy=MasterReference
CountSegments=IterSegments\Reference
If IterSegments\SegType=SEG_TAIL
Prev.Segments= Before IterSegments.Segments
PlaceAtX= Prev\X
PlaceAtY= Prev\Y
IterSegments\Reference=IterSegments\Reference+1
SetDir=Prev\Direction
Exit
End If
End If
Next
MoveSnakeExceptTail(ReferenceNumber)
SnakeLength=SnakeLength+1
NewSegment.Segments = New Segments
NewSegment\Reference=CountSegments
NewSegment\Daddy=MasterReference
NewSegment\Direction=SetDir
NewSegment\SegType=SEG_BODY
NewSegment\X=PlaceAtX
NewSegment\Y=PlaceAtY
Master\Length=SnakeLength
End Function
Function BuildSnake(ReferenceNumber,StartLength)
Player.Snake= New Snake
Player\Reference=ReferenceNumber
Player\Direction=DIR_RIGHT
Player\Colour%=Rand(COL_GREEN,COL_MULTI)
Player\Length%=StartLength
Player\HeadX%=((TILE_MAXX/2)+(Player\Length/2))
If (MenuOn)
Player\HeadY%=ReferenceNumber*2
Else
Player\HeadY%=((TILE_MAXY+-TILE_MINY)/2)
EndIf
BuildSegments(ReferenceNumber,StartLength)
End Function
Function BuildSegments(Ref,Size)
For Master.Snake=Each Snake
MasterReference=Master\Reference
If MasterReference=Ref Then Exit
Next
For Iter=1 To Size
Player.Segments = New Segments
Player\Reference=Iter
Player\Direction=Master\Direction
Player\Daddy=MasterReference
Select Iter
Case 1
Player\SegType=SEG_HEAD
Case Size
Player\SegType=SEG_TAIL
Default
Player\SegType=SEG_BODY
End Select
Player\X%=Master\HeadX-Iter
Player\Y%=Master\HeadY
Next
End Function
Function MoveSnakeExceptTail(Ref)
For Master.Snake=Each Snake
MasterReference=Master\Reference
If MasterReference=Ref
For IterSegments.Segments = Each Segments
If ((IterSegments\Daddy=MasterReference) And (IterSegments\SegType<>SEG_TAIL))
For iterTurn.Changepoints=Each Changepoints
If iterTurn\Daddy=MasterReference
If iterTurn\X=iterSegments\X And iterTurn\Y=iterSegments\Y
IterSegments\Direction=iterTurn\Direction
EndIf
EndIf
Next
MoveSegment(IterSegments.Segments)
If IterSegments\SegType=SEG_HEAD Then Master\HeadX=IterSegments\X: Master\HeadY=IterSegments\Y
If IterSegments\SegType=SEG_HEAD Then Master\Direction=IterSegments\Direction
End If
Next
Exit
EndIf
Next
End Function
Function MoveSnakeTail(Ref)
For Master.Snake=Each Snake
MasterReference=Master\Reference
If MasterReference=Ref Then Exit
Next
For IterSegments.Segments = Each Segments
If ((IterSegments\Daddy=MasterReference) And (IterSegments\SegType=SEG_TAIL))
For iterTurn.Changepoints=Each Changepoints
If iterTurn\Daddy=MasterReference
If iterTurn\X=iterSegments\X And iterTurn\Y=iterSegments\Y
IterSegments\Direction=iterTurn\Direction
Delete IterTurn
EndIf
EndIf
Next
MoveSegment(IterSegments.Segments)
End If
Next
End Function
Function CheckPosition(ReferenceNumber)
If ReferenceNumber=0 Then Return
For IterSegments.Segments = Each Segments
If IterSegments\Reference=ReferenceNumber
If IterSegments\X<TILE_MINX Then IterSegments\X=TILE_MAXX
If IterSegments\X>TILE_MAXX Then IterSegments\X=TILE_MINX
If IterSegments\Y<TILE_MINY Then IterSegments\Y=TILE_MAXY
If IterSegments\Y>TILE_MAXY Then IterSegments\Y=TILE_MINY
End If
Next
End Function
Function GetSegment.Segments(ReferenceNumber)
For IterSegments.Segments = Each Segments
If IterSegments\Reference=ReferenceNumber
Exit
End If
Next
Return IterSegments
End Function
Function GetSnake.Snake(ReferenceNumber)
For IterSnake.Snake = Each Snake
If IterSnake\Reference=ReferenceNumber
Exit
End If
Next
Return IterSnake
End Function
Function PixelX(X)
Return (X*TILE_SIZE)+SCREEN_LEFT
End Function
Function PixelY(Y)
Return (Y*TILE_SIZE)+SCREEN_TOP
End Function
Function DrawSnakes()
For iterSegs.Segments = Each Segments
Master.Snake=GetSnake.Snake(iterSegs\Daddy)
;DrawImage SegmentSprites,PixelX(iterSegs\X),PixelY(iterSegs\Y),Master\Colour
Color (((Master\Colour)+1)*32),(((Master\Colour)+1)*32),(((Master\Colour)+1)*32)
Text PixelX(iterSegs\X),PixelY(iterSegs\Y),"O"
Next
End Function
Function CheckNewLevel()
If CurrentScore>Difficulty*Stage*10
DoNewLevel()
End If
End Function
Function DoNewLevel()
Stage=Stage+1
GenerateWalls()
For AllSegs.Segments=Each Segments
Delete AllSegs
Next
For AllSnakes.Snake=Each Snake
Delete AllSnakes
Next
RespawnFood()
BuildSnake(1,Stage+2)
End Function
Function MoveSnakes(IgnoreBackground=False)
For Moving.Snake= Each Snake
MoveDir=Moving\Direction
AheadX=Moving\HeadX
AheadY=Moving\HeadY
Select MoveDir
Case DIR_UP
AheadY=((Moving\HeadY)-(SNAKE_SPEED))
Case DIR_DOWN
AheadY=((Moving\HeadY)+(SNAKE_SPEED))
Case DIR_LEFT
AheadX=((Moving\HeadX)-(SNAKE_SPEED))
Case DIR_RIGHT
AheadX=((Moving\HeadX)+(SNAKE_SPEED))
End Select
If AheadX<TILE_MINX Then AheadX=TILE_MAXX
If AheadX>TILE_MAXX Then AheadX=TILE_MINX
If AheadX<TILE_MINY Then AheadX=TILE_MAXY
If AheadX>TILE_MAXY Then AheadX=TILE_MINY
nRep=ReportTileLocation(AheadX,AheadY)
If (nRep=AHEAD_SNAKE) Then ChangeSnakeDirection(Moving\Reference,Rand(1,2))
If (nRep=AHEAD_WALL) Then ChangeSnakeDirection(Moving\Reference,Rand(1,2))
If (nRep<>AHEAD_FOOD) Then MoveSnakeExceptTail(Moving\Reference)
If (nRep=AHEAD_FOOD) Then EatFood(Moving\Reference)
MoveSnakeTail(Moving\Reference)
Next
End Function
Function ChangeSnakeDirection(ReferenceNumber,Change)
Player.Snake=GetSnake.Snake(ReferenceNumber)
NewDirection=GetNewDirection(Player\Direction,Change)
Turn.Changepoints=New Changepoints
Turn\Daddy=Player\Reference
Turn\Direction=NewDirection
Turn\X=Player\HeadX
Turn\Y=Player\HeadY
Player\Direction=NewDirection
End Function
Function GetNewDirection(OldDirection,DirectionChange)
Select OldDirection
Case DIR_UP
If DirectionChange=CHG_ANTICLOCK Then Return DIR_LEFT
If DirectionChange=CHG_CLOCK Then Return DIR_RIGHT
Case DIR_DOWN
If DirectionChange=CHG_ANTICLOCK Then Return DIR_RIGHT
If DirectionChange=CHG_CLOCK Then Return DIR_LEFT
Case DIR_LEFT
If DirectionChange=CHG_ANTICLOCK Then Return DIR_DOWN
If DirectionChange=CHG_CLOCK Then Return DIR_UP
Case DIR_RIGHT
If DirectionChange=CHG_ANTICLOCK Then Return DIR_UP
If DirectionChange=CHG_CLOCK Then Return DIR_DOWN
End Select
End Function
Function EatFood(EatingReference)
CurrentScore=CurrentScore+(Difficulty*Stage)/2
AddSegmentToSnake(EatingReference)
RespawnFood()
End Function
Function RespawnFood()
nTest=0
While nTest=0
FoodX=Rand(TILE_MAXX)
FoodY=Rand(TILE_MAXY)
nRep=ReportTileLocation(FoodX,FoodY)
If nRep=AHEAD_FOOD Then nTest=1
Wend
End Function
Function ReportTileLocation(X,Y)
If X>TILE_MAXX Then X=MINX
If Y>TILE_MAXY Then Y=MINY
If X<TILE_MINX Then X=TILE_MAXX
If Y<TILE_MINY Then Y=TILE_MAXY
If Wall(X,Y)=1 Then Return AHEAD_WALL
If FoodX=X And FoodY=Y Then Return AHEAD_FOOD
For iter.Segments=Each Segments
If Iter\X=X And Iter\Y=Y
Return AHEAD_SNAKE
End If
Next
Return AHEAD_SAFE
End Function
Function GenerateWalls()
If Difficulty>7 Then AddBorderWall
If Difficulty>5 Or Stage>5
For f=1 To Difficulty-5
X=Rand(TILE_MAXX/4)
Y=Rand(TILE_MAXY/6)
PlaceWallAtCoord(X,Y)
Next
End If
End Function
Function AddBorderWall()
If Difficulty>7
For iter=0 To ((TILE_MAXX/2)-1)
SetWall(iter,0)
SetWall(iter,TILE_MAXY)
If iter<=TILE_MAXY
SetWall(0,iter)
SetWall(TILE_MAXX,iter)
End If
Next
For iter=((TILE_MAXX/2)+1) To TILE_MAXX
SetWall(iter,0)
SetWall(iter,TILE_MAXY)
If iter<=TILE_MAXY
SetWall(0,iter)
SetWall(TILE_MAXX,iter)
End If
Next
End If
End Function
Function PlaceWallAtCoord(X,Y)
MAX=(Difficulty)
DIRCTN=Rand(0,4)
MDX=0;
MDY=0;
Select DIRCTN
Case DIR_UP
If Y<MAX Then MAX=Y
MDY=-1
Case DIR_DOWN
If ((Y+MAX) >(TILE_MAXY/6)) Then MAX=((TILE_MAXY/6)-Y)
MDY=1
Case DIR_LEFT
If X<MAX Then MAX=X
MDX=-1
Case DIR_RIGHT
If ((X+MAX) >(TILE_MAXX/4)) Then MAX=((TILE_MAXX/4)-X)
MDX=1
End Select
LNTH=Rand(1,MAX)
For iterate=0 To MAX
SetWall(X,Y)
X=X+MDX
Y=Y+MDY
Next
End Function
Function SetWall(X,Y)
Wall(X,Y)=1
Wall(TILE_MAXX-X,TILE_MAXY-Y)=1
Wall(X,TILE_MAXY-Y)=1
Wall(X-TILE_MAXX,Y)=1
End Function
Function SaveData()
Datafile=WriteFile(Datafile_path$)
WriteInt(Datafile,Sfx%)
WriteInt(Datafile,Music%)
WriteInt(Datafile,Difficulty%)
WriteInt(Datafile,HiScore1)
WriteString(Datafile,HiScoreName1$)
WriteInt(Datafile,HiScore2)
WriteString(Datafile,HiScoreName2$)
WriteInt(Datafile,HiScore3)
WriteString(Datafile,HiScoreName3$)
WriteInt(Datafile,KeyClockWise%)
WriteInt(Datafile,KeyAntiClockWise)
CloseFile Datafile
End Function
Function MoveSegment(Segment.Segments)
Select Segment\Direction
Case DIR_UP
Segment\Y=((Segment\Y)-(SNAKE_SPEED))
Case DIR_DOWN
Segment\Y=((Segment\Y)+(SNAKE_SPEED))
Case DIR_LEFT
Segment\X=((Segment\X)-(SNAKE_SPEED))
Case DIR_RIGHT
Segment\X=((Segment\X)+(SNAKE_SPEED))
End Select
CheckPosition(Segment\Reference)
End Function
Function LoadData()
; Datafile=ReadFile(Datafile_path$)
; Sfx%=ReadInt(Datafile)
; Music%=ReadInt(Datafile)
; Difficulty%=ReadInt(Datafile)
; HiScore1%=ReadInt(Datafile)
; HiScore1Name$=ReadString(Datafile)
; HiScore2%=ReadInt(Datafile)
; HiScore2Name$=ReadString(Datafile)
; HiScore3%=ReadInt(Datafile)
; HiScore3Name$=ReadString(Datafile)
; KeyClockWise%=ReadInt(Datafile)
; KeyAntiClockWise%=ReadInt(Datafile)
; CloseFile Datafile
End Function |
| ||
For some reason, although when I edit the post, the code is all present, it doesn''t all display. So here's the last half of the above in case it's not visible:
Function GetNewDirection(OldDirection,DirectionChange)
Select OldDirection
Case DIR_UP
If DirectionChange=CHG_ANTICLOCK Then Return DIR_LEFT
If DirectionChange=CHG_CLOCK Then Return DIR_RIGHT
Case DIR_DOWN
If DirectionChange=CHG_ANTICLOCK Then Return DIR_RIGHT
If DirectionChange=CHG_CLOCK Then Return DIR_LEFT
Case DIR_LEFT
If DirectionChange=CHG_ANTICLOCK Then Return DIR_DOWN
If DirectionChange=CHG_CLOCK Then Return DIR_UP
Case DIR_RIGHT
If DirectionChange=CHG_ANTICLOCK Then Return DIR_UP
If DirectionChange=CHG_CLOCK Then Return DIR_DOWN
End Select
End Function
Function EatFood(EatingReference)
CurrentScore=CurrentScore+(Difficulty*Stage)/2
AddSegmentToSnake(EatingReference)
RespawnFood()
End Function
Function RespawnFood()
nTest=0
While nTest=0
FoodX=Rand(TILE_MAXX)
FoodY=Rand(TILE_MAXY)
nRep=ReportTileLocation(FoodX,FoodY)
If nRep=AHEAD_FOOD Then nTest=1
Wend
End Function
Function ReportTileLocation(X,Y)
If X>TILE_MAXX Then X=MINX
If Y>TILE_MAXY Then Y=MINY
If X<TILE_MINX Then X=TILE_MAXX
If Y<TILE_MINY Then Y=TILE_MAXY
If Wall(X,Y)=1 Then Return AHEAD_WALL
If FoodX=X And FoodY=Y Then Return AHEAD_FOOD
For iter.Segments=Each Segments
If Iter\X=X And Iter\Y=Y
Return AHEAD_SNAKE
End If
Next
Return AHEAD_SAFE
End Function
Function GenerateWalls()
If Difficulty>7 Then AddBorderWall
If Difficulty>5 Or Stage>5
For f=1 To Difficulty-5
X=Rand(TILE_MAXX/4)
Y=Rand(TILE_MAXY/6)
PlaceWallAtCoord(X,Y)
Next
End If
End Function
Function AddBorderWall()
If Difficulty>7
For iter=0 To ((TILE_MAXX/2)-1)
SetWall(iter,0)
SetWall(iter,TILE_MAXY)
If iter<=TILE_MAXY
SetWall(0,iter)
SetWall(TILE_MAXX,iter)
End If
Next
For iter=((TILE_MAXX/2)+1) To TILE_MAXX
SetWall(iter,0)
SetWall(iter,TILE_MAXY)
If iter<=TILE_MAXY
SetWall(0,iter)
SetWall(TILE_MAXX,iter)
End If
Next
End If
End Function
Function PlaceWallAtCoord(X,Y)
MAX=(Difficulty)
DIRCTN=Rand(0,4)
MDX=0;
MDY=0;
Select DIRCTN
Case DIR_UP
If Y<MAX Then MAX=Y
MDY=-1
Case DIR_DOWN
If ((Y+MAX) >(TILE_MAXY/6)) Then MAX=((TILE_MAXY/6)-Y)
MDY=1
Case DIR_LEFT
If X<MAX Then MAX=X
MDX=-1
Case DIR_RIGHT
If ((X+MAX) >(TILE_MAXX/4)) Then MAX=((TILE_MAXX/4)-X)
MDX=1
End Select
LNTH=Rand(1,MAX)
For iterate=0 To MAX
SetWall(X,Y)
X=X+MDX
Y=Y+MDY
Next
End Function
Function SetWall(X,Y)
Wall(X,Y)=1
Wall(TILE_MAXX-X,TILE_MAXY-Y)=1
Wall(X,TILE_MAXY-Y)=1
Wall(X-TILE_MAXX,Y)=1
End Function
Function SaveData()
Datafile=WriteFile(Datafile_path$)
WriteInt(Datafile,Sfx%)
WriteInt(Datafile,Music%)
WriteInt(Datafile,Difficulty%)
WriteInt(Datafile,HiScore1)
WriteString(Datafile,HiScoreName1$)
WriteInt(Datafile,HiScore2)
WriteString(Datafile,HiScoreName2$)
WriteInt(Datafile,HiScore3)
WriteString(Datafile,HiScoreName3$)
WriteInt(Datafile,KeyClockWise%)
WriteInt(Datafile,KeyAntiClockWise)
CloseFile Datafile
End Function
Function MoveSegment(Segment.Segments)
Select Segment\Direction
Case DIR_UP
Segment\Y=((Segment\Y)-(SNAKE_SPEED))
Case DIR_DOWN
Segment\Y=((Segment\Y)+(SNAKE_SPEED))
Case DIR_LEFT
Segment\X=((Segment\X)-(SNAKE_SPEED))
Case DIR_RIGHT
Segment\X=((Segment\X)+(SNAKE_SPEED))
End Select
CheckPosition(Segment\Reference)
End Function
Function LoadData()
; Datafile=ReadFile(Datafile_path$)
; Sfx%=ReadInt(Datafile)
; Music%=ReadInt(Datafile)
; Difficulty%=ReadInt(Datafile)
; HiScore1%=ReadInt(Datafile)
; HiScore1Name$=ReadString(Datafile)
; HiScore2%=ReadInt(Datafile)
; HiScore2Name$=ReadString(Datafile)
; HiScore3%=ReadInt(Datafile)
; HiScore3Name$=ReadString(Datafile)
; KeyClockWise%=ReadInt(Datafile)
; KeyAntiClockWise%=ReadInt(Datafile)
; CloseFile Datafile
|
| ||
| I found the snake game to be tricky, as their is so many different ways to do it. What i did was to have temp variables holding the positions when moving each segment: The below is assuming the snakes are tile based. And your not giving each snake a head and a tail. I've found this to be pointless. Make the head the first item in the type collection and it will always be the first move_to_x = the co-ords you want your snake head to be moving to. move_to_y = same move_from_x ; these will record each pieces current position. move_from_y Start on first piece of the type collection. I'm assuming it's the head. Record it's current x-y position in the temp variables move_from_x and y. Move head to the co-ords held in the move_to_x and y vars. LOOP BACK TO BEGINNING So, in code, something like:
function move_snake(x,y) ; the co-ords to head is to move to
local move_to_x = x
local move_to_y = y
local move_from_x
local move_from_y
for snake_piece.snake = each snake
move_from_x = snake_piece\x
move_from_y = snake_piece\y
snake_piece\x = move_to_x
snake_piece\y = move_to_y
next
end function
That should move your whole snake. Your need check for new pieces being generated. The easiest way i reckon is to check in the actual function above, then set a flag, then generate at the end of the move function. Something like:
function move_snake(x,y) ; the co-ords to head is to move to
local move_to_x = x
local move_to_y = y
local move_from_x
local move_from_y
local head = 1
local status = 0 ; set to 2 generate new piece. 1 for collision with snake
for snake_piece.snake = each snake
if head = 1 then
status = check_head_collisions(move_to_x,move_to_y)
head = 0 ; unset the flag, as the head piece has been found
end if
move_from_x = snake_piece\x
move_from_y = snake_piece\y
snake_piece\x = move_to_x
snake_piece\y = move_to_y
screen_grid(move_to_x,move_to_y) = 1
screen_grid(move_from_x,move_from_y) = 0
next
if status = 2 then
snake_piece.snake = snake
snake_piece\x = move_from_x
snake_piece\y = move_from_y
screen_grid(snake_piece\x,snake_piece\y) = 1
elseif status = 1 then
;death???
end if
end function
function check_head_collisions(x,y)
return screen_grid(x,y)
End function
Where screen_grid is the 2d grid used to place everything. 0 = blank grid spot 1 = snake piece occupies 2 = pill to increase snake size. Does that help any? |
| ||
| Thanks for the reply, Ross. Actually, I have worked everything on a ggrid as suggested (references to "TILE_*" and "AHEAD_*" constants deal with the collision detection and grid squares. albeit in perhaps a clunky fashion, For certain reasons, I need more than one snake at a time, so setting the head to be the first instance in the Segment type isn't possible, that's why I included the "Daddy" field, as this links the segment tpe instances to their parent snake. The movement was split into two parts, MoveSnakeExceptTail() and MoveSnakeTail() so that segments could be added into the snake at the end before the tail. The Head and 'eating' was dealt with in the MoveSnakeExceptTail() function as trhe Head segment could be checked here. However, the Head and Tail of each snake are always recognised by the type of segment, The defining of the Head and Tail is done within the "BuildSegments()" function, called on creation of new snakes. Moving the segments to the head piece is not enough in itself, for when the snake changes direction (at the head), all other segments will ONLY change direction when they reach the same point along the snake's length. THat's where the inclusion of the "Changepoints" Type comes in. (Also, a very inconvenient and problematic issue with the game!) |