C++贪吃蛇小游戏 list版本 改进版本

/*-----------------------------------------------
自制简易版贪吃蛇 用list 取代了原先的vector结构 ,并且独立出了食物类,
使食物和蛇区分开来产生 感觉这种框架更容易实现后续的蛇蛇大作战 。
对于改变direction使用了多线程,玩家操作太快(比如方向是A,快速按了W和D)

容易导致反方向运动,蛇蛇直接死亡。20191008

添加change 变量修复了bug 20191009

------------------------------------------------*/

//Food.h begin--------------------------------------------------------------------------------------
#ifndef _FOOD_H_
#define _FOOD_H_

#include"Point.h"
#include"Snake.h"
#include<list>
using namespace std;
class Snake;

class Food
{
private:
Point food;
public:
Food();
Food(Point F);
void print();
void set_food(Point F);
Point get_food();
//判断是否应该产生食物。
bool IsFood(list<Point>body);
};

#endif // !_FOOD_H_

//Food.h end--------------------------------------------------------------------------------------

//Point.h begin--------------------------------------------------------------------------------------

#ifndef _POINT_H_
#define _POINT_H_
class Point
{
private:
int x;
int y;
public:
Point() :x(0), y(0) {};
Point(int X, int Y) :x(X), y(Y) {};
int get_x();
int get_y();
void set_x(int);
void set_y(int);
//重载 == 用于判断吃到食物和死完。
bool operator ==(const Point &A)const
{
if (this->x == A.x && this->y == A.y)
return true;
return false;
}

};

#endif // !_POINT_H_

//Point.h end--------------------------------------------------------------------------------------

//Snake.h begin--------------------------------------------------------------------------------------

#ifndef _SNAKE_H_
#define _SNAKE_H_
#include<list>
#include"Point.h"
#include"Food.h"

#include<graphics.h>
using namespace std;
class Food;
class Snake
{
private:
list<Point>body;
int len;
int direction;
public:
Snake();
Snake(Point head);
int get_len();
int get_direction();
//改变方向
void set_direction(int);
//移动
void move();
//打印
void print(PIMAGE snake_img);
//返回身体
list<Point> get_body();
//吃饭
void eat_food(Food);
};

#endif // !_SNAKE_H_

//Snake.h end--------------------------------------------------------------------------------------

//Point.cpp begin--------------------------------------------------------------------------------------

#include"Point.h"

int Point::get_x()
{
return x;
}

int Point::get_y()
{
return y;
}

void Point::set_x(int X)
{
x = X;
}
void Point::set_y(int Y)
{
y = Y;
}

//Point.cpp end--------------------------------------------------------------------------------------

//Food.cpp begin--------------------------------------------------------------------------------------

#include"Food.h"
#include<graphics.h>
Food::Food()
{

}
Food::Food(Point F)
{
food.set_x(F.get_x());
food.set_y(F.get_y());
}
void Food::print()
{
bar(food.get_x() * 10, food.get_y() * 10, food.get_x() * 10 + 10, food.get_y() * 10 + 10);
}

//设置食物
void Food::set_food(Point F)
{
food.set_x(F.get_x());
food.set_y(F.get_y());
}

//获取食物
Point Food::get_food()
{
return food;
}

//判断是否加食物
bool Food::IsFood(list<Point>body)
{
for (auto temp : body)
{
if (temp == food)
{
return false;
}
}
return true;
}

//Food.cpp end--------------------------------------------------------------------------------------

//Snake.cpp begin--------------------------------------------------------------------------------------

#include"Snake.h"
#include"Food.h"
#include<graphics.h>
#include<iostream>
#include<mutex>
using namespace std;
extern Food food;
extern bool ISFOOD;
extern bool ISDEAD;
extern int HEIGHT;
extern int WIDTH;
const int U = 0;
const int D = 1;
const int L = 2;
const int R = 3;


//初始化蛇
Snake::Snake() :len(1), direction(0)
{
Point snake_head;
body.push_back(snake_head);
}

//带起始位置的初始化
Snake::Snake(Point head) :len(1), direction(0)
{
body.push_back(head);
}

//获取蛇身长度
int Snake::get_len()
{
return this->len;
}

//获取移动方向
int Snake::get_direction()
{
return this->direction;
}

//改变移动方向
void Snake::set_direction(int Direction)
{
this->direction = Direction;
}

//移动
int px = 0;
int py = 0;
Point head;
void Snake::move()
{
px=0;
py=0;
head = body.front();
if (food.get_food() == head)
{
eat_food(food);
ISFOOD = true;
}
switch (direction)
{
case U:
py = -1;
break;
case D:
py = 1;
break;
case L:
px = -1;
break;
case R:
px = 1;
break;
default:
break;
}
//改变蛇头
body.front().set_x(body.front().get_x() + px);
body.front().set_y(body.front().get_y() + py);
if (body.front().get_x() > (HEIGHT / 10 - 1))
{
body.front().set_x(0);
}
if (body.front().get_x() < 0 )
{
body.front().set_x((HEIGHT / 10 - 1));
}
if (body.front().get_y() > (WIDTH / 10 - 1))
{
body.front().set_y(0);
}
if (body.front().get_y() < 0)
{
body.front().set_y((WIDTH / 10 - 1));
}
//蛇蛇移动的核心代码。
if (len > 1)
{
body.insert(++body.begin(), head);
body.pop_back();
}
}

//打印

void Snake::print(PIMAGE snake_img)
{
clearviewport(snake_img);
settarget(snake_img);
setfillcolor(RED); //设置蛇蛇颜色
bar(body.front().get_x() * 10, body.front().get_y()*10, body.front().get_x()*10+10, body.front().get_y()*10+10);
setfillcolor(BLUE);
int flag = true; //跳过蛇头(需要区分蛇头和蛇身的颜色的情况下)
for (auto temp : body)
{
if (flag)
{
flag = false;
continue;
}
//绘制矩形
bar(temp.get_x() * 10, temp.get_y() * 10, temp.get_x() * 10 + 10, temp.get_y() * 10 + 10);
}
setfillcolor(GREEN);//设置食物颜色
bar(food.get_food().get_x() * 10, food.get_food().get_y() * 10, food.get_food().get_x() * 10 + 10, food.get_food().get_y() * 10 + 10);
setfillcolor(WHITE);
settarget(NULL);
putimage(0,0,snake_img);
}

//获取蛇身,用来判断是否加食物和判断是否死亡
list<Point> Snake::get_body()
{
return body;
}

//蛇蛇吃饭
void Snake::eat_food(Food f)
{
body.push_back(f.get_food());
++len;
}

//Snake.cpp end--------------------------------------------------------------------------------------

//main.cpp begin--------------------------------------------------------------------------------------

#include<iostream>
#include<thread>
#include<time.h>
#include<graphics.h>
#include<conio.h>
#include<Windows.h>
#include"Point.h"
#include"Snake.h"
#include"Food.h"
#include<string>
#include<mutex>
using namespace std;
int HEIGHT = 600;
int WIDTH = 400;

bool ISDEAD= false; //判断死亡
bool ISFOOD = false; //判断食物
bool change = false; //判断能否改变方向。


Food food(Point(rand()%(HEIGHT/10-1), rand() % (WIDTH / 10 - 1)));
mutex my_mutex;
//方向
char ch;

void change_direction(Snake *snake)
{
while (true)
{
ch = getch();
if (change == false)
{
continue;
}
unique_lock<mutex>my_unique(my_mutex);
switch (ch)
{
case 'W':
case 'w':
if (snake->get_direction() == 1 || snake->get_direction() == 0)
break;
else
{
snake->set_direction(0);
break;
}
case 'S':
case 's':
if (snake->get_direction() == 1 || snake->get_direction() == 0)
break;
else
{
snake->set_direction(1);
break;
}
case 'A':
case 'a':
if (snake->get_direction() == 2 || snake->get_direction() == 3)
break;
else
{
snake->set_direction(2);
break;
}
case 'D':
case 'd':
if (snake->get_direction() == 2 || snake->get_direction() == 3)
break;
else
{
snake->set_direction(3);
break;
}
default:
break;
}
my_unique.unlock();
change = false;
}
}

int main()
{
unsigned int Srand = time(0);
srand(Srand);
initgraph(HEIGHT, WIDTH);
HWND hwnd = getHWnd();
HDC hdc = GetDC(hwnd);
SetWindowText(hwnd, "贪吃蛇小游戏");
Snake snake(Point(30,20));

//改变蛇移动方向的线程。
thread my_thread(change_direction, &snake);

PIMAGE snake_img = newimage(HEIGHT, WIDTH);
Point f(rand() % (HEIGHT / 10 - 1), rand() % (WIDTH / 10 - 1));

int i = 0; // 跳过头部
//游戏开始
while (true)
{
//蛇在移动
my_mutex.lock();
snake.move();
my_mutex.unlock();

change=true;
//产生食物
while (ISFOOD)
{
f.set_x(rand() % (HEIGHT / 10 - 1));
f.set_y(rand() % (WIDTH / 10 - 1));
food.set_food(f);
if (food.IsFood(snake.get_body()))
{
ISFOOD = false;
}
}

//打印蛇
snake.print();

i = 0;
//判断蛇是否死亡。
for (auto sk : snake.get_body())
{
if (i == 0)
{
i = 1;
continue;
}
if (snake.get_body().front() == sk)
{
int len = snake.get_len();
len *= 10;
string s = "少侠你的得分是";
s += to_string(len);
s += "分!";
char *score = (char*)s.c_str();
MessageBox(hwnd, score, "对不起!", MB_YESNO);
exit(0);
}
}
Sleep(100);
}
getch();

delimage(snake_img);

closegraph();
return 0;
}

//main.cpp end--------------------------------------------------------------------------------------

原文地址:https://www.cnblogs.com/yangshengjing/p/11636838.html