a.玩家结构体
b.枚举玩家三种状态:奔跑、跳跃、滑行
c.障碍物结构体
d.障碍物结点
e.枚举出障碍物类型
#include
#include
#include
#include
#include
#include"tools.h"
#pragma comment(lib,"Winmm.lib")
using namespace std;
#define WIN_WIDTH 1012
#define WIN_HEIGHT 396
#define OBSTACLE_COUNT 10
IMAGE img_bk[3];
IMAGE people_run[12];//人物跑步图片
IMAGE people_leap[12];//人物跑步图片
IMAGE people_slide[2];//人物滑行
int bk_x[3];//背景坐标
int bk_y;
int bk_speed[3] = { 1,4,8 };//背景运动速度
int obst_count;//增加障碍物时计数
bool update;//是否立即刷新
bool switch_kb;//是否需要打开按键开关
int scored;//得分
//枚举人物状态,奔跑,跳跃,滑行
enum PEOPLE_STATE
{
run,
leap,
slide
};
//人物结构体
struct People
{
int x;
int y;
int frame_run;//跑步时帧
int motion_state;//人物运动状态
int leap_height;//跳跃高度
int frame_leap;//人物跳跃帧
int jump_offset;//人物跳跃偏移量
int frame_slide;//人物滑行帧
int slide_distance;//人物滑行距离
int exist;
}player;
//障碍物结点
struct Node
{
struct Obstacle* obstacle_t;
struct Node* next;
};
//障碍物类型枚举
enum OBSTACLE_TYPE
{
tortoise,
lion,
fire,
hock1,
hock2,
hock3,
hock4,
obstacle_type_count
};
//障碍物结构体
struct Obstacle
{
OBSTACLE_TYPE type;//障碍物类型
int x;//坐标
int y;
int frame_index;//图片帧
bool exist;//判断是否存在
int speed;//运动速度
};
vector>obstacleImgs;//用C++的动态数组
void LoadObstImg();
struct Obstacle* InitOb();
void PrintObImg(struct Obstacle* p_ob);
void MoveOb(struct Obstacle* p_ob);
struct Node* CreateList();
struct Node* CreateNode(Obstacle* p_ob);
void InsertNode(struct Node* p_head, struct Obstacle* p_ob);
void PrintList(struct Node* p_head);
void UpdateOb();
bool CheckCollision(struct Obstacle* p_ob);
struct Node* list = NULL;
a.加载资源和数据初始化
b.背景绘制以及运动
c.玩家三种状态绘制与运动
d.键盘响应
e.判断玩家与障碍物碰撞
//加载图片
void LoadImg()
{
//加载背景
char bk_path[20] = {0};//背景图片路径
for (int i = 0; i < 3; i++)
{
sprintf(bk_path, "resource/bg%03d.png", i + 1);
loadimage(&img_bk[i], bk_path);
}
//加载背景音乐
mciSendString("open resource/bg.mp3 alias bgm", NULL, 0, NULL);
mciSendString("play bgm repeat", NULL, 0, NULL);
//加载人物
char people_path1[20] = { 0 };//人物奔跑图片路径
for (int i = 0; i < 12; i++)
{
sprintf(people_path1, "resource/hero%d.png", i + 1);
loadimage(&people_run[i], people_path1);
}
char people_path2[20] = { 0 };//人物跳跃图片路径
for (int i = 0; i < 12; i++)
{
sprintf(people_path1, "resource/g%02d.png", i + 1);
loadimage(&people_leap[i], people_path1);
}
char people_path3[20] = { 0 };//人物滑行图片路径
for (int i = 0; i < 2; i++)
{
sprintf(people_path3, "resource/d%d.png", i + 1);
loadimage(&people_slide[i], people_path3);
}
LoadObstImg();
}
//初始化数据
void InitData()
{
//加载窗口
initgraph(WIN_WIDTH, WIN_HEIGHT,1);
//背景X坐标初始为0
bk_x[3] = { 0 };
update = false;
switch_kb = true;
player.x = WIN_WIDTH*0.5 - people_run[0].getwidth()*0.5;
player.y = 360 - people_run[0].getheight();
player.frame_run = 0;
player.motion_state = run;
player.frame_leap = 0;
player.leap_height = 100;
player.jump_offset = -10;
player.frame_slide = 0;
player.slide_distance = 0;
player.exist = true;
scored = 0;
list = CreateList();//将头结点地址赋予list
for (int i = 0; i < OBSTACLE_COUNT; i++)
{
InsertNode(list, InitOb());
}
}
//打印图片
void PrintdImg()
{
//打印背景图片
putimagePNG2(bk_x[0], 0, &img_bk[0]);
putimagePNG2(bk_x[1], 119, &img_bk[1]);
putimagePNG2(bk_x[2], 330, &img_bk[2]);
//打印人物奔跑图片
if (run == player.motion_state)
{
putimagePNG2(player.x, player.y, &people_run[player.frame_run]);
//人物奔跑帧改变
player.frame_run = (player.frame_run + 1) % 12;
}
//打印人物跳跃图片
if (leap == player.motion_state)
{
putimagePNG2(player.x, player.y, &people_leap[player.frame_leap]);
}
//打印人物滑行图片
if (slide == player.motion_state)//如果是滑行就打印
{
player.y = 360 - people_slide[player.frame_slide].getheight();//打印当前图片帧的高度
putimagePNG2(player.x, player.y, &people_slide[player.frame_slide]);
}
//绘制跑步分数
settextcolor(BLACK);
settextstyle(20, 25, "黑体");
setbkmode(TRANSPARENT);
char count[40];
sprintf(count, "%d", scored);
outtextxy(10, 20, count);
outtextxy(textwidth(count)+10, 20, "分");
}
//图片更新运动
void Update()
{
for (int i = 0; i < 3; i++)
{
bk_x[i] -= bk_speed[i];
//当背景图片运动一个窗口距离时,重新回到原点
if (bk_x[i] <= -WIN_WIDTH)
{
bk_x[i] = 0;
}
}
scored++;//得分
//人物跳跃运动
if (leap == player.motion_state)
{
if (player.y < player.leap_height)//如果人物高度小于要求高度时,偏移量为正
{
player.jump_offset = 10;
}
player.y += player.jump_offset;//如果人物高度大于要求高度时,偏移量为负
if (player.frame_leap != 12)
{
player.frame_leap++;//跳跃图片帧改变
}
if (player.y >= 360 - people_run[0].getheight())
{
player.motion_state = run;
player.jump_offset = -10;
player.frame_leap = 0;
player.frame_run = 0;
player.frame_slide = 0;
player.y = 360 - people_run[0].getheight();
}
}
//人物滑行动作
if (slide == player.motion_state )
{
if (0 == player.frame_slide && player.slide_distance >= 4)
{
player.frame_slide += 1;
}
player.slide_distance++;//滑行距离
if (20 == player.slide_distance)
{
player.frame_slide = 0;
player.motion_state = run;
player.frame_run = 0;
player.slide_distance = 0;
player.y = 360 - people_run[0].getheight();
}
}
//检测是否碰撞,碰撞了人物和障碍物一起后移。
struct Node* p_check = list->next;
int one = 0;//用于标记当向前一步之后,while循环不再向前移动
while (p_check!=NULL)
{
if (p_check->obstacle_t->exist == false)
{
p_check = p_check->next;
continue;
}
if (CheckCollision(p_check->obstacle_t))
{
player.x -= p_check->obstacle_t->speed;
if (player.x <= -people_run->getwidth())
{
player.exist = false;
}
return;
}
else
{
if (one<=0 && player.x <= WIN_WIDTH * 0.5 - people_run[0].getwidth() * 0.5)
{
player.x += 2;//当人物不在当初位置时向前移动
one++;
}
}
p_check = p_check->next;
}
}
//按键响应
void KbControl()
{
char keyboard = {0};
if (_kbhit())
{
update = true;
keyboard = getch();
switch (keyboard)
{
case ' ':
if (slide == player.motion_state)//滑行时可以跳跃,但是Y坐标不在奔跑时高度,需要重新初始化
{
player.y = 360 - people_run[0].getheight();
}
player.motion_state = leap;
break;
case 80:
if (player.motion_state != leap)//跳跃时不允许滑行
{
player.motion_state = slide;
}
break;
default:
break;
}
}
}
a.创建障碍物链表
b.加载资源
c.障碍物运动和绘制d
d.碰撞检测
//加载障碍物图片
void LoadObstImg()
{
char obstacle_path[20];
IMAGE img_tortoise;
vectortortoiseArr;
for (int i = 0; i < 7; i++)
{
sprintf(obstacle_path, "resource/t%d.png", i + 1);
loadimage(&img_tortoise, obstacle_path);
tortoiseArr.push_back(img_tortoise);
}
obstacleImgs.push_back(tortoiseArr);
IMAGE img_lion;
vectorlionArr;
for (int i = 0; i < 6; i++)
{
sprintf(obstacle_path, "resource/p%d.png", i + 1);
loadimage(&img_lion, obstacle_path);
lionArr.push_back(img_lion);
}
obstacleImgs.push_back(lionArr);
IMAGE img_fire;
vectorfireArr;
for (int i = 0; i < 9; i++)
{
sprintf(obstacle_path, "resource/fire%d.png", i + 1);
loadimage(&img_fire, obstacle_path, 46, 68, true);
fireArr.push_back(img_fire);
}
obstacleImgs.push_back(fireArr);
IMAGE img_hock;
for (int i = 0; i < 4; i++)
{
vectorhockArr;
sprintf(obstacle_path, "resource/h%d.png", i + 1);
loadimage(&img_hock, obstacle_path,84,260,true);
hockArr.push_back(img_hock);
obstacleImgs.push_back(hockArr);
}
}
//初始化障碍物
struct Obstacle* InitOb()
{
//srand((unsigned int)time(NULL));
struct Obstacle* p_ob = (struct Obstacle*)malloc(sizeof(struct Obstacle));
assert(p_ob);
p_ob->exist = false;
return p_ob;
}
//打印障碍物
void PrintObImg(struct Obstacle* p_ob)
{
putimagePNG2(p_ob->x, p_ob->y, &obstacleImgs[p_ob->type][p_ob->frame_index]);
}
//障碍物运动
void MoveOb(struct Obstacle* p_ob)
{
p_ob->x -= p_ob->speed;
}
//创建头节点
struct Node* CreateList()
{
struct Node* p_head = (struct Node*)malloc(sizeof(struct Node));
assert(p_head);
p_head->obstacle_t = NULL;
p_head->next = NULL;
return p_head;
}
//创建结点
struct Node* CreateNode(Obstacle* p_ob)
{
struct Node* p_node = (struct Node*)malloc(sizeof(struct Node));
assert(p_node);
p_node->obstacle_t = p_ob;
p_node->next = NULL;
return p_node;
}
//连接结点
void InsertNode(struct Node* p_head, struct Obstacle* p_ob)
{
struct Node* p_newnode = CreateNode(p_ob);
p_newnode->next = p_head->next;
p_head->next = p_newnode;
}
//打印结点
void PrintList(struct Node* p_head)
{
struct Node* p_move = p_head->next;
while (p_move != NULL)
{
if (false == p_move->obstacle_t->exist)
{
p_move = p_move->next;
continue;
}
PrintObImg(p_move->obstacle_t);
MoveOb(p_move->obstacle_t);
//减缓障碍物帧率
static int currFrame = 0;
static int frame = 5;
currFrame++;
if (currFrame >= frame)
{
currFrame = 0;
int len = obstacleImgs[p_move->obstacle_t->type].size();//获取一种障碍物的图片数量
p_move->obstacle_t->frame_index = (p_move->obstacle_t->frame_index + 1) % len;
}
if (-obstacleImgs[p_move->obstacle_t->type][p_move->obstacle_t->frame_index].getwidth() >= p_move->obstacle_t->x)
{
p_move->obstacle_t->x = WIN_WIDTH;
p_move->obstacle_t->exist = false;
}
p_move = p_move->next;
}
}
//更新障碍物状态类型位置
void UpdateOb()
{
//srand((unsigned int)(time(NULL)));
struct Node* p_curr = list->next;
while (p_curr != NULL)
{
if (true == p_curr->obstacle_t->exist)
{
p_curr = p_curr->next;
continue;
}
p_curr->obstacle_t->exist = (bool)(rand() % 2);//随机产生障碍物的存在与否
if (true == p_curr->obstacle_t->exist)
{
p_curr->obstacle_t->type = (OBSTACLE_TYPE)(rand() % 4);//随机产生障碍物类型
if (hock1 == p_curr->obstacle_t->type)
{
p_curr->obstacle_t->type = (OBSTACLE_TYPE)(p_curr->obstacle_t->type + (rand() % 4));
}
p_curr->obstacle_t->frame_index = 0;
p_curr->obstacle_t->x = WIN_WIDTH;
p_curr->obstacle_t->y = 360 - obstacleImgs[p_curr->obstacle_t->type][p_curr->obstacle_t->frame_index].getheight();
if (lion == p_curr->obstacle_t->type)
{
p_curr->obstacle_t->speed = 10;
}
else if (tortoise == p_curr->obstacle_t->type)
{
p_curr->obstacle_t->speed = 8;
p_curr->obstacle_t->frame_index = rand() % 7;
}
else if (fire == p_curr->obstacle_t->type)
{
p_curr->obstacle_t->speed = 8;
p_curr->obstacle_t->frame_index = rand() % 7;
}
else if (p_curr->obstacle_t->type >= hock1 && p_curr->obstacle_t->type <= hock4)
{
p_curr->obstacle_t->speed = 8;
p_curr->obstacle_t->y = 0;
}
return;
}
p_curr = p_curr->next;
}
}
//判断碰撞
bool CheckCollision(struct Obstacle* p_ob)
{
int x01 = player.x + 25;
int y01 = player.y;
int x02 = 0;
int y02 = 0;
if (run == player.motion_state)
{
x02 = player.x + people_run->getwidth() - 20;
y02 = player.y + people_run->getheight();
}
else if (leap == player.motion_state)
{
x02 = player.x + people_leap->getwidth() - 20;
y02 = player.y + people_leap->getheight();
}
else if (slide == player.motion_state)
{
x02 = player.x + people_slide->getwidth() - 20;
y02 = player.y + people_slide->getheight();
}
int x11 = p_ob->x;
int x12 = p_ob->x + obstacleImgs[p_ob->type][p_ob->frame_index].getwidth();
int y11 = p_ob->y;
int y12 = p_ob->y + obstacleImgs[p_ob->type][p_ob->frame_index].getheight();
int zx = abs(abs(x01) + x02 - x11 - x12);
int x = abs(x02 - x01) + abs(x12 - x11);
int zy = abs(y01 + y02 - y11 - y12);
int y = abs(y02 - y01) + abs(y12 - y11);
return (x >= zx && y >= zy);
}
//游戏运行
void RunGame()
{
srand(unsigned int(time(NULL)));
while (player.exist == true)
{
if (timer(40, 0))
{
update = true;
}
KbControl();
if (update)
{
static int currTime = 0;
static int Time = 40 + rand() % 60;
currTime++;
if (currTime >= Time)
{
currTime = 0;
UpdateOb();
}
update = false;
BeginBatchDraw();
PrintdImg();
PrintList(list);
FlushBatchDraw();
Update();
}
}
}
int main(void)
{
LoadImg();
InitData();
RunGame();
getchar();
closegraph();
return 0;
}
#include
#include
#include
#pragma comment(lib, "winmm.lib")
// 载入PNG图并去透明部分
void putimagePNG(int picture_x, int picture_y, IMAGE* picture) //x为载入图片的X坐标,y为Y坐标
{
DWORD* dst = GetImageBuffer(); // GetImageBuffer()函数,用于获取绘图设备的显存指针,EASYX自带
DWORD* draw = GetImageBuffer();
DWORD* src = GetImageBuffer(picture); //获取picture的显存指针
int picture_width = picture->getwidth(); //获取picture的宽度,EASYX自带
int picture_height = picture->getheight(); //获取picture的高度,EASYX自带
int graphWidth = getwidth(); //获取绘图区的宽度,EASYX自带
int graphHeight = getheight(); //获取绘图区的高度,EASYX自带
int dstX = 0; //在显存里像素的角标
// 实现透明贴图 公式: Cp=αp*FP+(1-αp)*BP , 贝叶斯定理来进行点颜色的概率计算
for (int iy = 0; iy < picture_height; iy++)
{
for (int ix = 0; ix < picture_width; ix++)
{
int srcX = ix + iy * picture_width; //在显存里像素的角标
int sa = ((src[srcX] & 0xff000000) >> 24); //0xAArrggbb;AA是透明度
int sr = ((src[srcX] & 0xff0000) >> 16); //获取RGB里的R
int sg = ((src[srcX] & 0xff00) >> 8); //G
int sb = src[srcX] & 0xff; //B
if (ix >= 0 && ix <= graphWidth && iy >= 0 && iy <= graphHeight && dstX <= graphWidth * graphHeight)
{
dstX = (ix + picture_x) + (iy + picture_y) * graphWidth; //在显存里像素的角标
int dr = ((dst[dstX] & 0xff0000) >> 16);
int dg = ((dst[dstX] & 0xff00) >> 8);
int db = dst[dstX] & 0xff;
draw[dstX] = ((sr * sa / 255 + dr * (255 - sa) / 255) << 16) //公式: Cp=αp*FP+(1-αp)*BP ; αp=sa/255 , FP=sr , BP=dr
| ((sg * sa / 255 + dg * (255 - sa) / 255) << 8) //αp=sa/255 , FP=sg , BP=dg
| (sb * sa / 255 + db * (255 - sa) / 255); //αp=sa/255 , FP=sb , BP=db
}
}
}
}
// 适用于 y <0 以及x<0的任何情况
void putimagePNG2(int x, int y, IMAGE* picture) {
IMAGE imgTmp;
if (y < 0) {
SetWorkingImage(picture);
getimage(&imgTmp, 0, -y,
picture->getwidth(), picture->getheight() + y);
SetWorkingImage();
y = 0;
picture = &imgTmp;
}
if (x < 0) {
SetWorkingImage(picture);
getimage(&imgTmp, -x, 0, picture->getwidth() + x, picture->getheight());
SetWorkingImage();
x = 0;
picture = &imgTmp;
}
putimagePNG(x, y, picture);
}
// 适用于 y <0 以及y>0的任何情况
void putimagePNG2(int x, int y, int winWidth, IMAGE* picture) {
IMAGE imgTmp;
if (y < 0) {
SetWorkingImage(picture);
getimage(&imgTmp, 0, -y,
picture->getwidth(), picture->getheight() + y);
SetWorkingImage();
y = 0;
picture = &imgTmp;
}
if (x < 0) {
SetWorkingImage(picture);
getimage(&imgTmp, -x, 0, picture->getwidth() + x, picture->getheight());
SetWorkingImage();
x = 0;
picture = &imgTmp;
}
else if (x >= winWidth) {
return;
}
else if (x > winWidth-picture->getwidth()) {
SetWorkingImage(picture);
getimage(&imgTmp, 0, 0, winWidth - x, picture->getheight());
SetWorkingImage();
picture = &imgTmp;
}
putimagePNG(x, y, picture);
}
本游戏开发基于rock老师视频内容(视频学习网站上都能找到)以及自己学到的知识编写,可以简单学习链表和图形工具的运用,根据自己的喜好加以修改,仅供学习参考,不足之处还望指出,大家一起学习进步。
资源:链接:https://pan.baidu.com/s/1sLC0f1D77iQ-EUQrTbnu-Q
提取码:0lp8