The snake consist of one square called head and the rest called tail. Snake has a timer (200 ms) and it moves 20 pixels every time. You move the snake using arrow keys and collect points. It is simple
Snake game.
Global Variables:- Code: Select all
length // snake's length
score
highscore // saves in snake.sav, Save Group: High Score
game_over // 1 when it is game over, otherwise it is 0
index // new index for every part of tail; for every part of snake except for head
up, down, left, right // in which direction is snake moving
Global code:coordinates - saves the coordinates of snake's parts
- Code: Select all
typedef struct coord {
int partX;
int partY;
} coordinates;
#define MAX 462
coordinates array[MAX];
MAX should be 441, not 462.
destroy - script includes function destroy() which activates when snake collides with the wall, or tail
- Code: Select all
void destroy() {
game_over = 1;
DestroyActor("head");
DestroyActor("tail");
DestroyActor("point");
if (score > highscore)
highscore = score;
saveVars("snake.sav", "High Score");
CreateActor("game_over_message", "game_over", "no parent", "game_over_path", -465, 20, true);
CreateActor("space", "no animation", "no parent", "no path", -150, 190, true);
strcpy(space.text, "PRESS [SPACE] TO CONTINUE");
CreateActor("reset", "no animation", "no parent", "no path", -110, -150, true);
}
Destroy head, tail and a new point.
Set highscore.
Write messages.
set_coordinates - script include function set_coordinates() which sets coordinates x and y of every part of snake, except head
- Code: Select all
void set_coordinates () {
int i;
for (i = length - 1; i > 0; i--) {
array[i].partX = array[i - 1].partX;
array[i].partY = array[i - 1].partY;
}
}
head:When head collides with the wall or tail, function destroy() activates.Pressed key down (Event Key Down: down)- Code: Select all
if (up != 1) {
down = 1;
left = 0;
right = 0;
}
EventDisable("head", EVENTKEYDOWN);
Set direction to down, except if snake is already moving up. Next, Event Key Down is disabled and pressing any other arrow key will not change the snake's direction until this Event is activated again. This is important in case that player very quickly presses, in this case, arrow left, or right, but timer didn't activate and register that move, more about timer after this, and then arrow down, and snake was moving up. In other words, you pressed left, now up = 0 and left = 1, but timer didn't update new direction, and immediately after that you pressed down. up is not 1 any more and down is set to 1, by now timer should activate and update next direction to down. Then snake would move down, and head will go over the tail, which will activate Event Collide (snake and tail).
head's timer (200 ms):- Code: Select all
EventEnable("head", EVENTKEYDOWN);
if (up == 1)
array[0].partY += -20;
else if (down == 1)
array[0].partY += 20;
else if (left == 1)
array[0].partX += -20;
else if (right == 1)
array[0].partX += 20;
else {
array[0].partX = head.x;
array[0].partY = head.y;
}
x = array[0].partX;
y = array[0].partY;
if (x == point.x && y == point.y) {
score += 25;
DestroyActor("point");
length++;
CreateActor("tail", "tail", "no parent", "no path", 300, 300, true);
tail.index = length - 1;
}
set_coordinates();
Event Key Down is activated again, and snake, or precisely head, receives instructions from arrow keys.
New coordinates for head are set.
If head's and point's coordinates are same, if snake caught the point:
- increase the score
- destroy the point
- increase the length of snake
- create a new part of tail; it creates outside the view for these 200 ms, because coordinates are still unknown
- new part gets its index
Set coordinates for the rest of snake.
tail:Timer (200 ms) sets new coordinates for that part of tail:
- Code: Select all
x = array[index].partX;
y = array[index].partY;
view:When you start the game:
- Code: Select all
CreateActor("space", "no animation", "no parent", "no path", -140, 190, true);
strcpy(space.text, " PRESS [SPACE] TO BEGIN ");
CreateActor("reset", "no animation", "no parent", "no path", -110, -150, true);
game_over = 1;
When you press [SPACE]:
- Code: Select all
if (game_over == 1) {
int i;
int create = 1;
int point_x, point_y;
while (1) {
point_x = (int)(10 - rand(21)) * 20;
point_y = ((int)(10 - rand(21)) + 3) * 20 - 10;
for (i = 0; i < length; i++)
if ((array[i].partX == point_x) && (array[i].partY == point_y)) {
create = 0;
break;
}
if (create == 1) break;
}
CreateActor("point", "point", "no parent", "no path", point_x, point_y, true);
CreateActor("head", "head", "no parent", "no path", 0, 250, true);
DestroyActor("space");
DestroyActor("reset");
DestroyActor("game_over_message");
length = 1;
game_over = 0;
score = 0;
up = 0;
down = 0;
left = 0;
right = 0;
array[0].partX = 0;
array[0].partY = 250;
loadVars("snake.sav", "High Score");
}
The code executes if the game is not active.
Set a new point to catch, coordinates must not be the same as any part of snake.
Create the head.
Delete unnecessary messages.
Initialize variables.
Set head's coordinates.
Open the snake.sav which saves the highscore.
Deleting highscore:
- Code: Select all
if (game_over == 1) {
loadVars("snake.sav", "High Score");
highscore = 0;
saveVars("snake.sav", "High Score");
}
wall:wall creates new points you need to catch:
- Code: Select all
int i;
int create = 1;
int point_x, point_y;
if (game_over != 1) {
while (1) {
point_x = (int)(10 - rand(21)) * 20;
point_y = ((int)(10 - rand(21)) + 3) * 20 - 10;
for (i = 0; i < length; i++)
if ((array[i].partX == point_x) && (array[i].partY == point_y)) {
create = 0;
break;
}
if (create == 1) break;
}
CreateActor("point", "point", "no parent", "no path", point_x, point_y, true);
}
score, highscore:These two variables are written the same way. Digits on screen are not text, but independent actors. Value of the third digit of the score:
- Code: Select all
switch ((int) fmod ((int) (score / 100), 10)) {
case 0: ChangeAnimation("digit_c", "0", FORWARD); break;
case 1: ChangeAnimation("digit_c", "1", FORWARD); break;
case 2: ChangeAnimation("digit_c", "2", FORWARD); break;
case 3: ChangeAnimation("digit_c", "3", FORWARD); break;
case 4: ChangeAnimation("digit_c", "4", FORWARD); break;
case 5: ChangeAnimation("digit_c", "5", FORWARD); break;
case 6: ChangeAnimation("digit_c", "6", FORWARD); break;
case 7: ChangeAnimation("digit_c", "7", FORWARD); break;
case 8: ChangeAnimation("digit_c", "8", FORWARD); break;
case 9: ChangeAnimation("digit_c", "9", FORWARD); break;
}
Instead of making a new font, I did it this way. I think it is better to make a new font, it is more convenient, it takes less space, but I wanted to try it this way and to do it faster.