#include <iostream>
//using namespace std;
bool GameOver;
const int width = 20;
const int heigth = 20;
int x, y, FruitX, FruitY, score;
void Setup()//初始化设置
{
}
void Draw()//绘画界面
{
}
void Input()//扫描输入
{
}
void Logic()//游戏逻辑
{
}
int main()
{
Setup();
while (!GameOver)
{
Draw();
Input();
Logic();
}
}
Setup函数
void Setup()//初始化设置
{
GameOver = false;
x = width / 2;
y = heigth / 2;
FruitX = rand() % width;
FruitY = rand() % heigth;
score = 0;
}
我们需要对蛇头与苹果位置进行初始化,游戏结束标志位置为0,分数置为0。
其中坐标位置如下(i,j),右下角位置即(width,heigth)
(0,0)(0,1)(0,2)(0,3)(0,4)
(1,0)()()()()
(2,0)()()()()
(3,0)()()()()
(4,0)()()()(4,4)
我们让蛇头初始化位置在界面正中间,苹果位置随机出现。
Draw函数
void Draw()//绘画界面
{
system("cls");
for (int i = 0; i < width ; i++)
{
cout << "#";
}
cout << endl;
for (int i = 0; i < heigth; i++)
{
for (int j = 0; j < width ; j++)
{
if (j == 0)cout << "#";
if (i == y && j == x)cout << "O";
else if(i == FruitY && j == FruitX)cout << "A";
else cout << " ";
if (j == (width - 1))cout << "#";
}
cout << endl;
}
for (int i = 0; i < width ; i++)
{
cout << "#";
}
cout << endl;
}
首先我们搭建的墙壁是这样的
###########
# #
# #
# #
###########
为了更新每次画的界面system("cls");清空界面,熟悉matlab的同学应该熟悉这个命令。
第一个for循环打印了第一排的###########,并且进入下一行。
最后一个for循环打印了最后一排的###########,并且进入下一行。
中间两层for循环,对应着打印出的只有头尾两个#的每一行。
外层for循环循环height行,内部循环对每一行的位数判断头尾打印#,其余打印空格,并且进入下一行。内部的两段函数分别打印了蛇头O的位置与苹果A的位置,这两段代码的位置不要搞错,不要与墙壁的代码顺序搞乱,否则会被“ ”覆盖掉。
此时整体代码为
#include <iostream>
using namespace std;
bool GameOver;
const int width = 20;
const int heigth = 20;
int x, y, FruitX, FruitY, score;
void Setup()//初始化设置
{
GameOver = false;
x = width / 2;
y = heigth / 2;
FruitX = rand() % width;
FruitY = rand() % heigth;
score = 0;
}
void Draw()//绘画界面
{
system("cls");
for (int i = 0; i < width ; i++)
{
cout << "#";
}
cout << endl;
for (int i = 0; i < heigth; i++)
{
for (int j = 0; j < width ; j++)
{
if (j == 0)cout << "#";
if (i == y && j == x)cout << "O";
else if(i == FruitY && j == FruitX)cout << "A";
else cout << " ";
if (j == (width - 1))cout << "#";
}
cout << endl;
}
for (int i = 0; i < width ; i++)
{
cout << "#";
}
cout << endl;
}
void Input()//扫描输入
{
}
void Logic()//游戏逻辑
{
}
int main()
{
Setup();
while (!GameOver)
{
Draw();
Input();
Logic();
}
}
打印效果为
你会发现界面一直在频闪,正是因为主循环不断调用system("cls");刷新界面。刷新速度与CPU你的电脑性能有关,电脑越好闪烁速度越快。
此外刷新速度快意味着游戏中蛇的速度更快难度更大,为减小难度我们可以用<windows.h>中的Sleep();函数延时刷新时间。括号内数字越大延时越大,难度越小。
#include <iostream>
#include <windows.h>
using namespace std;
bool GameOver;
const int width = 20;
const int heigth = 20;
int x, y, FruitX, FruitY, score;
void Setup()//初始化设置
{
GameOver = false;
x = width / 2;
y = heigth / 2;
FruitX = rand() % width;
FruitY = rand() % heigth;
score = 0;
}
void Draw()//绘画界面
{
system("cls");
for (int i = 0; i < width ; i++)
{
cout << "#";
}
cout << endl;
for (int i = 0; i < heigth; i++)
{
for (int j = 0; j < width ; j++)
{
if (j == 0)cout << "#";
if (i == y && j == x)cout << "O";
else if(i == FruitY && j == FruitX)cout << "A";
else cout << " ";
if (j == (width - 1))cout << "#";
}
cout << endl;
}
for (int i = 0; i < width ; i++)
{
cout << "#";
}
cout << endl;
}
void Input()//扫描输入
{
}
void Logic()//游戏逻辑
{
}
int main()
{
Setup();
while (!GameOver)
{
Draw();
Input();
Logic();
Sleep(20);
}
}
至此我们的游戏界面算是完事了
Input函数
我们需要对输入的按键进行反馈,引入<conio.h>文件(其他库函数需要自己下载)
enum Direction
{
STOP,LEFT,RIGHT,UP,DOWN
};
Direction dir;
创建枚举,对STOP,LEFT,RIGHT,UP,DOWN分别赋值01234(枚举看笔记10)
void Input()//扫描输入
{
if (_kbhit())
{
switch (_getch())
{
case 'a':
dir = LEFT;
break;
case 's':
dir = DOWN;
break;
case 'w':
dir = UP;
break;
case 'd':
dir = RIGHT;
break;
case 'x':
GameOver = true ;
break;
}
}
}
_kbhit()函数检测是否有字符输入,没有则返回空
_getch()函数获取输入字符
将获取的字符转为标记,在这个函数中我们还可以增加更多的功能如x结束游戏,还可以暂停游戏等等。
#include <iostream>
#include <conio.h>
#include <windows.h>
using namespace std;
bool GameOver;
const int width = 20;
const int heigth = 20;
int x, y, FruitX, FruitY, score;
enum Direction
{
STOP, LEFT, RIGHT, UP, DOWN
};
Direction dir;
void Setup()//初始化设置
{
GameOver = false;
x = width / 2;
y = heigth / 2;
FruitX = rand() % width;
FruitY = rand() % heigth;
score = 0;
}
void Draw()//绘画界面
{
system("cls");
for (int i = 0; i < width ; i++)
{
cout << "#";
}
cout << endl;
for (int i = 0; i < heigth; i++)
{
for (int j = 0; j < width ; j++)
{
if (j == 0)cout << "#";
if (i == y && j == x)cout << "O";
else if (i == FruitY && j == FruitX)cout << "A";
else cout << " ";
if (j == (width - 1))cout << "#";
}
cout << endl;
}
for (int i = 0; i < width ; i++)
{
cout << "#";
}
cout << endl;
}
void Input()//扫描输入
{
if (_kbhit())
{
switch (_getch())
{
case 'a':
dir = LEFT;
break;
case 's':
dir = DOWN;
break;
case 'w':
dir = UP;
break;
case 'd':
dir = RIGHT;
break;
case 'x':
GameOver = true;
break;
}
}
}
void Logic()//游戏逻辑
{
}
int main()
{
Setup();
while (!GameOver)
{
Draw();
Input();
Logic();
Sleep(20);
}
}
Logic函数
我们已经有了STOP,LEFT,RIGHT,UP,DOWN标志就可以对蛇头位置进行操作了
void Logic()//游戏逻辑
{
switch (dir)
{
case STOP:
break;
case LEFT:
x--;
break;
case RIGHT:
x++;
break;
case UP:
y--;
break;
case DOWN:
y++;
break;
default:
break;
}
//if (x > width || y > heigth || x < 0 || y < 0)
//GameOver = true;
if (x > width)x = 0; else if (x < 0)x = width - 1;
if (y > heigth)y = 0; else if (y < 0)y = heigth - 1;
if (x == FruitX && y == FruitY)
{
score += 10;
FruitX = rand() % width;
FruitY = rand() % heigth;
}
}
第一段语句对蛇头操作,switch语句就是对STOP,LEFT,RIGHT,UP,DOWN不同标志的操作
第二段是两种墙壁操作,注释的代码是蛇头撞墙就死,未注释代码是撞墙从另一测出来(测试时候容易死,所以用未注释做测试,根据情况选择。)
第三段是对苹果,蛇投触碰到苹果即加10分,苹果改变位置。
#include <iostream>
#include <conio.h>
#include <windows.h>
using namespace std;
bool GameOver;
const int width = 20;
const int heigth = 20;
int x, y, FruitX, FruitY, score;
enum Direction
{
STOP, LEFT, RIGHT, UP, DOWN
};
Direction dir;
void Setup()//初始化设置
{
GameOver = false;
x = width / 2;
y = heigth / 2;
FruitX = rand() % width;
FruitY = rand() % heigth;
score = 0;
}
void Draw()//绘画界面
{
system("cls");
for (int i = 0; i < width ; i++)
{
cout << "#";
}
cout << endl;
for (int i = 0; i < heigth; i++)
{
for (int j = 0; j < width ; j++)
{
if (j == 0)cout << "#";
if (i == y && j == x)cout << "O";
else if (i == FruitY && j == FruitX)cout << "A";
else cout << " ";
if (j == (width - 1))cout << "#";
}
cout << endl;
}
for (int i = 0; i < width ; i++)
{
cout << "#";
}
cout << endl;
cout << "SCORE:" << score << endl;
}
void Input()//扫描输入
{
if (_kbhit())
{
switch (_getch())
{
case 'a':
dir = LEFT;
break;
case 's':
dir = DOWN;
break;
case 'w':
dir = UP;
break;
case 'd':
dir = RIGHT;
break;
case 'x':
GameOver = true;
break;
}
}
}
void Logic()//游戏逻辑
{
switch (dir)
{
case STOP:
break;
case LEFT:
x--;
break;
case RIGHT:
x++;
break;
case UP:
y--;
break;
case DOWN:
y++;
break;
default:
break;
}
//if (x > width || y > heigth || x < 0 || y < 0)
//GameOver = true;
if (x > width)x = 0; else if (x < 0)x = width - 1;
if (y > heigth)y = 0; else if (y < 0)y = heigth - 1;
if (x == FruitX && y == FruitY)
{
score += 10;
FruitX = rand() % width;
FruitY = rand() % heigth;
}
}
int main()
{
Setup();
while (!GameOver)
{
Draw();
Input();
Logic();
Sleep(20);
}
}
为了显示分数记得在Draw函数后加入输出流显示分数。
到此为止游戏的基本功能已经实现了还差最后的尾巴。
我们来分析一下有Ooooo的蛇
Ooooo按“s”向下运动变为
----------------------
oooo
O
----------------------
ooo
o
O
------------------------
oo
o
o
O
----------------------------再次向右按下
o
o
o
oO
-----------------------------
我们看到尾巴存在的位置都是蛇头经过的位置,我们可以用数组保存各个尾巴的位置。
#include <iostream>
#include <conio.h>
#include <windows.h>
using namespace std;
bool GameOver;
const int width = 20;
const int heigth = 20;
int x, y, FruitX, FruitY, score;
enum Direction
{
STOP, LEFT, RIGHT, UP, DOWN
};
Direction dir;
int TailX[100], TailY[100];
int nTail;
两个数组存放尾巴的XY坐标,并记录长度nTail
回到Draw函数,尾巴的存在也是设定位置,然后被刷新达到动态的效果。
void Draw()//绘画界面
{
system("cls");
for (int i = 0; i < width+2; i++)
{
cout << "#";
}
cout << endl;
for (int i = 0; i < heigth; i++)
{
for (int j = 0; j < width+2; j++)
{
if (j == 0)cout << "#";
if (i == y && j == x)cout << "O";
else if(i == FruitY && j == FruitX)cout << "A";
else
{
bool print=false;
for (int k = 0; k < nTail; k++)
{
if (TailX[k] == j && TailY[k] == i)
{
cout << "o";
print = true;
}
}
if (!print)
cout << " ";
}
if (j == (width - 1))cout << "#";
}
cout << endl;
}
for (int i = 0; i < width+2; i++)
{
cout << "#";
}
cout << endl;
cout << "SCORE:" << score << endl;
}
设置标志位print将蛇头位置记录给数组并且循环打印,这个代码块的位置依旧在“ ”之上,否则被覆盖。
到Logic函数中考虑尾巴的游戏逻辑。
void Logic()//游戏逻辑
{
int perX = TailX[0];
int perY = TailY[0];
int per2X, per2Y;
TailX[0] = x;
TailY[0] = y;
for (int i = 1; i < nTail; i++)
{
per2X = TailX[i];
per2Y = TailY[i];
TailX[i] = perX;
TailY[i] = perY;
perX = per2X;
perY = per2Y;
}
switch (dir)
{
case STOP:
break;
case LEFT:
x--;
break;
case RIGHT:
x++;
break;
case UP:
y--;
break;
case DOWN:
y++;
break;
default:
break;
}
//if (x > width || y > heigth || x < 0 || y < 0)
//GameOver = true;
if (x > width)x = 0; else if (x < 0)x = width - 1;
if (y > heigth)y = 0; else if (y < 0)y = heigth - 1;
for (int i = 0; i < nTail; i++)
{
if (TailX[i] == x && TailY[i] == y)
{
GameOver = true;
}
}
if (x == FruitX && y == FruitY)
{
score += 10;
FruitX = rand() % width;
FruitY = rand() % heigth;
nTail++;
}
}
第一部分我们将根据尾巴长度,进行循环将蛇头坐标向后传递
第二部分我们检测是否有数组与蛇头坐标一直,一致则结束游戏。
好了,你已经学会如何制作了,去玩吧!!!!你很棒!!!!
(小bug,有一定长度时,蛇头向左移时按下右键立即死亡,与运动方向相反方向都立刻死亡。)
你知道bug的原因是什么嘛?评论区留言