'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!) |