Snake

Dependencies:   microbit

Fork of microbit_snake by Mohammad Khan

A Snake Game with animation, score and continuous play

Steps:

  • Switch On.
  • Snake animation plays.
  • Game starts.
  • Press buttons to move the snake left, right, up and down.
  • Food appears as a dot on the display.
  • Try eating the food by manoeuvring Snake to run over it.
  • Snake grows as it eats food.
  • As it grows it becomes hard to avoid snake biting itself.
  • Game Over.
  • Snake is flashed and then score is scrolled.
  • Game restarts after replaying animation.

Controls:

  • Left Button (A)
    • If snake moving UP/DOWN moves snake to LEFT.
    • If snake moving LEFT moves snake to DOWN.
    • If snake moving RIGHT moves snake to UP.
  • Right Button (B)
    • If snake moving UP/DOWN moves snake to RIGHT.
    • If snake moving LEFT moves snake to UP.
    • If snake moving RIGHT moves snake to DOWN.

How it looks:

https://www.youtube.com/watch?v=unEs3NOvIKA

Binary to play with

/media/uploads/mazimkhan/microbit_snake_nrf51_microbit.hex

Revision:
3:a0200bceae4b
Parent:
2:38060465e019
Child:
4:9fd9402eca3d
--- a/main.cpp	Sun Apr 10 19:20:49 2016 +0000
+++ b/main.cpp	Sun Apr 10 23:31:53 2016 +0000
@@ -22,8 +22,8 @@
 #include "MicroBit.h"
 #include "DigitalOut.h"
 
-#define SNAKE_HEAD_PIXEL_BRIGHTNESS     25
-#define SNAKE_REST_PIXEL_BRIGHTNESS     15
+#define SNAKE_HEAD_PIXEL_BRIGHTNESS     150
+#define SNAKE_BONE_PIXEL_BRIGHTNESS     15
 #define SNAKE_FOOD_PIXEL_BRIGHTNESS     255
 
 template <class T> class Node{
@@ -83,6 +83,9 @@
         if (tail) {
             tail = tail->getPrev();
             node->detach();
+            if (tail == NULL){
+                head = NULL;
+            }
         }
         return node;
     }   
@@ -307,7 +310,7 @@
 
 class Game {
 public:
-    Game(MicroBit & ubit): uBit(ubit), foodx(-1), foody(-1), image(5,5),
+    Game(MicroBit & ubit): uBit(ubit), foodx(-1), foody(-1), image(5,5), score(0),
         buttonPressed(false) {
         uBit.display.setDisplayMode(DISPLAY_MODE_GREYSCALE);
         uBit.display.print(image);
@@ -328,11 +331,10 @@
     }
     
     bool move(){
-        // Display food
-        if (foodx != -1 && foody != -1){
-            image.setPixelValue(foodx, foody, 255);
-            uBit.display.print(image);
-        }
+        // Dim old head
+        Dimension x = snake.getHeadX();
+        Dimension y = snake.getHeadY();
+        image.setPixelValue(x, y, SNAKE_BONE_PIXEL_BRIGHTNESS);
         
         snake.grow();
         
@@ -350,6 +352,7 @@
             // food gone
             foodx = -1;
             foody = -1;
+            score++;
             
             // Since we have grown to the head. no need to delete tail.
         } else {
@@ -363,7 +366,7 @@
         }
         
         // Turn On head.
-        image.setPixelValue(nextX, nextY, 15);
+        image.setPixelValue(nextX, nextY, SNAKE_HEAD_PIXEL_BRIGHTNESS);
         uBit.display.print(image);
         buttonPressed = false;
         return true;
@@ -406,6 +409,8 @@
                     if (isGoodFood(x, y)){
                         foodx = x;
                         foody = y;
+                        image.setPixelValue(foodx, foody, 255);
+                        uBit.display.print(image);
                         break;
                     }
                 }
@@ -413,6 +418,99 @@
             uBit.sleep(500);
         }
     }
+    
+    void animateSnake(){
+#define ANIMATION_SPEED 50
+        // UP 2
+        foodx = 2;foody = 1;
+        move();
+        uBit.sleep(ANIMATION_SPEED);
+        
+        foodx = 2;foody = 0;
+        move();
+        uBit.sleep(ANIMATION_SPEED);
+        
+        // LEFT
+        foodx = 1;foody = 0;
+        left();
+        move();
+        uBit.sleep(ANIMATION_SPEED);
+        
+        // DOWN
+        foodx = 1;foody = 1;
+        left();
+        move();
+        uBit.sleep(ANIMATION_SPEED);
+        
+        foodx = 1;foody = 2;
+        move();
+        uBit.sleep(ANIMATION_SPEED);
+        move();
+        uBit.sleep(ANIMATION_SPEED);
+        move();
+        uBit.sleep(ANIMATION_SPEED);
+        
+        for (int i = 0; i < 4; i++){
+            // LEFT
+            left();
+            move();
+            uBit.sleep(ANIMATION_SPEED);
+            
+            // UP
+            right();
+            move();
+            uBit.sleep(ANIMATION_SPEED);
+            
+            move();
+            uBit.sleep(ANIMATION_SPEED);
+            move();
+            uBit.sleep(ANIMATION_SPEED);
+            move();
+            uBit.sleep(ANIMATION_SPEED);
+            
+            // LEFT
+            left();
+            move();
+            uBit.sleep(ANIMATION_SPEED);
+            
+            // DOWN
+            left();
+            move();
+            uBit.sleep(ANIMATION_SPEED);
+            
+            move();
+            uBit.sleep(ANIMATION_SPEED);
+            move();
+            uBit.sleep(ANIMATION_SPEED);
+            move();
+            uBit.sleep(ANIMATION_SPEED);
+        }
+        
+        // Back to the centre
+        left();
+        move();
+        uBit.sleep(ANIMATION_SPEED);
+        
+        left();
+        move();
+        uBit.sleep(ANIMATION_SPEED);
+        
+        move();
+        uBit.sleep(ANIMATION_SPEED);
+        move();
+        uBit.sleep(ANIMATION_SPEED);
+        
+        // eat the tail
+        while(snake.getHead()){
+            image.setPixelValue(snake.getTailX(), snake.getTailY(), 0);
+            uBit.display.print(image);
+            snake.reduce();
+            uBit.sleep(ANIMATION_SPEED);
+        }
+        
+        reset();
+    }
+    
     void showGameOver(){
         // switch off food
         if (foodx != -1 && foody != -1){
@@ -424,7 +522,7 @@
         // are not affected by display.setBrightness(). Possible Bug!!!
         Node<SnakeBone> * bone = snake.getHead();
         while (bone){
-            image.setPixelValue(bone->d.getX(), bone->d.getY(), 255);
+            image.setPixelValue(bone->d.getX(), bone->d.getY(), SNAKE_FOOD_PIXEL_BRIGHTNESS);
             bone = bone->getNext();
         }
         // Flash snake
@@ -434,9 +532,13 @@
             if (toggle)
                 uBit.display.setBrightness(255);
             else
-                uBit.display.setBrightness(15);
+                uBit.display.setBrightness(SNAKE_BONE_PIXEL_BRIGHTNESS);
             uBit.sleep(500);
         }
+        uBit.display.print(MicroBitImage(5,5));
+        uBit.display.setBrightness(255);
+        uBit.display.scroll("SCORE-"); // don't mind spaces in a scrolling display.
+        uBit.display.scroll(score, 300);
     }
     
     void reset(){
@@ -445,8 +547,10 @@
         
         foodx = -1;
         foody = -1;
+        score = 0;
         image = MicroBitImage(5, 5);
         uBit.display.setDisplayMode(DISPLAY_MODE_GREYSCALE);
+        image.setPixelValue(snake.getHeadX(), snake.getHeadY(), SNAKE_HEAD_PIXEL_BRIGHTNESS);
         uBit.display.print(image);
     }
     
@@ -457,6 +561,7 @@
     int foody;
     Snake snake;
     MicroBitImage image;
+    int score;
     
     // Sync button press and movement. Don't let quick button presses
     // change snake direction twice/thrice/... before moving. As a 
@@ -477,6 +582,7 @@
     game.right();
 }
 
+
 int main()
 {
     // Initialise the micro:bit runtime.
@@ -486,14 +592,9 @@
     uBit.messageBus.listen(MICROBIT_ID_BUTTON_B, MICROBIT_BUTTON_EVT_CLICK, onButtonB);
 
     // Continous play    
-    while (true)
-    {
+    while (true){
+        game.animateSnake();
         game.play();
-        
-        uBit.display.print(MicroBitImage(5,5));
-        uBit.display.setBrightness(255);
-        uBit.display.scroll("URBITTEN"); // don't mind spaces in a scrolling display.
-        
         game.reset();
     }
 }
\ No newline at end of file