C++入门指南之贪吃蛇游戏的实现

目录
  • 参考
  • 贪吃蛇游戏
    • 程序框架
    • 绘制游戏地图和蛇
  • 小蛇向右移动
    • 控制小蛇4个方向移动
    • 时间控制的改进
    • 失败判断与显示
    • 添加食物
    • 完整代码
  • 总结

参考

  • 《C和C++游戏趣味编程》

贪吃蛇游戏

键盘控制小蛇上、下、左、右移动,迟到食物后长度加1;蛇头碰到自身或窗口边缘,游戏失败

程序框架

#include <graphics.h>
#include <conio.h>
#include <stdio.h>

// 全局变量定义

void startup()                       // 初始化函数
{

}

void show()                          // 绘制函数
{

}

void updateWithoutInput()            // 与输入无关的更新
{

}

void updateWithInput()               // 和输入有关的更新
{

}

int main()
{
	startup();                       // 初始化函数,仅执行一次
	while (1)
	{
		show();                      // 进行绘制
		updateWithoutInput();        // 和输入无关的更新
		updateWithInput();           // 和输入有关的更新
	}
	return 0;
}

绘制游戏地图和蛇

绘制网格状的游戏地图,使用二维数组Blocks存储每个网格的信息。二维数组Blocks中也可以记录蛇的信息。设定元素值为0表示空,画出灰色的方格;元素值为1表示蛇头,蛇头后的蛇身依次为2、3、4、5等正整数,画出彩色的方格

int i, j;
for (i = 0; i < HEIGHT; i++)
{
	for (j = 0; j < WIDTH; j++)
	{
		if (Blocks[i][j] > 0)
		{
			setfillcolor(HSVtoRGB(Blocks[i][j] * 10, 0.9, 1));
		}
		else
		{
			setfillcolor(RGB(150, 150, 150));
		}
		fillrectangle(j * BLOCK_SIZE, i * BLOCK_SIZE, (j + 1) * BLOCK_SIZE, (i + 1) * BLOCK_SIZE);
	}
}

小蛇向右移动

假设小蛇初始元素值为54321,其中1位蛇头,5432位蛇身。首先将二维数组中所有大于0的元素加1,得到65432;然后将最大值6变成0,即去除了原来的蛇尾;最后将2右边的元素由0变成1,即实现了小蛇向右移动

void moveSnake()
{
	int i, j;
	for (i = 0; i < HEIGHT; i++)
	{
		for (j = 0; j < WIDTH; j++)
		{
			if (Blocks[i][j] > 0)
			{
				Blocks[i][j]++;
			}
		}
	}
	int oldTail_i, oldTail_j, oldHead_i, oldHead_j;
	int max = 0;
	for (i = 0; i < HEIGHT; i++)
	{
		for (j = 0; j < WIDTH; j++)
		{
			if (max < Blocks[i][j])
			{
				max = Blocks[i][j];
				oldTail_i = i;
				oldTail_j = j;
			}
			if (Blocks[i][j] == 2)
			{
				oldHead_i = i;
				oldHead_j = j;
			}
		}
	}
	int newHead_i = oldHead_i;
	int newHead_j = oldHead_j;
	newHead_j = oldHead_j + 1;
	Blocks[newHead_i][newHead_j] = 1;
	Blocks[oldTail_i][oldTail_j] = 0;
}
void updateWithoutInput()            // 与输入无关的更新
{
	moveSnake();
	Sleep(100);
}

控制小蛇4个方向移动

变量oldHead_i、oldHead_j存储移动前的蛇头位置,newHead_i、newHead_j存储移动后的蛇头位置。小蛇向上移动,只需把新蛇头的坐标设为旧蛇头的上方即可

newHead_i = oldHead_i - 1;

让玩家用A、S、D、W键控制游戏角色移动,定义字符变量moveDirection表示小蛇运动方向,在moveSnake函数中对其值进行判断,取A向左运动、D向右运动、W向上运动、S向下运动:

if (moveDirection == 'A')
{
	newHead_j = oldHead_j - 1;
}
else if (moveDirection == 'D')
{
	newHead_j = oldHead_j + 1;
}
else if (moveDirection == 'W')
{
	newHead_i = oldHead_i - 1;
}
else if (moveDirection == 'S')
{
	newHead_i = oldHead_i + 1;
}

在updateWithInput()函数中获得用户按键输入,如果是A、S、D、W键之一,就更新moveDirection变量,执行moveSnake()函数让小蛇向对应方向移动:

void updateWithInput()               // 和输入有关的更新
{
	if (_kbhit())
	{
		char input = _getch();
		if (input == 'A' || input == 'S' || input == 'D' || input == 'W')
		{
			moveDirection = input;
			moveSnake();
		}
	}
}

时间控制的改进

在Sleep()函数运行时,整个程序都会暂停,包括用户输入模块。用户会感觉到卡顿

利用静态变量,将updateWithoutInput()修改如下:

void updateWithoutInput()            // 与输入无关的更新
{
	static int waitIndex = 1;
	waitIndex++;                     // 每一帧加1
	if (waitIndex == 10)
	{
		moveSnake();
		waitIndex = 1;
	}
}

其中,updateWithoutInput()每次运行时,waitIndex加1,每隔10帧,才执行一次移动函数moveSnake()。这样可在不影响用户按键输入的情况下,降低小蛇的移动速度

失败判断与显示

定义全局变量isFailure表示游戏是否失败,初始化为0:

int isFailure = 0;

当小蛇碰到画面边界时,则认为游戏失败;当蛇头与蛇身发生碰撞时,游戏也失败。由于每次只有蛇头是新生成的位置,所以在moveSnake()函数中只需判断蛇头是否越过边界和碰撞:

	if (newHead_i >= HEIGHT || newHead_i < 0 || newHead_j >= WIDTH || newHead_j < 0 || Blocks[newHead_i][newHead_j] > 0)
	{
		isFailure = 1;
		return;
	}

在show()函数中添加游戏失败后的显示信息:
	if (isFailure)                   // 游戏失败
	{
		setbkmode(TRANSPARENT);      // 文字字体透明
		settextcolor(RGB(255, 0, 0));
		settextstyle(80, 0, _T("宋体"));
		outtextxy(240, 220, _T("游戏失败"));
	}

在updateWithoutInput()中添加代码,当isFailure为1时,直接返回:

void updateWithoutInput()            // 与输入无关的更新
{
 if (isFailure)
 {
  return;
 }
 //...
}

在updateWithInput()中,只有当按下键盘且isFailure为0时,才进行相应的处理:

void updateWithInput()               // 和输入有关的更新
{
 if (_kbhit() && isFailure == 0)
 {
  // ...
 }
}

添加食物

添加全局变量记录食物的位置:

int food_i, food_j;

在startup()函数中初始化食物的位置:

void startup()                       // 初始化函数
{
 food_i = rand() % (HEIGHT - 5) + 2;
 food_j = rand() % (WIDTH - 5) + 2;
}

在show()函数中在食物位置处绘制一个绿色小方块:

setfillcolor(RGB(0, 255, 0));
fillrectangle(food_j * BLOCK_SIZE, food_i * BLOCK_SIZE, (food_j + 1) * BLOCK_SIZE, (food_i + 1) * BLOCK_SIZE);

当新蛇头碰到食物时,只需保留原蛇尾,即可让蛇的长度加1。当吃到食物时,食物位置重新随机出现,蛇长度加1;当没有迟到食物时,旧蛇尾变成空白,蛇长度保持不变:

Blocks[newHead_i][newHead_j] = 1;// 新蛇头位置数值为1
if (newHead_i == food_i && newHead_j == food_j) // 如果新蛇头碰到食物
{
 food_i = rand() % (HEIGHT - 5) + 2; // 食物重新随机位置
 food_j = rand() % (WIDTH - 5) + 2;
}
else
{
 Blocks[oldTail_i][oldTail_j] = 0;   // 旧蛇尾变成空白
}

完整代码

#include <graphics.h>
#include <conio.h>
#include <stdio.h>
#define BLOCK_SIZE 20                // 每个小格子的长宽
#define HEIGHT 30                    // 高度上一共30个小格子
#define WIDTH 40                     // 宽度上一共40个小格子

// 全局变量定义
int Blocks[HEIGHT][WIDTH] = { 0 };
char moveDirection;
int isFailure = 0;
int food_i, food_j;                  // 食物的位置

void startup()                       // 初始化函数
{
 int i;
 Blocks[HEIGHT / 2][WIDTH / 2] = 1;  // 画面中间画蛇头
 for (i = 1; i <= 4; i++)            // 向左依次4个蛇身
 {
  Blocks[HEIGHT / 2][WIDTH / 2 - i] = i + 1;
 }
 moveDirection = 'D';
 food_i = rand() % (HEIGHT - 5) + 2;
 food_j = rand() % (WIDTH - 5) + 2;
 initgraph(WIDTH * BLOCK_SIZE, HEIGHT * BLOCK_SIZE);
 setlinecolor(RGB(200, 200, 200));
 BeginBatchDraw();                   // 开始批量绘制
}

void show()                          // 绘制函数
{
 cleardevice();
 int i, j;
 for (i = 0; i < HEIGHT; i++)
 {
  for (j = 0; j < WIDTH; j++)
  {
   if (Blocks[i][j] > 0)
   {
    setfillcolor(HSVtoRGB(Blocks[i][j] * 10, 0.9, 1));
   }
   else
   {
    setfillcolor(RGB(150, 150, 150));
   }
   fillrectangle(j * BLOCK_SIZE, i * BLOCK_SIZE, (j + 1) * BLOCK_SIZE, (i + 1) * BLOCK_SIZE);
  }
 }
 setfillcolor(RGB(0, 255, 0));    // 食物颜色为绿色
 fillrectangle(food_j * BLOCK_SIZE, food_i * BLOCK_SIZE, (food_j + 1) * BLOCK_SIZE, (food_i + 1) * BLOCK_SIZE);

 if (isFailure)                   // 游戏失败
 {
  setbkmode(TRANSPARENT);      // 文字字体透明
  settextcolor(RGB(255, 0, 0));
  settextstyle(80, 0, _T("宋体"));
  outtextxy(240, 220, _T("游戏失败"));
 }
 FlushBatchDraw();                // 批量绘制
}

void moveSnake()
{
 int i, j;
 for (i = 0; i < HEIGHT; i++)
 {
  for (j = 0; j < WIDTH; j++)
  {
   if (Blocks[i][j] > 0)     // 大于0的为小蛇元素
   {
    Blocks[i][j]++;
   }
  }
 }
 int oldTail_i, oldTail_j, oldHead_i, oldHead_j; // 存储旧蛇
 int max = 0;
 for (i = 0; i < HEIGHT; i++)
 {
  for (j = 0; j < WIDTH; j++)
  {
   if (max < Blocks[i][j])
   {
    max = Blocks[i][j];
    oldTail_i = i;
    oldTail_j = j;
   }
   if (Blocks[i][j] == 2)      // 旧蛇头
   {
    oldHead_i = i;
    oldHead_j = j;
   }
  }
 }
 int newHead_i = oldHead_i;          // 设定变量存储新蛇头
 int newHead_j = oldHead_j;

 if (moveDirection == 'A')           // 根据用户按键,设定新蛇头的位置
 {
  newHead_j = oldHead_j - 1;
 }
 else if (moveDirection == 'D')
 {
  newHead_j = oldHead_j + 1;
 }
 else if (moveDirection == 'W')
 {
  newHead_i = oldHead_i - 1;
 }
 else if (moveDirection == 'S')
 {
  newHead_i = oldHead_i + 1;
 }

 if (newHead_i >= HEIGHT || newHead_i < 0 || newHead_j >= WIDTH || newHead_j < 0 || Blocks[newHead_i][newHead_j] > 0) // 失败条件
 {
  isFailure = 1;
  return;
 }

 Blocks[newHead_i][newHead_j] = 1;               // 新蛇头位置数值为1
 if (newHead_i == food_i && newHead_j == food_j) // 如果新蛇头碰到食物
 {
  food_i = rand() % (HEIGHT - 5) + 2;         // 食物重新随机位置
  food_j = rand() % (WIDTH - 5) + 2;
 }
 else
 {
  Blocks[oldTail_i][oldTail_j] = 0;           // 旧蛇尾变成空白
 }
}
void updateWithoutInput()                           // 与输入无关的更新
{
 if (isFailure)
 {
  return;
 }
 static int waitIndex = 1;
 waitIndex++;                                     // 每一帧加1
 if (waitIndex == 10)
 {
  moveSnake();
  waitIndex = 1;
 }
}

void updateWithInput()                                // 和输入有关的更新
{
 if (_kbhit() && isFailure == 0)
 {
  char input = _getch();
  if (input == 'A' || input == 'S' || input == 'D' || input == 'W')
  {
   moveDirection = input;
   moveSnake();
  }
 }
}

int main()
{
 startup();                       // 初始化函数,仅执行一次
 while (1)
 {
  show();                      // 进行绘制
  updateWithoutInput();        // 和输入无关的更新
  updateWithInput();           // 和输入有关的更新
 }
 return 0;
}

总结

到此这篇关于C++入门指南之贪吃蛇游戏实现的文章就介绍到这了,更多相关C++实现贪吃蛇游戏内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • C++代码实现贪吃蛇小游戏

    本文实例为大家分享了C++实现贪吃蛇小游戏的具体代码,供大家参考,具体内容如下 1.游戏描述 贪吃蛇可谓是从小玩到大的经典趣味小游戏,蛇每吃到一次食物,身体就会长一节,如果撞到墙或者撞到自身,游戏结束. 2.代码实现 1.首先需要思考的问题是如何指定位置输出字符?这时候就有一个非常强大的函数叫 gotoxy() ,现在库函数里边已经没有了,只能我们自己实现,代码中注释很完整,自行阅读即可. 2.实现了指哪画哪的目标之后,就可以开始游戏内容制作了.首先便是圈地,即画地图,一个简简单单的循环就能安排

  • 贪吃蛇游戏C++命令行版实例代码

    本文实例讲述了贪吃蛇游戏C++命令行版的实现代码,是非常经典的游戏.分享给大家供大家参考.具体实现方法如下: 众所周知,贪吃蛇游戏是经典的计算机游戏. 游戏描述如下: 1. 贪吃蛇可以自动直线前进,或者玩家可以通过方向键操纵贪吃蛇上下左右前进,每次前进一格. 2. 贪吃蛇在规定的区域内活动,当: ①贪吃蛇触碰到墙壁时: ②贪吃蛇的蛇头触碰到蛇身或者蛇尾时: ③玩家的键盘输入不是方向键时: 命令行显示"Game Over!"并且退出游戏. 3. 贪吃蛇活动的区域内每次随机产生一颗&quo

  • C++结构体数组实现贪吃蛇

    本文实例为大家分享了C++结构体数组实现贪吃蛇的具体代码,供大家参考,具体内容如下 代码: #include<bits/stdc++.h> #include<windows.h> #include<conio.h> using namespace std; const int h=50,w=50,MaxLen=400; void gotoxy(short y,short x)//光标移动函数 { COORD pos={x,y}; SetConsoleCursorPosi

  • C++控制台实现贪吃蛇游戏

    本文实例为大家分享了C++实现贪吃蛇游戏的具体代码,供大家参考,具体内容如下 刚学完了C语言,便尝试的写了贪吃蛇的代码,但是效果不佳,很多的bug,所以,这个学了C++,便重新的写了这个小游戏,用类来封装! 先是头文件: struct Snake { int x, y; }; class snake { public: snake() //构造函数 { length = 3; s[2].x = 10; s[2].y = 10; s[1].x = 9; s[1].y = 10; s[0].x =

  • C++通过类实现控制台贪吃蛇

    本文实例为大家分享了C++实现控制台贪吃蛇的具体代码,供大家参考,具体内容如下 初学c++,算刚学完类吧,写个贪吃蛇来玩玩. 现是头文件 #pragma once #ifndef SNACK_H #define SNACK_H #define Frame_X 5//边框起点横坐标 #define Frame_Y 5//边框起点纵坐标 #define Frame_width 50//边框长度 #define Frame_height 25//边框高度 struct point//蛇个点坐标 { i

  • C++控制台循环链表实现贪吃蛇

    本文实例为大家分享了C++控制台循环链表实现贪吃蛇的具体代码,供大家参考,具体内容如下 -stdafx.h 为了简化程序定义一些宏和全局变量 #ifndef __STDAFX_H__ #define __STDAFX_H__ // ============上下左右============= const int UP = 72; const int DOWN = 80; const int LEFT = 75; const int RIGHT = 77; // ==============宽高==

  • C/C++实现贪吃蛇逐步运动效果

    本文实例为大家分享了C/C++实现贪吃蛇逐步运动效果的代码,供大家参考,具体内容如下 主要使用结构数组和结构指针,再用easyx图形库进行的绘图,以供讨论和学习 #include <conio.h> //建立储存蛇身的结构体 struct snack { int x; int y; }; //决定方向 int fangxiang=3;//w=0,s=1,a=2,d=3 // 按键变量 char anjian=0; //调整坐标关系 int tiaozheng(struct snack *a);

  • C++基于控制台实现的贪吃蛇小游戏

    本文实例讲述了C++基于控制台实现的贪吃蛇小游戏.分享给大家供大家参考.具体实现方法如下: #include <windows.h> #include <time.h> #include <stdio.h> #define MAX 100 #define UP 1 #define DOWN 2 #define LEFT 3 #define RIGHT 4 #define MOVING 5 #define STOP 0 HANDLE hMain_Out = NULL; H

  • C++实现简单贪吃蛇游戏

    我大概在一个多月前把自己上学期写的c代码的贪吃蛇游戏push到csdn上,并且说c风格的贪吃蛇写起来有些麻烦(贪吃蛇游戏的c语言实现),准备用面向对象的c++再写一遍.现在我们专业恰好刚教完了c++,学校也布置了一道简单的贪吃蛇的编程题目,实现下来,的确觉得c++的思路清晰很多,所以再次把c++的代码push上来,供大家对比参考:) 直接上代码,c++把整个游戏拆分成几个文件,分开上,有一定的c++基础的同学应该可以很容易看懂. 1.全局头文件(global.hpp) #ifndef _GLOB

  • 利用C/C++实现较完整贪吃蛇游戏

    记得在大一时刚学习c/c++语言,学到一半突然想用这门语言做一些小游戏出来,首先想到的便是贪吃蛇.于是本人利用空余时间写出了这么一个简单的小游戏. 由于当时的我还没有能力构造出用户界面,故直接使用dos界面运行.那么问题来了,如何让一个字符在dos界面上自由移动???对于这个问题我采用的解决方案是实现gotoxy函数来控制指针位置从而实现字符的移动.那么我们就先来实现这个函数. gotoxy 函数并非系统函数,我将其储存于 gotoxy.h 的头文件中方便调用. gotoxy.h #includ

随机推荐