C++实验课要求通过控制台编写一个简易的贪吃蛇游戏,在2个多小时的艰难探索后,终于完成了。之后习题课讲解这道题时,我望着屏幕上孤零零的贪吃蛇,不免有些难过。于是,我大幅度改造了游戏架构,通过类实现第二条蛇的生成,并编写AI控制程序。以下是实现的C++代码和成品下载。
导读
游戏界面
// Snakes.h :头文件
//用于声明Snake的类
#include <vector>
#include <stdexcept>
using namespace std;
class Snake
{
public:
void generate(int,int);
int getX(int);
int getY(int);
int getLength();
void eat();
void move(int);
private:
vector<int> snakeX;
vector<int> snakeY;
int food = 0;
int way = 0;
};
// Snakes.cpp
//说明Snake类的作用
#include <iostream>
#include <Windows.h>
#include <array>
#include <stdio.h>
#include <cstdlib>
#include <ctime>
#include Snakes.h
void Snake::move(int iWay)
{
if (way != 2 && iWay==1) //防止蛇掉头致死
{
way = 1;
}
else if (way != 1 && iWay == 2)
{
way = 2;
}
else if (way != 4 && iWay == 3)
{
way = 3;
}
else if (way != 3 && iWay == 4)
{
way = 4;
}
if (way != 0)
{
for (size_t i = food; i > 0; i--)//确保每一段蛇身紧跟着前一段蛇身的位置
{
if (food == 0)
{
break;
}
snakeX[i] = snakeX[i - 1];
snakeY[i] = snakeY[i - 1];
}
}
switch (way)//设别方向并改变坐标
{
default:
break;
case 0:
break;
case 1:
snakeY[0]--;
break;
case 2:
snakeY[0]++;
break;
case 3:
snakeX[0]--;
break;
case 4:
snakeX[0]++;
break;
}
}
void Snake::eat()
{
snakeX.push_back(snakeX[0]);
snakeY.push_back(snakeY[0]);
food++;
}
int Snake::getLength()
{
return food;
}
int Snake::getX(int i)
{
return snakeX[i];
}
int Snake::getY(int i)
{
return snakeY[i];
}
void Snake::generate(int x,int y)//生成蛇
{
snakeX.push_back(x);
snakeY.push_back(y);
}
// SnakeMain.cpp : Defines the entry point for the console application.
//两条贪吃蛇的实现
#include <iostream>
#include <Windows.h>
#include <array>
#include <stdio.h>
#include <ctime>
#include Snakes.h
#include <string>
#define KEY_DOWN(vk_code) GetAsyncKeyState(vk_code) & 0x8000 ? 1 : 0 //用于判断按键输入
using namespace std;
const int xb = 40, yb = xb;//边界大小,如果屏幕较小可以适当缩小该数值
array < array<int,xb+2>,yb+2 > map;//二维数组,-1蛇头 0空气 1砖块 2蛇身 3食物
int iway = 0;
void generateMap()//为map数组赋值,添加砖块
{
int x=0, y=1;
while (true)
{
x++;
if (x>xb)//判断坐标,防止越界
{
x = 1;
y++;
}
if (y > yb)
{
break;
}
if (x==1 || x==xb || y==1 ||y==yb)
{
map[x][y] = 1;
}
else
{
map[x][y] = 0;
}
}
map[2 + rand() % (xb - 1)][2 + rand() % (yb - 1)] = 3;
}
void printMap()//在控制台上打印游戏界面,使用string变量统一打印可以缓解屏闪问题
{
size_t x = 0, y = 1;
string str;
while (true)
{
x++;
if (x>xb)
{
x = 1;
y++;
str = str + \n;
}
if (y > yb)
{
break;
}
switch (map[x][y])
{
default:
break;
case -1:
str = str + ■;
break;
case 0:
str = str + ;
break;
case 1:
str = str + ■;
break;
case 2:
str = str + ■;
break;
case 3:
str = str + ■;
break;
}
}
system(cls);
cout << str;
}
void clearMap()//清除残留蛇身信息,使程序更新蛇身位置
{
size_t x = 0, y = 1;
while (true)
{
x++;
if (x>xb)
{
x = 1;
y++;
}
if (y > yb)
{
break;
}
if (map[x][y] == 2 || map[x][y]==-1)
{
map[x][y] = 0;
}
}
}
int main()
{
generateMap();
srand(time(0));
Snake player1;
Snake player2;//可以多次添加增加更多只蛇
player1.generate(xb / 2, yb / 2);
player2.generate(xb / 3, yb / 3);
while (true)
{
printMap();
Sleep(10);//延迟10秒
if (KEY_DOWN(VK_UP)) //判断键盘按下按钮
{
player1.move(1);
}
else if (KEY_DOWN(VK_DOWN)) {
player1.move(2);
}
else if (KEY_DOWN(VK_LEFT)) {
player1.move(3);
}
else if (KEY_DOWN(VK_RIGHT)) {
player1.move(4);
}
else//没按下按钮默认原方向(见Snakes.cpp)
{
player1.move(0);
}
int ix = 0, iy = 0,oldway=iway;//预先判断AI方向,确保无障碍
switch (iway)
{
default:
break;
case 1:
iy = -1;
break;
case 2:
iy = 1;
break;
case 3:
ix = -1;
break;
case 4:
ix = 1;
break;
}
if (rand() % 4 == 0 || map[player2.getX(0) + ix][player2.getY(0) + iy] != 0)
{
while (true)
{
ix = 0; iy = 0;
iway = 1 + rand() % 4;//随机试探方向
if (oldway == 2 && iway == 1) //防止AI直接掉头
{
iway = 2;
}
else if (oldway == 1 && iway == 2) {
iway = 1;
}
else if (oldway == 3 && iway == 4) {
iway = 3;
}
else if (oldway == 4 && iway == 3) {
iway = 4;
}
switch (iway)
{
default:
break;
case 1:
iy = -1;
break;
case 2:
iy = 1;
break;
case 3:
ix = -1;
break;
case 4:
ix = 1;
break;
}
if (map[player2.getX(0) + ix][player2.getY(0) + iy] == 3)//如果周围有食物,试探结束
break;
if (map[player2.getX(0) + ix][player2.getY(0) + iy] == 0)//如果周围是空气,试探结束
break;
if (rand() % 10000 == 0)//如果四周都无法通过,则随机选择一个方向
{
break;
}
}
}
if (map[player2.getX(0) + 1][player2.getY(0)] == 3)//遍历四个方向,如果有食物,则锁定该方向
iway = 4;
if (map[player2.getX(0) - 1][player2.getY(0)] == 3)
iway = 3;
if (map[player2.getX(0)][player2.getY(0) - 1] == 3)
iway = 1;
if (map[player2.getX(0)][player2.getY(0) + 1] == 3)
iway = 2;
player2.move(iway);
if (map[player1.getX(0)][player1.getY(0)] == 3)//玩家吃到食物
{
player1.eat();
}
if (map[player1.getX(0)][player1.getY(0)] == 1 || map[player1.getX(0)][player1.getY(0)] == 2)//玩家撞到蛇身或墙
{
cout << Game over!;
system(Pause);
return 0;
}
if (map[player2.getX(0)][player2.getY(0)] == 3)//同理
{
player2.eat();
}
if (map[player2.getX(0)][player2.getY(0)] == 1 || map[player2.getX(0)][player2.getY(0)] == 2)//AI撞到蛇身或墙
{
cout << You win!;
system(Pause);
return 0;
}
clearMap();
for (size_t i = 1; i <= player1.getLength(); i++)//更新蛇身在地图的位置
{
map[player1.getX(i)][player1.getY(i)] = 2;
}
for (size_t i = 1; i <= player2.getLength(); i++)
{
map[player2.getX(i)][player2.getY(i)] = 2;
}
map[player1.getX(0)][player1.getY(0)] = -1;//更新蛇头在地图的位置
map[player2.getX(0)][player2.getY(0)] = -1;
if (rand() % 100 > 90)//随机生成食物
{
ix = 2 + rand() % (xb - 1);
iy = 2 + rand() % (yb - 1);
if (map[ix][iy] == 0)//确保食物在空气中生成
{
map[ix][iy] = 3;
}
}
}
system(Pause);
return 0;
}
开发界面
成品下载链接:https://pan.baidu.com/s/1NBvh0baBEdp4xgkZFK5cIA 提取码: nrpu
欢迎来到Yari的网站:yar2001 » 快乐的两条贪吃蛇 C++控制台小游戏开发