Easyx使用(小游戏开发)
【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing @163.com】
easyx本身非常适合小游戏的开发。因为它可以画图,可以有键盘输入,可以有鼠标输入,也可以贴图,也可以做出各种效果,所以用来开发小游戏也是非常合适的。即使用来做大型游戏的demo,也是可以的。很多同学去学习easyx的api,本质上就是尝试开发游戏,当然这也无可厚非。今天我们可以简单开发一个贪吃蛇游戏。
1、贪吃蛇
贪吃蛇是一个很经典的游戏。本身贪吃蛇的长度很短,但是它每吃一个食物之后,身体就会变长。这样随着蛇的身体越来越长,它的行动也越来越受限,比如它不能碰壁,也不能碰到自己。一旦出现这些问题,那么游戏就会结束。
2、功能分解
要实现贪吃蛇也不难,整个功能可以切分成这几个部分。首先,初始化蛇的身体,比如分解成几个正方形。然后初始化食物的位置。接着就是绘制蛇的身体,绘制食物。这些都ok之后,就可以移动小蛇。如果无法移动,程序会结束;如果可以移动,则游戏继续。
3、初始化蛇的位置
整个小蛇是按照正方形来进行设计的,所以可以设几个正方形就可以了,当然也要给出初始运动方向,
// basic function defined herevoid 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 bodyfor (int i = 0; i < snake.length; ++i){if (food.x == snake.x[i] && food.y == snake.y[i]) {valid = false;break;}}}
}
5、绘制小蛇
小蛇的绘制其实不复杂,主要就是绘制几个正方形即可,
// draw snakevoid 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 foodvoid drawFood(const Food &food)
{setfillcolor(RED);fillrectangle(food.x, food.y, food.x + BLOCK_SIZE, food.y + BLOCK_SIZE);
}
7、小蛇的移动
小蛇的移动稍微复杂一点。这里面有一个小诀窍。首先把所有的小蛇身体,往后移动一格。再根据当前运动方向,确定第一个小格中的x和y怎么修改。修改的时候判断有没有食物,有实物的话,反而简单,直接长度+1,重新生成食物,退出继续循环。
如果不是食物,需要判断有没有出界,或者碰到自己。前面两个没遇到,就继续行走,遇到的话,就程序退出了。
// move snakebool moveSnake(Snake &snake, Food &food)
{// update snakefor (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 headerswitch (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 eatenif (snake.x[0] == food.x && snake.y[0] == food.y){snake.length++;generateFood(food, snake); // re-generate foodreturn true; //already eat food}// hit wallif (snake.x[0] < 0 || snake.x[0] >= WIDTH || snake.y[0] < 0 || snake.y[0] >= HEIGHT) {return false; }// hit snake itselffor (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 Snakestruct Snake
{int x[SNAKE_MAX_LENGTH]; int y[SNAKE_MAX_LENGTH]; int length; Direction dir;
};// struct of Foodstruct Food
{int x;int y;
};// basic function defined herevoid 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 bodyfor (int i = 0; i < snake.length; ++i){if (food.x == snake.x[i] && food.y == snake.y[i]) {valid = false;break;}}}
}// draw snakevoid 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 foodvoid drawFood(const Food &food)
{setfillcolor(RED);fillrectangle(food.x, food.y, food.x + BLOCK_SIZE, food.y + BLOCK_SIZE);
}// move snakebool moveSnake(Snake &snake, Food &food)
{// update snakefor (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 headerswitch (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 eatenif (snake.x[0] == food.x && snake.y[0] == food.y){snake.length++;generateFood(food, snake); // re-generate foodreturn true; //already eat food}// hit wallif (snake.x[0] < 0 || snake.x[0] >= WIDTH || snake.y[0] < 0 || snake.y[0] >= HEIGHT) {return false; }// hit snake itselffor (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 seedinitgraph(WIDTH, HEIGHT); setbkmode(TRANSPARENT);BeginBatchDraw();initSnake(snake);generateFood(food, snake);while (!gameOver) {if (_kbhit()) // non-block function{ // check keyboardchar ch = _getch();switch (ch) {case 'w': // upif (snake.dir != DOWN) snake.dir = UP;break;case 's': // downif (snake.dir != UP) snake.dir = DOWN;break;case 'a': // leftif (snake.dir != RIGHT) snake.dir = LEFT;break;case 'd': // rightif (snake.dir != LEFT) snake.dir = RIGHT;break;default:break;}}// logical checkgameOver = !moveSnake(snake, food); if (gameOver){break;}// re-draw picturecleardevice(); drawSnake(snake); drawFood(food); memset(buf, 0, 32); // draw score heresprintf(buf, "Score: %d", snake.length -3);outtextxy(500, 50, buf);EndBatchDraw();Sleep(250); // left some time to gamerBeginBatchDraw();}// update to clear screencleardevice();outtextxy(260, 220,"Game Over!!!");EndBatchDraw();_getch();closegraph(); //close windowreturn 0;
}