Easyx图形库使用(小游戏开发)

【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing @163.com】

        easyx本身非常适合小游戏的开发。因为它可以画图,可以有键盘输入,可以有鼠标输入,也可以贴图,也可以做出各种效果,所以用来开发小游戏也是非常合适的。即使用来做大型游戏的demo,也是可以的。很多同学去学习easyx的api,本质上就是尝试开发游戏,当然这也无可厚非。今天我们可以简单开发一个贪吃蛇游戏。

1、贪吃蛇

        贪吃蛇是一个很经典的游戏。本身贪吃蛇的长度很短,但是它每吃一个食物之后,身体就会变长。这样随着蛇的身体越来越长,它的行动也越来越受限,比如它不能碰壁,也不能碰到自己。一旦出现这些问题,那么游戏就会结束。

2、功能分解

        要实现贪吃蛇也不难,整个功能可以切分成这几个部分。首先,初始化蛇的身体,比如分解成几个正方形。然后初始化食物的位置。接着就是绘制蛇的身体,绘制食物。这些都ok之后,就可以移动小蛇。如果无法移动,程序会结束;如果可以移动,则游戏继续。

3、初始化蛇的位置

        整个小蛇是按照正方形来进行设计的,所以可以设几个正方形就可以了,当然也要给出初始运动方向,

// basic function defined here

void initSnake(Snake &snake)
{
	snake.length = 3; 
	snake.x[0] = WIDTH / 2 / BLOCK_SIZE * BLOCK_SIZE;  
	snake.y[0] = HEIGHT / 2 / BLOCK_SIZE * BLOCK_SIZE;
	snake.x[1] = WIDTH / 2 / BLOCK_SIZE * BLOCK_SIZE + BLOCK_SIZE ;
	snake.y[1] = HEIGHT / 2 / BLOCK_SIZE * BLOCK_SIZE + BLOCK_SIZE;
	snake.x[2] = WIDTH / 2 / BLOCK_SIZE * BLOCK_SIZE + BLOCK_SIZE * 2;
	snake.y[2] = HEIGHT / 2 / BLOCK_SIZE * BLOCK_SIZE + BLOCK_SIZE * 2;
	snake.dir = RIGHT; 
}

4、设置食物的位置

        有两个时间点需要设置食物的位置。一个是初始化的时候,还有一个就是当小蛇吃掉食物的时候,需要更新一个食物位置。过程中,注意食物的位置不能在蛇的身上。

void generateFood(Food &food, const Snake &snake)
{
	bool valid = false;
	while (!valid)
	{
		valid = true;
		food.x = (rand() % (WIDTH / BLOCK_SIZE)) * BLOCK_SIZE;
		food.y = (rand() % (HEIGHT / BLOCK_SIZE)) * BLOCK_SIZE;

		// check food in snake body
		
		for (int i = 0; i < snake.length; ++i)
		{
			if (food.x == snake.x[i] && food.y == snake.y[i]) 
			{
				valid = false;
				break;
			}
		}
	}
}

5、绘制小蛇

        小蛇的绘制其实不复杂,主要就是绘制几个正方形即可,

// draw snake

void drawSnake(const Snake &snake) 
{
	for (int i = 0; i < snake.length; ++i) 
	{
		setfillcolor(i == 0 ? BLUE : GREEN);  
		fillrectangle(snake.x[i], snake.y[i], snake.x[i] + BLOCK_SIZE, snake.y[i] + BLOCK_SIZE);
	}
}

6、食物的绘制

        相对而言,食物的绘制则更加简单,就是绘制一个正方形,注意颜色的区分,

// draw food

void drawFood(const Food &food)
{
	setfillcolor(RED);
	fillrectangle(food.x, food.y, food.x + BLOCK_SIZE, food.y + BLOCK_SIZE);
}

7、小蛇的移动

        小蛇的移动稍微复杂一点。这里面有一个小诀窍。首先把所有的小蛇身体,往后移动一格。再根据当前运动方向,确定第一个小格中的x和y怎么修改。修改的时候判断有没有食物,有实物的话,反而简单,直接长度+1,重新生成食物,退出继续循环。

        如果不是食物,需要判断有没有出界,或者碰到自己。前面两个没遇到,就继续行走,遇到的话,就程序退出了。

// move snake

bool moveSnake(Snake &snake, Food &food) 
{
	// update snake

	for (int i = snake.length - 1; i > 0; --i) 
	{
		snake.x[i] = snake.x[i - 1];
		snake.y[i] = snake.y[i - 1];
	}

	// adjust position of header

	switch (snake.dir) {
	case UP:
		snake.y[0] -= BLOCK_SIZE;
		break;

	case DOWN:
		snake.y[0] += BLOCK_SIZE;
		break;

	case LEFT:
		snake.x[0] -= BLOCK_SIZE;
		break;

	case RIGHT:
		snake.x[0] += BLOCK_SIZE;
		break;

	default:
		break;
	}

	// check food whether being eaten

	if (snake.x[0] == food.x && snake.y[0] == food.y)
	{
		snake.length++;
		generateFood(food, snake);  // re-generate food
		return true;  //already eat food
	}

	// hit wall

	if (snake.x[0] < 0 || snake.x[0] >= WIDTH || snake.y[0] < 0 || snake.y[0] >= HEIGHT) 
	{
		return false;  
	}

	// hit snake itself

	for (int i = 1; i < snake.length; ++i) 
	{
		if (snake.x[0] == snake.x[i] && snake.y[0] == snake.y[i]) 
		{
			return false;  
		}
	}

	return true;  
}

8、键盘输入

        整个小蛇的控制是通过键盘进行的。控制的按键是a、w、s、d,玩过cs的同学应该不会陌生。每一次按键确认之后,都要设置下小蛇的前进方向,根据小蛇是否正常运行,对小蛇和食物进行重新绘制,这样整个游戏就可以慢慢做好了。

        当然实际开发的时候,我们也会显示当前的得分,以及提示用户,什么时候程序已经结束了。最后这里给出完整的代码,有兴趣的同学可以好好看一下代码,

#define _CRT_SECURE_NO_WARNINGS
#include <graphics.h>
#include <conio.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctime>

static const int WIDTH = 640;  
static const int HEIGHT = 480; 
static const int BLOCK_SIZE = 20; 
static const int SNAKE_MAX_LENGTH = 100; 

enum Direction { UP, DOWN, LEFT, RIGHT };

// struct of Snake

struct Snake 
{
	int x[SNAKE_MAX_LENGTH];  
	int y[SNAKE_MAX_LENGTH]; 
	int length; 
	Direction dir; 
};

// struct of Food

struct Food 
{
	int x;
	int y;
};

// basic function defined here

void initSnake(Snake &snake)
{
	snake.length = 3; 
	snake.x[0] = WIDTH / 2 / BLOCK_SIZE * BLOCK_SIZE;  
	snake.y[0] = HEIGHT / 2 / BLOCK_SIZE * BLOCK_SIZE;
	snake.x[1] = WIDTH / 2 / BLOCK_SIZE * BLOCK_SIZE + BLOCK_SIZE ;
	snake.y[1] = HEIGHT / 2 / BLOCK_SIZE * BLOCK_SIZE + BLOCK_SIZE;
	snake.x[2] = WIDTH / 2 / BLOCK_SIZE * BLOCK_SIZE + BLOCK_SIZE * 2;
	snake.y[2] = HEIGHT / 2 / BLOCK_SIZE * BLOCK_SIZE + BLOCK_SIZE * 2;
	snake.dir = RIGHT; 
}

void generateFood(Food &food, const Snake &snake)
{
	bool valid = false;
	while (!valid)
	{
		valid = true;
		food.x = (rand() % (WIDTH / BLOCK_SIZE)) * BLOCK_SIZE;
		food.y = (rand() % (HEIGHT / BLOCK_SIZE)) * BLOCK_SIZE;

		// check food in snake body
		
		for (int i = 0; i < snake.length; ++i)
		{
			if (food.x == snake.x[i] && food.y == snake.y[i]) 
			{
				valid = false;
				break;
			}
		}
	}
}

// draw snake

void drawSnake(const Snake &snake) 
{
	for (int i = 0; i < snake.length; ++i) 
	{
		setfillcolor(i == 0 ? BLUE : GREEN);  
		fillrectangle(snake.x[i], snake.y[i], snake.x[i] + BLOCK_SIZE, snake.y[i] + BLOCK_SIZE);
	}
}

// draw food

void drawFood(const Food &food)
{
	setfillcolor(RED);
	fillrectangle(food.x, food.y, food.x + BLOCK_SIZE, food.y + BLOCK_SIZE);
}

// move snake

bool moveSnake(Snake &snake, Food &food) 
{
	// update snake

	for (int i = snake.length - 1; i > 0; --i) 
	{
		snake.x[i] = snake.x[i - 1];
		snake.y[i] = snake.y[i - 1];
	}

	// adjust position of header

	switch (snake.dir) {
	case UP:
		snake.y[0] -= BLOCK_SIZE;
		break;

	case DOWN:
		snake.y[0] += BLOCK_SIZE;
		break;

	case LEFT:
		snake.x[0] -= BLOCK_SIZE;
		break;

	case RIGHT:
		snake.x[0] += BLOCK_SIZE;
		break;

	default:
		break;
	}

	// check food whether being eaten

	if (snake.x[0] == food.x && snake.y[0] == food.y)
	{
		snake.length++;
		generateFood(food, snake);  // re-generate food
		return true;  //already eat food
	}

	// hit wall

	if (snake.x[0] < 0 || snake.x[0] >= WIDTH || snake.y[0] < 0 || snake.y[0] >= HEIGHT) 
	{
		return false;  
	}

	// hit snake itself

	for (int i = 1; i < snake.length; ++i) 
	{
		if (snake.x[0] == snake.x[i] && snake.y[0] == snake.y[i]) 
		{
			return false;  
		}
	}

	return true;  
}

int main(int argc, char* argv) 
{
	Snake snake; 
	Food food; 
	char buf[32] = {0};
	bool gameOver = false;

	srand((unsigned int)time(0));  // random seed

	initgraph(WIDTH, HEIGHT); 
	setbkmode(TRANSPARENT);

	BeginBatchDraw();
	initSnake(snake);
	generateFood(food, snake);

	while (!gameOver) 
	{
		if (_kbhit()) // non-block function
		{ 
			// check keyboard

			char ch = _getch();
			switch (ch) 
			{
			case 'w':  // up
				if (snake.dir != DOWN) 
					snake.dir = UP;
				break;

			case 's':  // down
				if (snake.dir != UP) 
					snake.dir = DOWN;
				break;

			case 'a':  // left
				if (snake.dir != RIGHT) 
					snake.dir = LEFT;
				break;

			case 'd':  // right
				if (snake.dir != LEFT) 
					snake.dir = RIGHT;
				break;

			default:
				break;
			}
		}

		// logical check

		gameOver = !moveSnake(snake, food); 
		if (gameOver)
		{
			break;
		}

		// re-draw picture

		cleardevice(); 
		drawSnake(snake);  
		drawFood(food);  

		memset(buf, 0, 32); // draw score here
		sprintf(buf, "Score: %d", snake.length -3);
		outtextxy(500, 50, buf);
		EndBatchDraw();

		Sleep(250); // left some time to gamer
		BeginBatchDraw();
	}

	// update to clear screen

	cleardevice();
	outtextxy(260, 220,"Game Over!!!");
	EndBatchDraw();

	_getch();
	closegraph();  //close window
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

嵌入式-老费

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值