Easyx | 游戏实例:是勇士就下100层

目录

目录

游戏简介

准备素材

开始编写

1  预编译

2  球和板子的结构体

3 初始化

加载背景图片

初始化板子

初始化球(玩家)

封装 Init 函数

4 绘制屏幕

背景图

画球(玩家)

画板子

封装 Draw 函数

5 移动球

检测按键左右移动

边界限制

落在板子上

封装 MovePlayer 函数

6 移动板子

向上移动

检测到顶

封装 MoveBoard 函数

7 游戏结束

8 准备阶段

9 最后——封装 main 函数

效果截图

完整代码

 


游戏简介

控制一个,让它待在板子上,不能掉下去木板持续上升,球也不能碰到顶

这句话中标的,是我们一步一步要实现的。蓝色背景的字,我们将要定义结构体

代码思路:

1. 球和板子的结构体

2. 初始化

3. 绘制屏幕

4. 移动球

5. 移动板子

6. 判断游戏结束

7. 准备阶段

准备素材

我使用了一张墙壁的背景图(至少比纯色好):

 还有一个 “Ready Go!" 的音效:https://sc.chinaz.com/yinxiao/180831571002.htm

开始编写

1  预编译

#include <stdio.h>
#include <graphics.h>
#include <time.h>
#include <conio.h>
#pragma comment(lib, "winmm.lib") //为音乐做准备
#define WIDTH 760
#define HEIGHT 640
#define BOARDNUM 11

2  球和板子的结构体

球(玩家)

x坐标 x

y坐标 y

半径 r

移动速度 speed

下落速度  dy

落在的板子的下标 index

颜色  color

// 玩家结构体
struct Player
{
	int x;
	int y;
	int r;
	int speed;
	int index;
	int dy;
	COLORREF color;
};

板子

x坐标 x

y坐标 y

高度 h

宽度 w

颜色 color

// 板子结构体
struct Board
{
	int x;
	int y;
	int w;
	int h;
	COLORREF color;
};

3 初始化

首先定义玩家和表示板子的一维数组

Player player;
Board board[BOARDNUM];

加载背景图片

注意:loadimage 函数中的文件地址参数类型为 LPCTSTR,  调整步骤如下:

① 打开解决方案管理器(Ctrl + Alt + L)

② 打开属性(Alt + Enter)

③ 选择配置属性下的高级

④ 找到字符集,将使用Unicode字符集改成使用多字节字符集

// 背景图
loadimage(&bk_img, ".\\Background.png", WIDTH, HEIGHT, true);

初始化板子

遍历每一个板子,依次从高到低设置y坐标。宽度为50~150的随机数,x坐标为0~(屏幕宽度-宽度)的随机数,高度固定为10,颜色也是随机数。

// 板子
for (int i = 0; i < BOARDNUM; i++)
{
	board[i].w = rand() % 100 + 50;
	board[i].x = rand() % WIDTH - board[i].w;
	board[i].y = 0;
	if (i == 0)
	{
		board[i].y = 100;
	}
	else
	{
		board[i].y = board[i - 1].y + 60;
	}
	board[i].h = 10;
	board[i].color = RGB(rand() % 256, rand() % 256, rand() % 256);
}

初始化球(玩家)

玩家的y坐标在100,x坐标由最上面的板子的x坐标决定。

// 玩家
player.x = board[0].x + rand() % board[0].w;
player.r = 10;
player.y = board[0].y - player.r;
player.speed = 5;
player.index = -1;
player.dy = 1;
player.color = LIGHTGRAY;

封装 Init 函数

// 初始化
void Init()
{
	// 背景图
	loadimage(&bk_img, ".\\Background.png", WIDTH, HEIGHT, true);

	// 板子
	for (int i = 0; i < BOARDNUM; i++)
	{
		board[i].w = rand() % 100 + 50;
		board[i].x = rand() % WIDTH - board[i].w;
		board[i].y = 0;
		if (i == 0)
		{
			board[i].y = 100;
		}
		else
		{
			board[i].y = board[i - 1].y + 60;
		}
		board[i].h = 10;
		board[i].color = RGB(rand() % 256, rand() % 256, rand() % 256);
	}

	// 玩家
	player.x = board[0].x + rand() % board[0].w;
	player.r = 10;
	player.y = board[0].y - player.r;
	player.speed = 5;
	player.index = -1;
	player.dy = 1;
	player.color = LIGHTGRAY;
}

4 绘制屏幕

背景图

把背景图放在 (0, 0) 的位置。

// 背景图
putimage(0, 0, &bk_img);

画球(玩家)

根据结构体中的 x, y, r 绘制一个灰色的圆当作玩家。

// 玩家
setfillcolor(player.color);
setlinecolor(WHITE);
fillcircle(player.x, player.y, player.r);

画板子

根据板子的 x, y, x+w, y+h 挨个画出长方形。

// 板子
for (int i = 0; i < BOARDNUM; i++)
{
	setfillcolor(board[i].color);
	setlinecolor(WHITE);
	fillrectangle(board[i].x, board[i].y, board[i].x + board[i].w, board[i].y + board[i].h);
}

封装 Draw 函数

// 绘制窗口
void Draw()
{
	cleardevice();

	// 背景图
	putimage(0, 0, &bk_img);

	// 玩家
	setfillcolor(player.color);
	setlinecolor(WHITE);
	fillcircle(player.x, player.y, player.r);

	// 板子
	for (int i = 0; i < BOARDNUM; i++)
	{
		setfillcolor(board[i].color);
		setlinecolor(WHITE);
		fillrectangle(board[i].x, board[i].y, board[i].x + board[i].w, board[i].y + board[i].h);
	}
}

5 移动球

检测按键左右移动

通过 GetAsyncKeyState 函数异步检测按键,改变球的x坐标。

其中 VK_LEFT 和 VK_RIGHT 分别表示 ← → 键。

// 左右移动
if (GetAsyncKeyState('a') || GetAsyncKeyState('A') || GetAsyncKeyState(VK_LEFT))
{
	player.x -= player.speed;
}
if (GetAsyncKeyState('d') || GetAsyncKeyState('D') || GetAsyncKeyState(VK_RIGHT))
{
	player.x += player.speed;
}

边界限制

判断球的x坐标,防止它跑出窗口(左右)。

// 边界限制
if (player.x <= player.r) player.x = player.r;
if (player.x >= WIDTH - player.r) player.x = WIDTH - player.r;

落在板子上

挨个判断每一个板子,球的x坐标在板子的 x x+w 的范围内,并且 y+r 在板子 y 上。

用 index 保存它落在的板子上的下标。index = -1 时表示它正在下落。

// 跟随板子
for (int i = 0; i < BOARDNUM; i++)
{
	if (player.x >= board[i].x && player.x <= board[i].x + board[i].w &&
		player.y + player.r >= board[i].y && player.y + player.r <= board[i].y + 10) // x坐标
	{
		player.index = i;
		break;
	}
	else player.index = -1;
}
if (player.index == -1)
{
	player.y += player.dy;
	if (player.dy < 10) player.dy++;
}
else
{
	player.y = board[player.index].y - player.r;
	player.dy = 1;
}

封装 MovePlayer 函数

void MovePlayer()
{
	// 左右移动
	if (GetAsyncKeyState('a') || GetAsyncKeyState('A') || GetAsyncKeyState(VK_LEFT))
	{
		player.x -= player.speed;
	}
	if (GetAsyncKeyState('d') || GetAsyncKeyState('D') || GetAsyncKeyState(VK_RIGHT))
	{
		player.x += player.speed;
	}

	// 边界限制
	if (player.x <= player.r) player.x = player.r;
	if (player.x >= WIDTH - player.r) player.x = WIDTH - player.r;

	// 跟随板子
	for (int i = 0; i < BOARDNUM; i++)
	{
		if (player.x >= board[i].x && player.x <= board[i].x + board[i].w &&
			player.y + player.r >= board[i].y && player.y + player.r <= board[i].y + 10) // x坐标
		{
			player.index = i;
			break;
		}
		else player.index = -1;
	}
	if (player.index == -1)
	{
		player.y += player.dy;
		if (player.dy < 10) player.dy++;
	}
	else
	{
		player.y = board[player.index].y - player.r;
		player.dy = 1;
	}
}

6 移动板子

向上移动

每一个板子的 y 坐标减少。

for (int i = 0; i < BOARDNUM; i++)
{
    board[i].y -= 2;
}

检测到顶

如果到顶了的话,重新初始化这块板子。

if (board[i].y + board[i].h <= 0)
{
	// 重新初始化
	board[i].y = BOARDNUM * 60;
	board[i].w = rand() % 100 + 50;
	board[i].x = rand() % WIDTH - board[i].w;
	board[i].color = RGB(rand() % 256, rand() % 256, rand() % 256);
}

封装 MoveBoard 函数

// 板子移动
void MoveBoard()
{
	for (int i = 0; i < BOARDNUM; i++)
	{
		board[i].y -= 2;
		if (board[i].y + board[i].h <= 0)
		{
			// 重新初始化
			board[i].y = BOARDNUM * 60;
			board[i].w = rand() % 100 + 50;
			board[i].x = rand() % WIDTH - board[i].w;
			board[i].color = RGB(rand() % 256, rand() % 256, rand() % 256);
		}
	}
}

7 游戏结束

如果球碰到顶或掉到底下,即为游戏结束。

if (player.y - player.r >= HEIGHT || player.y + player.r <= 0)
{
	MessageBox(GetHWnd(), "游戏结束!", "游戏", MB_OK | MB_ICONINFORMATION);
	break;
}

8 准备阶段

等待用户按下键盘,播放 “Ready Go!" 音效。

_getch();
PlaySound(".\\Ready.wav", NULL, SND_ASYNC | SND_FILENAME);
Sleep(1000);

9 最后——封装 main 函数

int main()
{
	initgraph(WIDTH, HEIGHT);
	srand(time(NULL));
	Init();
	Draw();
	_getch();
	PlaySound(".\\Ready.wav", NULL, SND_ASYNC | SND_FILENAME);
	Sleep(1000);
	BeginBatchDraw();
	while (true)
	{
		Draw();
		MovePlayer();
		MoveBoard();
		if (player.y - player.r >= HEIGHT || player.y + player.r <= 0)
		{
			MessageBox(GetHWnd(), "游戏结束!", "游戏", MB_OK | MB_ICONINFORMATION);
			break;
		}
		FlushBatchDraw();
		Sleep(1);
	}
	EndBatchDraw();
	closegraph();
	return 0;
}

效果截图

完整代码

/*
* 项目名称:是勇士就下100层
* 开发环境:vs2022 + Easyx
* 作者:轩
* 代码长度:184 行
* 完成时间:2022.12.31
* 用时:2.3 小时
*/

#include <stdio.h>
#include <graphics.h>
#include <time.h>
#include <conio.h>
#pragma comment(lib, "winmm.lib")
#define WIDTH 760
#define HEIGHT 640
#define BOARDNUM 11

// 玩家结构体
struct Player
{
	int x;
	int y;
	int r;
	int speed;
	int index;
	int dy;
	COLORREF color;
};

// 板子结构体
struct Board
{
	int x;
	int y;
	int w;
	int h;
	COLORREF color;
};

IMAGE bk_img;
Player player;
Board board[BOARDNUM];

// 初始化
void Init()
{
	// 背景图
	loadimage(&bk_img, ".\\Background.png", WIDTH, HEIGHT, true);

	// 板子
	for (int i = 0; i < BOARDNUM; i++)
	{
		board[i].w = rand() % 100 + 50;
		board[i].x = rand() % WIDTH - board[i].w;
		board[i].y = 0;
		if (i == 0)
		{
			board[i].y = 100;
		}
		else
		{
			board[i].y = board[i - 1].y + 60;
		}
		board[i].h = 10;
		board[i].color = RGB(rand() % 256, rand() % 256, rand() % 256);
	}

	// 玩家
	player.x = board[0].x + rand() % board[0].w;
	player.r = 10;
	player.y = board[0].y - player.r;
	player.speed = 5;
	player.index = -1;
	player.dy = 1;
	player.color = LIGHTGRAY;
}

// 绘制窗口
void Draw()
{
	cleardevice();

	// 背景图
	putimage(0, 0, &bk_img);

	// 玩家
	setfillcolor(player.color);
	setlinecolor(WHITE);
	fillcircle(player.x, player.y, player.r);

	// 板子
	for (int i = 0; i < BOARDNUM; i++)
	{
		setfillcolor(board[i].color);
		setlinecolor(WHITE);
		fillrectangle(board[i].x, board[i].y, board[i].x + board[i].w, board[i].y + board[i].h);
	}
}

// 玩家移动
void MovePlayer()
{
	// 左右移动
	if (GetAsyncKeyState('a') || GetAsyncKeyState('A') || GetAsyncKeyState(VK_LEFT))
	{
		player.x -= player.speed;
	}
	if (GetAsyncKeyState('d') || GetAsyncKeyState('D') || GetAsyncKeyState(VK_RIGHT))
	{
		player.x += player.speed;
	}

	// 边界限制
	if (player.x <= player.r) player.x = player.r;
	if (player.x >= WIDTH - player.r) player.x = WIDTH - player.r;

	// 跟随板子
	for (int i = 0; i < BOARDNUM; i++)
	{
		if (player.x >= board[i].x && player.x <= board[i].x + board[i].w &&
			player.y + player.r >= board[i].y && player.y + player.r <= board[i].y + 10) // x坐标
		{
			player.index = i;
			break;
		}
		else player.index = -1;
	}
	if (player.index == -1)
	{
		player.y += player.dy;
		if (player.dy < 10) player.dy++;
	}
	else
	{
		player.y = board[player.index].y - player.r;
		player.dy = 1;
	}
}

// 板子移动
void MoveBoard()
{
	for (int i = 0; i < BOARDNUM; i++)
	{
		board[i].y -= 2;
		if (board[i].y + board[i].h <= 0)
		{
			// 重新初始化
			board[i].y = BOARDNUM * 60;
			board[i].w = rand() % 100 + 50;
			board[i].x = rand() % WIDTH - board[i].w;
			board[i].color = RGB(rand() % 256, rand() % 256, rand() % 256);
		}
	}
}

int main()
{
	initgraph(WIDTH, HEIGHT);
	srand(time(NULL));
	Init();
	Draw();
	_getch();
	PlaySound(".\\Ready.wav", NULL, SND_ASYNC | SND_FILENAME);
	Sleep(1000);
	BeginBatchDraw();
	while (true)
	{
		Draw();
		MovePlayer();
		MoveBoard();
		if (player.y - player.r >= HEIGHT || player.y + player.r <= 0)
		{
			MessageBox(GetHWnd(), "游戏结束!", "游戏", MB_OK | MB_ICONINFORMATION);
			break;
		}
		FlushBatchDraw();
		Sleep(1);
	}
	EndBatchDraw();
	closegraph();
	return 0;
}

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值