Microsoft Small Basic
Program Listing:
Embed this in your website
<object id='sbapp' data='data:application/x-silverlight-2,' type='application/x-silverlight-2' width='640' height='480'> <param name='source' value='http://smallbasic.com/program/ClientBin/SBWeb.xap'/> <param name='onError' value='onSilverlightError' /> <param name='background' value='white' /> <param name='minRuntimeVersion' value='3.0.40624.0' /> <param name='autoUpgrade' value='true' /> <param name='initParams' value='programId=SNKBITE' /> </object>
' SNAKEBITE-SB
' by Davey~Wavey, v1 Nov. 2009
' Written for SmallBasic v0.7
'
' Inspired by the ZX81 game SNAKEBITE.
'
' Eat the snake by chewing off it's tail. Eat all tail segments to progress to next level.
' Watch out though, you may just make it angry!
'
' Use the cursor keys to move around. (You can press any other key to stop moving!)
' NOTE: If it crashes a lot, try commenting out the 'Sound.PlayChimes()' line. SB doesn't like sound!
'
' I've laid the code out so that all the normal routines used in a game are present. If you're
' learning to write your own game, a similar setup should work well for you. Have fun!
' set up the permanent loop (Q key terminates when on intro screen)
While
1
=
1
' initialise game environment
environment
(
)
' show intro
introScreen
(
)
While
lives
>
0
' INITIALISE LEVEL
' Next line won't play anything if we have already played the intro screen music!?!?!?!!!
' It also seems to cause the prog to crash more often when enabled.
'Sound.Play (progDir + "\muzak.mid")
levelConfig
(
)
' level maps can be found at end of program listing below - have fun designing some
paintLevel
(
)
snakeSetup
(
)
playerSetup
(
)
' MAIN LOOP
While
(
snakeSize
>
2
)
And
lives
>
0
' if snake 'change direction' delay has expired, try to change snake direction
If
snakeMoveDelay
=
0
Then
snakeDirection
(
)
' will only change direction at random times
moveSnake
(
)
EndIf
' alternative method to check for key press - also delays movement of player
If
playerMoveDelay
=
0
Then
checkKeys
(
)
movePlayer
(
)
' Check for PLAYER COLLISIONS
playerCollisions
(
)
EndIf
' ADJUST (or reset) DELAYS
' I admit this isn't the best way to do this.
' To get accurate speed, you should be calculating the
' frames-per-second and using that to slow various elements down.
If
snakeMoveDelay
>
0
Then
snakeMoveDelay
=
snakeMoveDelay
-
1
Else
snakeMoveDelay
=
level
[
thisLevel
]
[
"snakeDelay"
]
EndIf
If
playerMoveDelay
>
0
Then
playerMoveDelay
=
playerMoveDelay
-
1
Else
playerMoveDelay
=
playerDelay
EndIf
' test snake length increase - NOT CURRENTLY USED
'If Mouse.IsLeftButtonDown="True" AND processing=0 Then
' addSegment()
'ElseIf Mouse.IsLeftButtonDown="False" And processing=1 Then
' mUp()
'EndIf
EndWhile
' main level (or lives) loop
' next line is irrellevant as the Sound.Play command above doesn't work!
'Sound.Stop (progDir + "\muzak.mid")
' if we still have some lives, then we must have eaten all the snake
If
lives
>
0
Then
moveSnake
(
)
' update tail position since snake length just decreased
GraphicsWindow
.
ShowMessage
(
"YEAH, YOU BEAT THIS SNAKE!!!"
,
"WHOOPIE!"
)
' move to next level
thisLevel
=
thisLevel
+
1
' go back to level 1 if we've completed them all
If
thisLevel
>
levels
Then
thisLevel
=
1
EndIf
' increase player speed (by decreasing the delay) - player gets a slight advantage for each level cleared :-)
If
playerDelay
>
20
Then
playerDelay
=
playerDelay
-
10
EndIf
GraphicsWindow
.
Clear
(
)
EndIf
EndWhile
' lives > 0
' DEAD MEAT!
' next line doesn't work!
'Sound.Play (progDir + "\gameover.mid")
GraphicsWindow
.
ShowMessage
(
"THAT PUNKY SNAKE BEAT YOU THIS TIME!!! You scored: "
+
score
,
"EATEN!!!"
)
' next line is irrellevant as the Play command above doesn't work!
'Sound.Stop (progDir + "\gameover.mid")
EndWhile
' =====================================================================
' =====================================================================
' ====================== S U B R O U T I N E S ==============================
' =====================================================================
' =====================================================================
Sub
environment
' initialise the game environment
' progDir = Program.Directory + "\assets" ' this is used to locate the graphics and music used in the game
progDir
=
"http://smallbasic.com/drop/snakebite"
GraphicsWindow
.
Title
=
"~S~N~A~K~E~B~I~T~E~ v1 for SmallBasic by Davey~Wavey, Nov 2009"
GraphicsWindow
.
BackgroundColor
=
"Black"
GraphicsWindow
.
Width
=
800
' grass sprite is 128 x 128
GraphicsWindow
.
Height
=
600
' 4 x 128 plus status area
GraphicsWindow
.
Left
=
desktop
.
Width
/
2
-
(
GraphicsWindow
.
Width
/
2
)
' 800
GraphicsWindow
.
Top
=
desktop
.
Height
/
2
-
(
GraphicsWindow
.
Height
/
2
)
-
100
'50
gwTop
=
18
' set game window top offset
gwBottom
=
gwTop
+
(
4
*
128
)
gwLeft
=
(
GraphicsWindow
.
Width
/
2
)
-
(
3
*
128
)
' set game window left offset
gwRight
=
gwLeft
+
(
6
*
128
)
' initialise game environment
thisLevel
=
1
score
=
0
lives
=
5
playerDelay
=
500
' speed of player movement - lower value = faster player = easier (unless you go too fast!)
snakeMoveDelay
=
0
' this gets set by each level and is the speed of the snake - lower = faster
angrySnake
=
-
1
' a counter. if >0 it indicates that snake is angry (makes snake faster)
digestionDelay
=
0
' delay to prevent multiple tail pieces being eaten at once.
processing
=
0
' a flag used in sub processes to prevent multiple runs
player
=
""
' blank player array
snake
=
""
' blank snake array
'Timer.Interval = 2 ' set interval to check for key presses
'Timer.Tick = checkKeys
EndSub
' =====================================================================
Sub
introScreen
' display the game intro screen and wait for Space to be pressed
GraphicsWindow
.
Clear
(
)
' this Play command works, but then prevents any other music playing!?!?!
Sound
.
Play
(
progDir
+
"\intro.mid"
)
' show intro graphic
img
=
ImageList
.
LoadImage
(
progDir
+
"\titleScreen_800x600.jpg"
)
GraphicsWindow
.
DrawImage
(
img
,
0
,
0
)
' wait for keypress
lastkey
=
""
While
lastkey
<>
"Space"
lastkey
=
GraphicsWindow
.
LastKey
If
lastkey
=
"Q"
Then
Program
.
End
(
)
EndIf
EndWhile
Sound
.
Stop
(
progDir
+
"\intro.mid"
)
Program
.
Delay
(
500
)
EndSub
' =====================================================================
Sub
paintLevel
' draw the level objects at the start of each level
' create a black rectangle over the whole graphics window so we can create a fade effect after the level has been drawn
GraphicsWindow
.
BrushColor
=
"Black"
bbox
=
Shapes
.
AddRectangle
(
800
,
600
)
Shapes
.
SetOpacity
(
bbox
,
100
)
' draw dirt
img
=
ImageList
.
LoadImage
(
progDir
+
"\status_800x70.png"
)
For
y
=
0
to
600
Step
70
GraphicsWindow
.
DrawImage
(
img
,
0
,
y
)
EndFor
' draw the grass
img
=
ImageList
.
LoadImage
(
progDir
+
"\grass_128d.png"
)
For
x
=
0
To
5
For
y
=
0
To
3
GraphicsWindow
.
DrawImage
(
img
,
(
x
*
128
)
+
gwLeft
,
(
y
*
128
)
+
gwTop
)
EndFor
EndFor
' draw the flowers
img
=
ImageList
.
LoadImage
(
progDir
+
"\flower1_32.png"
)
Shapes
.
SetOpacity
(
img
,
20
)
For
x
=
1
To
20
GraphicsWindow
.
DrawImage
(
img
,
(
(
Math
.
GetRandomNumber
(
24
)
-
1
)
*
32
)
+
gwLeft
,
(
(
Math
.
GetRandomNumber
(
16
)
-
1
)
*
32
)
+
gwTop
)
EndFor
img
=
ImageList
.
LoadImage
(
progDir
+
"\flower2_32.png"
)
Shapes
.
SetOpacity
(
img
,
20
)
For
x
=
1
To
10
GraphicsWindow
.
DrawImage
(
img
,
(
(
Math
.
GetRandomNumber
(
24
)
-
1
)
*
32
)
+
gwLeft
,
(
(
Math
.
GetRandomNumber
(
16
)
-
1
)
*
32
)
+
gwTop
)
EndFor
' draw the level blocks
img
=
ImageList
.
LoadImage
(
progDir
+
"\wall_32.png"
)
For
my
=
1
To
16
For
mx
=
1
To
24
block
=
text
.
GetSubText
(
level
[
thisLevel
]
[
my
]
,
mx
,
1
)
' position WALLS
If
block
=
"W"
Then
GraphicsWindow
.
DrawImage
(
img
,
(
(
mx
-
1
)
*
32
)
+
gwLeft
,
(
(
my
-
1
)
*
32
)
+
gwTop
)
' DrawRectangle( (mx-1)*32, (my-1)*32, 32, 32 )
EndIf
' position PLAYER
If
block
=
"P"
Then
player
[
"x"
]
=
(
(
mx
-
1
)
*
32
+
12
)
+
gwLeft
' calculate x,y from 32 x 32 level grid blocks
player
[
"startX"
]
=
player
[
"x"
]
' remember start position for when player dies
player
[
"y"
]
=
(
(
my
-
1
)
*
32
+
12
)
+
gwTop
player
[
"startY"
]
=
player
[
"y"
]
EndIf
' position SNAKE
If
block
=
"S"
Then
level
[
thisLevel
]
[
"snakeX"
]
=
(
(
mx
-
1
)
*
32
+
16
)
+
gwLeft
level
[
thisLevel
]
[
"snakeY"
]
=
(
(
my
-
1
)
*
32
+
16
)
+
gwTop
EndIf
EndFor
EndFor
' draw the border (using the snake body part)
img
=
ImageList
.
LoadImage
(
progDir
+
"\body_18.png"
)
For
y
=
0
To
600
Step
530
For
x
=
5
to
790
Step
18
' draw top and bottom border
GraphicsWindow
.
DrawImage
(
img
,
x
,
y
)
EndFor
EndFor
For
x
=
0
To
800
Step
784
For
y
=
15
to
530
Step
18
' draw left and right border
GraphicsWindow
.
DrawImage
(
img
,
x
,
y
)
EndFor
EndFor
' show status bar
status
(
)
' fade the screen in
Shapes
.
Move
(
bbox
,
0
,
0
)
For
lwp
=
100
To
0
Step
-
1
Shapes
.
SetOpacity
(
bbox
,
lwp
)
Program
.
Delay
(
20
)
EndFor
EndSub
' =====================================================================
Sub
snakeSetup
' create the snake array and display snake in starting position
headPart
=
ImageList
.
LoadImage
(
progDir
+
"\head_24.png"
)
headAngryPart
=
ImageList
.
LoadImage
(
progDir
+
"\headAngry_24.png"
)
headSize
=
22
'24 ' radius of head
headOffset
=
11
bodyPart
=
ImageList
.
LoadImage
(
progDir
+
"\body_18.png"
)
bodySize
=
18
'18
bodyOffset
=
9
tailPart
=
ImageList
.
LoadImage
(
progDir
+
"\tail_16.png"
)
tailSize
=
16
'32 '16
tailOffset
=
8
snake
=
""
snake
[
0
]
[
"happySnake"
]
=
Shapes
.
AddImage
(
headPart
)
snake
[
0
]
[
"angrySnake"
]
=
Shapes
.
AddImage
(
headAngryPart
)
snakeSize
=
level
[
thisLevel
]
[
"snakeSize"
]
' this value will change during game as snake eats/is eaten
' remember current pen width
'pw = GraphicsWindow.PenWidth
'GraphicsWindow.PenWidth = 0
For
snakePart
=
1
to
snakeSize
' create the snake segments
If
snakePart
=
1
Then
'GraphicsWindow.BrushColor="Brown"
snake
[
snakePart
]
[
"sprite"
]
=
snake
[
0
]
[
"happySnake"
]
'Shapes.AddEllipse(headSize,headSize) ' head
' Zoom for this shape has been done above
ElseIf
snakePart
<>
snakeSize
Then
'GraphicsWindow.BrushColor="Chocolate"
snake
[
snakePart
]
[
"sprite"
]
=
Shapes
.
AddImage
(
bodyPart
)
'Shapes.AddEllipse(bodySize,bodySize) ' body
Else
'GraphicsWindow.BrushColor="SandyBrown"
snake
[
snakePart
]
[
"sprite"
]
=
Shapes
.
AddImage
(
tailPart
)
'Shapes.AddEllipse(tailSize,tailSize) ' tail
EndIf
' locate snake on screen - probably needs to be part of each level config
snake
[
snakePart
]
[
"x"
]
=
level
[
thisLevel
]
[
"snakeX"
]
snake
[
snakePart
]
[
"y"
]
=
level
[
thisLevel
]
[
"snakeY"
]
' as all segments start at the same x,y we must increment the initial delay for each successive segment
If
snakePart
>
2
Then
snake
[
snakePart
]
[
"delay"
]
=
(
(
snakePart
-
1
)
*
(
bodySize
-
4
)
)
+
4
Else
snake
[
2
]
[
"delay"
]
=
bodySize
'18
EndIf
EndFor
' set initial direction
snake
[
1
]
[
"moves"
]
=
level
[
thisLevel
]
[
"snakeDir"
]
snake
[
1
]
[
"delay"
]
=
"0"
' need to initialise delay for snake head - used to determine delay before direction change
' reinstate previous pen width
'GraphicsWindow.PenWidth=pw
EndSub
' =====================================================================
Sub
playerSetup
' create the player and display at start position
'GraphicsWindow.BrushColor="Lime"
img
=
ImageList
.
LoadImage
(
progDir
+
"\player2_24.png"
)
' from www.freeicons.dk
player
[
"sprite"
]
=
Shapes
.
AddImage
(
img
)
'Shapes.AddRectangle( 20,20 )
Shapes
.
Move
(
player
[
"sprite"
]
,
player
[
"x"
]
-
11
,
player
[
"y"
]
-
11
)
' -11 offset instead of -12 works better!?!?!
playerMoveDelay
=
playerDelay
' initialise player movement speed (delay)
EndSub
' =====================================================================
Sub
snakeDirection
' check if snake is ready for a CHANGE of DIRECTION
' using the 'delay' element of the snake head (snake[1]) as a counter for the change direction delay
' this delay gets decreased in the moveSnake sub
If
snake
[
1
]
[
"delay"
]
=
0
Then
' reset change direction delay
snake
[
1
]
[
"delay"
]
=
level
[
thisLevel
]
[
"dirDelay"
]
' yes, time for a direction change, but only 25% chance of changing
If
Math
.
GetRandomNumber
(
4
)
<>
3
Then
' not yet - leave the snake going the same way and delay another direction change for a while
snake
[
1
]
[
"delay"
]
=
level
[
thisLevel
]
[
"dirDelay"
]
Else
' yep, let's change direction
dir
=
Math
.
GetRandomNumber
(
4
)
' EDGE BOUNCE - if snake is heading into window edge, force a direction change
'If (dir = 1 And snake[1]["y"] < 20) Then
' dir = 3 ' go S
'EndIf
'If (dir = 3 And snake[1]["y"] > GraphicsWindow.Height-(20)) Then
' dir = 1 ' go N
'EndIf
'If (dir = 4 And snake[1]["x"] < 20) Then
' dir = 2 ' go E
'EndIf
'If (dir = 2 And snake[1]["x"] > GraphicsWindow.Width-(8+20)) Then
' dir = 4 ' go W
'EndIf
' point snake head in appropriate direction
snake
[
1
]
[
"moves"
]
=
dir
' reset delay until next direction change
snake
[
1
]
[
"delay"
]
=
level
[
thisLevel
]
[
"dirDelay"
]
EndIf
' ANGRY SNAKE calculation
' to slow this effect down, we're only trying to instigate 'angry mode' at each direction change
If
(
level
[
thisLevel
]
[
"getAngry"
]
=
1
)
Then
' only try to instigate angry mode in snake is currently happy
If
angrySnake
<
0
Then
'GraphicsWindow.Title="HAPPY SNAKE {:-)"
rn
=
Math
.
GetRandomNumber
(
100
)
If
(
rn
=
7
)
Then
angrySnake
=
Math
.
GetRandomNumber
(
50
)
+
20
level
[
thisLevel
]
[
"snakeDelay"
]
=
level
[
thisLevel
]
[
"snakeDelay"
]
/
2
EndIf
' if angrySnake counter has reached zero, reset snake speed back to normal
ElseIf
angrySnake
=
0
Then
level
[
thisLevel
]
[
"snakeDelay"
]
=
level
[
thisLevel
]
[
"snakeDelay"
]
*
2
' set snake delay back to level setting
EndIf
If
angrySnake
>
-
1
Then
angrySnake
=
angrySnake
-
1
' decrease angry snake counter
'GraphicsWindow.Title="ANGRY SNAKE }:-/"
EndIf
EndIf
EndIf
' change direction delay=0
EndSub
' =====================================================================
Sub
moveSnake
' move snake segments
For
snakePart
=
1
To
snakeSize
' find out which direction we're moving in
dir
=
text
.
GetSubText
(
snake
[
snakePart
]
[
"moves"
]
,
1
,
1
)
' check if head is about to collide with a wall
If
snakePart
=
1
Then
shapes
.
Rotate
(
snake
[
1
]
[
"sprite"
]
,
(
(
dir
-
1
)
*
90
)
)
' point snake head in correct direction
snakeCollisions
(
)
EndIf
' only move snakepart if it's delay is zero - or this is the head, which always gets moved
If
snakePart
=
1
Or
snake
[
snakePart
]
[
"delay"
]
=
0
Then
' take direction off moves list for this snake part
If
snakePart
>
1
Then
snake
[
snakePart
]
[
"moves"
]
=
Text
.
GetSubTextToEnd
(
snake
[
snakePart
]
[
"moves"
]
,
2
)
EndIf
' add this movement onto next snake part's movement list
If
snakePart
<
snakeSize
Then
snake
[
snakepart
+
1
]
[
"moves"
]
=
text
.
Append
(
snake
[
snakepart
+
1
]
[
"moves"
]
,
dir
)
EndIf
' update x,y co-ordinates of snake part
If
dir
=
1
Then
snake
[
snakePart
]
[
"y"
]
=
snake
[
snakePart
]
[
"y"
]
-
1
' moving N
ElseIf
dir
=
2
Then
snake
[
snakePart
]
[
"x"
]
=
snake
[
snakePart
]
[
"x"
]
+
1
' moving E
ElseIf
dir
=
3
Then
snake
[
snakePart
]
[
"y"
]
=
snake
[
snakePart
]
[
"y"
]
+
1
' moving S
ElseIf
dir
=
4
Then
snake
[
snakePart
]
[
"x"
]
=
snake
[
snakePart
]
[
"x"
]
-
1
' moving W
EndIf
' wrap snake at window edge
If
snake
[
snakePart
]
[
"x"
]
<
gwLeft
Then
snake
[
snakePart
]
[
"x"
]
=
gwRight
ElseIf
snake
[
snakePart
]
[
"x"
]
>
gwRight
Then
snake
[
snakePart
]
[
"x"
]
=
gwLeft
ElseIf
snake
[
snakePart
]
[
"y"
]
<
gwTop
Then
snake
[
snakePart
]
[
"y"
]
=
gwBottom
-
8
ElseIf
snake
[
snakePart
]
[
"y"
]
>
gwBottom
-
8
Then
snake
[
snakePart
]
[
"y"
]
=
gwTop
EndIf
EndIf
' The offsets allow for the various snake segment sizes
If
snakePart
=
1
Then
offset
=
headOffset
ElseIf
snakePart
<>
snakeSize
Then
offset
=
bodyOffset
Else
offset
=
tailOffset
EndIf
' DRAW SNAKE PART in new position
shapes
.
Move
(
snake
[
snakePart
]
[
"sprite"
]
,
snake
[
snakePart
]
[
"x"
]
-
offset
,
snake
[
snakePart
]
[
"y"
]
-
offset
)
' DECREASE SNAKE PART DELAY
If
snake
[
snakePart
]
[
"delay"
]
>
0
Then
snake
[
snakePart
]
[
"delay"
]
=
snake
[
snakePart
]
[
"delay"
]
-
1
EndIf
EndFor
' as snake gets shorter, processing speed increases, so we need to add a delay
If
snakeSize
<
7
Then
'level[thisLevel]["snakeSize"] Then
'For snakePart = snakeSize To level[thisLevel]["snakeSize"]
Program
.
Delay
(
0.2
*
(
level
[
thisLevel
]
[
"snakeSize"
]
-
snakeSize
)
)
'EndFor
EndIf
EndSub
' =====================================================================
Sub
snakeCollisions
' this is a recursive function
' it checks for a snake collision with a level object (i.e. a wall) in the current snake direction
' if it finds one, it chooses a new direction, then calls itself to check it for a collision
' after completing, 'dir' will have a direction that does not cause a collision
' Up
If
dir
=
1
Then
sx
=
math
.
Floor
(
(
snake
[
1
]
[
"x"
]
-
gwLeft
)
/
32
)
+
1
sy
=
math
.
Floor
(
(
(
snake
[
1
]
[
"y"
]
-
gwTop
)
-
(
headSize
/
2
)
)
/
32
)
+
1
If
Text
.
GetSubText
(
level
[
thisLevel
]
[
sy
]
,
sx
,
1
)
=
"W"
Then
' choose a new direction then check it for collisions by recursing this sub
dir
=
Math
.
GetRandomNumber
(
4
)
snakeCollisions
(
)
EndIf
' Down
ElseIf
dir
=
3
Then
sx
=
math
.
Floor
(
(
snake
[
1
]
[
"x"
]
-
gwLeft
)
/
32
)
+
1
sy
=
math
.
Floor
(
(
(
snake
[
1
]
[
"y"
]
-
gwTop
)
+
(
headSize
/
2
)
)
/
32
)
+
1
If
Text
.
GetSubText
(
level
[
thisLevel
]
[
sy
]
,
sx
,
1
)
=
"W"
Then
' choose a new direction then check it for collisions by recursing this sub
dir
=
Math
.
GetRandomNumber
(
4
)
snakeCollisions
(
)
EndIf
' Right
ElseIf
dir
=
2
Then
sx
=
math
.
Floor
(
(
(
snake
[
1
]
[
"x"
]
-
gwLeft
)
+
(
headSize
/
2
)
)
/
32
)
+
1
sy
=
math
.
Floor
(
(
snake
[
1
]
[
"y"
]
-
gwTop
)
/
32
)
+
1
If
Text
.
GetSubText
(
level
[
thisLevel
]
[
sy
]
,
sx
,
1
)
=
"W"
Then
' choose a new direction then check it for collisions by recursing this sub
dir
=
Math
.
GetRandomNumber
(
4
)
snakeCollisions
(
)
EndIf
' Left
ElseIf
dir
=
4
Then
sx
=
math
.
Floor
(
(
(
snake
[
1
]
[
"x"
]
-
gwLeft
)
-
(
headSize
/
2
)
)
/
32
)
+
1
sy
=
math
.
Floor
(
(
snake
[
1
]
[
"y"
]
-
gwTop
)
/
32
)
+
1
If
Text
.
GetSubText
(
level
[
thisLevel
]
[
sy
]
,
sx
,
1
)
=
"W"
Then
' choose a new direction then check it for collisions by recursing this sub
dir
=
Math
.
GetRandomNumber
(
4
)
snakeCollisions
(
)
EndIf
EndIf
' set snake in new safe direction
snake
[
1
]
[
"moves"
]
=
dir
EndSub
' =====================================================================
Sub
checkKeys
' indicate if player is to move
keyPress
=
GraphicsWindow
.
LastKey
EndSub
' =====================================================================
Sub
movePlayer
' depending on the key pressed, move the player in the required direction
' unless we hit the edge of the screen, or a wall
If
keyPress
<>
""
Then
' only process if a key was pressed
move
=
0
' initially prevent any movement
' CHECK LEFT
If
keyPress
=
"Left"
Then
px
=
math
.
Floor
(
(
(
player
[
"x"
]
-
13
)
-
gwLeft
)
/
32
)
+
1
' subtract 13 from x to allow for half sprite width offset
py
=
math
.
Floor
(
(
(
player
[
"y"
]
-
gwTop
)
)
/
32
)
+
1
' hit edge of screen?
If
player
[
"x"
]
-
13
>
gwLeft
Then
move
=
1
EndIf
' hit a wall?
If
Text
.
GetSubText
(
level
[
thisLevel
]
[
py
]
,
px
,
1
)
=
"W"
Then
move
=
0
EndIf
EndIf
' CHECK RIGHT
If
keyPress
=
"Right"
Then
px
=
math
.
Floor
(
(
(
player
[
"x"
]
+
13
)
-
gwLeft
)
/
32
)
+
1
py
=
math
.
Floor
(
(
player
[
"y"
]
-
gwTop
)
/
32
)
+
1
' hit edge of screen?
If
player
[
"x"
]
+
13
<
gwRight
Then
move
=
1
EndIf
' hit a wall?
If
Text
.
GetSubText
(
level
[
thisLevel
]
[
py
]
,
px
,
1
)
=
"W"
Then
move
=
0
EndIf
EndIf
' CHECK UP
If
keyPress
=
"Up"
Then
px
=
math
.
Floor
(
(
(
player
[
"x"
]
)
-
gwLeft
)
/
32
)
+
1
py
=
math
.
Floor
(
(
(
player
[
"y"
]
-
13
)
-
gwTop
)
/
32
)
+
1
' hit edge of screen?
If
player
[
"y"
]
-
13
>
gwTop
Then
move
=
1
EndIf
' hit a wall?
If
Text
.
GetSubText
(
level
[
thisLevel
]
[
py
]
,
px
,
1
)
=
"W"
Then
move
=
0
EndIf
EndIf
' CHECK DOWN
If
keyPress
=
"Down"
Then
px
=
math
.
Floor
(
(
(
player
[
"x"
]
)
-
gwLeft
)
/
32
)
+
1
py
=
math
.
Floor
(
(
(
player
[
"y"
]
+
13
)
-
gwTop
)
/
32
)
+
1
' hit edge of screen?
If
player
[
"y"
]
+
13
<
gwBottom
Then
move
=
1
EndIf
' hit a wall?
If
Text
.
GetSubText
(
level
[
thisLevel
]
[
py
]
,
px
,
1
)
=
"W"
Then
move
=
0
EndIf
EndIf
' ADJUST PLAYER LOCATION and rotate player to point the correct direction
If
keyPress
=
"Left"
Then
player
[
"x"
]
=
player
[
"x"
]
-
move
Shapes
.
Rotate
(
player
[
"sprite"
]
,
270
)
EndIf
If
keyPress
=
"Right"
Then
player
[
"x"
]
=
player
[
"x"
]
+
move
Shapes
.
Rotate
(
player
[
"sprite"
]
,
90
)
EndIf
If
keyPress
=
"Up"
Then
player
[
"y"
]
=
player
[
"y"
]
-
move
Shapes
.
Rotate
(
player
[
"sprite"
]
,
0
)
EndIf
If
keyPress
=
"Down"
Then
player
[
"y"
]
=
player
[
"y"
]
+
move
Shapes
.
Rotate
(
player
[
"sprite"
]
,
180
)
EndIf
' MOVE PLAYER SPRITE
Shapes
.
Move
(
player
[
"sprite"
]
,
player
[
"x"
]
-
11
,
player
[
"y"
]
-
11
)
keyPress
=
""
EndIf
EndSub
' =====================================================================
Sub
playerCollisions
' detect player colliding with various things
' detect player/snake tail collision
If
(
digestionDelay
<=
0
)
Then
' have no idea why I have to subtract 4 from the tailOffset calculations here!!
If
(
math
.
Abs
(
player
[
"x"
]
-
(
snake
[
snakeSize
]
[
"x"
]
-
tailOffset
)
-
4
)
<
10
)
And
(
Math
.
Abs
(
player
[
"y"
]
-
(
snake
[
snakeSize
]
[
"y"
]
-
tailOffset
)
-
4
)
<
10
)
AND
snake
[
snakeSize
]
[
"delay"
]
=
0
Then
digestionDelay
=
60
' don't allow another piece to be eaten for a while
' decrease snake length
snakeSize
=
snakeSize
-
1
shapes
.
Remove
(
snake
[
snakeSize
]
[
"sprite"
]
)
snake
[
snakeSize
]
[
"sprite"
]
=
snake
[
snakeSize
+
1
]
[
"sprite"
]
'level[thisLevel]["snakeDelay"] = level[thisLevel]["snakeDelay"] - (2*thisLevel) ' make snake faster each level - now set in level settings, therefore redundant here
Sound
.
PlayChimes
(
)
score
=
score
+
10
' increase player score
status
(
)
' update status area
EndIf
Else
digestionDelay
=
digestionDelay
-
1
' just decrease the delay
EndIf
' detect player/snake head collision
If
(
math
.
Abs
(
player
[
"x"
]
-
(
snake
[
1
]
[
"x"
]
-
headOffset
)
)
<
16
)
And
(
Math
.
Abs
(
player
[
"y"
]
-
(
snake
[
1
]
[
"y"
]
-
headOffset
)
)
<
16
)
Then
playerEaten
(
)
EndIf
EndSub
' =====================================================================
Sub
playerEaten
' when eaten, animate the player sprite for a while
Sound
.
PlayBellRing
(
)
lives
=
lives
-
1
status
(
)
' update status area
' set player back to their start location
player
[
"x"
]
=
player
[
"startX"
]
player
[
"y"
]
=
player
[
"startY"
]
' if player was eaten at player start location, move player to snake start location to prevent continuous death
If
(
math
.
Abs
(
player
[
"x"
]
-
(
snake
[
1
]
[
"x"
]
-
headOffset
)
)
<
36
)
And
(
Math
.
Abs
(
player
[
"y"
]
-
(
snake
[
1
]
[
"y"
]
-
headOffset
)
)
<
36
)
Then
player
[
"x"
]
=
level
[
thisLevel
]
[
"snakeX"
]
player
[
"y"
]
=
level
[
thisLevel
]
[
"snakeY"
]
EndIf
' you spin me right round baby, right round, like a record....
For
x
=
1
to
3
For
y
=
0
To
360
Shapes
.
Rotate
(
player
[
"sprite"
]
,
y
)
Shapes
.
SetOpacity
(
player
[
"sprite"
]
,
y
/
2
)
Program
.
Delay
(
2
)
EndFor
EndFor
If
lives
>
0
Then
Shapes
.
Animate
(
player
[
"sprite"
]
,
player
[
"x"
]
-
11
,
player
[
"y"
]
-
11
,
500
)
For
lwp
=
1
to
1000000
EndFor
EndIf
EndSub
' =====================================================================
Sub
addSegment
' NOT USING THIS AT PRESENT - USEFUL IF FOOD IS ADDED FOR SNAKE TO EAT
' this code hasn't been updated since snake was changed from Ellipse shapes to graphic shapes, so needs some work if used!
processing
=
1
' flag that we're working on it!
' increase snake size and delay movement of new tail
snakeSize
=
snakeSize
+
1
snake
[
snakeSize
]
[
"delay"
]
=
snake
[
snakeSize
-
1
]
[
"delay"
]
+
12
' need to remove old tail due to Small Basic's layering of graphic shapes
Shapes
.
Remove
(
snake
[
snakeSize
-
1
]
[
"sprite"
]
)
' add a new body part
GraphicsWindow
.
BrushColor
=
"Chocolate"
snake
[
snakeSize
-
1
]
[
"sprite"
]
=
Shapes
.
AddEllipse
(
bodySize
,
bodySize
)
Shapes
.
Move
(
snake
[
snakeSize
-
1
]
[
"sprite"
]
,
snake
[
snakeSize
-
1
]
[
"x"
]
,
snake
[
snakeSize
-
1
]
[
"y"
]
)
' add new tail
snake
[
snakeSize
]
[
"x"
]
=
snake
[
snakeSize
-
1
]
[
"x"
]
snake
[
snakeSize
]
[
"y"
]
=
snake
[
snakeSize
-
1
]
[
"y"
]
GraphicsWindow
.
BrushColor
=
"SandyBrown"
snake
[
snakeSize
]
[
"sprite"
]
=
Shapes
.
AddEllipse
(
tailSize
,
tailSize
)
Shapes
.
Move
(
snake
[
snakeSize
]
[
"sprite"
]
,
snake
[
snakeSize
]
[
"x"
]
,
snake
[
snakeSize
]
[
"y"
]
)
EndSub
Sub
mUp
' NOT USED AT PRESENT - put here to handle mouse button presses
' used in conjunction with AddSegment subroutine above
processing
=
0
' cancel the mousedown action - have to do this 'cos the 'puter is much faster than our likkle fingers
EndSub
' =====================================================================
Sub
status
' show the various game values in status area
GraphicsWindow
.
BrushColor
=
"White"
GraphicsWindow
.
PenColor
=
"White"
GraphicsWindow
.
FontSize
=
32
GraphicsWindow
.
DrawText
(
20
,
550
,
"Round: Lives: Score:"
)
GraphicsWindow
.
FillRectangle
(
140
,
555
,
80
,
32
)
GraphicsWindow
.
FillRectangle
(
370
,
555
,
80
,
32
)
GraphicsWindow
.
FillRectangle
(
610
,
555
,
160
,
32
)
GraphicsWindow
.
BrushColor
=
"Black"
GraphicsWindow
.
DrawText
(
170
,
550
,
thisLevel
)
GraphicsWindow
.
DrawText
(
400
,
550
,
lives
)
GraphicsWindow
.
DrawText
(
640
,
550
,
score
)
EndSub
' =====================================================================
Sub
levelConfig
' configuration settings for each of the levels
'
' to add new levels, simply duplicate the last one below, change it's level number, make a new layout,
' then increase the 'levels' value below. To test your new level without playing all the earlier ones, change
' the 'thisLevel' variable (at the beginning of the program code above).
levels
=
5
level
[
1
]
[
"snakeDir"
]
=
Math
.
GetRandomNumber
(
4
)
' start snake off in a random direction: 1=N, 2=E, 3=S, 4=W
level
[
1
]
[
"snakeSize"
]
=
12
' length of snake
level
[
1
]
[
"snakeDelay"
]
=
700
' speed of snake (higher = slower)
level
[
1
]
[
"dirDelay"
]
=
50
' delay (moves) before snake can change direction (lower = more jittery snake)
level
[
1
]
[
"getAngry"
]
=
1
' flag indicating if the snake can switch to angry mode (=1) or not (=0)
' W = wall segment
' S = Snake start location
' P = Player start location
level
[
0
]
[
0
]
=
".........1.........2...."
' just a ruler
level
[
1
]
[
1
]
=
"W W"
level
[
1
]
[
2
]
=
" "
level
[
1
]
[
3
]
=
" WWWWWWWWWWWWWW "
level
[
1
]
[
4
]
=
" "
level
[
1
]
[
5
]
=
" "
level
[
1
]
[
6
]
=
" S "
level
[
1
]
[
7
]
=
" "
level
[
1
]
[
8
]
=
" "
level
[
1
]
[
9
]
=
" "
level
[
1
]
[
10
]
=
" "
level
[
1
]
[
11
]
=
" "
level
[
1
]
[
12
]
=
" P "
level
[
1
]
[
13
]
=
" "
level
[
1
]
[
14
]
=
" WWWWWWWWWWWWWW "
level
[
1
]
[
15
]
=
" "
level
[
1
]
[
16
]
=
"W W"
level
[
2
]
[
"snakeDir"
]
=
Math
.
GetRandomNumber
(
4
)
' start snake off in a random direction: 1=N, 2=E, 3=S, 4=W
level
[
2
]
[
"snakeSize"
]
=
14
' length of snake
level
[
2
]
[
"snakeDelay"
]
=
1100
' speed of snake (higher = slower)
level
[
2
]
[
"dirDelay"
]
=
50
' delay (moves) before snake can change direction (lower = more jittery snake
level
[
2
]
[
"getAngry"
]
=
1
' flag indicating if the snake can switch to angry mode (=1) or not (=0)
level
[
0
]
[
0
]
=
".........1.........2...."
' just a ruler
level
[
2
]
[
1
]
=
" "
level
[
2
]
[
2
]
=
" WWWWWWWWWWWWWWWW "
level
[
2
]
[
3
]
=
" W W "
level
[
2
]
[
4
]
=
" W WWWWWWWWWWWWW W "
level
[
2
]
[
5
]
=
" W WW WWW WW W "
level
[
2
]
[
6
]
=
" W WWWWWWWWWWWWW W "
level
[
2
]
[
7
]
=
" W P WW S W "
level
[
2
]
[
8
]
=
" WWWWW W WWWWWW "
level
[
2
]
[
9
]
=
" WW W W "
level
[
2
]
[
10
]
=
" W WWWWWWW W "
level
[
2
]
[
11
]
=
" WWW W WW WW W "
level
[
2
]
[
12
]
=
" W WWWW WWWWWWW W "
level
[
2
]
[
13
]
=
" W W "
level
[
2
]
[
14
]
=
" WWWWWWWWWWWWWWWW "
level
[
2
]
[
15
]
=
" "
level
[
2
]
[
16
]
=
" "
level
[
3
]
[
"snakeDir"
]
=
1
'Math.GetRandomNumber(4) ' start snake off in a random direction: 1=N, 2=E, 3=S, 4=W
level
[
3
]
[
"snakeSize"
]
=
16
' length of snake
level
[
3
]
[
"snakeDelay"
]
=
600
' speed of snake (higher = slower)
level
[
3
]
[
"dirDelay"
]
=
30
' delay (moves) before snake can change direction (lower = more jittery snake
level
[
3
]
[
"getAngry"
]
=
1
' flag indicating if the snake can switch to angry mode (=1) or not (=0)
level
[
0
]
[
0
]
=
".........1.........2...."
' just a ruler
level
[
3
]
[
1
]
=
" "
level
[
3
]
[
2
]
=
" WWWW WWWW "
level
[
3
]
[
3
]
=
" WW W W WWW "
level
[
3
]
[
4
]
=
" WW W WW "
level
[
3
]
[
5
]
=
" W WWW WWW W "
level
[
3
]
[
6
]
=
" W W W W "
level
[
3
]
[
7
]
=
" WW WWWWW WWWWWW WW "
level
[
3
]
[
8
]
=
" W P W "
level
[
3
]
[
9
]
=
" WW WWWWW WWWWWW WW "
level
[
3
]
[
10
]
=
" W WW W W WW W "
level
[
3
]
[
11
]
=
" W WWWW WWWWW W "
level
[
3
]
[
12
]
=
" WW W W WW "
level
[
3
]
[
13
]
=
" WWWWWWW WWWWWWWW "
level
[
3
]
[
14
]
=
" WSW "
level
[
3
]
[
15
]
=
" W "
level
[
3
]
[
16
]
=
" "
level
[
4
]
[
"snakeDir"
]
=
3
'Math.GetRandomNumber(4) ' start snake off in a random direction: 1=N, 2=E, 3=S, 4=W
level
[
4
]
[
"snakeSize"
]
=
18
' length of snake
level
[
4
]
[
"snakeDelay"
]
=
500
' speed of snake (higher = slower)
level
[
4
]
[
"dirDelay"
]
=
20
' delay (moves) before snake can change direction (lower = more jittery snake
level
[
4
]
[
"getAngry"
]
=
0
' flag indicating if the snake can switch to angry mode (=1) or not (=0)
level
[
0
]
[
0
]
=
".........1.........2...."
' just a ruler
level
[
4
]
[
1
]
=
" W "
level
[
4
]
[
2
]
=
" WSW "
level
[
4
]
[
3
]
=
" W W "
level
[
4
]
[
4
]
=
" W W "
level
[
4
]
[
5
]
=
" W W "
level
[
4
]
[
6
]
=
" W WW "
level
[
4
]
[
7
]
=
" W WW "
level
[
4
]
[
8
]
=
" W WW "
level
[
4
]
[
9
]
=
" WW W "
level
[
4
]
[
10
]
=
" WW W "
level
[
4
]
[
11
]
=
" WW W "
level
[
4
]
[
12
]
=
" W W "
level
[
4
]
[
13
]
=
" W W "
level
[
4
]
[
14
]
=
" W W "
level
[
4
]
[
15
]
=
" WPW "
level
[
4
]
[
16
]
=
" W "
level
[
5
]
[
"snakeDir"
]
=
3
'Math.GetRandomNumber(4) ' start snake off in a random direction: 1=N, 2=E, 3=S, 4=W
level
[
5
]
[
"snakeSize"
]
=
20
' length of snake
level
[
5
]
[
"snakeDelay"
]
=
300
' speed of snake (higher = slower)
level
[
5
]
[
"dirDelay"
]
=
20
' delay (moves) before snake can change direction (lower = more jittery snake
level
[
5
]
[
"getAngry"
]
=
0
' flag indicating if the snake can switch to angry mode (=1) or not (=0)
level
[
0
]
[
0
]
=
".........1.........2...."
' just a ruler
level
[
5
]
[
1
]
=
"WW WW"
level
[
5
]
[
2
]
=
"W P W"
level
[
5
]
[
3
]
=
" WWWWWWWWWWWWWW "
level
[
5
]
[
4
]
=
"WWWWWW WWW WW"
level
[
5
]
[
5
]
=
" "
level
[
5
]
[
6
]
=
" WWWWWWWWWWWWWWW "
level
[
5
]
[
7
]
=
"WW WWW WWWWW"
level
[
5
]
[
8
]
=
" "
level
[
5
]
[
9
]
=
"WW WWW WWW WW"
level
[
5
]
[
10
]
=
" WWWWWWWWWWWWWW "
level
[
5
]
[
11
]
=
" "
level
[
5
]
[
12
]
=
"WWWWWW WWW WW"
level
[
5
]
[
13
]
=
" WWWWWWWWWWWWWW "
level
[
5
]
[
14
]
=
" "
level
[
5
]
[
15
]
=
"W WWWWW WWWWW W"
level
[
5
]
[
16
]
=
"WW S WW"
EndSub
Copyright (c) Microsoft Corporation. All rights reserved.