microbit的贪吃蛇游戏

micro:bit编程、教学、展示
STEM
回复
头像
shaoziyang
帖子: 706
注册时间: 2019年 10月 21日 13:48

microbit的贪吃蛇游戏

#1

帖子 shaoziyang » 2019年 11月 24日 20:08

来自:https://www.hackster.io/abhijaysaini/mi ... ame-86c95d

这是hackster上一个在microbit上编写的贪吃蛇游戏,使用了Mbed(C++)进行编程,作者目前没有提供源码,只有HEX文件。希望有兴趣的网友可以移植到makecode或micropython上。

 
图片

头像
shaoziyang
帖子: 706
注册时间: 2019年 10月 21日 13:48

Re: microbit的贪吃蛇游戏

#2

帖子 shaoziyang » 2019年 11月 24日 20:15

main.cpp

代码: 全选

#include "MicroBit.h"
#include "FixedStack.h"


MicroBit uBit;
bool FINISHED; // True if player WINS the game
enum DIRECTION {LEFT, RIGHT, UP, DOWN}; // Game Controls
const uint8_t WIDTH = 5; // WIDTH of the LED matrix
const uint8_t HEIGHT = 5; // HEIGHT of the LED matrix
const uint8_t SNAKE_BRIGHTNESS = 25; // Snake's brightness on the screen
const uint8_t FRUIT_BRIGHTNESS = 255; // Fruit's brightness on the screen


class RandomPixel {
public:
  uint8_t X; // x-coordinate of the fruit
  uint8_t Y; // y-coordinate of the fruit

  RandomPixel();
  void refresh(); // Refresh the X and Y coordinates of the fruit to a random, unoccupied position
  void display(MicroBitImage m, uint8_t brightness); // Display the fruit on the LED Matrix
} Fruit;


class Snake {
public:
  signed char X; // x-coordinate of the Head of the Snake
  signed char Y; // y-coordinate of the Head of the Snake
  uint8_t score; // Current score of the game
  DIRECTION direction; // Current heading of the Snake
  FixedStack* body; // Snake's body implemented using the FixedStack data structure
  bool setDirection; // The player is allowed to set the Snake's direction only once per movement of the Snake

  Snake();
  bool offScreen(); // Returns true if the Snake goes outside the 5x5 LED Matrix
  void move(); // Increment the Snake's position in the direction it's headed
  void display(MicroBitImage m, uint8_t brightness); // Display the Snake's body on the LED Matrix
  bool occupied(uint8_t x, uint8_t y); // Returns true if the Snake's body is currently occupying the specified coordinates
  bool selfDestruct(); // Returns true if the Snake runs into itself
} SnakeBody;


/*
Snake function definitions
*****************************************
*/
Snake::Snake() {
  X = uBit.random(WIDTH-2);
  Y = uBit.random(HEIGHT);
  score = 1;
  setDirection = true;
  direction = RIGHT;
  body = new FixedStack(1);
  body->push(new Node(X, Y));
}

bool Snake::offScreen() {
  if (X < 0 || X > (WIDTH-1) || Y < 0 || Y > (HEIGHT-1))
  return true;
  return false;
}

void Snake::move() {
  switch (direction) {
    case UP:    Y--;
    break;
    case DOWN:  Y++;
    break;
    case LEFT:  X--;
    break;
    case RIGHT: X++;
    break;
  }

  if (X == (Fruit.X) && Y == (Fruit.Y)) {

    body->incrementMaxSize(new Node(X, Y));
    score++;
    if (score == 25) FINISHED = true;
    else Fruit.refresh();

  }else delete body->push(new Node(X, Y));

  setDirection = true;
}

void Snake::display(MicroBitImage m, uint8_t brightness) {
  Node* itr = body->peek();
  while (itr) {
    m.setPixelValue(itr->x_cord, itr->y_cord, brightness);
    itr = itr->next;
  }
}

bool Snake::occupied(uint8_t x, uint8_t y) {
  Node* itr = this->body->peek();
  while (itr) {
    if (itr->x_cord == x && itr->y_cord == y)
      return true;
    itr = itr->next;
  }
  return false;
}

bool Snake::selfDestruct() {
  if (this->body->size() >= 5) {
    Node* itr = this->body->peek()->next->next->next->next;
    while (itr) {
      if (itr->x_cord == this->body->peek()->x_cord && itr->y_cord == this->body->peek()->y_cord) {
        return true;
      }
      itr = itr->next;
    }
  }
  return false;
}
/*
*****************************************
*/


/*
RandomPixel function definitions
*****************************************
*/
RandomPixel::RandomPixel() {
  uBit.init();
  (this->X) = uBit.random(2)+3;
  (this->Y) = uBit.random(HEIGHT);
}

void RandomPixel::refresh() {
  do {
    (this->X) = uBit.random(WIDTH);
    (this->Y) = uBit.random(HEIGHT);
  } while(SnakeBody.occupied(this->X, this->Y));
}

void RandomPixel::display(MicroBitImage m, uint8_t brightness) {
  m.setPixelValue(X, Y, brightness);
}
/*
*****************************************
*/

/*
User Events
*****************************************
*/
void onButtonA(MicroBitEvent e) {
  if (SnakeBody.setDirection) {
    switch (SnakeBody.direction) {
      case UP:    SnakeBody.direction = LEFT;
      break;
      case DOWN:  SnakeBody.direction = RIGHT;
      break;
      case LEFT:  SnakeBody.direction = DOWN;
      break;
      case RIGHT: SnakeBody.direction = UP;
      break;
    }
    SnakeBody.setDirection = false;
  }
}

void onButtonB(MicroBitEvent e) {
  if (SnakeBody.setDirection) {
    switch (SnakeBody.direction) {
      case UP:    SnakeBody.direction = RIGHT;
      break;
      case DOWN:  SnakeBody.direction = LEFT;
      break;
      case LEFT:  SnakeBody.direction = UP;
      break;
      case RIGHT: SnakeBody.direction = DOWN;
      break;
    }
    SnakeBody.setDirection = false;
  }
}
/*
*****************************************
*/


int main() {
  uBit.init();
  FINISHED = false;
  uBit.display.setDisplayMode(DISPLAY_MODE_GREYSCALE);
  uBit.display.setBrightness(100);
  uBit.display.print("SNAKE", 500);
  uBit.display.print(3);
  uBit.sleep(800);
  uBit.display.print(2);
  uBit.sleep(800);
  uBit.display.print(1);
  uBit.sleep(800);

  const uint8_t game[] = {
    0, 0, 0, 0, 0,
    0, 0, 0, 0, 0,
    0, 0, 0, 0, 0,
    0, 0, 0, 0, 0,
    0, 0, 0, 0, 0,
  };
  MicroBitImage map(WIDTH, HEIGHT, game);

  uBit.messageBus.listen(MICROBIT_ID_BUTTON_A, MICROBIT_EVT_ANY, onButtonA);
  uBit.messageBus.listen(MICROBIT_ID_BUTTON_B, MICROBIT_EVT_ANY, onButtonB);

  map.setPixelValue(SnakeBody.X, SnakeBody.Y, SNAKE_BRIGHTNESS);
  map.setPixelValue(Fruit.X, Fruit.Y, FRUIT_BRIGHTNESS);
  uBit.display.print(map);

  uBit.sleep(1000);

  while (1) {
    map.clear();
    SnakeBody.move();

    if (SnakeBody.offScreen() || SnakeBody.selfDestruct() || FINISHED)
      break;

    SnakeBody.display(map, SNAKE_BRIGHTNESS);
    Fruit.display(map, FRUIT_BRIGHTNESS);
    uBit.display.print(map);

    uBit.sleep(750);
  }


  uBit.display.clear();


  /*
    Game over Animations
  */
  if (FINISHED) {
    MicroBitImage fill("255,255,255,255,255\n255,255,255,255,255\n255,255,255,255,255\n255,255,255,255,255\n255,255,255,255,255\n");
    uBit.display.print(fill);
    MicroBitImage f1("0,0,0,0,0\n0,0,0,0,0\n0,0,255,0,0\n0,0,0,0,0\n0,0,0,0,0\n");
    MicroBitImage f2("0,0,0,0,0\n0,255,255,255,0\n0,255,0,255,0\n0,255,255,255,0\n0,0,0,0,0\n");
    MicroBitImage f3("255,255,255,255,255\n255,0,0,0,255\n255,0,0,0,255\n255,0,0,0,255\n255,255,255,255,255\n");

    uBit.sleep(1000);
    while (1) {
      uBit.display.clear();

      uBit.display.print(f2);
      uBit.sleep(500);

      uBit.display.print(f1);
      uBit.sleep(500);

      uBit.display.clear();
      uBit.sleep(500);

      uBit.display.print(f1);
      uBit.sleep(500);

      uBit.display.print(f2);
      uBit.sleep(500);

      uBit.display.print(f3);
      uBit.sleep(500);
    }
  }else{
    uBit.display.scroll("GAME OVER", 100);
    uBit.display.scroll("SCORE:", 100);

    while (1) {
      uBit.display.print(SnakeBody.score);
      uBit.sleep(1000);
    }
  }
}
FixedStack.cpp

代码: 全选

#include <cstdio>
#include "FixedStack.h"

FixedStack::FixedStack(int max) {
  this->head = NULL;
  this->max_size = max;
  this->stack_size = 0;
}

int FixedStack::size() { return this->stack_size; }

bool FixedStack::isEmpty() {
  if (this->head)
  return false;
  return true;
}

Node* FixedStack::peek() {
  return this->head;
}

Node* FixedStack::push(Node* node) {

  if (!isEmpty()) {
    Node* temp = this->head;
    this->head = node;
    node->next = temp;

    if (stack_size < max_size) {
      this->stack_size++;
      return NULL;
    }else{
        temp = this->head;
        while (temp->next->next) {
        temp = temp->next;
        }

        Node* tr = temp->next;
        temp->next = NULL;
        return tr;
    }
  }else {
    node->next = NULL;
    this->head = node;
    this->stack_size++;
    return NULL;
  }
}


void FixedStack::incrementMaxSize(Node* node) {
  node->next = this->head;
  this->head = node;
  this->max_size++;
  this->stack_size++;
}
FixedStack.h

代码: 全选

#ifndef FSTK
#define FSTK

/*
  Definition: The Node class stores data for exactly ONE pixel
              Specifically, the X and Y coordinates of the pixel

  Usage:      A collection of Nodes creates the "Snake" body
              (stored inside the FixedStack Data Structure)
*/
class Node {

public:
  uint8_t x_cord; // x-coordinate of the pixel
  uint8_t y_cord; // y-coordinate of the pixel
  Node* next; // (Internal) Pointer to the next Node

  // Initializing the data fields
  Node(uint8_t x, uint8_t y) {
    this->next = NULL;
    this->x_cord = x;
    this->y_cord = y;
  }

};

/*
  Definition: The FixedStack is derived from the Stack (Last In First Out or LIFO) Data Structure
              The FixedStack has a Fixed Max Size, meaning that items at the bottom of the stack will be removed as additional items are pushed onto the stack
              The Max Size can be incremented, but cannot be reduced

  Usage:      The Snake class (defined in the "main.cpp" file) uses a FixedStack to contruct the "body" of the "Snake"
*/
class FixedStack {

private:
  int max_size; // Max Size of the FixedStack
  int stack_size; // Current size of the FixedStack (Excludes NULL elements)
  Node* head; // Head of the FixedStack

public:
  FixedStack(int size); // Initialize the FixedStack with a max size
  int size(); // Returns the current size of the FixedStack
  bool isEmpty(); // Returns true if the FixedStack is empty
  Node* peek(); //Rreturns the head Node of the FixedStack
  Node* push(Node* node); // Push a Node onto the FixedStack. Returns the last Node if overflows and NULL otherwise.
  void incrementMaxSize(Node* node); // Increase the max size of the FixedStack by 1 and push a new Node onto the FixedStack

};

#endif
 

回复

  • 随机主题
    回复总数
    阅读次数
    最新文章