UnderwareDESIGN

General => Competitions => CleverCoders => Topic started by: kevin on March 01, 2009, 06:44:35 AM

Title: Challenge #16 - Snake Game
Post by: kevin on March 01, 2009, 06:44:35 AM

(http://www.underwaredesign.com/PlayBasicSig.png) (http://www.playbasic.com)


Challenge #16 - Snake Game


     This is an another retro game remake challenge.  Your objective is to make your own version of the classic Snake / Tron game.    In your edition of  game,  the player will guide the snakes head in four directions using the keys or joy pad.  The snake is constantly moving,  it should never stop.   It can not move over/through itself or screen edges (or other walls).   So if it's moving left,  the player would die if they try to move right. 

    The objective is to guide to snake (without touching it self or the walls) to pick up a food items.  You pick up items by running into them with the snakes head.  With each item the snake eats,  it grows one link longer.     Food items should appear randomly on the screen, for a random amount of time, before moving to another location.  So the player has to react quickly to collect them.  As an added bonus the player could have a health bar,  indicating how it's been since the player last ate.  if the bar runs out, the snake dies from starvation.

    While a very simple game on the surface,  it includes a number of good challenges for new game programmers.  Namely , getting your head around object management.  So you're going to have to build some code to cope with managing the various food items objects, the snakes growing length and the collisions between the snake and the food and snake and itself... 

     As with all challenges, the visuals/physics are not important, the challenge here is core game mechanic.  Good luck


Reference Materials

  Epic Snake (http://www.eipcprograms.com/product.php?id=20)



Submission

* Submissions can be written in any version of PlayBasic (http://www.playbasic.com)

* Submission can only be accepted in Source Code form only.

* Authors can use external Media (images/music) provided you created the media/and or have permission to distribute the includes media or the Media is in the public domain.

* Zip up your Submissions and please try to keep it smaller than 500K !

* Authors automatically give consent for their submission(s) to distributed and used for promotional purposes via UnderwareDesign.com, PlayBasic code tank.

* Authors can submit as many times as they like.

* To make a submission, zip up your projects source code + media and either post it in this thread, or create your own thread in either the Source Codes or Show Case forums and post a link bellow.



Dead Line

Anytime before the next ice age



Prizes

     * The Best submissions will be periodically highlighted through the Playbasic IDE news service. 




Return to Challenge Index (http://www.underwaredesign.com/forums/index.php?topic=3225.0)



Title: Re: Challenge #16 - Snake Game
Post by: Big C. on March 06, 2009, 03:50:14 PM
ok here is my mockup...

[pbcode]
; PROJECT : Snake-Challenge-Light
; AUTHOR  : Big C.
; CREATED : 03.03.2009
; EDITED  : 08.03.2009
; ---------------------------------------------------------------------

RemStart
Your task is to guide the snake so it eats the food.
The quicker you eat, the more you score.
And just like real food-eating snakes, the more you gobble,
the longer you become.  Try To steer clear of your own
growing tail (and avoid the walls in a future version)...
it won't be long before it's game over.

Features:

08.03.09 V0.02
-  If it's moving left, the player would die if they try to move right.
-  It can not move through screen edges.
-  Some minor changes

06.03.09 V0.01
-  The player will guide the snakes head in four directions using the keys
-  The snake is constantly moving,  it should never stop.
-  It can not move over/through itself
-  Food items should appear randomly on the screen
-  Pick up items by running into them with the snakes head
-  With each item the snake eats,  it grows one link longer.

ToDo's:
-  It can not move through other ingame walls (in future version).
-  Food items should appear for a random amount of time, before moving to another location.
-  Bonus: The player could have a health bar,  indicating how it's been since the player last ate.
          If the bar runs out, the snake dies from starvation.

RemEnd

OpenScreen 640,480,16,1

TitleScreen "Challenge #16 - Snake Game coded with PB V1.64i - V0.02"

Constant North = 1
Constant East = 2
Constant South = 3
Constant West = 4

Global Direction = East

Global Head_X = 15   ;starting X-Point of our Snake-Head
Global Head_Y = 12   ;starting Y-Point of our Snake-Head
Global Food_X = RndRange(0, 63)
Global Food_Y = RndRange(0, 47)

Global Eat = 0
Global Score = 0
Global Size = 0
Global GameOver = 0

Global GetTime
Global LastMove = 0

; This Type define the position of body item
Type TSnake
   PosX
   PosY
EndType

;create a Linked List for the snakebody
Dim Snake As TSnake List

;our snake-body has 5 items
/*For I = 0 To 4
   Snake = New TSnake
   Snake.PosX = Head_X - 5 + I
   Snake.PosY = Head_Y
Next I*/

Psub CheckInput()
   ;check for North and not South
   If UpKey()
      If Direction <> South
         Direction = North
      Else
         GameOver = 1
      EndIf
   EndIf
   
   ;check for East and not West
   If RightKey()
      If Direction <> West
         Direction = East
      Else
         GameOver = 1
      EndIf
   EndIf
   
   ;check for South and not North
   If DownKey()
      If Direction <> North
         Direction = South
      Else
         GameOver = 1
      EndIf
   EndIf
   
   ;check for West and not East
   If LeftKey()
      If Direction <> East
         Direction = West
      Else
         GameOver = 1
      EndIf
   EndIf
EndPsub

Psub MoveSnake()
   GetTime = Timer()
   ;slow down the speed... after 75 millisec snake is moving
   If (GetTime - LastMove) > 75
      LastMove = GetTime
   
      ;check if snake has found something to eat
      If Head_X = Food_X And Head_Y = Food_Y
         Food_X = RndRange(0, 63)
         Food_Y = RndRange(0, 47)
         Eat = 1
         Score = Score + 10
      Else
         Eat = 0
      EndIf    
      
      ;here we let snake growing... Everytime snake head is moving
      ;to a new tile create a new type instance
      Snake = New TSnake
      Snake.PosX = Head_X
      Snake.PosY = Head_Y
      
      Head_X = Head_X - (Direction=West) + (Direction=East)
      Head_Y = Head_Y - (Direction=North) + (Direction=South)
      
      If Head_X < 0 Or Head_X > 64 Or Head_Y < 0 Or Head_Y > 48
         GameOver = 1
      EndIf

      /*If Head_X < 0 Then Head_X = 63
      If Head_X > 63 Then Head_X = 0
      If Head_Y < 0 Then Head_Y = 47
      If Head_Y > 47 Then Head_Y = 0*/

      
      ;nothing found to eat... ok delete the first (and oldest) listed entry
      ;to simulate a moving ;)
      If Eat = 0
         For Each Snake()
            If GetListNext(Snake()) = -1   
               Snake = NULL
            EndIf
         Next
      EndIf
      
      Size = GetListSize(Snake())
      
   EndIf
EndPsub

Psub CheckCollision()
   ;check if snake collide with his body
   For Each Snake()
      If Head_X = Snake.PosX And Head_Y = Snake.PosY
         GameOver = 1
      EndIf
   Next
EndPsub

Psub DrawSnake()
   ;Drawing Body
   For Each Snake()
      Ink RGB(127,127,127)
      Box Snake.PosX*10,Snake.PosY*10,(Snake.PosX*10)+10,(Snake.PosY*10)+10,1
   Next
   
   ;Drawing the Head of Snake
   Ink RGB(255,255,255)
   Box Head_X*10,Head_Y*10,(Head_X*10)+10,(Head_Y*10)+10,1
   
   ;Drawing Food
   Ink RGB (255,255,0)
   Box Food_X*10,Food_Y*10,(Food_X*10)+10,(Food_Y*10)+10,1
   
   ;Writing Score
   Ink RGB(255,255,255)
   Text 0, 0, "Score: " + Str$(Score)
   Text 0, 15, "Body Size: " + Str$(Size)
EndPsub

;the Main GameLoop
Repeat
   Cls RGB(0,0,0)
   CheckCollision()
   If GameOver
      Ink RGB(255,255,255)
      CenterText 320, 240, "G A M E  O V E R"
      Sync
      FlushKeys
      WaitKey
      End
   EndIf
   CheckInput()
   MoveSnake()
   DrawSnake()
   Sync
Until EscKey()
End
[/pbcode]

For better understanding what is happend if snake didn't find to eat and is moving his body here is my testcode to check the Linked List.

[pbcode]
; PROJECT : Project1
; AUTHOR  : Big C.
; CREATED : 06.03.2009
; EDITED  : 06.03.2009
; ---------------------------------------------------------------------

Type TTest
   Number
   Item$
EndType

Dim Test As TTest List

Global i = 0

Do
   Cls 0
   Print "Up Arrow Key: New Object"
   Print "Down Arrow Key: Delete First Item"
   
   If UpKey()
      i = i + 1
      Test = New TTest
      Test.Number = i
      Test.Item$ = "Item"+Str$(i)
      FlushKeys
   EndIf
   
   If DownKey()
      For Each Test()
         If GetListNext(Test()) = -1   
            First = GetListFirst(Test())
            Item = GetListPos(Test())
            Test = NULL
         EndIf
      Next
      FlushKeys
   EndIf
      
   Print "ListSize: " + Str$(GetListSize(Test())) + "   First: " + Str$(First) + "    Pos: " + Str$(Item)
      
   For Each Test()
       Print "Nr. " + Str$(Test.Number) + " Item: " + Test.Item$ + " Position: " + Str$(GetListPos(Test()))
   Next
   
   Sync
   
Loop
[/pbcode]

08.03.09 Updat to V0.02... two less ToDo's

Big C.

Title: Re: Challenge #16 - Snake Game
Post by: micky4fun on March 07, 2009, 07:58:36 AM
Hi Big C.

nice little demo , works very well , a 2 player version would be good i think , both players would have to race to pickup item while missing each other

thanks for posting code has help me a lot to understand the how segmant follows each other and more linked lists understanding

im going to give the challenge a go try and make a full game of it , but will post outcome if i get that far in the show case part of forum
as its not all my code , just modifyed snippets of playbasic demo's and would be totally unfair to this challenge..

thanks mick :)
Title: Re: Challenge #16 - Snake Game
Post by: Big C. on March 08, 2009, 04:27:23 AM
hey mick,

thx for comment...

Quotea 2 player version would be good i think

yes indeed but it increase the challenge requirements  ;)...  we will see...  :)

Hint for you: I've updated my entry post...

Big C.

Title: Re: Challenge #16 - Snake Game
Post by: micky4fun on March 08, 2009, 05:01:38 PM
Hi Big C.

Thanks for update , ile look forward to end result , nive to see how other coders do things , always pick up tips etc

thank for entry

mick :)
Title: Re: Challenge #16 - Snake Game
Post by: monkeybot on September 29, 2009, 05:03:28 PM
here is a snake i knocked up.

I can get to about 400...just

[pbcode]
; PROJECT : snake
; AUTHOR  : Monkeybot
; CREATED : 28/09/2009
; EDITED  : 29/09/2009
; ---------------------------------------------------------------------
;TODO
;Function display() change this to linked list
;
;
explicit on
constant startLevel=5
constant Debug=0
constant maxLength=2000
constant pillnum=9
Constant pillsize=5
Constant up=3
Constant down=1
Constant left=4
Constant right=2
local ws
if (screenmodeExist(800,600,16)) then ws=false
if(ScreenModeExist(1366,768,16)) then ws=true;;

if ws=true
  openscreen 1366,768,16,2
else
  openscreen 800,600,16,2
endif


global highscore=0
do
 global score=0
 global dead=0
 global gamespeed#=startlevel ;fps
 setfps(50)
 global gameloop=timer()
 global countdownTimer=timer()
 global radius#=10
 global sHeight=getscreenheight()
 global sWidth=getscreenwidth()
 global speed=(radius#*2)-2
 global length=6
 global count=0
 global dir=0
 global txtdisplay=0
 global time=0
 global txtX,txtY,txts$
 loadfont "ariel",1,40,1
 loadfont "ariel",2,20,1
 setfont 2
 type snakebody
    x,y,radius#,colour
 endtype

 type pills
    x,y,value,display
 endtype
 dim sb(maxLength) as snakebody
 dim pill1(pillnum) as pills
     prepSnake()
     preppills()

         repeat
              cls 0
              score=length+gamespeed#*10
              readkeys()
              if timer()>gameloop then dosnake()
              displaypills()
              checkpills()
              displaySnake()
              displayScore()
              if txtdisplay=1 then display()
              increaseDiff()
              if debug then debugInfo()
              displayframe()
              eyes()
                  ;circlec sb(0).x,sb(0).y,4,0,$f0f0f0
              sync
         until dead
     local x,y
     x=swidth/2
     y=sheight/2
     setfont 1
     cls 0
     ink $ff0000
     
     centertext x,y-40,"YOU ARE DEAD!!!!!!!"
     centertext x,y,"You got "+str$(score)
     if score>highscore then CenterText x,y+40,"Woooooo Highscore":highscore=score
     centertext x,y+80,"press any key or Escape to quit"
     sync
     wait 1000
     waitnokey
     waitkey
loop
function eyes()
   local x,y,angle#,xx#,yy#
   ;circlec sb(0).x,sb(0).y,4,0,$f0f0f0
   x=sb(0).x
   y=sb(0).y
   angle#=(dir-1)*90
   ink $ff00ff
   xx#= x+(sin(angle#))*10
   yy#= y+(cos(angle#))*10
   circle xx#,yy#,5,0
   line x,y,xx#,yy#
   ;circle (x+radius#)+sin(angle),(y+radius#)+cos(angle),5,0
endfunction

Function increaseDiff()
local l
    if timer()>countdownTimer
       if gamespeed#<10 then gamespeed#=gamespeed#+0.4;+l)
       countdownTimer=timer()+30000  
    endif
EndFunction

Function readkeys()
local k
shitter:
k=scancode()
   if k=200 then dir=up
   if k=208 then dir=down
   if k=203 then dir=left
   if k=205 then dir=right
   if k=57 and length<maxLength then length=length+1;:moveVars()
   if k=25 then waitnokey:waitkey
EndFunction


Function movevars()
local q
     for q=length-1 to 0 step-1          
         sb(q+1).x=sb(q).x
         sb(q+1).y=sb(q).y
        sb(q+1).radius#=sb(q).radius#
        sb(q+1).colour=sb(q).colour
        sb(q).colour=$00ff00
         
     next
EndFunction


Function displaySnake()
local q
ink sb(0).colour=$00ff00
   for q=0 to length
       ink sb(q).colour
       circle  sb(q).x,sb(q).y,sb(q).radius#,1
   next
EndFunction


Function dosnake()
   
local q
  moveVars()
     select dir
        case up
             sb(0).y=sb(0).y-speed
        case down
             sb(0).y=sb(0).y+speed
        case right
             sb(0).x=sb(0).x+speed
        case left
             sb(0).x=sb(0).x-speed
      endselect
   gameloop=timer()+((10-gamespeed#)*50);(100*gamespeed#);/gamespeed#))
   if gameloop-timer()<10 then gameloop=timer()+10
   checkcollision()
EndFunction

Function checkcollision()
local q,x,y,xx,yy
x=swidth/2
y=sheight/2
   
   xx=sb(0).x
   yy=sb(0).y
   if xx<20 or xx>swidth-20 then dead=1
   if yy<50 or yy>sheight-10 then dead=1   
    for q=1 to length
        if (circlesintersect( sb(0).x , sb(0).y , radius#-2 , sb(q).x , sb(q).y ,radius#-2) =1)
         dead=1
         exitfor  
        endif
    next
EndFunction

Function displayPills()
local q
ink $f0f0f0
   for q= 0 to pillNum
       if pill1(q).display=1 then circle pill1(q).x,pill1(q).y,5,0
   next
EndFunction

Function  checkpills()
local q,pillCount,value
   for q=0 to pillNum
    if pill1(q).display=0 then pillCount=pillCount+1
      if (circlesintersect( sb(0).x , sb(0).y , pillsize , pill1(q).x , pill1(q).y,radius#) =1) and pill1(q).display=1
          pill1(q).display=0
            value=pill1(q).value
          gamespeed#=gamespeed#+0.1
          length=length+value
          sb(1).radius#=radius#+(value/2)
          txtx=pill1(q).x
          txty=pill1(q).y
          txts$=str$(pill1(q).value)
          txtdisplay=true
          time=timer() +2000  
          display()
      endif
   next
   if pillCount>Pillnum then prepPills()
EndFunction

Function prepPills()
local q
     for q=0  to pillnum
         pill1(q).x=rndrange(50,sWidth-50)
         pill1(q).y=rndrange(80,sheight-50)
         pill1(q).value=1+rnd(14)
         pill1(q).display=1
     next
EndFunction

Function display()
   ;change this to linked list
        setfont 1
       if timer()>time then txtdisplay=false
       ink $ffff00
       text txtx,txty,"+"+txts$
EndFunction


Function prepSnake()
        sb(0).x=400;swidth/2
        sb(0).y=400;sheight/2
        dir=rndrange(1,4)
        sb(0).radius#=radius#
        sb(0).colour=$00ff00
EndFunction

Function displayScore()
local div,a$,b$,c$,d$,qw   ,w
         ink $ffffff
        setfont 1
        w=int(gamespeed#)
        a$="score:"+str$(score)
        b$="Speed:"+str$(w);gamespeed#)
        d$="highscore:"+str$(highscore)
        qw=gettextwidth(a$+d$)
        div=(swidth-qw)/4
        text 0,0,a$
        centertext swidth/2,0,b$
        text swidth-gettextwidth (d$),0,d$;"highscore:"+str$(highscore)      
EndFunction

function debugInfo()
   local w
        setfont 2
        ink $555555
        text 100,100,dir
        text 100,120,gameloop-timer();/1000
        text 100,140,"countdown:"+str$(-(timer()-countdownTimer)/1000)
        text 100,160,"length:"+str$(length)
        text 100,200,"x:"
        text 100,240,"y:"
        text 120+(w*30),200,sb(w).x
        text 120+(w*30),240,sb(w).y
endfunction

Function displayframe()
        boxc 0,40,swidth-1,sheight-1,0,$ffffff
EndFunction




[/pbcode]

Title: Re: Challenge #16 - Snake Game
Post by: Big C. on October 02, 2009, 03:08:21 PM
n1 one monkeybot and very fast  :)
Title: Re: Challenge #16 - Snake Game
Post by: kevin on October 03, 2009, 12:17:07 AM

Yeah, that's a good one.
Title: Re: Challenge #16 - Snake Game
Post by: micky4fun on October 03, 2009, 06:32:41 PM
Hi , monkeybot 

not quite got 400 yet , but nearly there ,, nice program

mick :)

Title: Re: Challenge #16 - Snake Game
Post by: monkeybot on October 04, 2009, 11:55:34 AM
Thanks for the comments. :)