Game of Snake Slows Down As Snake Grows???
So, another forum member, __red__, had a class for a few of us at the Hackerspace in Charlotte to work with Propellers. We build these name badges that have an embedded 7 x 8 LED grid, and could print our name across them. Pretty cool, right?
So, I figured, this is basically a "low res" display, but I could run something like Snake on it. So, I did. However, I noticed the game starting to slow down as the snake got bigger. I was kind of surprised at that, but figured, eh, I'll just increase the clock speed. So I turned it up to 80 MHz, but while that mostly solved the problem, I found that once the Snake gets really big - like, takes up half the screen big - it's still slowing down the game. Now, we're talking about a 7x8 grid of LEDs. We're talking about tracking, at most, 56 points, and that's if the snake was the size of the entire game. It shouldn't be lagging. But it is. And as this is my first Spin program, I'm guessing I'm missing something. Here's the code, and thanks in advance.
Also, I'm thinking that the GameTick method would be the main culprit, but I dunno.
So, I figured, this is basically a "low res" display, but I could run something like Snake on it. So, I did. However, I noticed the game starting to slow down as the snake got bigger. I was kind of surprised at that, but figured, eh, I'll just increase the clock speed. So I turned it up to 80 MHz, but while that mostly solved the problem, I found that once the Snake gets really big - like, takes up half the screen big - it's still slowing down the game. Now, we're talking about a 7x8 grid of LEDs. We're talking about tracking, at most, 56 points, and that's if the snake was the size of the entire game. It shouldn't be lagging. But it is. And as this is my first Spin program, I'm guessing I'm missing something. Here's the code, and thanks in advance.
Also, I'm thinking that the GameTick method would be the main culprit, but I dunno.
CON
_clkmode=xtal1+pll16x 'Run at 16x5 = 80mhz!
_xinfreq=5_000_000 'We are using a 5Mhz Crystal
GameSpeedMultiplier = 5
StartingPixels = 4
XBounds = 7
YBounds = 6
S2Pin = 17
S3Pin = 18
S4Pin = 19
OBJ
rr: "RealRandom.spin"
printer: "LedPrinter"
VAR
byte SnakePixelsX[56]
byte SnakePixelsY[56]
byte CurrentLength
long DrawStack[20]
long MoveStack[20]
long InputStack[20]
long NumberArray[10]
long ScoreArray[5]
byte GraphicsCogID
byte CurrentDirection ' 0 is up, 1 is right, 2 is down, 3 is left.
long Seed
byte FruitX
byte FruitY
byte FruitExists
byte GameOver
byte TurnQueued
byte ButtonPressed
byte GameState
long Score
long FruitValue
byte LongMessage[4000]
PUB Main
cognew(Input, @InputStack)
cognew(OpeningDisplay, @DrawStack)
repeat while GameState == 0
waitcnt(clkfreq/5 + cnt)
waitcnt(clkfreq + cnt)
initializeSnake
cognew(Graphics, @DrawStack)
GenerateFruit
repeat while GameOver == 0
GameTick
waitcnt(clkfreq * 2 + cnt)
COGSTOP(GraphicsCogID)
EndGame
pri Input
repeat
if ina[S2Pin] == 0 AND TurnQueued == 0 AND ButtonPressed == 0
TurnQueued := 1
TurnCounterClockwise
waitcnt(clkfreq/10 + cnt)
WatchForButtonRelease(S2PIN)
elseif ina[S4Pin] == 0 AND TurnQueued == 0 AND ButtonPressed == 0
TurnQueued := 1
TurnClockwise
waitcnt(clkfreq/10 + cnt)
WatchForButtonRelease(S4PIN)
elseif ina[S3Pin] == 0
COGSTOP(GraphicsCogID)
GameState := 1
pri WatchForButtonRelease (PIN) | i
repeat while i < 4
if ina[PIN] == 1
i++
else
i := 0
ButtonPressed := 0
pri TurnCounterClockwise
if CurrentDirection == 0
CurrentDirection := 3
else
CurrentDirection -= 1
pri TurnClockwise
if CurrentDirection == 3
CurrentDirection := 0
else
CurrentDirection += 1
pri GameTick | collision,i
waitcnt(clkfreq/GameSpeedMultiplier + cnt)
collision := DetectFruitCollision
if collision == 1
eatFruit
repeat i from CurrentLength -1 to 1
SnakePixelsX[CurrentLength - 1] := SnakePixelsX[0]
SnakePixelsY[CurrentLength - 1] := SnakePixelsY[0]
if CurrentDirection == 0
SnakePixelsY[0] += 1
elseif CurrentDirection == 1
SnakePixelsX[0] -= 1
elseif CurrentDirection == 2
SnakePixelsY[0] -= 1
else
SnakePixelsX[0] += 1
DetectOutOfBounds
DetectSelfCollision
if FruitExists == 1
FruitValue -= 1
TurnQueued := 0
pri DetectSelfCollision | i,n
repeat i from 0 to CurrentLength - 1
repeat n from 0 to CurrentLength - 1
ifnot i == n
if SnakePixelsX[i] == SnakePixelsX[n] AND SnakePixelsY[i] == SnakePixelsY[n]
FruitX := SnakePixelsX[i]
FruitY := SnakePixelsY[i]
FruitExists := 1
GameOver := 1
pri DetectOutOfBounds | i
repeat i from 0 to CurrentLength - 1
if SnakePixelsX[i] > XBounds OR SnakePixelsY[i] > YBounds
GameOver := 1
FruitX := SnakePixelsX[i+1]
FruitY := SnakePixelsY[i+1]
elseif SnakePixelsX[i] < 0 OR SnakePixelsY[i] < 0
GameOver := 1
FruitX := SnakePixelsX[i+1]
FruitY := SnakePixelsY[i+1]
PRI OpeningDisplay
GraphicsCogID := COGID
repeat while GameState == 0
Printer.Print(string("PRESS S3 TO START"))
pri eatFruit
FruitExists := 0
SnakePixelsX[currentLength] := SnakePixelsX[CurrentLength - 1]
SnakePixelsY[currentLength] := SnakePixelsY[CurrentLength - 1]
CurrentLength++
Score += FruitValue
GenerateFruit
pri clearScreen
dira[20..27] := 0
pri Graphics | i,Counter
GraphicsCogID := COGID
repeat
if GameOver == 0
repeat i from 0 to CurrentLength - 1
lightPixel(SnakePixelsX[i], SnakePixelsY[i])
elseif GameOver == 1
repeat i from 1 to CurrentLength - 1
if SnakePixelsX[i] <> FruitX OR SnakePixelsY[i] <> FruitY
lightPixel(SnakePixelsX[i], SnakePixelsY[i])
if FruitExists == 1 AND Counter > 50
lightPixel(FruitX, FruitY)
Counter := 0
Counter++
pri GenerateFruit | collision
collision := 1
repeat while collision == 1
fruitX := Roll(0, 7)
fruitY := Roll(0, 6)
collision := DetectFruitCollision
FruitExists := 1
FruitValue := 100
pri DetectFruitCollision | collision, i
repeat i from 0 to CurrentLength - 1
if FruitX == SnakePixelsX[i] AND FruitY == SnakePixelsY[i]
collision := 1
return collision
pri Roll(minValue, maxValue) : returnValue
returnValue := ||(Seed?//256)
repeat while returnValue < minValue OR returnValue > maxValue
returnValue := ||(Seed?//256)
return returnValue
pri lightPixel(X, Y)
dira[20..27] := 0
dira[X + 20] := 1
outa[X + 20] := 0
if X > Y
dira[Y + 20] := 1
outa[Y + 20] := 1
else
dira[Y + 21] := 1
outa[Y + 21] := 1
pri EndGame | ScoreText,ScoreNumAsText,i
COGNEW(DrawX, @DrawStack)
waitcnt(clkfreq + cnt)
COGSTOP(GraphicsCogID)
if Score > 999
ScoreArray[0] := (Score - (Score // 1000)) / 1000
Score -= ScoreArray[0] * 1000
if Score > 99
ScoreArray[1] := (Score - (Score // 100)) / 100
Score -= ScoreArray[1] * 100
if Score > 9
ScoreArray[2] := (Score - (Score // 10)) / 10
Score -= ScoreArray[2] * 10
if Score > 0
ScoreArray[3] := Score
ScoreText := string("SCORE ")
repeat i from 0 to 3
ScoreNumAsText := NumberArray[ScoreArray[i]]
bytemove(ScoreText+strsize(ScoreText),ScoreNumAsText,strsize(ScoreNumAsText)+1)
repeat
Printer.Print(ScoreText)
pri DrawX | i
GraphicsCogID := COGID
repeat
repeat i from 0 to 7
lightPixel(i, i)
lightPixel(i, XBounds - (i + 1))
Pri initializeSnake
CurrentDirection := 1
CurrentLength := 4
SnakePixelsX[0] := 4
SnakePixelsY[0] := 3
SnakePixelsX[1] := 5
SnakePixelsY[1] := 3
SnakePixelsX[2] := 6
SnakePixelsY[2] := 3
SnakePixelsX[3] := 7
SnakePixelsY[3] := 3
NumberArray[0] := string("0")
NumberArray[1] := string("1")
NumberArray[2] := string("2")
NumberArray[3] := string("3")
NumberArray[4] := string("4")
NumberArray[5] := string("5")
NumberArray[6] := string("6")
NumberArray[7] := string("7")
NumberArray[8] := string("8")
NumberArray[9] := string("9")
rr.Start
Seed := rr.Random
rr.Stop
dira[S2Pin] := 0
dira[S3Pin] := 0
dira[S4Pin] := 0
