这是贪吃蛇的效果图。一边看《新三国》,一边写的结果。第一次写C++的,用类实现,还挺好玩的。
设计总共分为3个类:地图,蛇,食物
先上传全部代码:头文件
#include <stdio.h> #include <stdlib.h> #include <string> #include <iterator> #include <algorithm> #include <iostream> #include <vector> #include <deque> #include <list> #include <set> #include<Windows.h> #include<conio.h> using namespace std; typedef unsigned char uchar; struct Point{ int x; int y; }; enum SnakeState{ Eat = 0, NotEat = 1, HitWall = -1, Common = 10 }snakeState; enum SnakeDir{ Up = 72, Down = 80, Left = 75, Right = 77 }; class CSnake; class CFood; class CMap{ public: CMap(int t, int l, int w, int h); ~CMap(); void mapUpdate(CSnake& s,CFood& f); bool mapShow(); private: int top; int left; int width; int height; uchar **mat; uchar dir; uchar lastDir; CSnake *snake; CFood *food; }; class CSnake{ public: CSnake(int t, int l, int w, int h); ~CSnake(); friend class CMap; int newHeadPoint(uchar dir, Point foodpoint); private: int top; int left; int width; int height; vector<Point*> snakeBody; Point headPoint; }; class CFood{ public: CFood(int t, int l, int w, int h); ~CFood(); friend class CMap; Point newFoodPoint(); private: int top; int left; int width; int height; Point foodPoint; };
cpp文件:
#include <stdio.h> #include <stdlib.h> #include <string> #include <iterator> #include <algorithm> #include <iostream> #include <vector> #include <deque> #include <list> #include <set> #include<Windows.h> #include<conio.h> #include "main.h" using namespace std; void delay(int n) { for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { int k = 100 + 100; } } } CMap::CMap(int t, int l, int w, int h) { top = t; left = l; width = w; height = h; dir = Down; lastDir = Down; //内存分配 mat = new uchar*[height]; for (int i = 0; i < height; i++) { mat[i] = new uchar[width]; } //初始化路径矩阵边界 for (int i = 0; i < height; i++) { mat[i][0] = '#'; for (int j = 1; j < width - 1; j++) { if (i == 0 || i == height - 1) { mat[i][j] = '#'; } else { mat[i][j] = ' '; } } mat[i][width - 1] = '#'; } snake = new CSnake(0, 0, 50, 25); food = new CFood(0, 0, 50, 25); } CMap::~CMap() { for (int i = 0; i < height; i++) { delete mat[i]; } delete mat; } void CMap::mapUpdate(CSnake& s, CFood& f) { mat[f.foodPoint.y][f.foodPoint.x] = 'O'; for (int i = 0; i < s.snakeBody.size(); i++) { if (i == 0) { mat[s.snakeBody[i]->y][s.snakeBody[i]->x] = '@'; } else { mat[s.snakeBody[i]->y][s.snakeBody[i]->x] = '*'; } } } bool CMap::mapShow() { //设置顶点坐标,使得绘制一直在起点 COORD coord; coord.X = top; coord.Y = left; SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord); for (int i = 1; i < height - 1; i++) { memset(mat[i] + 1, ' ', width - 2); } //更新食物坐标和蛇坐标 mapUpdate(*snake, *food); while (kbhit()) { dir = getch(); if (lastDir + dir == 152)//利用ascii码特性,防止蛇走反方向 { dir = lastDir; } } //更新蛇坐标 int res = snake->newHeadPoint(dir,food->foodPoint); lastDir = dir; if (res == Eat) { //产生新的食物坐标 food->newFoodPoint(); } //绘制所有,包括地图,蛇,食物 for (int i = 0; i < height; i++) { for (int j = 0; j < width; j++) { cout << mat[i][j]; } cout << endl; } if (res == HitWall) { return true; } return false; } CSnake::CSnake(int t, int l, int w, int h) { top = t; left = l; width = w; height = h; //随机起始坐标 srand(5); headPoint.x = rand() % (width - 2) + 1; headPoint.y = rand() % (height - 2) + 1; Point *tmp = new Point(); tmp->x = headPoint.x; tmp->y = headPoint.y; snakeBody.push_back(tmp); } CSnake::~CSnake() { for (int i = 0; i < snakeBody.size(); i++) { delete snakeBody[i]; } } int CSnake::newHeadPoint(uchar dir, Point foodpoint) { switch (dir) { //上 case Up:headPoint.y--; break; //下 case Down:headPoint.y++; break; //左 case Left:headPoint.x--; break; //右 case Right:headPoint.x++; break; default: break; } if ((headPoint.x == 0) || (headPoint.x == width - 1) || (headPoint.y == 0) || (headPoint.y == height - 1)) { return HitWall; } //吃到食物 if ((headPoint.x == foodpoint.x) && (headPoint.y == foodpoint.y)) { Point *tmp = new Point(); tmp->x = foodpoint.x; tmp->y = foodpoint.y; snakeBody.insert(snakeBody.begin(), tmp); headPoint.x = foodpoint.x; headPoint.y = foodpoint.y; return Eat; } else//没吃到食物 { for (int i = snakeBody.size() - 1; i > 0; i--) { snakeBody[i]->x = snakeBody[i - 1]->x; snakeBody[i]->y = snakeBody[i - 1]->y; } snakeBody[0]->x = headPoint.x; snakeBody[0]->y = headPoint.y; return NotEat; } return Common; } CFood::CFood(int t, int l, int w, int h) { top = t; left = l; width = w; height = h; srand(8); newFoodPoint(); } CFood::~CFood() { } Point CFood::newFoodPoint() { foodPoint.x = rand() % (width - 2) + 1; foodPoint.y = rand() % (height - 2) + 1; return foodPoint; } int main(int argc, char *argv[]) { CMap map(0, 0, 50, 25); while (1) { bool res= map.mapShow(); delay(8000); if (res) { cout << "GAME OVER!" << endl; break; } } return 0; }
首先看食物类:
class CFood{ public: CFood(int t, int l, int w, int h); ~CFood(); friend class CMap; Point newFoodPoint(); private: int top; int left; int width; int height; Point foodPoint; }; CFood::CFood(int t, int l, int w, int h) { top = t; left = l; width = w; height = h; srand(8); newFoodPoint(); } CFood::~CFood() { } Point CFood::newFoodPoint() { foodPoint.x = rand() % (width - 2) + 1; foodPoint.y = rand() % (height - 2) + 1; return foodPoint; }
newFoodPoint函数用于产生随机的食物坐标点,当吃掉食物时调用这个函数。这个类比较简单。
class CSnake{ public: CSnake(int t, int l, int w, int h); ~CSnake(); friend class CMap; int newHeadPoint(uchar dir, Point foodpoint); private: int top; int left; int width; int height; vector<Point*> snakeBody; Point headPoint; }; CSnake::CSnake(int t, int l, int w, int h) { top = t; left = l; width = w; height = h; //随机起始坐标 srand(5); headPoint.x = rand() % (width - 2) + 1; headPoint.y = rand() % (height - 2) + 1; Point *tmp = new Point(); tmp->x = headPoint.x; tmp->y = headPoint.y; snakeBody.push_back(tmp); } CSnake::~CSnake() { for (int i = 0; i < snakeBody.size(); i++) { delete snakeBody[i]; } } int CSnake::newHeadPoint(uchar dir, Point foodpoint) { switch (dir) { //上 case Up:headPoint.y--; break; //下 case Down:headPoint.y++; break; //左 case Left:headPoint.x--; break; //右 case Right:headPoint.x++; break; default: break; } if ((headPoint.x == 0) || (headPoint.x == width - 1) || (headPoint.y == 0) || (headPoint.y == height - 1)) { return HitWall; } //吃到食物 if ((headPoint.x == foodpoint.x) && (headPoint.y == foodpoint.y)) { Point *tmp = new Point(); tmp->x = foodpoint.x; tmp->y = foodpoint.y; snakeBody.insert(snakeBody.begin(), tmp); headPoint.x = foodpoint.x; headPoint.y = foodpoint.y; return Eat; } else//没吃到食物 { for (int i = snakeBody.size() - 1; i > 0; i--) { snakeBody[i]->x = snakeBody[i - 1]->x; snakeBody[i]->y = snakeBody[i - 1]->y; } snakeBody[0]->x = headPoint.x; snakeBody[0]->y = headPoint.y; return NotEat; } return Common; }
这个是蛇的类,主要实现一个newHeadPoint的函数用于规划蛇身体snakeBody的位置坐标。还有一个headPoint的点结构体。
输入参数是一个方向参数dir和食物坐标参数。方向来控制蛇身的移动,食物坐标来检测是否吃到食物。
通过不断移动蛇身体的坐标,最后把headPoint点赋给第一个点来实现蛇身体的移动。
class CMap{ public: CMap(int t, int l, int w, int h); ~CMap(); void mapUpdate(CSnake& s,CFood& f); bool mapShow(); private: int top; int left; int width; int height; uchar **mat; uchar dir; uchar lastDir; CSnake *snake; CFood *food; }; CMap::CMap(int t, int l, int w, int h) { top = t; left = l; width = w; height = h; dir = Down; lastDir = Down; //内存分配 mat = new uchar*[height]; for (int i = 0; i < height; i++) { mat[i] = new uchar[width]; } //初始化路径矩阵边界 for (int i = 0; i < height; i++) { mat[i][0] = '#'; for (int j = 1; j < width - 1; j++) { if (i == 0 || i == height - 1) { mat[i][j] = '#'; } else { mat[i][j] = ' '; } } mat[i][width - 1] = '#'; } snake = new CSnake(0, 0, 50, 25); food = new CFood(0, 0, 50, 25); } CMap::~CMap() { for (int i = 0; i < height; i++) { delete mat[i]; } delete mat; } void CMap::mapUpdate(CSnake& s, CFood& f) { mat[f.foodPoint.y][f.foodPoint.x] = 'O'; for (int i = 0; i < s.snakeBody.size(); i++) { if (i == 0) { mat[s.snakeBody[i]->y][s.snakeBody[i]->x] = '@'; } else { mat[s.snakeBody[i]->y][s.snakeBody[i]->x] = '*'; } } } bool CMap::mapShow() { //设置顶点坐标,使得绘制一直在起点 COORD coord; coord.X = top; coord.Y = left; SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord); for (int i = 1; i < height - 1; i++) { memset(mat[i] + 1, ' ', width - 2); } //更新食物坐标和蛇坐标 mapUpdate(*snake, *food); while (kbhit()) { dir = getch(); if (lastDir + dir == 152)//利用ascii码特性,防止蛇走反方向 { dir = lastDir; } } //更新蛇坐标 int res = snake->newHeadPoint(dir,food->foodPoint); lastDir = dir; if (res == Eat) { //产生新的食物坐标 food->newFoodPoint(); } //绘制所有,包括地图,蛇,食物 for (int i = 0; i < height; i++) { for (int j = 0; j < width; j++) { cout << mat[i][j]; } cout << endl; } if (res == HitWall) { return true; } return false; }
地图类。类的初始化会把mat数组给初始化了。边界为#,蛇身为*,食物为O
mapUpdate函数用于更新mat数组。mapShow为界面显示地图。这个都比较简单。
流程为:
清空mat矩阵中部——更新数组——按键检测——蛇移动——绘制所有