天天酷跑-C语言搭建童年游戏(easyx)

游戏索引

游戏名称:天天酷跑



游戏介绍:

本游戏是在B站博主<程序员Rock>的视频指导下完成

想学的更详细的小伙伴可以移步到<程序员Rock>视频

【程序员Rock】C语言项目:手写天天酷跑丨大一课程设计首选项目,手把手带你用C语言游戏开发
 


游戏效果展示#

天天酷跑


游戏模块:

<1>安装easyx图形库

<2>创建项目
<3>导入素材
<4>创建游戏开始界面
<5>循环滚动背景实现
<6>创建人物实现奔跑

<7>实现人物的跳跃和下蹲

<8>创建障碍物

<9>实现人物的血条

<10>人物和障碍物的碰撞

<11>实现游戏的积分

<12>游戏输赢的判定


目录

游戏索引

 写代码前的准备工作 

搭建项目环境easyx:

导入游戏素材 : 

修改项目属性:

导入我们的辅助项目: 

tools.h

tools.cpp

导入操作#

实现游戏开始界面 

 游戏的定义与声明

游戏的初始化 

 实现游戏背景展示

图片背景的显示

图片移动的实现

实现用户的按键操作

实现人物的展示 

​编辑

奔跑人物的显示

人物的跳跃和下蹲的实现

渲染障碍物 

显示障碍物

更新障碍物的位置

随机生成小乌龟

人物与障碍物的碰撞检测

人物血量的显示 

游戏分数的显示 

游戏输赢的判定 

游戏赢的判定

游戏输的判定

游戏主函数 

全部代码的实现 


素材已上传至百度网盘:
百度网盘 请输入提取码

提取码:ABCD

 写代码前的准备工作 

搭建项目环境easyx:

要想在我们的窗口实现图片交互

应该给编译器安装 easyx 图形库

这边我用图片展示详细的安装操作

(1)我们先在网页找到官网

(2)然后点击下载

(3)将 easyx 安装到目标编译器

(4)出现安装成功就代表可以使用了

接下来我们就可以写放心写代码啦!!!

导入游戏素材 : 

在当前项目的目录下创建文件夹,并把解压好的文件 res 拷贝进去

修改项目属性:

 <1>点击项目找到项目属性

<2>将字符集改成多字符集

这里图片操作的时候需要

<3>将编译器对SDL的检查关掉

导入我们的辅助项目: 

tools.h
#pragma once
#include <graphics.h>

//返回距离上一次调用间隔的时间(单位:ms),第一次调用时返回0
int getDelay(); 

void putimagePNG(int  picture_x, int picture_y, IMAGE* picture);

// 适用于 y <0 以及y>0的任何情况
void putimagePNG2(int x, int y, IMAGE* picture);
void putimagePNG2(int x, int y, int winWidth, IMAGE* picture);

// 判断两个矩形是否相交
bool rectIntersect(int a1X, int a1Y, int a2X, int a2Y,
    int b1X, int b1Y, int b2X, int b2Y);

void  preLoadSound(const char* name);
void  playSound(const char* name);

void drawBloodBar(int x, int y, int width, int height, int lineWidth, int boardColor, int emptyColor, int fillColor, float percent);
tools.cpp
#include <stdio.h>
#include <Windows.h>
#include "tools.h"

#include <mmsystem.h>//播放音乐
#pragma comment(lib, "winmm.lib")


int getDelay() {
    static unsigned long long lastTime = 0;
    unsigned long long currentTime = GetTickCount();
    if (lastTime == 0) {
        lastTime = currentTime;
        return 0;
    }
    else {
        int ret = currentTime - lastTime;
        lastTime = currentTime;
        return ret;
    }
}

// 载入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);
}

//设A[x01,y01,x02,y02]  B[x11,y11,x12,y12].
bool rectIntersect(int x01, int y01, int x02, int y02,
    int x11, int y11, int x12, int y12)
{
    int zx = abs(x01 + x02 - x11 - x12);
    int x = abs(x01 - x02) + abs(x11 - x12);
    int zy = abs(y01 + y02 - y11 - y12);
    int y = abs(y01 - y02) + abs(y11 - y12);
    return  (zx <= x && zy <= y);
}

void  preLoadSound(const char* name) {
    char cmd[512];
    sprintf_s(cmd, sizeof(cmd), "open %s alias %s-1", name, name);
    mciSendString(cmd, 0, 0, 0);
    sprintf_s(cmd, sizeof(cmd), "open %s alias %s-2", name, name);
    mciSendString(cmd, 0, 0, 0);
}

void  playSound(const char* name) {
    static int index = 1;
    char cmd[512];

    if (index == 1) {
        sprintf_s(cmd, sizeof(cmd), "play %s-1", name);
        mciSendString(cmd, 0, 0, 0);
        sprintf_s(cmd, sizeof(cmd), "close %s-2", name);
        mciSendString(cmd, 0, 0, 0);
        sprintf_s(cmd, sizeof(cmd), "open %s alias %s-2", name, name);
        mciSendString(cmd, 0, 0, 0);
        index++;
    }
    else if (index == 2) {
        sprintf_s(cmd, sizeof(cmd), "play %s-2", name);
        mciSendString(cmd, 0, 0, 0);
        sprintf_s(cmd, sizeof(cmd), "close %s-1", name);
        mciSendString(cmd, 0, 0, 0);
        sprintf_s(cmd, sizeof(cmd), "open %s alias %s-1", name, name);
        mciSendString(cmd, 0, 0, 0);
        index = 1;
    }
}

void drawBloodBar(int x, int y, int width, int height, int lineWidth, int boardColor, int emptyColor, int fillColor, float percent) {
    LINESTYLE lineStyle;
    getlinestyle(&lineStyle);
    int lineColor = getlinecolor();
    int fileColor = getfillcolor();

    if (percent < 0) {
        percent = 0;
    }

    setlinecolor(BLUE);
    setlinestyle(PS_SOLID | PS_ENDCAP_ROUND, lineWidth);
    setfillcolor(emptyColor);
    fillrectangle(x, y, x + width, y + height);
    setlinestyle(PS_SOLID | PS_ENDCAP_FLAT, 0);
    setfillcolor(fillColor);
    setlinecolor(fillColor);
    if (percent > 0) {
        fillrectangle(x + 0.5 * lineWidth, y + lineWidth * 0.5, x + width * percent, y + height - 0.5 * lineWidth);
    }
    
    setlinecolor(lineColor);
    setfillcolor(fillColor);
    setlinestyle(&lineStyle);
}
导入操作#

<1>点击项目添加现有项

<2>选定我们要添加的辅助项目选择添加就好啦

实现游戏开始界面 

按钮放置的位置我们可以通过 画图软件 或者 微信截图 来获取

void startUI() {
	// 添加背景音乐
	mciSendString("play res/bg.mp3 repeat", 0, 0, 0);
	IMAGE imgMenu, imgMenu1;
	int	flag = 0;
	loadimage(&imgMenu, "res/Menu1.png");
	loadimage(&imgMenu1, "res/menu.png");
	while (1) {
		BeginBatchDraw();
		putimage(0, 0, &imgMenu);
		putimagePNG(474, 150, &imgMenu1);
		ExMessage	msg;
		if (peekmessage(&msg)) {
			//判断是否有左键按下
			if (msg.message == WM_LBUTTONDOWN &&msg.x > 474 && msg.x < 720 && msg.y>150 && msg.y < 170) {
            //按键点击的范围
				flag = 1;
			}
		}
		    //判断鼠标按下后有没有松开
		else if (msg.message == WM_LBUTTONUP && flag == 1) {
			mciSendString("close res/bg.mp3", 0, 0, 0);
			EndBatchDraw();
			return;
		}
		EndBatchDraw();
	}
}

 游戏的定义与声明

//这里采用宏定义为的是更好的维护
#define WIN_WIDTH 1012     //窗口的宽度
#define	 WIN_HEIGHT 396    //窗口的高度
#define OBSTACLE_COUNT 10  //障碍物数量
#define WIN_SCORE 20       //获胜的分数

IMAGE imaBgs[3];            //图片类型的指针
int bgX[3];		            //背景图片
int bgspeed[3] = { 1,2,4 }; //背景移动的速度进行控制

IMAGE bgHeros[12];          //人物帧数-图片张数
int HeroX;                  //人物坐标
int HeroY;
int HeroIndex;              //玩家奔跑的图片帧序号

//判断人物的跳跃和下蹲
bool heroJump;              
bool herodown;

int jumpHeightMax;
int jumpHeightOff;//跳跃偏移量

int update; //表示是否需要马上刷新画面

int heroBlood;
int score;

//枚举障碍物,计算障碍物的种类
typedef enum {
	TORTOISE,//乌龟	
	LION,    //狮子
	HOOK1,   //挡板
	HOOK2,
	HOOK3,
	HOOK4,
	OBSTACLE_TYPE_COUNT     //直接表示障碍物的个数		
}obstacle_type; 

obstacle_type type;

vector<vector<IMAGE>> obstacleImags; //动态二维数组存放各个障碍物的图片


typedef struct obstacle
{
	obstacle_type type;	       //障碍物类型
	int imaIndex;              //当前显示图片的序号
	int x, y;	               //障碍物的坐标
	int speed;                 //障碍物速度
	int power;                 //杀伤力
	bool exist;                //存在检测
	bool hited;	               //碰撞检测
	bool passed;               //通过检测
} obstacle_t;

obstacle_t obstacles[OBSTACLE_COUNT];

int lastObsIndex;


IMAGE imgHeroDown[2];
IMAGE imgSZ[10];

游戏的初始化 

void init()
{
	//创建游戏界面
	initgraph(WIN_WIDTH, WIN_HEIGHT);

	//循环来读取用数组来接收
	char name[64];
	for (int i = 0; i < 3; i++) {
		sprintf(name, "res/bg%03d.png", i + 1);
		loadimage(&imaBgs[i], name);//加载背景资源 
		bgX[i] = 0;
	}

	//加载人物奔跑的图片帧数
	for (int i = 0; i < 12; i++) {
		sprintf(name, "res/hero%d.png", i + 1);
		loadimage(&bgHeros[i], name);
	}
	//设置人物奔跑的位置
	HeroX = WIN_WIDTH * 0.5 - bgHeros[0].getwidth() * 0.5;
	HeroY = 345 - bgHeros[0].getheight();
	HeroIndex = 0;

	heroJump = false;

	jumpHeightMax = 345 - bgHeros[0].getheight() - 120;//跳跃的最大高度
	jumpHeightOff = -4; 

	update = true;
	//加载小乌龟
	IMAGE imgTort;
	loadimage(&imgTort, "res/t1.png");    //加载乌龟图片,这里只用了一张
	vector<IMAGE>imgTortArray;            //定义乌龟障碍图片空数组
	imgTortArray.push_back(imgTort);      //将imgTort尾插到空数组,若多个图片可利用循环添加见LION
	obstacleImags.push_back(imgTortArray);//将乌龟图片数组尾插到上面的二维数组中
	//加载小狮子
	IMAGE imaLion;
	vector<IMAGE> imaLionArray;
	for (int i = 0; i < 6; i++) {
		sprintf(name, "res/p%d.png", i + 1);
		loadimage(&imaLion, name);
		imaLionArray.push_back(imaLion);
	}
	obstacleImags.push_back(imaLionArray);


	//初始化障碍物池
	for (int i = 0; i < OBSTACLE_COUNT; i++)
	{
		obstacles[i].exist = false;
	}

	//加载下蹲素材
	loadimage(&imgHeroDown[0], "res/d1.png");
	loadimage(&imgHeroDown[1], "res/d2.png");
	herodown = false;

	//柱子挡板
	IMAGE imgH;

	for (int i = 0; i < 4; i++) {
		vector<IMAGE> imgHookArray;
		sprintf(name, "res/sz/h%d.png", i + 1);
		loadimage(&imgH, name, 70, 260, true);
		imgHookArray.push_back(imgH);
		obstacleImags.push_back(imgHookArray);
	}
	//血量
	heroBlood = 100;
	//预加载音效
	preLoadSound("res/hit.mp3");

	lastObsIndex = -1;
	//分数初始化
	score = 0;

	//加载数字图片
	for (int i = 0; i < 10; i++) {
		sprintf(name, "res/sz/%d.png", i);
		loadimage(&imgSZ[i], name);
	}
}

 实现游戏背景展示

图片背景的显示

void updateBg()
{
	putimagePNG2(bgX[0], 0, &imaBgs[0]);
	putimagePNG2(bgX[1], 119, &imaBgs[1]);
	putimagePNG2(bgX[2], 330, &imaBgs[2]);
}

图片移动的实现

void fly()
{
	for (int i = 0; i < 3; i++) 
	{
		bgX[i] -= bgspeed[i];     //调整背景移速
		if (bgX[i] < -WIN_WIDTH) 
		{
			bgX[i] = 0;
		}
	}
}

实现用户的按键操作

void keyEvent()
{
	char ch;
	if (_kbhit())      //如果有按键按下kbhit返回true
	{    
		ch = _getch(); //getch()不需要按空格就可以直接读取
		if (ch == 'w'||ch == 'W') {
			jump();    
		}
		else if (ch == 's' || ch == 'S') {
			down();
		}
	}
}

实现人物的展示 

奔跑人物的显示

void updateHero()
{
	if (!herodown) {
		putimagePNG2(HeroX, HeroY, &bgHeros[HeroIndex]);//显示奔跑人物
	}
	else {
		int y = 345 - imgHeroDown[HeroIndex].getheight();
		putimagePNG2(HeroX, y, &imgHeroDown[HeroIndex]);//显示下蹲人物
	}
}

人物的跳跃和下蹲的实现

void jump()//跳跃分装函数
{
	heroJump = true;  //启动跳跃功能
	update = true;    //若启动跳跃开关则立马刷新启动功能
}

void down()//下蹲分装函数
{
	herodown = true;
	update = true;
	HeroIndex = 0;
}

void fly()
{
	//实现跳跃
	if (heroJump) {
		if (HeroY < jumpHeightMax) {
			jumpHeightOff = 4;              
		}
		HeroY += jumpHeightOff;

		if (HeroY > 345 - bgHeros[0].getheight()) {
			heroJump = false;  
			jumpHeightOff = -4; 
		}
	}

	//实现下蹲
	else if (herodown) {
		static int count = 0;
		count++;
		int delays[2] = { 8,30 };
		if (count >= delays[HeroIndex]) {
			count = 0;
			HeroIndex++;
			if (HeroIndex == 2) {
				HeroIndex = 0;
				herodown = false;
			}
		}

	}
	else {
		HeroIndex = (HeroIndex + 1) % 12;//跳跃时腿不动
	}

渲染障碍物 

显示障碍物

void updateEnemy()
{

	//渲染障碍物
	for (int i = 0; i < OBSTACLE_COUNT; i++)
	{
		if (obstacles[i].exist) 
		{
			putimagePNG2(obstacles[i].x, obstacles[i].y, WIN_WIDTH, &obstacleImags[obstacles[i].type][obstacles[i].imaIndex]);
		}
	}
}

更新障碍物的位置

// 更新障碍物的坐标
for (int i = 0; i < OBSTACLE_COUNT; i++) {
	if (obstacles[i].exist) {
		obstacles[i].x -= obstacles[i].speed + bgspeed[2];
		if (obstacles[i].x < -obstacleImags[obstacles[i].type][0].getwidth() * 2) 
        {
			obstacles[i].exist = false;
		}

		int len = obstacleImags[obstacles[i].type].size(); 
		obstacles[i].imaIndex = (obstacles[i].imaIndex + 1) % len;
	}
}

随机生成小乌龟

	//随机生成小乌龟
	static int frameCount = 0;     //静态出函数不会销毁
	static int torToiseFre = 50;
	frameCount++;
	if (frameCount > torToiseFre) 
	{
    //帧数够计数器,就生成小乌龟
		frameCount = 0; 
		torToiseFre = 50 + rand() % 60;
		creatObstacle();
	}
         

人物与障碍物的碰撞检测

void checkHit()
{
	for (int i = 0; i < OBSTACLE_COUNT; i++) {
		if (obstacles[i].exist && obstacles[i].hited == false) {
			int a1x, a1y, a2x, a2y;
			int off = 30; 
			if (!herodown) {		//非下蹲状态
				a1x = HeroX + off;
				a1y = HeroY + off;
				a2x = HeroX + bgHeros[HeroIndex].getwidth() - off;
				a2y = HeroY + bgHeros[HeroIndex].getheight();
			}
			else
			{
				a1x = HeroX + off;
				a1y = 345 - imgHeroDown[HeroIndex].getheight();
				a2x = HeroX + imgHeroDown[HeroIndex].getwidth() - off;
				a2y = 345;
			}

			//障碍物的区域
			IMAGE img = obstacleImags[obstacles[i].type][obstacles[i].imaIndex];
			int b1x = obstacles[i].x + off;
			int b1y = obstacles[i].y + off;
			int b2x = obstacles[i].x + img.getwidth() - off;
			int b2y = obstacles[i].y + img.getheight() - off;
			if (rectIntersect(a1x, a1y, a2x, a2y, b1x, b1y, b2x, b2y)) {
				heroBlood -= obstacles[i].power;
				playSound("res/hit.mp3");
				obstacles[i].hited = true;
			}
		}
	}
}

人物血量的显示 

void updateBloodBar()
{
	drawBloodBar(10, 10, 200, 10, 2, BLUE, DARKGRAY, RED, heroBlood / 100.0);
}

游戏分数的显示 

void checkScore() 
{
    //每躲避一个障碍物就加一分
	for (int i = 0; i < OBSTACLE_COUNT; i++) {
		if (obstacles[i].exist &&obstacles[i].passed == false &&obstacles[i].hited == false &&obstacles[i].x + obstacleImags[obstacles[i].type][0].getwidth() < HeroX)
		{
			score++;
			obstacles[i].passed = true;

		}
	}
}


void updateScore()
{
	char str[8];
	sprintf(str, "%d", score);

	int x = 20;
	int y = 25;

	for (int i = 0; str[i]; i++) {
		int sz = str[i] - '0';
		putimagePNG(x, y, &imgSZ[sz]);
		x += imgSZ[sz].getwidth() + 5;
	}
}

游戏输赢的判定 

游戏赢的判定

void checkWin()
{
	if (score >= WIN_SCORE)
	{
		FlushBatchDraw();
		mciSendString("play res/win.mp3", 0, 0, 0);
		Sleep(2000);
		loadimage(0, "res/Menu1.png");
		FlushBatchDraw(); 
		mciSendString("stop Music.mp3", 0, 0, 0);
		system("pause");
		mciSendString("play Music.mp3 repeat", 0, 0, 0);
		heroBlood = 100;
		score = 0;
	}
}

游戏输的判定

void checkOver()
{
	if (heroBlood <= 0)
	{
		loadimage(0, "res/Maclk.png");
		FlushBatchDraw();
		mciSendString("stop res/Maclk.mp3", 0, 0, 0);
		system("pause");

		//暂停之后,若选择直接开始下一局
		heroBlood = 100;
		score = 0;
		mciSendString("play res/Maclk.mp3 repeat", 0, 0, 0);
	}
}

游戏主函数 

双缓冲绘图

BeginBatchDraw() - 开始双缓冲

EndBatchDraw()    - 结束双缓冲

双缓冲区:打印一个的同时显示另一个,不断重复这个过程,避免了屏幕闪耀问题

int main(void)
{
	init(); 
	startUI();
	mciSendString("play Music.mp3 repeat", 0, 0, 0);
	int timer = 0;

	while (1) {
		keyEvent();         //按键接收
		timer += getDelay();
		if (timer > 30) {
			timer = 0;
			update = true;	//30次刷新一次,帧休眠,不然速度太快
		}

		if (update) {
			update = false; 
			BeginBatchDraw();
			updateBg();       //渲染游戏背景
			updateHero();     //渲染人物图片
			updateEnemy();    //渲染障碍物
			updateBloodBar();
			updateScore();    //渲染分数图片
			checkWin();       //检查游戏是否胜利
			EndBatchDraw();

			checkOver();      //检查游戏是否结束
			checkScore();     //计算得分

			fly();            //实现人物跳跃,下蹲,障碍物的移动效果
		}
	}

	system("pause");
	return 0;
}

全部代码的实现 

#include<stdio.h>
#include<graphics.h>
#include"tools.h"
#include<conio.h>
#include<vector>
using namespace std;

#define WIN_WIDTH 1012     
#define	 WIN_HEIGHT 396    
#define OBSTACLE_COUNT 10  
#define WIN_SCORE 20       

IMAGE imaBgs[3];            
int bgX[3];		            
int bgspeed[3] = { 1,2,4 }; 

IMAGE bgHeros[12];          
int HeroX;                  
int HeroY;
int HeroIndex;            


bool heroJump;              
bool herodown;

int jumpHeightMax;
int jumpHeightOff;

int update; 

int heroBlood;
int score;

typedef enum {
	TORTOISE,
	LION,   
	HOOK1,  
	HOOK2,
	HOOK3,
	HOOK4,
	OBSTACLE_TYPE_COUNT    	
}obstacle_type; 

obstacle_type type;

vector<vector<IMAGE>> obstacleImags; 


typedef struct obstacle
{
	obstacle_type type;	   
	int imaIndex;              
	int x, y;	              
	int speed;                 
	int power;                 
	bool exist;               
	bool hited;	               
	bool passed;            
} obstacle_t;

obstacle_t obstacles[OBSTACLE_COUNT];

int lastObsIndex;


IMAGE imgHeroDown[2];
IMAGE imgSZ[10];

void init()
{
	initgraph(WIN_WIDTH, WIN_HEIGHT);
	char name[64];
	for (int i = 0; i < 3; i++) {
		sprintf(name, "res/bg%03d.png", i + 1);
		loadimage(&imaBgs[i], name);
		bgX[i] = 0;
	}

	
	for (int i = 0; i < 12; i++) {
		sprintf(name, "res/hero%d.png", i + 1);
		loadimage(&bgHeros[i], name);
	}
	HeroX = WIN_WIDTH * 0.5 - bgHeros[0].getwidth() * 0.5;
	HeroY = 345 - bgHeros[0].getheight();
	HeroIndex = 0;

	heroJump = false;

	jumpHeightMax = 345 - bgHeros[0].getheight() - 120;
	jumpHeightOff = -4; 

	update = true;
	IMAGE imgTort;
	loadimage(&imgTort, "res/t1.png");    
	vector<IMAGE>imgTortArray;            
	imgTortArray.push_back(imgTort);      
	obstacleImags.push_back(imgTortArray);
	IMAGE imaLion;
	vector<IMAGE> imaLionArray;
	for (int i = 0; i < 6; i++) {
		sprintf(name, "res/p%d.png", i + 1);
		loadimage(&imaLion, name);
		imaLionArray.push_back(imaLion);
	}
	obstacleImags.push_back(imaLionArray);


	for (int i = 0; i < OBSTACLE_COUNT; i++)
	{
		obstacles[i].exist = false;
	}

	
	loadimage(&imgHeroDown[0], "res/d1.png");
	loadimage(&imgHeroDown[1], "res/d2.png");
	herodown = false;


	IMAGE imgH;

	for (int i = 0; i < 4; i++) {
		vector<IMAGE> imgHookArray;
		sprintf(name, "res/sz/h%d.png", i + 1);
		loadimage(&imgH, name, 70, 260, true);
		imgHookArray.push_back(imgH);
		obstacleImags.push_back(imgHookArray);
	}
	
	heroBlood = 100;
	
	preLoadSound("res/hit.mp3");

	lastObsIndex = -1;
	
	score = 0;

	for (int i = 0; i < 10; i++) {
		sprintf(name, "res/sz/%d.png", i);
		loadimage(&imgSZ[i], name);
	}
}

void creatObstacle()
{
	int i;
	for (i = 0; i < OBSTACLE_COUNT; i++)  
	{
		if (obstacles[i].exist == false)
		{
			break;
		}
	}
	if (i >= OBSTACLE_COUNT) {
		return;
	}

	obstacles[i].exist = true;
	obstacles[i].hited = false;
	obstacles[i].imaIndex = 0;
	obstacles[i].type = (obstacle_type)(rand() % 3);

	if (lastObsIndex >= 0 &&
		obstacles[lastObsIndex].type >= HOOK1 &&
		obstacles[lastObsIndex].type <= HOOK4 &&
		obstacles[i].type == LION &&
		obstacles[lastObsIndex].x > (WIN_WIDTH - 500)) {
		obstacles[i].type = TORTOISE;
	}
	lastObsIndex = i;

	if (obstacles[i].type == HOOK1)
	{
		obstacles[i].type = (obstacle_type)((int)(obstacles[i].type) + rand() % 4);
	}
	obstacles[i].x = WIN_WIDTH; 
	obstacles[i].y = 350 - obstacleImags[obstacles[i].type][0].getheight();

	if (obstacles[i].type == TORTOISE) {
		obstacles[i].speed = 0;
		obstacles[i].power = 5;
	}

	else if (obstacles[i].type == LION) {
		obstacles[i].speed = 4;
		obstacles[i].power = 20;
	}

	else if (obstacles[i].type >= HOOK1 && obstacles[i].type <= HOOK4) {
		obstacles[i].speed = 0;
		obstacles[i].power = 20;
		obstacles[i].y = 0; 
	}

	obstacles[i].passed == false;
}

void checkHit()
{
	for (int i = 0; i < OBSTACLE_COUNT; i++) {
		if (obstacles[i].exist && obstacles[i].hited == false) {
			int a1x, a1y, a2x, a2y;
			int off = 30; 
			if (!herodown) {		
				a1x = HeroX + off;
				a1y = HeroY + off;
				a2x = HeroX + bgHeros[HeroIndex].getwidth() - off;
				a2y = HeroY + bgHeros[HeroIndex].getheight();
			}
			else
			{
				a1x = HeroX + off;
				a1y = 345 - imgHeroDown[HeroIndex].getheight();
				a2x = HeroX + imgHeroDown[HeroIndex].getwidth() - off;
				a2y = 345;
			}

			IMAGE img = obstacleImags[obstacles[i].type][obstacles[i].imaIndex];
			int b1x = obstacles[i].x + off;
			int b1y = obstacles[i].y + off;
			int b2x = obstacles[i].x + img.getwidth() - off;
			int b2y = obstacles[i].y + img.getheight() - off;
			if (rectIntersect(a1x, a1y, a2x, a2y, b1x, b1y, b2x, b2y)) {
				heroBlood -= obstacles[i].power;
				playSound("res/hit.mp3");
				obstacles[i].hited = true;
			}
		}
	}
}


void fly()
{
	for (int i = 0; i < 3; i++) 
	{
		bgX[i] -= bgspeed[i];     
		if (bgX[i] < -WIN_WIDTH) 
		{
			bgX[i] = 0;
		}
	}

	if (heroJump) {
		if (HeroY < jumpHeightMax) {
			jumpHeightOff = 4;              
		}
		HeroY += jumpHeightOff;

		if (HeroY > 345 - bgHeros[0].getheight()) {
			heroJump = false;  
			jumpHeightOff = -4; 
		}
	}

	else if (herodown) {
		static int count = 0;
		count++;
		int delays[2] = { 8,30 };
		if (count >= delays[HeroIndex]) {
			count = 0;
			HeroIndex++;
			if (HeroIndex == 2) {
				HeroIndex = 0;
				herodown = false;
			}
		}

	}
	else {
		HeroIndex = (HeroIndex + 1) % 12;
	}

	
	static int frameCount = 0;     
	static int torToiseFre = 50;
	frameCount++;
	if (frameCount > torToiseFre) 
	{
		frameCount = 0; 
		torToiseFre = 50 + rand() % 60;
		creatObstacle();
	}
                    
	
	for (int i = 0; i < OBSTACLE_COUNT; i++) {
		if (obstacles[i].exist) {
			obstacles[i].x -= obstacles[i].speed + bgspeed[2];
			if (obstacles[i].x < -obstacleImags[obstacles[i].type][0].getwidth() * 2) {
				obstacles[i].exist = false;
			}

			int len = obstacleImags[obstacles[i].type].size(); 
			obstacles[i].imaIndex = (obstacles[i].imaIndex + 1) % len;
		}
	}

	
	checkHit();
}


    
void updateBg()
{
	putimagePNG2(bgX[0], 0, &imaBgs[0]);
	putimagePNG2(bgX[1], 119, &imaBgs[1]);
	putimagePNG2(bgX[2], 330, &imaBgs[2]);
}

void jump()
{
	heroJump = true; 
	update = true;    
}

void down()
{
	herodown = true;
	update = true;
	HeroIndex = 0;
}

void keyEvent()
{
	char ch;
	if (_kbhit())      
	{    
		ch = _getch(); 
		if (ch == 'w'||ch == 'W') {
			jump();    
		}
		else if (ch == 's' || ch == 'S') {
			down();
		}
	}
}

void updateEnemy()
{


	for (int i = 0; i < OBSTACLE_COUNT; i++)
	{
		if (obstacles[i].exist) 
		{
			putimagePNG2(obstacles[i].x, obstacles[i].y, WIN_WIDTH, &obstacleImags[obstacles[i].type][obstacles[i].imaIndex]);
		}
	}
}

void updateHero()
{
	if (!herodown) {
		putimagePNG2(HeroX, HeroY, &bgHeros[HeroIndex]);
	}
	else {
		int y = 345 - imgHeroDown[HeroIndex].getheight();
		putimagePNG2(HeroX, y, &imgHeroDown[HeroIndex]);
	}
}

void updateBloodBar()
{
	drawBloodBar(10, 10, 200, 10, 2, BLUE, DARKGRAY, RED, heroBlood / 100.0);
}

void checkOver()
{
	if (heroBlood <= 0)
	{
		loadimage(0, "res/Maclk.png");
		FlushBatchDraw();
		mciSendString("stop res/Maclk.mp3", 0, 0, 0);
		system("pause");
		heroBlood = 100;
		score = 0;
		mciSendString("play res/Maclk.mp3 repeat", 0, 0, 0);
	}
}


void checkScore() 
{

	for (int i = 0; i < OBSTACLE_COUNT; i++) {
		if (obstacles[i].exist &&obstacles[i].passed == false &&obstacles[i].hited == false &&obstacles[i].x + obstacleImags[obstacles[i].type][0].getwidth() < HeroX)
		{
			score++;
			obstacles[i].passed = true;

		}
	}
}


void updateScore()
{
	char str[8];
	sprintf(str, "%d", score);

	int x = 20;
	int y = 25;

	for (int i = 0; str[i]; i++) {
		int sz = str[i] - '0';
		putimagePNG(x, y, &imgSZ[sz]);
		x += imgSZ[sz].getwidth() + 5;
	}
}

void checkWin()
{
	if (score >= WIN_SCORE)
	{
		FlushBatchDraw();
		mciSendString("play res/win.mp3", 0, 0, 0);
		Sleep(2000);
		loadimage(0, "res/Menu1.png");
		FlushBatchDraw(); 
		mciSendString("stop Music.mp3", 0, 0, 0);
		system("pause");
		mciSendString("play Music.mp3 repeat", 0, 0, 0);
		heroBlood = 100;
		score = 0;
	}
}

void startUI() {
	mciSendString("play res/bg.mp3 repeat", 0, 0, 0);
	IMAGE imgMenu, imgMenu1;
	int	flag = 0;
	loadimage(&imgMenu, "res/Menu1.png");
	loadimage(&imgMenu1, "res/menu.png");
	while (1) {
		BeginBatchDraw();
		putimage(0, 0, &imgMenu);
		putimagePNG(474, 150, &imgMenu1);
		ExMessage	msg;
		if (peekmessage(&msg)) {
			
			if (msg.message == WM_LBUTTONDOWN &&msg.x > 474 && msg.x < 720 && msg.y>150 && msg.y < 170) {
				flag = 1;
			}
		}
		   
		else if (msg.message == WM_LBUTTONUP && flag == 1) {
			mciSendString("close res/bg.mp3", 0, 0, 0);
			EndBatchDraw();
			return;
		}
		EndBatchDraw();
	}
}

int main(void)
{
	init(); 
	startUI();
	mciSendString("play Music.mp3 repeat", 0, 0, 0);
	int timer = 0;

	while (1) {
		keyEvent();
		timer += getDelay();
		if (timer > 30) {
			timer = 0;
			update = true;	
		}

		if (update) {
			update = false; 
			BeginBatchDraw();
			updateBg();    
			updateHero();
			updateEnemy();
			updateBloodBar();
			updateScore();
			checkWin();
			EndBatchDraw();

			checkOver();
			checkScore();

			fly();
		}
	}

	system("pause");

	return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/342032.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Web安全漏洞专项靶场—SQL注入—docker环境—sqli-labs靶场—详细通关指南

SQL注入—sqli-labs靶场 零、前言一、环境搭建①、VirtualBox②、Kali Linux③、Docker 二、闯关开始1、Less-1——union2、Less-2—数字型—union3、Less-3—)—union4、Less-4—")—union5、Less-5——布尔盲注6、Less-6—"—布尔盲注7、Less-7—))7.1—布尔盲注7.…

Git学习笔记(第8章):IEAD实现GitHub操作(VSCode)

目录 8.1 VSCode登录GitHub账号 8.2 创建远程库 8.3 本地库推送到远程库(push) 8.4 远程库拉取到本地库(pull) 8.5 远程库克隆到本地库(clone) 8.1 VSCode登录GitHub账号 Step1&#xff1a;安装“GitHub Pull Requests and Issues”插件 Step2&#xff1a;登录GitHub账号 …

加密项目调研的评估框架

当谈到加密货币时&#xff0c;您在决定是否投资之前需要考虑几个关键因素。无论您是刚刚开始接触新的加密项目还是正在寻求扩展您的投资组合&#xff0c;拥有一个方便的加密项目评估框架都会很有帮助。 本文将解释一个分步框架&#xff0c;以帮助您评估各种加密项目。 您如何…

Kubernetes的ConfigMap

文章目录 环境概念配置pod使用ConfigMap创建ConfigMapkubectl create configmap目录文件自定义key值literal值 产生器&#xff08;generator&#xff09;文件自定义key值literal值 定义容器环境变量单个ConfigMap多个ConfigMap 配置ConfigMap里所有键值对为环境变量在pod命令里…

透明拼接屏在汽车领域的应用

随着科技的进步&#xff0c;透明拼接屏作为一种新型的显示技术&#xff0c;在汽车领域的应用越来越广泛。尼伽小编将围绕透明拼接屏在汽车本身、4S店、展会、工厂等方面的应用进行深入探讨&#xff0c;并展望未来的设计方向。 一、透明拼接屏在汽车本身的应用 车窗显示&#x…

JeecgBoot 3.6.1使用Online表单开发生成代码,如何定义自定义查询条件

一、使用Online表单生成代码&#xff0c;运行结果如下 二、如果我们想要加入一些筛选条件&#xff0c;例如用姓名查询 1.可在生成的前端代码中加入如下代码&#xff0c;文件为****data.ts //查询数据 export const searchFormSchema: FormSchema[] [ ];2.对如上代码进行编辑…

3D应用开发工具HOOPS引领数字化工厂浪潮:制造业转型的关键角色!

随着科技的迅猛发展&#xff0c;制造业正经历着数字化转型的浪潮。在这一变革的前沿&#xff0c;Tech Soft 3D 的 HOOPS技术正扮演着关键的角色。 本文将深入研究HOOPS技术如何在数字化工作流程中发挥作用&#xff0c;以及它是如何引领制造业朝着更高效、智能的未来迈进的。 …

【C语言进阶】预处理详解

引言 对预处理的相关知识进行详细的介绍 ✨ 猪巴戒&#xff1a;个人主页✨ 所属专栏&#xff1a;《C语言进阶》 &#x1f388;跟着猪巴戒&#xff0c;一起学习C语言&#x1f388; 目录 引言 预定义符号 #define定义常量 #define定义宏 带有副作用的宏参数 宏替换的规则 …

空气净化器or宠物空气净化器?五款猫用空气净化器优质推荐!

作为一个养猫家庭的主人&#xff0c;每天都要面对清理猫砂盘的挑战&#xff0c;这种令人难以形容的气味实在让人难以忍受。尤其是家里有小孩和老人&#xff0c;他们可能会出现过敏性鼻炎等问题&#xff0c;而抵抗力较差的人更容易受到影响。此外&#xff0c;换毛季节到来时&…

Qt 拖拽事件示例

一、引子 拖拽这个动作,在桌面应用程序中是非常实用和具有很友好的交互体验的。我们常见的譬如有,将文件拖拽到某个窗口打开,或者拖拽文件到指定位置上传;在绘图软件中,选中某个模板、并拖拽到画布上,画布上变回绘制该模板的图像… 诸如此类,数不胜数。 那么,在Qt中我…

【MySQL】最左匹配原则

最左匹配原则 0x1 简单说下什么是最左匹配原则 顾名思义&#xff1a;最左优先&#xff0c;以最左边的为起点任何连续的索引都能匹配上。同时遇到范围查询(>、<、between、like&#xff09;就会停止匹配。 例如&#xff1a;b 2 如果建立(a&#xff0c;b&#xff09;顺序…

远程桌面--虚拟机与主机的文件传输

注意&#xff1a; 确保VMware开头的服务全部在运行进入虚拟机打开文件管理器点击计算机右键选择属性在选择远程管理选择允许 1.winR 输入mstsc 2.输入虚拟机的ip地址 2.输入虚拟机的密码 上面的Administrator是虚拟机的用户名&#xff0c;有时会需要我们手动输入 3.验证…

MySQL连表操作之一对多

MySQL连表操作之一对多 目录 引入外键 Navicat创建外键使用外键SQL命令创建外键代码删除外键代码增加外键通过外键进行数据操作 正文 回到顶部 引入 当我们在数据库中创建表的时候&#xff0c;有可能某些列中值内容量很大&#xff0c;而且重复。 例子&#xff1a;创建一个…

基于SpringBoot Vue二手闲置物品交易系统

大家好✌&#xff01;我是Dwzun。很高兴你能来阅读我&#xff0c;我会陆续更新Java后端、前端、数据库、项目案例等相关知识点总结&#xff0c;还为大家分享优质的实战项目&#xff0c;本人在Java项目开发领域有多年的经验&#xff0c;陆续会更新更多优质的Java实战项目&#x…

C语言之反汇编查看函数栈帧的创建与销毁

文章目录 一、 什么是函数栈帧&#xff1f;二、 理解函数栈帧能解决什么问题呢&#xff1f;三、 函数栈帧的创建和销毁解析3.1、什么是栈&#xff1f;3.2、认识相关寄存器和汇编指令3.2.1 相关寄存器3.2.2 相关汇编命令 3.3、 解析函数栈帧的创建和销毁3.3.1 预备知识3.3.2 代码…

Python 猎户星空Orion-14B,截止到目前为止,各评测指标均名列前茅,综合指标最强;Orion-14B表现强大,LLMs大模型

1.简介 Orion-14B-Base是一个具有140亿参数的多语种大模型&#xff0c;该模型在一个包含2.5万亿token的多样化数据集上进行了训练&#xff0c;涵盖了中文、英语、日语、韩语等多种语言。在多语言环境下的一系列任务中展现出卓越的性能。在主流的公开基准评测中&#xff0c;Orio…

Qt —— 自定义飞机仪表控件(附源码)

示例效果 部署环境 本人亲测版本Vs2017+Qt5.12.4,其他版本应该也可使用。 源码1 qfi_ADI::qfi_ADI( QWidget *parent ) :QGraphicsView ( parent ),m_scene ( nullptr )

英语连读技巧12

1. this thing – 这件事 连读听起来就像是&#xff1a;【the sing】 连读的音标为&#xff1a; 例句&#xff1a;i cannot get this thing off my mind. 发音指导&#xff1a;注意 “this” 和 “thing” 两个词在连读时&#xff0c;“s” 和 “th” 的音接近融合&#xf…

浏览器提示“此网站的安全证书有问题”

有时候在浏览一些网站的时候&#xff0c;点进去的时候不是直接显示内容&#xff0c;而是弹出来一个警告的界面&#xff0c;告诉你此网站的安全证书有问题&#xff0c;浏览器是建议你不要再继续访问了&#xff0c;当然你也可以选择继续访问。那么&#xff0c;你还敢继续访问一个…

2.1.2 关系模式

1. 什么是关系模式 2. 定义关系模式 3. 关系模式与关系 1&#xff0e;什么是关系模式 关系模式是型&#xff0c;关系是值 。 关系模式是对关系的描述&#xff1a; 描述关系元组集合的结构 &#xff0c; 属性构成 l&#xff0c;属性来自的域 l&#…