跳到主要内容 C++ 火柴人跑酷游戏开发流程详解 | 极客日志
C++ 算法
C++ 火柴人跑酷游戏开发流程详解 本文详细讲解了使用 C++ 和 EasyX 图形库开发火柴人跑酷游戏的完整流程。从基础窗口搭建开始,逐步实现角色动画、资源加载、输入控制、障碍物生成与移动、碰撞检测及计分系统。教程分为十二个阶段,涵盖双缓冲防闪烁、定时器控制帧率、随机障碍物生成、难度递增等核心功能,最终提供带注释的完整可运行代码,适合初学者学习游戏开发基础逻辑。
火柴人跑酷游戏开发流程文档
第一阶段:基础框架搭建(v1.0)
1.1 基础头文件和常量定义
#include <graphics.h>
#include <stdio.h>
#include <time.h>
#define WIDTH 640
{
(WIDTH, HEIGHT);
( ){
(WHITE);
();
(LIGHTBLUE);
( , FLOOR_Y, WIDTH, HEIGHT);
();
( );
}
();
;
}
#define HEIGHT 400
#define FLOOR_Y 360
int main ()
initgraph
while
1
setbkcolor
cleardevice
setfillcolor
solidrectangle
0
FlushBatchDraw
Sleep
10
closegraph
return
0
第二阶段:角色系统开发(v2.0)
2.1 角色状态和属性定义 enum State { Run, Roll, Jump };
struct FireMan {
int x, y;
State state;
int w, h;
};
#define ROLE_IMGW 70
#define ROLE_IMGH 100
#define BEGIN_X 50
#define BEGIN_Y FLOOR_Y-ROLE_IMGH
struct FireMan fireMan ={ BEGIN_X, BEGIN_Y, Run, ROLE_IMGW, ROLE_IMGH };
2.2 简单角色绘制 void DrawRole () {
setfillcolor (RED);
fillrectangle (fireMan.x, fireMan.y, fireMan.x + fireMan.w, fireMan.y + fireMan.h);
}
第三阶段:资源管理系统(v3.0)
3.1 图像资源加载 IMAGE runIMG[8 ];
void LoadResources () {
char fileURL[50 ]="" ;
for (int i =1 ; i <=8 ; i++){
sprintf_s (fileURL,50 ,"./Res/Run/move8_%d.jpg" , i);
loadimage (&runIMG[i -1 ], fileURL, ROLE_IMGW, ROLE_IMGH);
}
}
3.2 更新角色绘制 void DrawRole () {
putimage (fireMan.x, fireMan.y, runIMG +0 );
}
【注意】:如果无法正常使用 loadimage 函数,把项目改为:使用多字节字符集
bug 修复:以上代码,为何画面有不时的闪烁和抖动?
答:画面闪烁和抖动的主要原因是没有使用双缓冲技术。虽然你使用了 FlushBatchDraw(),但缺少了 BeginBatchDraw() 来开启批量绘制。主要修改点:添加双缓冲初始化 BeginBatchDraw() — EndBatchDraw()
int main () {
initgraph (WIDTH, HEIGHT);
LoadResources ();
BeginBatchDraw ();
while (1 ){
setbkcolor (WHITE);
cleardevice ();
setfillcolor (LIGHTBLUE);
solidrectangle (0 , FLOOR_Y, WIDTH, HEIGHT);
DrawRole ();
FlushBatchDraw ();
Sleep (10 );
}
EndBatchDraw ();
closegraph ();
return 0 ;
}
第四阶段:动画系统(v4.0)
4.1 动画帧控制 int frameNum =0 ;
#define MAX_FRAME 8
void MoveRole () {
switch (fireMan.state){
case Run:{
frameNum++;
if (frameNum == MAX_FRAME){ frameNum =0 ;}
break ;
}
case Roll:{
frameNum++;
if (frameNum == MAX_FRAME){ frameNum =0 ;}
break ;
}
case Jump:{
frameNum =0 ;
}
default :break ;
}
}
void DrawRole () {
putimage (fireMan.x, fireMan.y, runIMG + frameNum);
}
4.2 定时器控制
火柴人奔跑的速度太快了,我们新增一个定时器,来控制火柴人奔跑的速度。
bool Timer (clock_t & lastTime,int interval) {
clock_t currentTime =clock ();
if (currentTime - lastTime >= interval){
lastTime = currentTime;
return true ;
}
return false ;
}
clock_t animLastTime =0 ;
while (1 ){
if (Timer (animLastTime,30 )){
MoveRole ();
}
}
效果 :火柴人奔跑速度明显减缓,30 毫秒之后才会切换下一帧动画。
#include <graphics.h>
#include <stdio.h>
#include <time.h>
#define WIDTH 640
#define HEIGHT 400
#define FLOOR_Y 360
enum State { Run, Roll, Jump };
struct FireMan {
int x, y;
State state;
int w, h;
};
#define ROLE_IMGW 70
#define ROLE_IMGH 100
#define BEGIN_X 50
#define BEGIN_Y FLOOR_Y-ROLE_IMGH
struct FireMan fireMan ={ BEGIN_X, BEGIN_Y, Run, ROLE_IMGW, ROLE_IMGH };
IMAGE runIMG[8 ];
void LoadResources () {
char fileURL[50 ]="" ;
for (int i =1 ; i <=8 ; i++){
sprintf_s (fileURL,50 ,"./Res/Run/move8_%d.jpg" , i);
loadimage (&runIMG[i -1 ], fileURL, ROLE_IMGW, ROLE_IMGH);
}
}
int frameNum =0 ;
#define MAX_FRAME 8
bool Timer (clock_t & lastTime,int interval) {
clock_t currentTime =clock ();
if (currentTime - lastTime >= interval){
lastTime = currentTime;
return true ;
}
return false ;
}
clock_t animLastTime =0 ;
void MoveRole () {
switch (fireMan.state){
case Run:{
frameNum++;
if (frameNum == MAX_FRAME){ frameNum =0 ;}
break ;
}
case Roll:{
frameNum++;
if (frameNum == MAX_FRAME){ frameNum =0 ;}
break ;
}
case Jump:{
frameNum =0 ;
}
default :break ;
}
}
void DrawRole () {
putimage (fireMan.x, fireMan.y, runIMG + frameNum);
}
int main () {
initgraph (WIDTH, HEIGHT);
LoadResources ();
BeginBatchDraw ();
while (1 ){
setbkcolor (WHITE);
cleardevice ();
setfillcolor (LIGHTBLUE);
solidrectangle (0 , FLOOR_Y, WIDTH, HEIGHT);
DrawRole ();
if (Timer (animLastTime,30 )){
MoveRole ();
}
FlushBatchDraw ();
Sleep (10 );
}
EndBatchDraw ();
closegraph ();
return 0 ;
}
第五阶段:输入控制系统(v5.0)
5.1 跳跃功能 int speed =-10 ;
#define JUMP_MIN_Y 60
void KeyDown () {
if (GetAsyncKeyState (VK_UP)){
fireMan.state = Jump;
}
}
void MoveRole () {
switch (fireMan.state){
case Run:{
frameNum++;
if (frameNum == MAX_FRAME){ frameNum =0 ;}
break ;
}
case Roll:{
frameNum++;
if (frameNum == MAX_FRAME){ frameNum =0 ;}
break ;
}
case Jump:{
frameNum =0 ;
fireMan.y += speed;
if (fireMan.y < JUMP_MIN_Y){
speed =-speed;
}
if (fireMan.y >= BEGIN_Y){
fireMan.y = BEGIN_Y;
speed =-speed;
fireMan.state = Run;
}
}
default :break ;
}
}
#include <graphics.h>
#include <stdio.h>
#include <time.h>
#define WIDTH 640
#define HEIGHT 400
#define FLOOR_Y 360
enum State { Run, Roll, Jump };
struct FireMan {
int x, y;
State state;
int w, h;
};
#define ROLE_IMGW 70
#define ROLE_IMGH 100
#define BEGIN_X 50
#define BEGIN_Y FLOOR_Y-ROLE_IMGH
struct FireMan fireMan ={ BEGIN_X, BEGIN_Y, Run, ROLE_IMGW, ROLE_IMGH };
IMAGE runIMG[8 ];
void LoadResources () {
char fileURL[50 ]="" ;
for (int i =1 ; i <=8 ; i++){
sprintf_s (fileURL,50 ,"./Res/Run/move8_%d.jpg" , i);
loadimage (&runIMG[i -1 ], fileURL, ROLE_IMGW, ROLE_IMGH);
}
}
int frameNum =0 ;
#define MAX_FRAME 8
bool Timer (clock_t & lastTime,int interval) {
clock_t currentTime =clock ();
if (currentTime - lastTime >= interval){
lastTime = currentTime;
return true ;
}
return false ;
}
clock_t animLastTime =0 ;
int speed =-10 ;
#define JUMP_MIN_Y 60
void KeyDown () {
if (GetAsyncKeyState (VK_UP)){
fireMan.state = Jump;
}
}
void MoveRole () {
switch (fireMan.state){
case Run:{
frameNum++;
if (frameNum == MAX_FRAME){ frameNum =0 ;}
break ;
}
case Roll:{
frameNum++;
if (frameNum == MAX_FRAME){ frameNum =0 ;}
break ;
}
case Jump:{
frameNum =0 ;
fireMan.y += speed;
if (fireMan.y < JUMP_MIN_Y){
speed =-speed;
}
if (fireMan.y >= BEGIN_Y){
fireMan.y = BEGIN_Y;
speed =-speed;
fireMan.state = Run;
}
}
default :break ;
}
}
void DrawRole () {
putimage (fireMan.x, fireMan.y, runIMG + frameNum);
}
int main () {
initgraph (WIDTH, HEIGHT);
LoadResources ();
BeginBatchDraw ();
while (1 ){
setbkcolor (WHITE);
cleardevice ();
setfillcolor (LIGHTBLUE);
solidrectangle (0 , FLOOR_Y, WIDTH, HEIGHT);
DrawRole ();
if (Timer (animLastTime,30 )){
MoveRole ();
}
KeyDown ();
FlushBatchDraw ();
Sleep (10 );
}
EndBatchDraw ();
closegraph ();
return 0 ;
}
第六阶段:下蹲功能(v6.0)
6.1 翻滚动画资源 IMAGE rollIMG[8 ];
#define ROLE_DOWN_IMGW 50
#define ROLE_DOWN_IMGH 50
for (int i =1 ; i <=8 ; i++){
sprintf_s (fileURL,50 ,"./Res/Roll/gun8_%d.jpg" , i);
loadimage (rollIMG + i -1 , fileURL, ROLE_DOWN_IMGW, ROLE_DOWN_IMGH);
}
6.2 下蹲逻辑 void KeyDown () {
if (GetAsyncKeyState (VK_DOWN)){
fireMan.state = Roll;
}
}
void MoveRole () {
switch (fireMan.state){
case Run:{
frameNum++;
if (frameNum == MAX_FRAME){ frameNum =0 ;}
break ;
}
case Roll:{
frameNum++;
if (frameNum == MAX_FRAME){ frameNum =0 ;}
fireMan.y = BEGIN_Y +(ROLE_IMGH - ROLE_DOWN_IMGH);
break ;
}
case Jump:{
frameNum =0 ;
fireMan.y += speed;
if (fireMan.y < JUMP_MIN_Y){
speed =-speed;
}
if (fireMan.y >= BEGIN_Y){
fireMan.y = BEGIN_Y;
speed =-speed;
fireMan.state = Run;
}
}
default :break ;
}
}
void DrawRole () {
switch (fireMan.state){
case Run:
putimage (fireMan.x, fireMan.y, runIMG + frameNum);
break ;
case Roll:
putimage (fireMan.x, fireMan.y, rollIMG + frameNum);
break ;
case Jump:;
break ;
}
}
void LoadResources () {
loadimage (&jumpIMG,"./Res/Jump/jump.jpg" , ROLE_IMGW, ROLE_IMGH);
}
void DrawRole () {
switch (fireMan.state){
case Run:
putimage (fireMan.x, fireMan.y, runIMG + frameNum);
break ;
case Roll:
putimage (fireMan.x, fireMan.y, rollIMG + frameNum);
break ;
case Jump:
putimage (fireMan.x, fireMan.y,&jumpIMG);
break ;
}
}
#include <graphics.h>
#include <stdio.h>
#include <time.h>
#define WIDTH 640
#define HEIGHT 400
#define FLOOR_Y 360
enum State { Run, Roll, Jump };
struct FireMan {
int x, y;
State state;
int w, h;
};
#define ROLE_IMGW 70
#define ROLE_IMGH 100
#define BEGIN_X 50
#define BEGIN_Y FLOOR_Y-ROLE_IMGH
struct FireMan fireMan ={ BEGIN_X, BEGIN_Y, Run, ROLE_IMGW, ROLE_IMGH };
IMAGE runIMG[8 ]; IMAGE rollIMG[8 ]; IMAGE jumpIMG;
#define ROLE_DOWN_IMGW 50
#define ROLE_DOWN_IMGH 50
void LoadResources () {
char fileURL[50 ]="" ;
for (int i =1 ; i <=8 ; i++){
sprintf_s (fileURL,50 ,"./Res/Run/move8_%d.jpg" , i);
loadimage (&runIMG[i -1 ], fileURL, ROLE_IMGW, ROLE_IMGH);
}
for (int i =1 ; i <=8 ; i++){
sprintf_s (fileURL,50 ,"./Res/Roll/gun8_%d.jpg" , i);
loadimage (rollIMG + i -1 , fileURL, ROLE_DOWN_IMGW, ROLE_DOWN_IMGH);
}
loadimage (&jumpIMG,"./Res/Jump/jump.jpg" , ROLE_IMGW, ROLE_IMGH);
}
int frameNum =0 ;
#define MAX_FRAME 8
bool Timer (clock_t & lastTime,int interval) {
clock_t currentTime =clock ();
if (currentTime - lastTime >= interval){
lastTime = currentTime;
return true ;
}
return false ;
}
clock_t animLastTime =0 ;
int speed =-10 ;
#define JUMP_MIN_Y 60
void KeyDown () {
if (GetAsyncKeyState (VK_UP)){
fireMan.state = Jump;
}
if (GetAsyncKeyState (VK_DOWN)){
fireMan.state = Roll;
}
}
void MoveRole () {
switch (fireMan.state){
case Run:{
frameNum++;
if (frameNum == MAX_FRAME){ frameNum =0 ;}
break ;
}
case Roll:{
frameNum++;
if (frameNum == MAX_FRAME){ frameNum =0 ;}
fireMan.y = BEGIN_Y +(ROLE_IMGH - ROLE_DOWN_IMGH);
break ;
}
case Jump:{
frameNum =0 ;
fireMan.y += speed;
if (fireMan.y < JUMP_MIN_Y){
speed =-speed;
}
if (fireMan.y >= BEGIN_Y){
fireMan.y = BEGIN_Y;
speed =-speed;
fireMan.state = Run;
}
}
default :break ;
}
}
void DrawRole () {
switch (fireMan.state){
case Run:
putimage (fireMan.x, fireMan.y, runIMG + frameNum);
break ;
case Roll:
putimage (fireMan.x, fireMan.y, rollIMG + frameNum);
break ;
case Jump:
putimage (fireMan.x, fireMan.y,&jumpIMG);
break ;
}
}
int main () {
initgraph (WIDTH, HEIGHT);
LoadResources ();
BeginBatchDraw ();
while (1 ){
setbkcolor (WHITE);
cleardevice ();
setfillcolor (LIGHTBLUE);
solidrectangle (0 , FLOOR_Y, WIDTH, HEIGHT);
DrawRole ();
if (Timer (animLastTime,30 )){
MoveRole ();
}
KeyDown ();
FlushBatchDraw ();
Sleep (10 );
}
EndBatchDraw ();
closegraph ();
return 0 ;
}
第七阶段:障碍物系统(v7.0)
7.1 障碍物定义 #include <vector>
enum ObstacleType { CACTUS, BIRD };
struct Obstacle {
int x, y;
ObstacleType type;
int width, height;
};
std::vector<Obstacle> obstacles;
int gameSpeed =5 ;
7.2 障碍物绘制 void DrawObstacles () {
for (const auto & obs : obstacles){
setfillcolor (GREEN);
fillrectangle (obs.x, obs.y, obs.x + obs.width, obs.y + obs.height);
}
}
7.3 障碍物生成和移动 void GenerateObstacle () {
static int timer =0 ;
timer++;
if (timer >100 ){
Obstacle obs;
obs.type = CACTUS;
obs.width =30 ;
obs.height =60 ;
obs.x = WIDTH;
obs.y = FLOOR_Y - obs.height;
obstacles.push_back (obs);
timer =0 ;
}
}
void MoveObstacles () {
for (auto it = obstacles.begin (); it != obstacles.end ();){
it->x -= gameSpeed;
if (it->x + it->width <0 ){
it = obstacles.erase (it);
}else {
++it;
}
}
}
一、基础定义:ObstacleType 枚举与 Obstacle 结构体
在分析函数前,需先明确障碍物的'类型标识'和'数据载体',这是所有障碍物操作的基础。
enum ObstacleType { CACTUS, BIRD };
struct Obstacle {
int x, y;
ObstacleType type;
int width, height;
};
std::vector<Obstacle> obstacles;
int gameSpeed =5 ;
二、GenerateObstacle 函数:生成障碍物(创建新障碍物并添加到数组)
功能:按固定频率在屏幕右侧生成仙人掌障碍物,确保游戏中持续出现新挑战。
void GenerateObstacle () {
static int timer =0 ;
timer++;
if (timer >100 ){
Obstacle obs;
obs.type = CACTUS;
obs.width =30 ;
obs.height =60 ;
obs.x = WIDTH;
obs.y = FLOOR_Y - obs.height;
obstacles.push_back (obs);
timer =0 ;
}
}
三、DrawObstacles 函数:绘制障碍物(将数组中的障碍物显示到屏幕)
功能:遍历所有已生成的障碍物,在屏幕上绘制对应的图形(当前用绿色矩形代表仙人掌)。
void DrawObstacles () {
for (const auto & obs : obstacles){
setfillcolor (GREEN);
fillrectangle (obs.x, obs.y, obs.x + obs.width, obs.y + obs.height);
}
}
四、MoveObstacles 函数:移动与清理障碍物(让障碍物向左移动,移除屏幕外的障碍物)
功能:实现障碍物的水平移动(模拟角色向前跑的视觉效果),并清理屏幕左侧已消失的障碍物(避免内存泄漏)。
void MoveObstacles () {
for (auto it = obstacles.begin (); it != obstacles.end ();){
it->x -= gameSpeed;
if (it->x + it->width <0 ){
it = obstacles.erase (it);
}else {
++it;
}
}
}
核心逻辑:因为角色位置固定(视觉上向前跑),所以让障碍物向左移动,模拟相对运动;删除屏幕外的障碍物是为了释放内存,避免数组无限增大。
问题:MoveObstacles 函数中,为何 it 放在 else 里面且需要自增?
7.4 障碍物出现频率改为随机
第一步:添加随机数初始化(在 main 函数开头)
int main () {
srand ((unsigned int )time (NULL ));
initgraph (WIDTH, HEIGHT);
LoadResources ();
BeginBatchDraw ();
while (1 ){
}
}
第二步:修改 GenerateObstacle 函数
void GenerateObstacle () {
static int timer =0 ;
static int randomThreshold =0 ;
timer++;
if (randomThreshold ==0 ){
randomThreshold =rand ()%150 +50 ;
}
if (timer > randomThreshold){
Obstacle obs;
obs.type = CACTUS;
obs.width =30 ;
obs.height =60 ;
obs.x = WIDTH;
obs.y = FLOOR_Y - obs.height;
obstacles.push_back (obs);
timer =0 ;
randomThreshold =0 ;
}
}
#include <graphics.h>
#include <stdio.h>
#include <time.h>
#include <vector>
#define WIDTH 640
#define HEIGHT 400
#define FLOOR_Y 360
enum State { Run, Roll, Jump };
struct FireMan {
int x, y;
State state;
int w, h;
};
#define ROLE_IMGW 70
#define ROLE_IMGH 100
#define BEGIN_X 50
#define BEGIN_Y FLOOR_Y-ROLE_IMGH
struct FireMan fireMan ={ BEGIN_X, BEGIN_Y, Run, ROLE_IMGW, ROLE_IMGH };
IMAGE runIMG[8 ]; IMAGE rollIMG[8 ]; IMAGE jumpIMG;
#define ROLE_DOWN_IMGW 50
#define ROLE_DOWN_IMGH 50
int frameNum =0 ;
#define MAX_FRAME 8
clock_t animLastTime =0 ;
int speed =-10 ;
#define JUMP_MIN_Y 60
std::vector<Obstacle> obstacles;
int gameSpeed =5 ;
void LoadResources () {
char fileURL[50 ]="" ;
for (int i =1 ; i <=8 ; i++){
sprintf_s (fileURL,50 ,"./Res/Run/move8_%d.jpg" , i);
loadimage (&runIMG[i -1 ], fileURL, ROLE_IMGW, ROLE_IMGH);
}
for (int i =1 ; i <=8 ; i++){
sprintf_s (fileURL,50 ,"./Res/Roll/gun8_%d.jpg" , i);
loadimage (rollIMG + i -1 , fileURL, ROLE_DOWN_IMGW, ROLE_DOWN_IMGH);
}
loadimage (&jumpIMG,"./Res/Jump/jump.jpg" , ROLE_IMGW, ROLE_IMGH);
}
bool Timer (clock_t & lastTime,int interval) {
clock_t currentTime =clock ();
if (currentTime - lastTime >= interval){
lastTime = currentTime;
return true ;
}
return false ;
}
void KeyDown () {
if (GetAsyncKeyState (VK_UP)){
fireMan.state = Jump;
}
if (GetAsyncKeyState (VK_DOWN)){
fireMan.state = Roll;
}
}
void MoveRole () {
switch (fireMan.state){
case Run:{
frameNum++;
if (frameNum == MAX_FRAME){ frameNum =0 ;}
break ;
}
case Roll:{
frameNum++;
if (frameNum == MAX_FRAME){ frameNum =0 ;}
fireMan.y = BEGIN_Y +(ROLE_IMGH - ROLE_DOWN_IMGH);
break ;
}
case Jump:{
frameNum =0 ;
fireMan.y += speed;
if (fireMan.y < JUMP_MIN_Y){
speed =-speed;
}
if (fireMan.y >= BEGIN_Y){
fireMan.y = BEGIN_Y;
speed =-speed;
fireMan.state = Run;
}
}
default :break ;
}
}
void DrawRole () {
switch (fireMan.state){
case Run:
putimage (fireMan.x, fireMan.y, runIMG + frameNum);
break ;
case Roll:
putimage (fireMan.x, fireMan.y, rollIMG + frameNum);
break ;
case Jump:
putimage (fireMan.x, fireMan.y,&jumpIMG);
break ;
}
}
enum ObstacleType { CACTUS, BIRD };
struct Obstacle {
int x, y;
ObstacleType type;
int width, height;
};
void GenerateObstacle () {
static int timer =0 ;
static int randomThreshold =0 ;
timer++;
if (randomThreshold ==0 ){
randomThreshold =rand ()%150 +50 ;
}
if (timer > randomThreshold){
Obstacle obs;
obs.type = CACTUS;
obs.width =30 ;
obs.height =60 ;
obs.x = WIDTH;
obs.y = FLOOR_Y - obs.height;
obstacles.push_back (obs);
timer =0 ;
randomThreshold =0 ;
}
}
void DrawObstacles () {
for (const auto & obs : obstacles){
setfillcolor (GREEN);
fillrectangle (obs.x, obs.y, obs.x + obs.width, obs.y + obs.height);
}
}
void MoveObstacles () {
for (auto it = obstacles.begin (); it != obstacles.end ();){
it->x -= gameSpeed;
if (it->x + it->width <0 ){
it = obstacles.erase (it);
}else {
++it;
}
}
}
int main () {
srand ((unsigned int )time (NULL ));
initgraph (WIDTH, HEIGHT);
LoadResources ();
BeginBatchDraw ();
while (1 ){
setbkcolor (WHITE);
cleardevice ();
setfillcolor (LIGHTBLUE);
solidrectangle (0 , FLOOR_Y, WIDTH, HEIGHT);
DrawRole ();
if (Timer (animLastTime,30 )){
MoveRole ();
}
KeyDown ();
GenerateObstacle ();
DrawObstacles ();
MoveObstacles ();
FlushBatchDraw ();
Sleep (10 );
}
EndBatchDraw ();
closegraph ();
return 0 ;
}
第八阶段:碰撞检测(v8.0)
8.1 碰撞检测函数 bool gameOver =false ;
bool CheckCollision () {
for (const auto & obs : obstacles){
if (fireMan.x + fireMan.w > obs.x && fireMan.x < obs.x + obs.width && fireMan.y + fireMan.h > obs.y && fireMan.y < obs.y + obs.height){
return true ;
}
}
return false ;
}
CheckCollision 碰撞函数解读:
main 函数代码:
int main () {
srand ((unsigned int )time (NULL ));
initgraph (WIDTH, HEIGHT);
LoadResources ();
BeginBatchDraw ();
while (1 ){
setbkcolor (WHITE);
cleardevice ();
setfillcolor (LIGHTBLUE);
solidrectangle (0 , FLOOR_Y, WIDTH, HEIGHT);
GenerateObstacle ();
DrawObstacles ();
DrawRole ();
KeyDown ();
if (!gameOver){
if (Timer (animLastTime,30 )){
MoveRole ();
}
MoveObstacles ();
if (CheckCollision ()){
gameOver =true ;
}
}
FlushBatchDraw ();
Sleep (10 );
}
EndBatchDraw ();
closegraph ();
return 0 ;
}
第九阶段:计分系统(v9.0)
9.1 分数显示 int score =0 ;
void MoveObstacles () {
for (auto it = obstacles.begin (); it != obstacles.end ();){
it->x -= gameSpeed;
if (it->x + it->width <0 ){
it = obstacles.erase (it);
score +=10 ;
}else {
++it;
}
}
}
while (1 ){
settextcolor (BLACK);
char scoreText[50 ];
sprintf_s (scoreText,50 ,"Score: %d" , score);
outtextxy (500 ,20 , scoreText);
}
第十阶段:按 R 重新开始(v10.0)
10.1 按 R 重新开始,并显示对应分数 void KeyDown () {
if (GetAsyncKeyState ('R' )&& gameOver){
gameOver =false ;
obstacles.clear ();
score =0 ;
frameNum =0 ;
fireMan ={ BEGIN_X, BEGIN_Y, Run, ROLE_IMGW, ROLE_IMGH };
}
}
int main () {
while (1 ){
if (!gameOver){
if (Timer (animLastTime,30 )){
MoveRole ();
}
MoveObstacles ();
if (CheckCollision ()){
gameOver =true ;
}
}else {
settextcolor (RED);
settextstyle (60 ,0 ,_T("黑体" ));
outtextxy (WIDTH /2 -120 , HEIGHT /2 -50 ,_T("游戏结束!" ));
settextstyle (30 ,0 ,_T("黑体" ));
outtextxy (WIDTH /2 -100 , HEIGHT /2 +20 ,_T("按 R 键重新开始" ));
char scoreStr[50 ];
sprintf_s (scoreStr,50 ,"最终得分:%d" , score);
outtextxy (WIDTH /2 -80 , HEIGHT /2 +60 ,_T(scoreStr));
}
gameSpeed =5 + score /100 ;
FlushBatchDraw ();
Sleep (10 );
}
EndBatchDraw ();
closegraph ();
return 0 ;
}
#include <graphics.h>
#include <stdio.h>
#include <time.h>
#include <vector>
#define WIDTH 640
#define HEIGHT 400
#define FLOOR_Y 360
#define ROLE_IMGW 70
#define ROLE_IMGH 100
#define BEGIN_X 50
#define BEGIN_Y FLOOR_Y-ROLE_IMGH
#define ROLE_DOWN_IMGW 50
#define ROLE_DOWN_IMGH 50
#define MAX_FRAME 8
#define JUMP_MIN_Y 60
IMAGE runIMG[8 ]; IMAGE rollIMG[8 ]; IMAGE jumpIMG;
int gameSpeed =5 ;
bool gameOver =false ;
clock_t animLastTime =0 ;
int speed =-10 ;
int frameNum =0 ;
int score =0 ;
enum State { Run, Roll, Jump };
enum ObstacleType { CACTUS, BIRD };
struct FireMan {
int x, y;
State state;
int w, h;
};
struct Obstacle {
int x, y;
ObstacleType type;
int width, height;
};
struct FireMan fireMan ={ BEGIN_X, BEGIN_Y, Run, ROLE_IMGW, ROLE_IMGH };
std::vector<Obstacle> obstacles;
void LoadResources () {
char fileURL[50 ]="" ;
for (int i =1 ; i <=8 ; i++){
sprintf_s (fileURL,50 ,"./Res/Run/move8_%d.jpg" , i);
loadimage (&runIMG[i -1 ], fileURL, ROLE_IMGW, ROLE_IMGH);
}
for (int i =1 ; i <=8 ; i++){
sprintf_s (fileURL,50 ,"./Res/Roll/gun8_%d.jpg" , i);
loadimage (rollIMG + i -1 , fileURL, ROLE_DOWN_IMGW, ROLE_DOWN_IMGH);
}
loadimage (&jumpIMG,"./Res/Jump/jump.jpg" , ROLE_IMGW, ROLE_IMGH);
}
bool Timer (clock_t & lastTime,int interval) {
clock_t currentTime =clock ();
if (currentTime - lastTime >= interval){
lastTime = currentTime;
return true ;
}
return false ;
}
void KeyDown () {
if (GetAsyncKeyState (VK_UP)){
fireMan.state = Jump;
}
if (GetAsyncKeyState (VK_DOWN)){
fireMan.state = Roll;
}
if (GetAsyncKeyState ('R' )&& gameOver){
gameOver =false ;
obstacles.clear ();
score =0 ;
frameNum =0 ;
fireMan ={ BEGIN_X, BEGIN_Y, Run, ROLE_IMGW, ROLE_IMGH };
}
}
void MoveRole () {
switch (fireMan.state){
case Run:{
frameNum++;
if (frameNum == MAX_FRAME){ frameNum =0 ;}
break ;
}
case Roll:{
frameNum++;
if (frameNum == MAX_FRAME){ frameNum =0 ;}
fireMan.y = BEGIN_Y +(ROLE_IMGH - ROLE_DOWN_IMGH);
break ;
}
case Jump:{
frameNum =0 ;
fireMan.y += speed;
if (fireMan.y < JUMP_MIN_Y){
speed =-speed;
}
if (fireMan.y >= BEGIN_Y){
fireMan.y = BEGIN_Y;
speed =-speed;
fireMan.state = Run;
}
}
default :break ;
}
}
void DrawRole () {
switch (fireMan.state){
case Run:
putimage (fireMan.x, fireMan.y, runIMG + frameNum);
break ;
case Roll:
putimage (fireMan.x, fireMan.y, rollIMG + frameNum);
break ;
case Jump:
putimage (fireMan.x, fireMan.y,&jumpIMG);
break ;
}
}
void GenerateObstacle () {
static int timer =0 ;
static int randomThreshold =0 ;
timer++;
if (randomThreshold ==0 ){
randomThreshold =rand ()%150 +50 ;
}
if (timer > randomThreshold){
Obstacle obs;
obs.type = CACTUS;
obs.width =30 ;
obs.height =60 ;
obs.x = WIDTH;
obs.y = FLOOR_Y - obs.height;
obstacles.push_back (obs);
timer =0 ;
randomThreshold =0 ;
}
}
void DrawObstacles () {
for (const auto & obs : obstacles){
setfillcolor (GREEN);
fillrectangle (obs.x, obs.y, obs.x + obs.width, obs.y + obs.height);
}
}
void MoveObstacles () {
for (auto it = obstacles.begin (); it != obstacles.end ();){
it->x -= gameSpeed;
if (it->x + it->width <0 ){
it = obstacles.erase (it);
score +=10 ;
}else {
++it;
}
}
}
bool CheckCollision () {
for (const auto & obs : obstacles){
if (fireMan.x + fireMan.w > obs.x && fireMan.x < obs.x + obs.width && fireMan.y + fireMan.h > obs.y && fireMan.y < obs.y + obs.height){
return true ;
}
}
return false ;
}
int main () {
srand ((unsigned int )time (NULL ));
initgraph (WIDTH, HEIGHT);
LoadResources ();
BeginBatchDraw ();
while (1 ){
setbkcolor (WHITE);
cleardevice ();
setfillcolor (LIGHTBLUE);
solidrectangle (0 , FLOOR_Y, WIDTH, HEIGHT);
settextcolor (BLACK);
char scoreText[50 ];
sprintf_s (scoreText,50 ,"Score: %d" , score);
outtextxy (500 ,20 , scoreText);
GenerateObstacle ();
DrawObstacles ();
DrawRole ();
KeyDown ();
if (!gameOver){
if (Timer (animLastTime,30 )){
MoveRole ();
}
MoveObstacles ();
if (CheckCollision ()){
gameOver =true ;
}
}else {
settextcolor (RED);
settextstyle (60 ,0 ,_T("黑体" ));
outtextxy (WIDTH /2 -120 , HEIGHT /2 -50 ,_T("游戏结束!" ));
settextstyle (30 ,0 ,_T("黑体" ));
outtextxy (WIDTH /2 -100 , HEIGHT /2 +20 ,_T("按 R 键重新开始" ));
char scoreStr[50 ];
sprintf_s (scoreStr,50 ,"最终得分:%d" , score);
outtextxy (WIDTH /2 -80 , HEIGHT /2 +60 ,_T(scoreStr));
}
gameSpeed =5 + score /100 ;
FlushBatchDraw ();
Sleep (10 );
}
EndBatchDraw ();
closegraph ();
return 0 ;
}
第十一阶段:完善功能(v11.0)
11.1 多种障碍物【添加小鸟】
void GenerateObstacle () {
static int timer =0 ;
static int randomThreshold =0 ;
timer++;
if (randomThreshold ==0 ){
randomThreshold =rand ()%150 +50 ;
}
if (timer > randomThreshold){
Obstacle obs;
if (rand ()%2 ==0 ){
obs.type = CACTUS;
obs.width =30 ;
obs.height =60 ;
obs.x = WIDTH;
obs.y = FLOOR_Y - obs.height;
}else {
obs.type = BIRD;
obs.width =40 ;
obs.height =30 ;
obs.x = WIDTH;
obs.y =250 ;
}
obstacles.push_back (obs);
timer =0 ;
randomThreshold =0 ;
}
}
void DrawObstacles () {
for (const auto & obs : obstacles){
if (obs.type == CACTUS){
setfillcolor (GREEN);
fillrectangle (obs.x, obs.y, obs.x + obs.width, obs.y + obs.height);
}elseif (obs.type == BIRD){
setfillcolor (BROWN);
POINT triangle[3 ];
triangle[0 ].x = obs.x;
triangle[0 ].y = obs.y;
triangle[1 ].x = obs.x - obs.width /2 ;
triangle[1 ].y = obs.y + obs.height;
triangle[2 ].x = obs.x + obs.width /2 ;
triangle[2 ].y = obs.y + obs.height;
fillpolygon (triangle,3 );
}
}
}
bool CheckCollision () {
for (const auto & obs : obstacles){
if (obs.type == CACTUS){
if (fireMan.x + fireMan.w > obs.x && fireMan.x < obs.x + obs.width && fireMan.y + fireMan.h > obs.y && fireMan.y < obs.y + obs.height){
return true ;
}
}elseif (obs.type == BIRD){
if (fireMan.x + fireMan.w > obs.x - obs.width /2 && fireMan.x < obs.x + obs.width /2 && fireMan.y + fireMan.h > obs.y && fireMan.y < obs.y + obs.height){
return true ;
}
}
}
return false ;
}
11.2 难度递增
gameSpeed =5 + score /100 ;
效果 :游戏有仙人掌和小鸟两种障碍物,难度随分数增加
#include <graphics.h>
#include <stdio.h>
#include <time.h>
#include <vector>
#define WIDTH 640
#define HEIGHT 400
#define FLOOR_Y 360
#define ROLE_IMGW 70
#define ROLE_IMGH 100
#define BEGIN_X 50
#define BEGIN_Y FLOOR_Y-ROLE_IMGH
#define ROLE_DOWN_IMGW 50
#define ROLE_DOWN_IMGH 50
#define MAX_FRAME 8
#define JUMP_MIN_Y 60
IMAGE runIMG[8 ]; IMAGE rollIMG[8 ]; IMAGE jumpIMG;
int gameSpeed =5 ;
bool gameOver =false ;
clock_t animLastTime =0 ;
int speed =-10 ;
int frameNum =0 ;
int score =0 ;
enum State { Run, Roll, Jump };
enum ObstacleType { CACTUS, BIRD };
struct FireMan {
int x, y;
State state;
int w, h;
};
struct Obstacle {
int x, y;
ObstacleType type;
int width, height;
};
struct FireMan fireMan ={ BEGIN_X, BEGIN_Y, Run, ROLE_IMGW, ROLE_IMGH };
std::vector<Obstacle> obstacles;
void LoadResources () {
char fileURL[50 ]="" ;
for (int i =1 ; i <=8 ; i++){
sprintf_s (fileURL,50 ,"./Res/Run/move8_%d.jpg" , i);
loadimage (&runIMG[i -1 ], fileURL, ROLE_IMGW, ROLE_IMGH);
}
for (int i =1 ; i <=8 ; i++){
sprintf_s (fileURL,50 ,"./Res/Roll/gun8_%d.jpg" , i);
loadimage (rollIMG + i -1 , fileURL, ROLE_DOWN_IMGW, ROLE_DOWN_IMGH);
}
loadimage (&jumpIMG,"./Res/Jump/jump.jpg" , ROLE_IMGW, ROLE_IMGH);
}
bool Timer (clock_t & lastTime,int interval) {
clock_t currentTime =clock ();
if (currentTime - lastTime >= interval){
lastTime = currentTime;
return true ;
}
return false ;
}
void KeyDown () {
if (GetAsyncKeyState (VK_UP)){
fireMan.state = Jump;
}
if (GetAsyncKeyState (VK_DOWN)){
fireMan.state = Roll;
}
if (GetAsyncKeyState ('R' )&& gameOver){
gameOver =false ;
obstacles.clear ();
score =0 ;
frameNum =0 ;
fireMan ={ BEGIN_X, BEGIN_Y, Run, ROLE_IMGW, ROLE_IMGH };
}
}
void MoveRole () {
switch (fireMan.state){
case Run:{
frameNum++;
if (frameNum == MAX_FRAME){ frameNum =0 ;}
break ;
}
case Roll:{
frameNum++;
if (frameNum == MAX_FRAME){ frameNum =0 ;}
fireMan.y = BEGIN_Y +(ROLE_IMGH - ROLE_DOWN_IMGH);
break ;
}
case Jump:{
frameNum =0 ;
fireMan.y += speed;
if (fireMan.y < JUMP_MIN_Y){
speed =-speed;
}
if (fireMan.y >= BEGIN_Y){
fireMan.y = BEGIN_Y;
speed =-speed;
fireMan.state = Run;
}
}
default :break ;
}
}
void DrawRole () {
switch (fireMan.state){
case Run:
putimage (fireMan.x, fireMan.y, runIMG + frameNum);
break ;
case Roll:
putimage (fireMan.x, fireMan.y, rollIMG + frameNum);
break ;
case Jump:
putimage (fireMan.x, fireMan.y,&jumpIMG);
break ;
}
}
void GenerateObstacle () {
static int timer =0 ;
static int randomThreshold =0 ;
timer++;
if (randomThreshold ==0 ){
randomThreshold =rand ()%150 +50 ;
}
if (timer > randomThreshold){
Obstacle obs;
if (rand ()%2 ==0 ){
obs.type = CACTUS;
obs.width =30 ;
obs.height =60 ;
obs.x = WIDTH;
obs.y = FLOOR_Y - obs.height;
}else {
obs.type = BIRD;
obs.width =40 ;
obs.height =30 ;
obs.x = WIDTH;
obs.y =250 ;
}
obstacles.push_back (obs);
timer =0 ;
randomThreshold =0 ;
}
}
void DrawObstacles () {
for (const auto & obs : obstacles){
if (obs.type == CACTUS){
setfillcolor (GREEN);
fillrectangle (obs.x, obs.y, obs.x + obs.width, obs.y + obs.height);
}elseif (obs.type == BIRD){
setfillcolor (BROWN);
POINT triangle[3 ];
triangle[0 ].x = obs.x;
triangle[0 ].y = obs.y;
triangle[1 ].x = obs.x - obs.width /2 ;
triangle[1 ].y = obs.y + obs.height;
triangle[2 ].x = obs.x + obs.width /2 ;
triangle[2 ].y = obs.y + obs.height;
fillpolygon (triangle,3 );
}
}
}
void MoveObstacles () {
for (auto it = obstacles.begin (); it != obstacles.end ();){
it->x -= gameSpeed;
if (it->x + it->width <0 ){
it = obstacles.erase (it);
score +=10 ;
}else {
++it;
}
}
}
bool CheckCollision () {
for (const auto & obs : obstacles){
if (obs.type == CACTUS){
if (fireMan.x + fireMan.w > obs.x && fireMan.x < obs.x + obs.width && fireMan.y + fireMan.h > obs.y && fireMan.y < obs.y + obs.height){
return true ;
}
}elseif (obs.type == BIRD){
if (fireMan.x + fireMan.w > obs.x - obs.width /2 && fireMan.x < obs.x + obs.width /2 && fireMan.y + fireMan.h > obs.y && fireMan.y < obs.y + obs.height){
return true ;
}
}
}
return false ;
}
int main () {
srand ((unsigned int )time (NULL ));
initgraph (WIDTH, HEIGHT);
LoadResources ();
BeginBatchDraw ();
while (1 ){
setbkcolor (WHITE);
cleardevice ();
setfillcolor (LIGHTBLUE);
solidrectangle (0 , FLOOR_Y, WIDTH, HEIGHT);
settextcolor (BLACK);
char scoreText[50 ];
sprintf_s (scoreText,50 ,"Score: %d" , score);
outtextxy (500 ,20 , scoreText);
GenerateObstacle ();
DrawObstacles ();
DrawRole ();
KeyDown ();
if (!gameOver){
if (Timer (animLastTime,30 )){
MoveRole ();
}
MoveObstacles ();
if (CheckCollision ()){
gameOver =true ;
}
}else {
settextcolor (RED);
settextstyle (60 ,0 ,_T("黑体" ));
outtextxy (WIDTH /2 -120 , HEIGHT /2 -50 ,_T("游戏结束!" ));
settextstyle (30 ,0 ,_T("黑体" ));
outtextxy (WIDTH /2 -100 , HEIGHT /2 +20 ,_T("按 R 键重新开始" ));
char scoreStr[50 ];
sprintf_s (scoreStr,50 ,"最终得分:%d" , score);
outtextxy (WIDTH /2 -80 , HEIGHT /2 +60 ,_T(scoreStr));
}
gameSpeed =5 + score /100 ;
FlushBatchDraw ();
Sleep (10 );
}
EndBatchDraw ();
closegraph ();
return 0 ;
}
第十二阶段:完整代码【加注释】
#include <graphics.h>
#include <stdio.h>
#include <time.h>
#include <vector>
#define WIDTH 640
#define HEIGHT 400
#define FLOOR_Y 360
#define ROLE_IMGW 70
#define ROLE_IMGH 100
#define BEGIN_X 50
#define BEGIN_Y FLOOR_Y-ROLE_IMGH
#define ROLE_DOWN_IMGW 50
#define ROLE_DOWN_IMGH 50
#define MAX_FRAME 8
#define JUMP_MIN_Y 60
IMAGE runIMG[8 ];
IMAGE rollIMG[8 ];
IMAGE jumpIMG;
int gameSpeed =5 ;
bool gameOver =false ;
clock_t animLastTime =0 ;
int speed =-10 ;
int frameNum =0 ;
int score =0 ;
enum State { Run, Roll, Jump };
enum ObstacleType { CACTUS, BIRD };
struct FireMan {
int x, y;
State state;
int w, h;
};
struct Obstacle {
int x, y;
ObstacleType type;
int width, height;
};
struct FireMan fireMan ={ BEGIN_X, BEGIN_Y, Run, ROLE_IMGW, ROLE_IMGH };
std::vector<Obstacle> obstacles;
void LoadResources () {
char fileURL[50 ]="" ;
for (int i =1 ; i <=8 ; i++){
sprintf_s (fileURL,50 ,"./Res/Run/move8_%d.jpg" , i);
loadimage (&runIMG[i -1 ], fileURL, ROLE_IMGW, ROLE_IMGH);
}
for (int i =1 ; i <=8 ; i++){
sprintf_s (fileURL,50 ,"./Res/Roll/gun8_%d.jpg" , i);
loadimage (rollIMG + i -1 , fileURL, ROLE_DOWN_IMGW, ROLE_DOWN_IMGH);
}
loadimage (&jumpIMG,"./Res/Jump/jump.jpg" , ROLE_IMGW, ROLE_IMGH);
}
bool Timer (clock_t & lastTime,int interval) {
clock_t currentTime =clock ();
if (currentTime - lastTime >= interval){
lastTime = currentTime;
return true ;
}
return false ;
}
void KeyDown () {
if (GetAsyncKeyState (VK_UP)){
fireMan.state = Jump;
}
if (GetAsyncKeyState (VK_DOWN)){
fireMan.state = Roll;
}
if (GetAsyncKeyState ('R' )&& gameOver){
gameOver =false ;
obstacles.clear ();
score =0 ;
frameNum =0 ;
fireMan ={ BEGIN_X, BEGIN_Y, Run, ROLE_IMGW, ROLE_IMGH };
}
}
void MoveRole () {
switch (fireMan.state){
case Run:{
frameNum++;
if (frameNum == MAX_FRAME){
frameNum =0 ;
}
break ;
}
case Roll:{
frameNum++;
if (frameNum == MAX_FRAME){
frameNum =0 ;
}
fireMan.y = BEGIN_Y +(ROLE_IMGH - ROLE_DOWN_IMGH);
break ;
}
case Jump:{
frameNum =0 ;
fireMan.y += speed;
if (fireMan.y < JUMP_MIN_Y){
speed =-speed;
}
if (fireMan.y >= BEGIN_Y){
fireMan.y = BEGIN_Y;
speed =-speed;
fireMan.state = Run;
}
break ;
}
default :break ;
}
}
void DrawRole () {
switch (fireMan.state){
case Run:
putimage (fireMan.x, fireMan.y, runIMG + frameNum);
break ;
case Roll:
putimage (fireMan.x, fireMan.y, rollIMG + frameNum);
break ;
case Jump:
putimage (fireMan.x, fireMan.y,&jumpIMG);
break ;
}
}
void GenerateObstacle () {
static int timer =0 ;
static int randomThreshold =0 ;
timer++;
if (randomThreshold ==0 ){
randomThreshold =rand ()%150 +50 ;
}
if (timer > randomThreshold){
Obstacle obs;
if (rand ()%2 ==0 ){
obs.type = CACTUS;
obs.width =30 ;
obs.height =60 ;
obs.x = WIDTH;
obs.y = FLOOR_Y - obs.height;
}else {
obs.type = BIRD;
obs.width =40 ;
obs.height =30 ;
obs.x = WIDTH;
obs.y =250 ;
}
obstacles.push_back (obs);
timer =0 ;
randomThreshold =0 ;
}
}
void DrawObstacles () {
for (const auto & obs : obstacles){
if (obs.type == CACTUS){
setfillcolor (GREEN);
fillrectangle (obs.x, obs.y, obs.x + obs.width, obs.y + obs.height);
}elseif (obs.type == BIRD){
setfillcolor (BROWN);
POINT triangle[3 ];
triangle[0 ].x = obs.x;
triangle[0 ].y = obs.y;
triangle[1 ].x = obs.x - obs.width /2 ;
triangle[1 ].y = obs.y + obs.height;
triangle[2 ].x = obs.x + obs.width /2 ;
triangle[2 ].y = obs.y + obs.height;
fillpolygon (triangle,3 );
}
}
}
void MoveObstacles () {
for (auto it = obstacles.begin (); it != obstacles.end ();){
it->x -= gameSpeed;
if (it->x + it->width <0 ){
it = obstacles.erase (it);
score +=10 ;
}else {
++it;
}
}
}
bool CheckCollision () {
for (const auto & obs : obstacles){
if (obs.type == CACTUS){
if (fireMan.x + fireMan.w > obs.x &&
fireMan.x < obs.x + obs.width &&
fireMan.y + fireMan.h > obs.y &&
fireMan.y < obs.y + obs.height){
return true ;
}
}
elseif (obs.type == BIRD){
if (fireMan.x + fireMan.w > obs.x - obs.width /2 &&
fireMan.x < obs.x + obs.width /2 &&
fireMan.y + fireMan.h > obs.y &&
fireMan.y < obs.y + obs.height){
return true ;
}
}
}
return false ;
}
int main () {
srand ((unsigned int )time (NULL ));
initgraph (WIDTH, HEIGHT);
LoadResources ();
BeginBatchDraw ();
while (1 ){
setbkcolor (WHITE);
cleardevice ();
setfillcolor (LIGHTBLUE);
solidrectangle (0 , FLOOR_Y, WIDTH, HEIGHT);
settextcolor (BLACK);
char scoreText[50 ];
sprintf_s (scoreText,50 ,"Score: %d" , score);
outtextxy (500 ,20 , scoreText);
GenerateObstacle ();
DrawObstacles ();
DrawRole ();
KeyDown ();
if (!gameOver){
if (Timer (animLastTime,30 )){
MoveRole ();
}
MoveObstacles ();
if (CheckCollision ()){
gameOver =true ;
}
}else {
settextcolor (RED);
settextstyle (60 ,0 ,_T("黑体" ));
outtextxy (WIDTH /2 -120 , HEIGHT /2 -50 ,_T("游戏结束!" ));
settextstyle (30 ,0 ,_T("黑体" ));
outtextxy (WIDTH /2 -100 , HEIGHT /2 +20 ,_T("按 R 键重新开始" ));
char scoreStr[50 ];
sprintf_s (scoreStr,50 ,"最终得分:%d" , score);
outtextxy (WIDTH /2 -80 , HEIGHT /2 +60 ,_T(scoreStr));
}
gameSpeed =5 + score /100 ;
FlushBatchDraw ();
Sleep (10 );
}
EndBatchDraw ();
closegraph ();
return 0 ;
}
开发流程总结 版本 主要功能 效果展示 v1.0 基础窗口和地面 白色背景 + 蓝色地面 v2.0 简单角色 红色矩形代表火柴人 v3.0 加载资源 真实火柴人图片 v4.0 奔跑动画 火柴人奔跑动画 v5.0 跳跃功能 按上键跳跃 v6.0 下蹲功能 按空格键下蹲 v7.0 障碍物系统 绿色障碍物移动 v8.0 碰撞检测 碰到障碍物游戏停止 v9.0 计分系统 显示分数 v10.0 游戏重开 重新开始 v11.0 完善功能 多种障碍物 + 难度递增
游戏效果演示 微信扫一扫,关注极客日志 微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
相关免费在线工具 加密/解密文本 使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online
Base64 字符串编码/解码 将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
Base64 文件转换器 将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online
Markdown 转 HTML 将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML 转 Markdown 互为补充。 在线工具,Markdown 转 HTML在线工具,online
HTML 转 Markdown 将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML 转 Markdown在线工具,online
JSON 压缩 通过删除不必要的空白来缩小和压缩JSON。 在线工具,JSON 压缩在线工具,online