游戏功能介绍
/如果各种问题,请各位大神评论区指出/
1.J:蛇移动加速
2. 空格:游戏暂停
3.K:游戏存档(只支持一次存档)
4.自定义地图(使用鼠标)
5.多种功能食物
6.背景音乐与音效
7.蛇的多级速度
8.固定障碍物
9.esc返回游戏大厅
10.简单的积分功能
####### 使用的VS编辑器###########
应用到的基础知识
函数 链表 指针 结构体 类(这个属于C++)
功能分析
实现
墙模块
经过项目分析,可以得出再墙模块中,需要维护一个二维数组,对整个游戏中的元素进行设置,所以可以声明一个二维数组,char gameArray[][],具体的行数和列数可以定义出一个枚举,比如本游戏中设置的是26行,26列,enum{ROW=26,COL=26};
那么墙模块开发阶段,需要提供得主要接口是 初始化墙initwall,以及打印墙,也就是将二维数组中得内容打印到控制台中,draw方法,当然对外还要提供出一个可以修改二维数组元素的方法以及根据索引获取二维数组元素的方法:getWall,setWall
游戏中的实现元素
游戏中元素分为:墙壁,蛇,事物以及蛇的可行区域和右侧的版本号和游戏玩法提示
墙壁
*号表示,代表一个区域范围,也就是蛇的可移动区域,蛇如果碰到墙壁视为死亡,
蛇
分为蛇头,蛇身,蛇头用@符号表示,蛇身用=等号表示,当蛇吃到食物时候,蛇身+1,一意为着长度变长,贪吃蛇可以通过不断地吃食物来增加自己的身体
食物
#井号表示,蛇碰到食物会将食物吃掉
可移动区域
空格 表示,代表蛇可以移动的区域
提示信息
右侧展示,可以显示当前贪吃蛇版本号,制作人员,游戏玩法等提示信息
游戏规则
当运行游戏时候,画面静止不动,可以默认让蛇头超右,游戏中设置w s a d 4个按键分别代表,上,下,左,右,也是用户比较常用的方向按键,当用户输入w或者s或者d时候激活游戏,注意输入a不可以激活,因为蛇不可以180°转弯,因此蛇的移动方向只可以一直向前或者920°旋转
当蛇吃掉食物时候,此时蛇会增加一个身段,另外食物需要重新随机的设置到屏幕上
游戏结束方式有两种:
蛇碰到墙壁为死亡
蛇碰到蛇身子,把自己吃掉也视为死亡
游戏移动
当激活游戏后,也分为两种,一种是死亡,这个是当 蛇头碰到蛇身或者是碰到墙壁两种死亡,这个暂时先不考虑,第二种是正常移动,先分析下正常移动
在正常移动的时候,也分为两种状态
第一种:蛇没吃到食物
这个时候,蛇只是单纯的移动,没吃到食物的时候,蛇会更新蛇头的位置,并且将之前蛇尾巴的位置为空格,也就是表示向前移动
第二种:蛇吃到食物
当吃到食物时,当前的蛇头的位置应该为之前食物的位置,那么蛇尾由于吃到了食物,就还是在原有位置,然后食物再重新分配到一个其他的位置,这个位置不能是蛇,也不能是墙。
游戏截图
main()函数中用到了鼠标与键盘控制的函数(鼠标响应)
// _怎么添加鼠标响应.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include <iostream>
#include <Windows.h>
void WriteChar(int x, int y, const char* szInfo)
{
HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
COORD pos = {
x * 2,y };
SetConsoleCursorPosition(hOut, pos);
printf(szInfo);
}
int main()
{
HANDLE hIn = GetStdHandle(STD_INPUT_HANDLE);
SetConsoleMode(hIn, ENABLE_WINDOW_INPUT | ENABLE_MOUSE_INPUT);
//PINPUT_RECORD p=NULL;
INPUT_RECORD stcInput;
DWORD dwSize = 0;
while (true)
{
ReadConsoleInput(
hIn,
&stcInput, //这里应该传什么,传递一个有效的内存区域
1,
&dwSize
);
//我们判断结构体中的EventType去确定是不是一个鼠标事件
if (stcInput.EventType == MOUSE_EVENT)
{
int nButtonState = stcInput.Event.MouseEvent.dwButtonState;
if (nButtonState == FROM_LEFT_1ST_BUTTON_PRESSED)
{
int x = stcInput.Event.MouseEvent.dwMousePosition.X;
int y = stcInput.Event.MouseEvent.dwMousePosition.Y;
WriteChar(x / 2, y, "☆");
}
}
}
}
拿这段代码运行一下,用鼠标在cmd中按住左拖拽一下
---------------------------------------------------------------------------------------我是分割线-------------------------------------------------------------
各个头文件功能简介
//控制台
#include <windows.h>
#include <stdio.h>
#include <math.h>
#include <string.h>
#include "main.h"
#include "Wall.h" //墙类
#include "Snake.h" //蛇类
#include "Food.h" //食物类
#include "Scene.h" //基类
#include "Hall.h" //主界面
#include "Game.h" //功能按键设置类
#include "Editor.h" //地图编辑与废弃
上代码–(头文件与cpp文件已分开写-----内含注释)
common.h
#ifndef __COMMON_H__
#define __COMMON_H__
#include <windows.h>
#include <stdio.h>
#include <math.h>
#include <string.h>
#include <iostream>
using namespace std;
#define MAX_LINE 1024
#pragma comment(lib,"winmm.lib")
/*
设置光标位置
*/
static void gotoxy(int x, int y)
{
COORD c;
c.X = x;
c.Y = y;
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), c);
}
/******************************************************************************************/
/*
文字颜色函数
*/
static int color(int c)
{
//SetConsoleTextAttribute是API设置控制台窗口字体颜色和背景色的函数
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), c); //更改文字颜色
return 0;
}
#endif
食物类头文件Food.h
#ifndef __FOOD_H__
#define __FOOD_H__
#include "common.h"
#include "Wall.h"
//食物类
class Food
{
public:
Food(Wall *tempWall);
void setFood();
int foodX;
int foodY;
Wall *wall;
};
#endif
Food.cpp
#include "Food.h"
#include <Windows.h>
#include <time.h>
Food::Food(Wall *tempWall) :wall(tempWall)
{
}
/******************************************************************************************/
void Food::setFood()
{
while (true)
{
srand((unsigned)time(NULL));
foodX = rand() % (Wall::ROW - 2) + 1;
foodY = rand() % (Wall::COL - 2) + 1;
//如果随机的位置是蛇头或蛇身,就重新生成随机数
if (wall->getWall(foodX, foodY) == ' ')
{
int rnd = rand() % 2;
if (rnd == 0)
{
color(5);
wall->setWall(foodX, foodY, '#'); //普通食物
gotoxy(foodY * 2, foodX);
printf("#");
}
else if (rnd == 1)
{
color(5);
wall->setWall(foodX, foodY, '$'); //使蛇变短食物
gotoxy(foodY * 2, foodX);
printf("$");
}
else
{
color(5);
wall->setWall(foodX, foodY, '&'); //加速食物
gotoxy(foodY * 2, foodX);
printf("&");
}
break;
}
}
}
Game.h
#ifndef __GAME_H__
#define __GAME_H__
#include "Wall.h"
#include "Snake.h"
#include "Food.h"
#include "Scene.h"
//游戏功能类
class Game : public Scene
{
public:
Game();
virtual ~Game();
public:
virtual bool init(bool load);
//virtual void destroy();
virtual void draw();
virtual void keyEventProc(char key, bool down);
virtual void mouseEventProc(int x, int y);
void onGameOver();
private:
bool isDead;
char curKey;
char preKey;
Wall *wall;
Food *food;
Snake *snake;
bool pause;
};
#endif
Game.cpp
#include "Game.h"
#include "main.h"
Game::Game()
{
isDead = false;
pause = false;
curKey = 0;
preKey = 0;
wall = new Wall;
food = new Food(wall);
snake = new Snake(wall, food);
}
/******************************************************************************************/
Game::~Game()
{
}
/******************************************************************************************/
bool Game::init(bool load)
{
cleanScreen();
wall->initWall();
if (load)
{
wall->loadMap();
}
wall->drawWall();
if (!wall->hasFood())
{
food->setFood();
}
if (load)
{
snake->load();
}
else
{
snake->InitSnake();
}
PlaySound(NULL, NULL, NULL);
return true;
}
/******************************************************************************************/
//void Game::destroy()
//{
//}
/******************************************************************************************/
void Game::draw()
{
//判断如果是第一次按了,左键,才不能激活游戏
//判断上一次移动方向
if (preKey == 0 )
{
return;
}
if (curKey == 0)
{
return;
}
if (isDead)
{
return;
}
if (pause)
{
return;
}
if (snake->move(curKey) == true)
{
gotoxy(0, Wall::ROW);
printf("得分:%d分", snake->getScore());
Sleep(snake->getSleepTime());
}
else
{
isDead = true;
onGameOver