贪吃蛇C++源码,使用面向对象方式编写

网上好多贪吃蛇的源码,不过大部分都是用C面向过程的.自己用面向对象写了一个贪吃蛇,不足之处还请大家见谅.


我定义了3个类.

地图类:包括地图的抽象数组, 地图里面包含一个食物的坐标.用户可以自定义地图的起始坐标和宽度高度.

蛇类: 类中有蛇的出生长度,所属地图,方向,是否存活. 蛇可以吃掉食物,左右上下移动,死亡.

控制类: 记录分数,并操纵蛇移动,控制游戏进度暂停/结束.


"GreedySnake.h" //包含了蛇类和地图类.

#ifndef __GREEDYSNAKE_H_
#define __GREEDYSNAKE_H_

#define MAXLENGTH 200
#define MAXMAPWIDTH 200
#define MAXMAPHEIGHT 200

enum Direction{ LEFT = 'a', RIGHT = 'd', UP = 'w', DOWN = 's' };

struct Point
{
	int x, y;
};

void setWindowSize(int lines, int cols);		//设置窗口大小
void gotoXY(int x, int y);		//光标跳转到指定位置
void setColor(int colorId);		//设置输出颜色
bool isOverlap(Point &p1, Point &p2); //判断两个坐标是否重叠

class Map
{
private:
	bool _mapObj[MAXMAPWIDTH][MAXMAPHEIGHT];	//地图数组模型
	Point _mapStartingCoord,	//地图起始坐标
		_food;	//食物坐标
	int _mapWidth,	//地图宽度
		_mapHeight;	//地图高度
public:						 
	Map(const int x, const int y, const int width, const int height);	//绘制地图
	void refreshFood();	//刷新食物
	int getWidth()const { return _mapWidth; }
	int getHeight()const { return _mapHeight; }
	Point getMapStartingCoord()const { return _mapStartingCoord; }
	Point getFoodCoord()const { return _food; }
	~Map(){}
};


class Snake
{
private:
	Map *_belongs;		//所属地图
	Direction _direction;	//方向
	int _length;		//长度
	bool _isLife;	//是否存活
public:
	Snake(Map *map, int defaultLenth);
	bool eatFood();
	void draw()const;
	void moveUp();
	void moveDown();
	void moveLeft();
	void moveRight();
	void dead();
	Map * getBelongsMap()const{ return _belongs; }
	int getLength()const { return _length; }
	bool isLife()const { return _isLife; }
	~Snake();
	int _x[MAXLENGTH], _y[MAXLENGTH];

};

#endif

实现代码 "GreedySnake.cpp" 该文件中还包含了几个画图操作必要的函数

#include "GreedySnake.h"
#include <Windows.h>
#include <cstdlib>
#include <cmath>
#include <iostream>
#include <ctime>
using std::cout; using std::endl;

int i, j;

void setWindowSize(int cols, int lines)		//设置窗口大小
{
	char cmd[30];
	sprintf_s(cmd, "mode con cols=%d lines=%d", cols * 2, lines);
	system(cmd);
}

void gotoXY(const int x, const int y)		//光标跳转到指定位置
{
	COORD point;
	point.X = 2 * x;
	point.Y = y;
	SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), point);
}

void gotoXY(const Point &p)		//光标跳转到指定位置
{
	COORD point;
	point.X = 2 * p.x;
	point.Y = p.y;
	SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), point);
}

void setColor(int colorId)		//设置输出颜色
{
	SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), colorId);
}

Map::Map(const int x, const int y, const int width, const int height)	
{
	_mapStartingCoord.x = x;
	_mapStartingCoord.y = y;
	_mapWidth = width + 2;		
	_mapHeight = height + 2;	
	memset(_mapObj, 0, sizeof(_mapObj));

	for (i = 1; i <= width; ++i)		//初始化抽象地图数组
	{
		for (j = 1; j <= height; ++j)
			_mapObj[i][j] = 1;
	}
	
	gotoXY(x, y);
	setColor(11);
	for (i = 0; i != _mapWidth; ++i)		//根据抽象地图数组把地图画出来
	{
		for (j = 0; j != _mapHeight; ++j)
		{
			if (_mapObj[i][j])
				cout << "■";
			else
				cout << "□";
		}
		cout << endl;
	}

	refreshFood();
}

void Map::refreshFood()			//刷新食物
{
	_food.x = rand() % (_mapWidth - 2) + 1 + _mapStartingCoord.x;
	_food.y = rand() % (_mapHeight - 2) + 1 + _mapStartingCoord.y;
	gotoXY(_food.x, _food.y);
	setColor(12);
	cout << "●" << endl;
}

Snake::Snake(Map *map, int defaultLenth)
{
	_belongs = map;
	_isLife = true;
	_direction = DOWN;
	_x[0] = _belongs->getWidth() / 2 + _belongs->getMapStartingCoord().x;	//蛇出现在地图最中央
	_y[0] = _belongs->getHeight() / 2 + _belongs->getMapStartingCoord().y;
	_length = defaultLenth;
	int i;
	for (i = 1; i != _length; ++i)
	{
		_x[i] = _x[0];
		_y[i] = _y[i - 1] - 1;
	}
	draw();
}

bool Snake::eatFood()
{
	if (_x[0] == _belongs->getFoodCoord().x && _y[0] == _belongs->getFoodCoord().y)		//判断是否吃到食物
	{
		_x[_length] = _x[_length - 1];		//先让新增加的蛇屁股坐标等与进食前的蛇屁股,移动后会自动刷新
		_y[_length] = _y[_length - 1];
		++_length;
		_belongs->refreshFood();
		return true;
	}
	return false;
}


void Snake::draw()const
{
	setColor(14);
	for (int i = 0; i < _length; ++i)
	{
		gotoXY(_x[i], _y[i]);
		cout << "★" << endl;
	}
}

void Snake::moveUp()
{
	gotoXY(_x[_length - 1], _y[_length - 1]);
	setColor(11);
	cout << "■";
	for (i = _length - 1; i != 0; --i)
	{
		_x[i] = _x[i - 1];
		_y[i] = _y[i - 1];
	}
	_y[0] -= 1;
	draw();
}

void Snake::moveDown()
{
	gotoXY(_x[_length - 1], _y[_length - 1]);
	setColor(11);
	cout << "■";
	for (i = _length - 1; i != 0; --i)	//蛇的移动算法, 让后一节的坐标等于前一节的坐标
	{
		_x[i] = _x[i - 1];
		_y[i] = _y[i - 1];
	}
	_y[0] += 1;
	draw();
}

void Snake::moveLeft()
{
	gotoXY(_x[_length - 1], _y[_length - 1]);
	setColor(11);
	cout << "■";
	for (i = _length - 1; i != 0; --i)
	{
		_x[i] = _x[i - 1];
		_y[i] = _y[i - 1];
	}
	_x[0] -= 1;
	draw();
}

void Snake::moveRight()
{
	gotoXY(_x[_length - 1], _y[_length - 1]);
	setColor(11);
	cout << "■";
	for (i = _length - 1; i != 0; --i)
	{
		_x[i] = _x[i - 1];
		_y[i] = _y[i - 1];
	}
	_x[0] += 1;
	draw();
}

void Snake::dead()
{
	if (_x[0] <= _belongs->getMapStartingCoord().x		//判断是否碰到地图边框
		|| _x[0] >= _belongs->getWidth() + _belongs->getMapStartingCoord().x - 1
		|| _y[0] <= _belongs->getMapStartingCoord().y
		|| _y[0] >= _belongs->getHeight() + _belongs->getMapStartingCoord().y - 1)
		_isLife = false;

	for (i = 3; i <= _length - 1; ++i)		//判断是否碰到自己,从第4节开始算,因为头肯定碰不到第2/3节
	{
		if (_x[0] == _x[i] && _y[0] == _y[i])
			_isLife = false;
	}
}

控制类头文件 "Controller.h"

#ifndef __CONTROLLER_H_
#define __CONTROLLER_H_
#include "GreedySnake.h"

class Controller
{
private:
	Snake *_snake;	//要控制的蛇
	char _dir;		//存储方向键
	int _gameSpeed;	//游戏速度
	int _score;	//分数
public:
	Controller(Snake *s, int speed = 200, char dir = 'q') :_snake(s), _gameSpeed(speed), _dir(dir), _score(0){ }
	void start();		//开始游戏
	void pause();		//暂停
	void stop();		//停止
	void showScore();	//显示分数
	~Controller(){}
};

#endif

控制类实现代码 "Controller.cpp"

#include "Controller.h"
#include <conio.h>
#include <Windows.h>
#include <iostream>
using std::cout;

void Controller::start()
{
	char key = '\0';
	showScore();
	while (1)
	{
		if (_snake->isLife())
		{
			if (_kbhit())
			{
				gotoXY(0, _snake->getBelongsMap()->getHeight() + 2);
				_dir = _getche();
			}
			switch (_dir)
			{
			case UP:
				if (key != DOWN)	//判断是否朝相反方向移动,下同
				{
					_snake->moveUp();
					key = _dir;
				}
				else
					_snake->moveDown(); break;
			case DOWN:
				if (key != UP)
				{
					_snake->moveDown();
					key = _dir;
				}
				else
					_snake->moveUp(); break;
			case LEFT:
				if (key != RIGHT)
				{
					_snake->moveLeft();
					key = _dir;
				}
				else
					_snake->moveRight(); break;
			case RIGHT:
				if (key != LEFT)
				{
					_snake->moveRight();
					key = _dir;
				}
				else
					_snake->moveLeft(); break;
			case 8: pause(); break;	//空格键暂停
			default:break;
			}
			_snake->dead();
			Sleep(_gameSpeed);
			if (_snake->eatFood())
			{
				++_score;
				showScore();
			}
		}
		else
		{
			stop();
			break;
		}
	}
}

void Controller::pause()
{
	while (1)
	{
		if (_kbhit())
		{
			gotoXY(0, _snake->getBelongsMap()->getHeight() + 2);
			_dir = _getche();
		}
		if (_dir == 8)
			start();
	}
}

void Controller::stop()
{
	int x = _snake->getBelongsMap()->getWidth() / 2;
	int y = _snake->getBelongsMap()->getHeight() / 2;
	gotoXY(x, y);
	setColor(30);
	cout << "game over!";
	Sleep(3000);
}

void Controller::showScore()
{
	gotoXY(3, 1);
	setColor(14);
	cout << _score;
}

最后是 "main.cpp"

/* GreedySnake by ian*/

#include "GreedySnake.h"
#include "Controller.h"
#include <cmath>
#include <iostream>
#include <ctime>

void initWindow(int windowWidth, int windowHeight)
{
	setWindowSize(windowWidth, windowHeight);
	gotoXY(windowWidth / 2 - 3, 0);
	setColor(23);
	std::cout << "Greedy Snake" << std::endl;
	setColor(90);
	std::cout << "Score:" << std::endl;
	gotoXY(windowHeight - 7, 1);
	std::cout << "by ian." << std::endl;
}


int main()
{
	srand((unsigned)time(0));

	initWindow(28, 30);
	Map *map = new Map(0,2,25, 25);
	Snake *snake = new Snake(map, 3);
	Controller c(snake);
	c.start();
	delete map;
}


以下是游戏界面.

.


个人感觉控制类的实现还不是太好, 也希望大家能指出

  • 18
    点赞
  • 67
    收藏
    觉得还不错? 一键收藏
  • 7
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值