C++实现贪吃蛇

开发环境

Vs 2015 + EasyX

需求分析

  1. 蛇能上下左右移动
  2. 蛇能吃食物
  3. 能判断蛇的死亡

主要的类

蛇的长度,每节蛇的坐标,蛇移动的方向;
蛇初始化,移动,改变方向,吃食物,画蛇,蛇是否死亡

食物

食物的坐标,食物是否被吃掉;
初始化食物,新的食物,画食物;
因为蛇吃食物时需要知道食物的坐标,所以需要获得食物坐标的方法;
因为蛇吃食物后需要改变食物是否被吃的状态,所以需要获得食物坐标的方法;
因为需要根据食物是否被吃来确定是否需要新食物,所以需要获得食物状态的方法;

主函数

首先应初始化蛇和食物,直接用构造函数初始化即可,然后在一个死循环中完成游戏逻辑,每一个循环为一个游戏帧;
游戏逻辑为:首先判断是否有键盘按下,若有蛇改变方向,若没有蛇按原方向运动,并绘制蛇和食物,然后执行蛇吃食物方法,此方法中若吃了食物则改变食物状态,根据食物状态判断是否产生新的食物。

实现

头文件

头文件主要完成蛇和食物的定义

#ifndef _GREEDYSNAKE_H
#define _GREEDYSNAKE_H
#include 
#include 
#include 
#include 

//方向枚举
enum Ch { up = 72, down = 80, left = 75, right = 77 };

//坐标结构体
struct Coor
{
	int x;
	int y;
};

class Food
{
private:
	Coor fzb;//食物的坐标
	bool isEat;//食物有没有吃到食物
public:
	Food();
	void NewFood();
	Coor GetZb();
	bool GetIsEat();
	void SetIsEat(bool b);
	void DrawFood();//画食物
};

Food::Food()
{
	fzb.x = rand() % 64 * 10;
	fzb.y = rand() % 48 * 10;
	isEat = false;
}

void Food::NewFood()
{
	fzb.x = rand() % 64 * 10;
	fzb.y = rand() % 48 * 10;
	isEat = false;
}

Coor Food::GetZb()
{
	return  fzb;
}

bool Food::GetIsEat()
{
	return isEat;
}

void Food::SetIsEat(bool b)
{
	isEat = b;
}

void Food::DrawFood()
{
	roundrect(fzb.x, fzb.y, fzb.x + 10, fzb.y + 10, 10, 10);
}

//蛇类
class Snake
{
private:
	int n;//蛇当前的节数
	Ch ch;//方向
	Coor szb[100];//蛇的每一节坐标,100为蛇的最大长度
public:
	Snake();
	void DrawSnake();//画蛇
	void MoveSnake();//移动蛇
	void ChangeCh();//改变方向
	void EatFood(Food &food);//吃食物
	void GameOver();//判断游戏是否结束
};

Snake::Snake()
{
	/*mciSendString("play 甩葱歌.mp3 alias BGM", 0, 0, 0);
	mciSendString("play BGM repeat", 0, 0, 0);*/

	n = 3;
	ch = right;
	szb[0].x = 20;
	szb[0].y = 200;
	szb[1].x = 10;
	szb[1].y = 200;
	szb[2].x = 0;
	szb[2].y = 200;
}

void Snake::DrawSnake()
{
	cleardevice();//清除窗口
	for (int i = 0; i < n; i++)
	{
		rectangle(szb[i].x, szb[i].y, szb[i].x + 10, szb[i].y + 10);
	}
}

void Snake::MoveSnake()
{
	//移动蛇的思路是后面一节蛇的坐标继承前面一节蛇的坐标
	for (int i = n - 1; i > 0; i--)
	{
		szb[i] = szb[i - 1];
	}
	//蛇头的移动与方向有关
	switch (ch)
	{
	case up:
		szb[0].y -= 10;
		break;
	case down:
		szb[0].y += 10;
		break;
	case left:
		szb[0].x -= 10;
		break;
	case right:
		szb[0].x += 10;
		break;
	}
}

void Snake::ChangeCh()
{
	int move;
	move = _getch();
	switch (move)
	{
	case up:
		if (ch != down)
			ch = up;
		break;
	case down:
		if (ch != up)
			ch = down;
		break;
	case right:
		if (ch != left)
			ch = right;
		break;
	case left:
		if (ch != right)
			ch = left;
		break;
	}
}

void Snake::EatFood(Food &food)//若想改变food的成员变量用引用
{
	if (szb[0].x == food.GetZb().x && szb[0].y == food.GetZb().y)
	{
		n++;
		food.SetIsEat(true);
	}
}

//判断游戏结束
void Snake::GameOver()
{
	//蛇头超出边界
	if (szb[0].x < 0 || szb[0].x>640 || szb[0].y < 0 || szb[0].y>480)
	{
		closegraph();//关闭窗口
		exit(0);//结束进程
	}
	//蛇头与蛇身相撞
	for (int i = n - 1; i > 0; i--)
	{
		if (szb[0].x == szb[i].x && szb[0].y == szb[i].y)
		{
			closegraph();//关闭窗口
			exit(0);//结束进程
		}
	}
}

#endif

源文件

源文件主要执行的是游戏帧

#include "GreedySnake.h"

int main()
{
	srand((unsigned int)time(NULL));//初始化随机数种子
	initgraph(640, 480);//初始化一个窗口,大小为640*480
	Snake snake;
	Food food;
	while (1)//游戏环节为一个死循环
	{
		if(!_kbhit())//_kbhit检测有无按键,若一直没有按键则蛇按原方向一直移动
		{
			snake.MoveSnake();//移动蛇
			snake.DrawSnake();//画蛇
			food.DrawFood();//画食物
			snake.EatFood(food);//吃食物
			if (food.GetIsEat())//若食物被吃了则创建食物
				food.NewFood();//创建食物
			snake.GameOver();//判断游戏是否结束
			Sleep(100);//休眠100毫秒
		}
		else
		//检测到按键
		snake.ChangeCh();//改变方向
	}
	return 0;
}

注意点

  1. 方向的枚举
enum Ch { up = 72, down = 80, left = 75, right = 77 };
  1. 蛇的移动是将前一节的坐标给后一节
  2. 检测有无按键的函数

你可能感兴趣的:(项目)