实验内容:
1)实现贪吃蛇游戏基本功能,屏幕上随机出现一个“食物”,称为豆子。玩家能利用上下左右键控制“蛇”的移动,“蛇”吃到“豆子”后“蛇”身体加长一节,得分增加,“蛇”碰到边界或蛇头与蛇身相撞,“蛇”死亡,游戏结束。
2)进行交互界面的设计,要有开始键、暂停键和停止退出的选项,能够控制游戏进程。对蛇吃到豆子进行分值计算,可以设置游戏速度,游戏音乐等拓展元素。
实现方法:
1.设定游戏界面,实现友好交互,并进行游戏初始化。
2.食物在游戏区域内随机生成,蛇碰到食物后在尾端增加一个长度。
3.蛇:采用双向队列,蛇每运动一步,就从双向队列中弹出队尾,然后将新的队首(即蛇头)压入队列首部,然后再清除蛇尾打印蛇身即可。通过键盘输入,判断蛇头下一个位置。
4.游戏结束条件:蛇头位置与设定的墙壁位置重合,或者蛇头所在位置为身体。
部分代码:
food.cpp:
void Food::DrawFood(Snake& csnake)//绘制食物
{
/*利用rand函数获得坐标,并将其范围限制在2-29内,即在地图内,如果获得的坐标与蛇身重叠,则重新获取。
同时每5颗食物就出现一颗限时食物*/
while (true)
{
int tmp_x = rand() % 30;
int tmp_y = rand() % 30;
if(tmp_x < 2) tmp_x += 2;
if(tmp_y < 2) tmp_y += 2;
bool flag = false;
for (auto& point : csnake.snake)
{
if ((point.GetX() == tmp_x && point.GetY() == tmp_y) || (tmp_x == big_x && tmp_y == big_y)) {
flag = true;
break;
}
}
if (flag)
continue;
x = tmp_x;
y = tmp_y;
SetCursorPosition(x, y);
SetColor(13);
std::cout << "★" ;
++cnt;
cnt %= 5;
if (cnt == 0)
{
DrawBigFood(csnake);
}
break;
}
}
snake.cpp:
void Snake::InitSnake()//初始化蛇
{
for (auto& point : snake)
{
point.PrintCircular();
}
}
void Snake::Move()//蛇增长
{
switch (direction)
{
case Direction::UP:
snake.emplace_back(Point(snake.back().GetX(), snake.back().GetY() - 1 ));
break;
case Direction::DOWN:
snake.emplace_back(Point(snake.back().GetX(), snake.back().GetY() + 1 ));
break;
case Direction::LEFT:
snake.emplace_back(Point(snake.back().GetX() - 1, snake.back().GetY() ));
break;
case Direction::RIGHT:
snake.emplace_back(Point(snake.back().GetX() + 1, snake.back().GetY() ));
break;
default:
break;
}
SetColor(14);
snake.back().PrintCircular();
}
void Snake::NormalMove()//蛇正常移动,头增长,尾缩短
{
Move();
snake.front().Clear();
snake.pop_front();
}
bool Snake::OverEdge()//超出边界
{
return snake.back().GetX() < 30 &&
snake.back().GetY() < 30 &&
snake.back().GetX() > 1 &&
snake.back().GetY() > 1;
}
bool Snake::HitItself()//撞到自身
{
std::deque<Point>::size_type cnt = 1;
Point *head = new Point(snake.back().GetX(), snake.back().GetY());//获得头部坐标
for (auto& point : snake) //如果整条蛇中与蛇头不相同的坐标不等于蛇长,则意味着蛇头碰撞到自身
{
if ( !(point == *head) )
++cnt;
else
break;
}
delete head;
if(cnt == snake.size())
return true;
else
return false;
}
bool Snake::ChangeDirection()//改变方向
{
char ch;
if (kbhit())//kbhit函数返回值为两个,需注意
{
ch = getch();
switch (ch)
{
case -32:
ch = getch();
switch (ch)
{
case 72:
if (direction != Direction::DOWN)//如果方向与当前运动方向相反,无效
direction = Direction::UP;
break;
case 80:
if (direction != Direction::UP)
direction = Direction::DOWN;
break;
case 75:
if (direction != Direction::RIGHT)
direction = Direction::LEFT;
break;
case 77:
if (direction != Direction::LEFT)
direction = Direction::RIGHT;
break;
default:
break;
}
return true;
case 27://ESC
return false;
default:
return true;
}
}
return true;
}
bool Snake::GetFood(const Food& cfood)
{
if (snake.back().GetX() == cfood.x && snake.back().GetY() == cfood.y)
return true;
else
return false;
}
bool Snake::GetBigFood(Food& cfood)
{
if (snake.back().GetX() == cfood.big_x && snake.back().GetY() == cfood.big_y)
{
cfood.big_flag = false;
cfood.big_x = 0;
cfood.big_y = 0;
SetCursorPosition(1, 0);
std::cout << " " ;
return true;
}
else
return false;
}
StartInterface.cpp
void StartInterface::PrintFirst()//蛇从左边出现到完全出现的过程
{
for (auto& point : startsnake)
{
point.Print();
Sleep(speed);
}
}
void StartInterface::PrintSecond()//蛇从左向右移动的过程
{
for (int i = 10; i != 40; ++i) //蛇头需要从10移动到40
{
/*计算蛇头的下一个位置,并将其压入startsnake中,绘制出来,将蛇尾去掉*/
int j = ( ((i-2)%8) < 4 )?( 15 + (i-2)%8 ) : ( 21 - (i-2)%8 );
startsnake.emplace_back( Point(i, j) );
startsnake.back().Print();
startsnake.front().Clear();
startsnake.pop_front();
Sleep(speed);
}
}
void StartInterface::PrintThird()//蛇从接触右边到消失的过程
{
while ( !startsnake.empty() || textsnake.back().GetX() < 33 ) //当蛇还没消失或文字没移动到指定位置
{
if ( !startsnake.empty() ) //如果蛇还没消失,继续移动
{
startsnake.front().Clear();
startsnake.pop_front();
}
ClearText();//清除已有文字
PrintText();//绘制更新位置后的文字
Sleep(speed);
}
}
void StartInterface::PrintText()
{
for (auto& point : textsnake)
{
if (point.GetX() >= 0)
point.Print();
}
}
void StartInterface::ClearText()
{
for (auto& point : textsnake) //清除的同时将文字整体向右移动一格
{
if (point.GetX() >= 0)
point.Clear();
point.ChangePosition(point.GetX() + 1, point.GetY());
}
}
void StartInterface::Action()
{
PrintFirst();
PrintSecond();
PrintThird();
}
运行结果: