标签:game 技术分享 移动 print img leo create .com 二维数组

假期无事,整理电脑文件的时候发现了以前大二时做的坦克小游戏,心血来潮,决定再来一发贪吃蛇。
游戏玩法不必多说,主要是算法实现和绘制过程。
首先,利用一个二维数组 mp[][] 来存储地图信息,其中的值表示:
0:空
1:被蛇覆盖
2:食物
有了这个地图数组,生成随机食物的时候就可以避免生成到蛇身上。
那蛇的身体如何存储呢?也很简单,用队列(存储每一个小格的坐标信息)。
队列的头尾方向与蛇的头尾方向正好相反。
蛇每走一步,在蛇头方向的下一位置画一个小方格,同时把该位置放置到队列尾端。取出队列第一个元素,也即是蛇的尾部的坐标,把该位置的小方格清掉。
画一个小格,擦掉一个小格,再画一个,再擦一个……如此反复循环,小蛇就会爬了~
代码不多,写到一个文件里了:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <conio.h>
#include <windows.h>
#include <queue>
#ifdef _MSC_VER // M$的编译器要给予特殊照顾
#if _MSC_VER <= 1200 // VC6及以下版本
#error 你是不是还在用VC6?!
#else // VC6以上版本
#if _MSC_VER >= 1600 // 据说VC10及以上版本有stdint.h了
#include <stdint.h>
#else // VC10以下版本,自己定义int8_t和uint16_t
typedef signed char int8_t;
typedef unsigned short uint16_t;
#endif
#ifndef __cplusplus // 据说VC都没有stdbool.h,不用C++编译,自己定义bool
typedef int bool;
#define true 1
#define false 0
#endif
#endif
#else // 其他的编译器都好说
#include <stdint.h>
#ifndef __cplusplus // 不用C++编译,需要stdbool.h里的bool
#include <stdbool.h>
#endif
#endif
using namespace std;
HANDLE g_hConsoleOutput; // 控制台输出句柄
// 方向
enum { DIR_UP = 0, DIR_LEFT, DIR_DOWN, DIR_RIGHT };
// 绘画开始位置
const int START_ROW = 3;
const int START_COL = 3;
// 蛇的初始值
const int START_X = 5;
const int START_Y = 6;
const int START_LENGTH = 5;
// 地图大小
const int WIDTH = 32;
const int HEIGHT = 24;
// 定位到游戏池中的方格
#define gotoxyInPool(x, y) gotoxyWithFullwidth(x+START_ROW, y+START_COL)
int mp[HEIGHT][WIDTH];
typedef struct Point
{
int x, y;
} Point;
typedef struct Snake // 这个结构体存储游戏相关数据
{
Point head;
queue<Point>body;
int dir;
public :
void setDir();
Point getHead();
int nextStep();
} Snake;
// =============================================================================
typedef struct SnakeControl // 这个结构体存储控制相关数据
{
// 游戏池内每格的颜色
// 由于此版本是彩色的,仅用游戏池数据无法存储颜色信息
// 当然,如果只实现单色版的,就没必要用这个数组了
int8_t color[28][16];
bool dead; // 挂
bool pause; // 暂停
unsigned score; // 得分(这个也可以用蛇的长度表示)
} SnakeControl;
// =============================================================================
// 以全角定位到某点
void gotoxyWithFullwidth(short y, short x);
void initGame(Snake * snake, SnakeControl * control);
void printSnake(Snake * snake, SnakeControl * control);
void createFood(Snake * snake);
void GoToNextStep(Snake * snake, SnakeControl * control, int dir);
void keydownControl(Snake * snake, SnakeControl * control, int key);
void runGame(Snake * snake, SnakeControl * control);
void printPrompting();
void printPoolBorder();
void printScore(const Snake *snake, const SnakeControl *control);
int main()
{
Snake snake;
SnakeControl control;
CONSOLE_CURSOR_INFO cursorInfo = { 1, FALSE }; // 光标信息
g_hConsoleOutput = GetStdHandle(STD_OUTPUT_HANDLE); // 获取控制台输出句柄
SetConsoleCursorInfo(g_hConsoleOutput, &cursorInfo); // 设置光标隐藏
SetConsoleTitleA("贪吃蛇");
printPrompting();
while (1)
{
SetConsoleTextAttribute(g_hConsoleOutput, 0x07);
system("cls");
initGame(&snake,&control); // 初始化游戏
printPrompting(); // 显示提示信息
printPoolBorder(); // 显示游戏池边界
runGame(&snake,&control); // 运行游戏
SetConsoleTextAttribute(g_hConsoleOutput, 0xF0);
char * str = "Game Over";
int len = strlen(str);
// 居中显示
int x = HEIGHT / 2 + START_ROW ;
int y = WIDTH / 2 + START_COL - len/4;
gotoxyWithFullwidth(x, y);
printf("%s",str);
SetConsoleTextAttribute(g_hConsoleOutput, 0x07);
system("pause > nul");
system("cls");
}
gotoxyWithFullwidth(0, 0);
CloseHandle(g_hConsoleOutput);
system("pause > nul");
return 0;
}
// =============================================================================
// 以全角定位到某点
void gotoxyWithFullwidth(short y, short x)
{
static COORD cd;
cd.X = (short)(x << 1);
cd.Y = y;
SetConsoleCursorPosition(g_hConsoleOutput, cd);
}
void initGame(Snake * snake, SnakeControl * control)
{
//清空数据
memset(mp, 0, sizeof mp);
while (!snake->body.empty()) snake->body.pop();
//出生点
Point next;
next.x = START_X ;
next.y = START_Y ;
snake->dir = DIR_RIGHT;
snake->head.x = next.x;
snake->head.y = next.y;
for (int i = 0; i < START_LENGTH; ++i)snake->body.push(next);
//生成食物
createFood(snake);
//控制信息
control->dead = false;
control->pause = false;
control->score = 0;
}
//生成随机食物
void createFood(Snake * snake)
{
int x = 0, y = 0;
do
{
x = rand() % HEIGHT;
y = rand() % WIDTH;
} while (mp[x][y] == 1); // 不能生成到蛇的身体上面
mp[x][y] = 2;
gotoxyInPool(x, y);
// 用相应颜色,显示一个实心方块
SetConsoleTextAttribute(g_hConsoleOutput, 0xA);
printf("■");
}
void GoToNextStep(Snake * snake, SnakeControl * control, int dir)
{
int x = snake->head.x;
int y = snake->head.y;
Point next;
switch (dir)
{
case DIR_UP:
next.x = x - 1;
next.y = y;
break;
case DIR_DOWN:
next.x = x + 1;
next.y = y;
break;
case DIR_LEFT:
next.x = x;
next.y = y - 1;
break;
case DIR_RIGHT:
next.x = x;
next.y = y + 1;
break;
default:
break;
}
if (next.x >= 0 && next.x < HEIGHT && next.y >= 0 && next.y < WIDTH )
{
if (mp[next.x][next.y] == 1)
{
control->dead = true;
return;
}
bool isEat = mp[next.x][next.y] == 2;
Point last = snake->body.front();
snake->head.x = next.x;
snake->head.y = next.y;
snake->body.push(next);
snake->dir = dir;
// 画下一个头的位置
mp[next.x][next.y] = 1;
gotoxyInPool(next.x , next.y );
SetConsoleTextAttribute(g_hConsoleOutput, 0xF);
printf("■");
// 如果没有吃到食物,删掉尾巴的痕迹
if (!isEat)
{
snake->body.pop();
mp[last.x][last.y] = 0;
gotoxyInPool(last.x , last.y );
SetConsoleTextAttribute(g_hConsoleOutput, 0xA);
printf("%2s", "");
}
else
{
createFood(snake);
printScore(snake, control);
}
}
else
{
control->dead = true;
}
}
void keydownControl(Snake * snake, SnakeControl * control, int key)
{
if (key == 13) // 暂停/解除暂停
{
control->pause = !control->pause;
if (control->pause)
{
SetConsoleTextAttribute(g_hConsoleOutput, 0xE);
gotoxyWithFullwidth(5, 38);
printf(" 已暂停 ");
return;
}
else
{
//清楚提示信息
SetConsoleTextAttribute(g_hConsoleOutput, 0xE);
gotoxyWithFullwidth(5, 38);
printf("%18s","");
//显示得分信息
printScore(snake, control);
}
}
if (control->pause) // 暂停状态,不作处理
{
return;
}
int dir = 0;
switch (key)
{
case ‘w‘: case ‘W‘: case ‘8‘: case 72: // 上
dir = DIR_UP;
break;
case ‘a‘: case ‘A‘: case ‘4‘: case 75: // 左
dir = DIR_LEFT;
break;
case ‘d‘: case ‘D‘: case ‘6‘: case 77: // 右
dir = DIR_RIGHT;
break;
case ‘s‘: case ‘S‘: case ‘2‘: case 80: // 下
dir = DIR_DOWN;
break;
default:
return;
}
// 不允许掉头
if (snake->dir != dir && (snake->dir + dir) % 2 == 0)
{
return;
}
snake->dir = dir;
}
void runGame(Snake * snake, SnakeControl * control)
{
int ch;
clock_t clockLast, clockNow;
clockLast = clock(); // 计时
printScore(snake, control); // 显示游戏池
while (!control->dead) // 没挂
{
while (_kbhit()) // 有键按下
{
ch = _getch();
if (ch == 27) // Esc键
{
return;
}
keydownControl(snake, control, ch); // 处理按键
}
if (!control->pause) // 未暂停
{
clockNow = clock(); // 计时
// 两次记时的间隔超过0.45秒
if (clockNow - clockLast > 0.15F * CLOCKS_PER_SEC)
{
clockLast = clockNow;
GoToNextStep(snake, control, snake->dir);; // 蛇自动往前走
}
}
}
}
void printPrompting()
{
// 边框
SetConsoleTextAttribute(g_hConsoleOutput, 0xF);
gotoxyWithFullwidth(3, 37);
printf("┏━━━━━━━━━┓");
gotoxyWithFullwidth(4, 37);
printf("┃%18s┃", "", "");
gotoxyWithFullwidth(5, 37);
printf("┃%18s┃", "", "");
gotoxyWithFullwidth(6, 37);
printf("┃%18s┃", "", "");
gotoxyWithFullwidth(7, 37);
printf("┗━━━━━━━━━┛");
SetConsoleTextAttribute(g_hConsoleOutput, 0xB);
gotoxyWithFullwidth(10, 37);
printf("■控制说明:");
gotoxyWithFullwidth(12, 38);
printf("□向左移动:← A 4");
gotoxyWithFullwidth(13, 38);
printf("□向右移动:→ D 6");
gotoxyWithFullwidth(14, 38);
printf("□向下移动:↓ S 2");
gotoxyWithFullwidth(15, 38);
printf("□向上移动:↑ W 8");
gotoxyWithFullwidth(26, 37);
printf("■By: woffee 17.01.20");
}
// =============================================================================
// 显示得分信息
void printScore(const Snake *snake, const SnakeControl *control)
{
SetConsoleTextAttribute(g_hConsoleOutput, 0xE);
gotoxyWithFullwidth(5, 41);
printf("得分:%d", snake->body.size());
}
// =============================================================================
// 显示游戏边界
void printPoolBorder()
{
int x, y;
SetConsoleTextAttribute(g_hConsoleOutput, 0xF0);
x = START_ROW-1, y = START_COL-1;
for (int i = 0; i <= WIDTH ; ++i) { gotoxyWithFullwidth(x, y); printf("%2s", ""); y++; }
x = START_ROW + HEIGHT, y = START_COL;
for (int i = 0; i <= WIDTH ; ++i) { gotoxyWithFullwidth(x, y); printf("%2s", ""); y++; }
x = START_ROW, y = START_COL-1;
for (int i = 0; i <= HEIGHT; ++i) { gotoxyWithFullwidth(x, y); printf("%2s", ""); x++; }
x = START_ROW-1, y = START_COL + WIDTH;
for (int i = 0; i <= HEIGHT; ++i) { gotoxyWithFullwidth(x, y); printf("%2s", ""); x++; }
}
标签:game 技术分享 移动 print img leo create .com 二维数组
原文地址:http://www.cnblogs.com/woffee/p/6322168.html