上篇再博客里面有,接下來我們實現我們剩下要實現的功能
文章目錄?
碰撞檢測
血條的實現
積分計數器
?
前言
我們現在要繼續優化我們的程序才可以使這個程序更加的全面
碰撞的檢測
定義全局變量
實現全局變量
void checkHit() {for (int i = 0; i < OBSTACLE_CUONT; i++) {if (obstacles[i].exist && obstacles[i].hited == false) {int ax1, ay1, ax2, ay2;//角色的碰撞寬度高度設置if (!heroDown) {ax1 = heroX;ay1 = heroY;ax2 = heroX + imgHero[i].getwidth();ay2 = heroY - imgHero[i].getheight();}else {ax1 = heroX;ay1 = 397 - imgHeroDown[i].getheight();ax2 = heroX + imgHeroDown[i].getwidth();ay2 = 397;}//障礙物的碰撞寬度高度設置int bx1 = obstacles[i].x;int by1 = obstacles[i].y;int bx2 = obstacles[i].x + obstacleImags[obstacles[i].type][obstacles[i].imgIndex].getwidth();int by2 = obstacles[i].y - obstacleImags[obstacles[i].type][obstacles[i].imgIndex].getheight()-10;if (rectIntersect(ax1, ay1, ax2, ay2, bx1, by1, bx2, by2)) {//寫到這里,只要我們有圖片和障礙物相交在一起就會扣血,因為在屏幕里面,怪是要到屏幕之外才是結束存在的heroBoold -= obstacles[i].power;printf("血量剩余%d\n", heroBoold);obstacles[i].hited = true;}}}}
我們來看到這個代碼是實現碰撞檢測的,我們來畫一個圖
我們要找出這兩個人的x1,x2,y1,y2的坐標后面的by-10是因為我這圖片的問題,就是kunkun和別的尺寸有問題才-10,一般是不需要減10的,正常寫就好接下來我們就要判斷是否發生碰撞了
接下里我們就要學習是否發生碰撞這個判斷條件了
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);
}
這個是我們要用到的函數,這個函數參數
x01--人的x1? ? y01--人的y1? ?x02--人的x2? ?y02--人的y2? ?x11--障礙物的x1? ?y11--障礙物的y1
x12--障礙物的x2? y12--障礙物的y2?
zx和x的理解
這個就是zx和x之間的原理?
?
這個是zy和y的原理跟x差不多
當我們實現這個碰撞檢測的時候,我們就可以繼續寫了,我們就利用這個碰撞檢測來實現這個血條的扣血
在run函數里面實現進行每一次的檢測
這里我們打開了hitd這個開關,我們不需要寫一個關閉這個開關的程序,因為每一次創建一個障礙物的時候,他都會進行一次初始化,這個開關它會關閉,碰到之后再繼續打開
血條的扣血
我們定義一個這個函數來顯示血條?
?這個是血條扣除的函數
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);
}
參數部分:
x, y
: 血條左上角的坐標width, height
: 血條的寬度和高度lineWidth
: 邊框的寬度boardColor
: 背景色(未使用,但可以用于描邊)emptyColor
: 進度條背景(未填充部分)的顏色fillColor
: 進度條已填充部分的顏色percent
: 進度條已填充部分的百分比,取值范圍為0到1
?接下來分析這個函數里面的代碼內容
LINESTYLE
是一個數據類型,用于表示線條的樣式。它通常在圖形編程庫(比如 EasyX)中用來存儲與線條相關的屬性,比如線條的寬度、樣式、端點樣式等
典型的 LINESTYLE
結構體可能包含:
- 線條寬度(
width
):指定線條的寬度 - 線條樣式(
style
):指定線條的樣式,常見的樣式包括實線、虛線等 - 線條端點樣式(
cap
):設置線條的端點樣式,比如圓形端點、方形端點等 - 線條連接樣式(
join
):設置線段連接點的樣式,如圓形連接、尖角連接等
示例:
在 EasyX 中,LINESTYLE
的定義可能類似于:
typedef struct _LINESTYLE {int width; // 線條寬度int style; // 線條樣式int cap; // 端點樣式int join; // 連接點樣式
} LINESTYLE;
這個是eaxyx里面的
?
總結來說,LINESTYLE
是一個結構體,用來存儲和管理與線條繪制相關的多種樣式設置
LINESTYLE lineStyle;
getlinestyle(&lineStyle);
int lineColor = getlinecolor();
int fileColor = getfillcolor();
這個代碼是
getlinestyle(&lineStyle)
:獲取當前的線條樣式getlinecolor()
:獲取當前的線條顏色getfillcolor()
:獲取當前的填充顏色
這個是獲取你系統自帶的默認的顏色,避免你后面沒有顏色和樣例
這個是一個浮點數,就是血條的百分比含量?,當為小于0的時候,就歸屬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);
-
setlinecolor(BLUE);
- 這行代碼設置 線條的顏色為藍色。通常,這會影響矩形的邊框顏色(即輪廓)。
BLUE
是 EasyX 圖形庫中的預定義顏色常量,表示藍色。
-
setlinestyle(PS_SOLID | PS_ENDCAP_ROUND, lineWidth);
- 這行代碼設置 線條的樣式。
PS_SOLID
表示線條是 實線(不是虛線或點線)。PS_ENDCAP_ROUND
表示線條的端點是 圓形,即線段的兩端是圓頭,而不是方頭或平頭。lineWidth
是線條的寬度,通常是一個整數,表示線條的粗細(例如 2 表示線條寬度為 2 像素)。
- 這行代碼設置 線條的樣式。
-
setfillcolor(emptyColor);
- 這行代碼設置 填充顏色,即矩形內部的顏色。
emptyColor
是傳入的一個變量,表示血條的背景顏色,通常是透明或灰色,表示血條沒有被填充的部分。
-
fillrectangle(x, y, x + width, y + height);
- 這行代碼用于 繪制矩形。
x, y
是矩形的左上角坐標,x + width, y + height
是矩形的右下角坐標。這樣,矩形的大小和位置就由這些坐標確定了。- 這個矩形會被 填充為之前設置的
emptyColor
,即矩形的背景顏色。
這個下一個就是恢復樣例和顏色了,避免下一次使用不是默認的樣例和顏色
-
setlinestyle(PS_SOLID | PS_ENDCAP_FLAT, 0);
- 這行代碼 恢復線條樣式:
PS_SOLID
表示線條是 實線。PS_ENDCAP_FLAT
表示線條的端點是 平頭,即線段的兩端是直角,而不是圓形端點。0
表示 線寬為 0,這意味著不會顯示邊框,這通常用于消除矩形或其他圖形的外部輪廓,只顯示填充
- 這行代碼 恢復線條樣式:
這個后面就是填充血條的顏色,上面那個是空血條的顏色
-
setfillcolor(fillColor);
- 這行代碼設置 填充顏色 為
fillColor
,也就是血條的 實際填充顏色,即顯示血量的顏色。通常這個顏色是 紅色、綠色 或其他表示血量的顏色。
- 這行代碼設置 填充顏色 為
-
setlinecolor(fillColor);
- 這行代碼將 線條顏色 設置為
fillColor
,即設置血條邊框的顏色為填充顏色。這個通常是為了確保血條的邊框與填充顏色一致,給人一致的視覺效果。
- 這行代碼將 線條顏色 設置為
核心句子
if (percent > 0) {fillrectangle(x + 0.5 * lineWidth, y + lineWidth * 0.5, x + width * percent, y + height - 0.5 * lineWidth);
}
- 左上角坐標:
x + 0.5 * lineWidth
和y + lineWidth * 0.5
x + 0.5 * lineWidth
:由于在繪制矩形時需要考慮線條寬度,所以x
坐標偏移了0.5 * lineWidth
,確保邊框的線寬(lineWidth
)不會影響矩形的顯示位置,確保繪制的矩形與邊框之間有一定的間隔。y + lineWidth * 0.5
:同樣,y
坐標也進行了偏移,確保矩形的上邊界與線條寬度相適應。
- 右下角坐標:
x + width * percent
和y + height - 0.5 * lineWidth
x + width * percent
:這里的x + width * percent
計算了矩形的 實際寬度,它是根據當前血量的百分比percent
來決定的。如果percent
為 0,矩形的寬度為 0;如果percent
為 1,矩形的寬度將是血條的最大寬度width
。y + height - 0.5 * lineWidth
:y + height
為矩形的下邊界,減去0.5 * lineWidth
是為了避免線條的寬度影響矩形的底部顯示。
我們這里不需要修改這個左上角標的值的,只需要修改右下角標的值,這樣就可以實現動態繪畫這個血條了
setlinecolor(lineColor);
setfillcolor(fillColor);
setlinestyle(&lineStyle);
這個是恢復之前的顏色,避免下一次使用不是默認的值,我們之前就把初始化的東西用變量儲存起來了
積分計數器
void checkpassed() {for (int i = 0; i < OBSTACLE_CUONT; i++) {if (obstacles[i].exist &&obstacles[i].passed == false &&obstacles[i].x + obstacleImags[obstacles[i].type][0].getwidth()) {score++;obstacles[i].passed = true;printf("%d", score);}}
}
這個就是我們來檢測是否跳過這個障礙物,我們只需要檢測這個開關是否關閉,還有這個長度是否超過這個圖片的長度還有這個障礙物是否存在,執行完成之后,就打開這個開關,防止一直加分,然后就是我們要加一個分數繪制在這個窗口
void updateScore() {//ASCLL碼值 ‘5’-‘0’=5char str[8];sprintf(str, "%d", score);int x = 20;int y = 25;for (int i = 0; str[i] != 0; i++) {int num = str[i] - '0';putimage(x, y, &imgSZ[num]);x += imgSZ[num].getwidth();}
}
我們只需要把這個score格式化一下從int到char類型,然后利用sprintf來讀取對應的數字到數組里面,然后就是用for循環來來便利?,這里也運用了ASCII值的轉換,后買你x+=這一個代碼是為了是圖片連起來
源碼
//圖片的長寬
#define _CRT_SECURE_NO_WARNINGS 1
#define WIN_LONG 1150
#define WIN_WIDTH 538
#define OBSTACLE_CUONT 20#include<time.h>
#include<stdio.h>
#include<graphics.h>
//這個是用來調用按鍵是否輸入的
#include<conio.h>
//這個是用來使用變長數組的
#include<vector>
#include<windows.h>
//播放音樂的時候用的兩行代碼
#include<mmsystem.h>
#pragma comment(lib,"winmm.lib")#include"tools.h"
using namespace std; //聲明命名空間
/* 背 景 制 作 */
//背景圖數組
IMAGE imgBgs[2];
//背景圖的x
int bgX[2];
//用來存放速度
int bgspeed[2] = { 4,8 };
/* 角 色 制 作*/
//角色奔跑
IMAGE imgHero[12];
//玩家會被彈飛還有下蹲啥的,所以要設置全局變量
int heroX; //x坐標
int heroY; //y坐標
int heroIndex; //玩家奔跑時圖片的序號bool heroJump; //表示玩家正在跳躍(跳躍開關)
bool heroDown; //表示玩家正在下蹲(下蹲開關)int heroBoold;int jumpHeightMax;
int herojumpOff;
int update; //表示是否需要馬上刷新畫面int score;/* 烏 龜 制 作*/
//IMAGE imgTortoise; //小烏龜
//int torToiseX; //小烏龜的x坐標
//int torToiseY; //小烏龜的y坐標
//bool torToiseExist;//當前窗口是否有小烏龜
//由于障礙物越來越多,則需要進行封裝,這樣就可以簡化代碼行數,實現代碼不擁擠typedef enum {TORTOISE, //奶龍0LION, //獅子1//四個柱子HOOK1,HOOK2,HOOK3,HOOK4,OBSTACLE_TYPE_COUNT//常看有幾種障礙物(因為是從0開始,所以更加方便看有幾種類型)ho
}obstacle_type;//IMAGE obstacleImage[3][12];用這個的話會浪費些許內存,因為烏龜只有一個圖片
vector<vector<IMAGE>>obstacleImags(OBSTACLE_TYPE_COUNT,vector<IMAGE>(12));//里面一個成員的又一個成員(可變數組)
//相當于int data[ int ]typedef struct obstacle {obstacle_type type;//障礙物的類型int imgIndex; //當前顯示的圖片的序號//但是這樣有障礙物的數字代表不是特別可讀,所以我們可以利用枚舉類型,更加可讀int x, y; //障礙物的x與y坐標int speed;int power; //傷害bool exist;bool hited; //碰撞bool passed;
}obstacle_t;//由于我們不可以把障礙物直接全部都是弄出來,要逐個逐個的,就像捕魚達人一樣,所以我們要建立一個池子來存儲這個預備隊員,就像籃球,一個上場一個下場
obstacle_t obstacles[OBSTACLE_CUONT];
//玩家下滑圖片儲存的數組
IMAGE imgHeroDown[2];
//創建窗口IMAGE imgSZ[10];void init() {//創建窗口//第三個參數是為了顯示控制臺的參數//第三個參數是為了顯示控制臺的參數//在initgraph后面, EX_SHOWCONSOLE這個在打包刪除了initgraph(WIN_LONG, WIN_WIDTH);/*背 景 制 作*///加載背景圖 loadimage函數(取地址,具體的文件名字)char name[64];for (int i = 0; i < 2; i++) {//"ret/bg001.png" "ret/bg002.png" "ret/bg003.png"sprintf(name, "ret/bg%03d.png", i + 1);//這個是要在win32平臺和多字節字符串的情況下才可以運行loadimage(&imgBgs[i], name);//初始化背景圖的x軸坐標bgX[i] = 0;}/*人 物 制 作*///加載玩家奔跑for (int i = 0; i < 12; i++) {//"跑步1" "跑步2"sprintf(name, "ret/跑步%d.png", i + 1);loadimage(&imgHero[i], name);}//設置玩家初始位置//窗口寬度*0.5-自己寬度*0.5heroX = 600 * 0.5 - 200 * 0.5 - 80;heroY = 300;heroIndex = 0;//玩家跳躍heroJump = false;jumpHeightMax = 80;//記得是減,不是加,注意坐標原點herojumpOff = -6;update = true;/*小 烏 龜 制 作*///loadimage(&imgTortoise, "ret/奶龍.png");//torToiseExist = false;//torToiseY = 400;/*小 奶 龍 改 版*/IMAGE imgTort;loadimage(&imgTort, "ret/奶龍.png");vector<IMAGE>imgTorArray;imgTorArray.push_back(imgTort);obstacleImags[TORTOISE] = imgTorArray;/*kunkun 圖片制作*/IMAGE imgLion;vector<IMAGE>imgLionArray;for (int i = 0; i < 12; i++) {sprintf(name, "ret/kun%d.png", i + 1);loadimage(&imgLion, name);imgLionArray.push_back(imgLion);}obstacleImags[LION] = imgLionArray;//初始化障礙物池for (int i = 0; i < OBSTACLE_CUONT; i++) {obstacles[i].exist = false;}//加載下蹲素材loadimage(&imgHeroDown[0], "ret/d1.png");loadimage(&imgHeroDown[1], "ret/d2.png");heroDown = false;//加載柱子// 創建單獨的數組或 vector 存儲每個障礙物的圖片IMAGE imgH1;loadimage(&imgH1, "ret/hook1.png", 63, 310);vector<IMAGE> imgHook1Array;imgHook1Array.push_back(imgH1);obstacleImags[HOOK1] = imgHook1Array;IMAGE imgH2;loadimage(&imgH2, "ret/hook2.png", 63, 310);vector<IMAGE> imgHook2Array;imgHook2Array.push_back(imgH2);obstacleImags[HOOK2] = imgHook2Array;IMAGE imgH3;loadimage(&imgH3, "ret/hook3.png", 63, 310);vector<IMAGE> imgHook3Array;imgHook3Array.push_back(imgH3);obstacleImags[HOOK3] = imgHook3Array;IMAGE imgH4;loadimage(&imgH4, "ret/hook4.png", 63, 310);vector<IMAGE> imgHook4Array;imgHook4Array.push_back(imgH4);obstacleImags[HOOK4] = imgHook4Array;heroBoold = 100;mciSendString("open ret/bk.mp3", NULL, 0, NULL);mciSendString("play ret/bk.mp3 repeat", NULL, 0, NULL);//加載數字for (int i = 0; i < 10; i++) {sprintf(name, "ret/sz/%d.png", i);loadimage(&imgSZ[i], name);}
}void creatObstacle() {srand((unsigned)time(NULL));int i = 0;for ( i = 0; i < OBSTACLE_CUONT; i++) {if (obstacles[i].exist == false) {break;}}if (i >= OBSTACLE_CUONT) {return;}obstacles[i].exist = true;obstacles[i].hited = false;obstacles[i].imgIndex = 0;obstacles[i].passed = false;//obstacles[i].type = (obstacle_type)(rand() % OBSTACLE_TYPE_COUNT);//由于vs的語法要求比較嚴,所以我們進行強制轉換為枚舉類型obstacles[i].x = WIN_LONG;obstacles[i].y = 380;obstacles[i].type=(obstacle_type)(rand() % 3);if (obstacles[i].type == HOOK1) {obstacles[i].type = (obstacle_type)((int)(obstacles[i].type)+rand()%4);}//速度,傷害的配置的話,就是各有所需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 = 10;}else if (obstacles[i].type >= HOOK1 && obstacles[i].type <= HOOK4) {obstacles[i].speed = 0;obstacles[i].power = 10;obstacles[i].y = 0;}}//玩家和障礙物的碰撞檢測處理void checkHit() {for (int i = 0; i < OBSTACLE_CUONT; i++) {if (obstacles[i].exist && obstacles[i].hited == false) {int ax1, ay1, ax2, ay2;//角色的碰撞寬度高度設置if (!heroDown) {ax1 = heroX;ay1 = heroY;ax2 = heroX + imgHero[i].getwidth();ay2 = heroY - imgHero[i].getheight();}else {ax1 = heroX;ay1 = 397 - imgHeroDown[i].getheight();ax2 = heroX + imgHeroDown[i].getwidth();ay2 = 397;}//障礙物的碰撞寬度高度設置int bx1 = obstacles[i].x;int by1 = obstacles[i].y;int bx2 = obstacles[i].x + obstacleImags[obstacles[i].type][obstacles[i].imgIndex].getwidth();int by2 = obstacles[i].y - obstacleImags[obstacles[i].type][obstacles[i].imgIndex].getheight()-10;if (rectIntersect(ax1, ay1, ax2, ay2, bx1, by1, bx2, by2)) {//寫到這里,只要我們有圖片和障礙物相交在一起就會扣血,因為在屏幕里面,怪是要到屏幕之外才是結束存在的heroBoold -= obstacles[i].power;printf("血量剩余%d\n", heroBoold);obstacles[i].hited = true;}}}}void run() {srand((unsigned)time(NULL));for (int i = 0; i < 2; i++) {bgX[i] -= bgspeed[i];//用于返回到當時圖片的位置,這樣才可以在后面繼續奔跑if (bgX[i] < -WIN_WIDTH) {bgX[i] = 0;}}//玩家幀序列heroIndex = (heroIndex + 1) % 12;//0~11的移動(因為就這么多圖片)//實現跳躍(改變玩家的i坐標)//有個上升下降的過程()//因為這個是套在while里面的,隨著函數的不斷推進,他會一直跳躍,直到觸發另外一個if開關if (heroJump) {//下降階段if (heroY < jumpHeightMax) {herojumpOff = 6;}//一開始處于上升,后面處于下降heroY += herojumpOff;//280初始值if (heroY > 280) {heroJump = false;herojumpOff = -6;}}else if (heroDown) {static int count = 0;int delays[2] = { 15,20 };count++;//由于下蹲就兩張圖片,所以我們要延續時間(這里可以用靜態變量,來延緩幀數)if (count >= delays[heroIndex]) {count = 0;heroIndex++;if (heroIndex >= 2) {heroIndex = 0;heroDown = false;}}}else{ heroIndex = (heroIndex + 1) % 12;}//生成障礙物(如果跟著系統的30ms來整出小奶龍的話,那就滿篇小奶龍了)//我們可以計算,這個函數調用的次數*30ms來決定這個烏龜是否生成,比如我們要3s生成一次,那我們就調用100次*30ms就可以了進率1000//那我們要知道調用多少次,用靜態變量,因為這樣調用完之后銷毀也會保存在靜態區static int frameCount = 0;static int enemyFre = 50;frameCount++;if (frameCount > enemyFre) {frameCount = 0;enemyFre = 50 + rand() % 50; // 50~99creatObstacle();}//更新奶龍位置//if (torToiseExist) {// torToiseX -= 4;// //當奶龍完全讓自己出去的時候// if (torToiseX < -151) {// torToiseExist = false;// }//}//更新障礙物的坐標for (int i = 0; i < OBSTACLE_CUONT; i++) {if (obstacles[i].exist) {obstacles[i].x -= obstacles[i].speed + bgspeed[1];if (obstacles[i].x < -300) {obstacles[i].exist = false;}//由于我們的坤坤為了可以出現變動,所以哦我們要加這個變化圖片int len = obstacleImags[obstacles[i].type].size(); //type為第幾行obstacles[i].imgIndex = (obstacles[i].imgIndex + 1) % len;//(我們不用障礙物的圖片數量不一樣,所以我們要用len)}}//玩家和障礙物的碰撞檢測處理checkHit();
}//渲染游戲背景
void updateBg() {//x軸是確定圖片滾到哪里的 y軸是確定位置的//這里的滾動是有這個bgX來變化來進行圖片的滾動//由于這個是一次一次吧圖片加載出來的,但是我們想一次性一起加載出來這個時候就要添加//BeginBatchDraw()和EndBatchDraw()//一個是開始批量繪制圖形,一個是結束開始批量繪制圖形putimage(bgX[0], 0, &imgBgs[0]);putimage(bgX[1],397, &imgBgs[1]);}
void jump() {//實現跳躍的時候,坐標是慢慢移動的,而不是直接蹦上去瞬移了heroJump = true;//啟動開關update = true; //在30毫秒過程中,如果在30毫秒點擊空格跳躍,則這個立馬刷新,直接步入到下面那個if語句然后直接進入,這樣可以接受按鍵
}
void down() {heroDown = true;update = true;heroIndex = 0;
}//處理用戶按鍵輸入
void keyEvent() {char ch;//如果有按鍵按下,則這個kbhit函數是返回為真,沒有則反之if (_kbhit()) {/*scanf("%c", &c);*/ //這里用scanf的話這里是要按下回車才可以繼續執行,降低了可玩性,所以不用scanfch = _getch(); //這個是scanf的pilus版,這個是不需要按下回車,直接讀取這個輸入的字符//由于vs版本,這個getch和kbhit都是要加_這個的,不加會報警告if (ch == ' ') {jump();//功能相對獨立的要封裝成一個函數}else if (ch == 's') {down();}}/*char c;scanf("%c", &c);*///這里會卡死直接這樣寫,因為他會等待這個玩家輸入//解決方法就是判斷玩家到底有沒有按鍵按下去,寫一個if語句
}void checkover() {if (heroBoold <= 0) {loadimage(0, "ret/kunkunjie.png");FlushBatchDraw();mciSendString("stop ret/bk.mp3", 0, 0, 0);system("pause");//暫停之后刷新游戲角色數據heroBoold = 100;score = 0;mciSendString("play ret/bk.mp3 repeat", 0, 0, 0);}
}void checkpassed() {for (int i = 0; i < OBSTACLE_CUONT; i++) {if (obstacles[i].exist &&obstacles[i].passed == false &&obstacles[i].x + obstacleImags[obstacles[i].type][0].getwidth()) {score++;obstacles[i].passed = true;printf("%d", score);}}
}void updatezhang()
{//渲染奶龍//if (torToiseExist) {// putimage(torToiseX, torToiseY, &imgTortoise);//}for (int i = 0; i < OBSTACLE_CUONT;i++) {if (obstacles[i].exist) {//我們要取走第幾行呢?我們可以利用我們的枚舉類型,這個是對應我們的圖片的行數(type對應著枚舉->行數)putimage(obstacles[i].x, obstacles[i].y, &obstacleImags[obstacles[i].type][obstacles[i].imgIndex]);}}}
void updateHero() {//這個奔跑和跳躍這個可以實現,但是下蹲不行了,所以需要加一個判斷if (!heroDown) {putimage(heroX, heroY, &imgHero[heroIndex]);}else {int y = 395 - 15;putimage(heroX, y, &imgHeroDown[heroIndex]);}}void updateBoold() {drawBloodBar(10, 10, 200, 10, 2, BLUE, DARKGRAY, RED, heroBoold / 100.0);
}void updateScore() {//ASCLL碼值 ‘5’-‘0’=5char str[8];sprintf(str, "%d", score);int x = 20;int y = 25;for (int i = 0; str[i] != 0; i++) {int num = str[i] - '0';putimage(x, y, &imgSZ[num]);x += imgSZ[num].getwidth();}
}int main() {init();//顯示菜單loadimage(0, "ret/kunkunkai.png");system("pause");int timer = 0;while (1) {/*由于根據游戲設計,這里是要循環多次才可以跳好所以我們這里需要設計一個按鍵來執行立馬跳躍,就不用循環多次了(按鍵跳躍)*/keyEvent();//這個的好處就是可以隨時接受按鍵接受timer += getDelay(); //升級版sleepif (timer > 30) {timer = 0;update = true;//這里是sleep的升級版本,沒進過30秒鐘刷新一次,然后進入游戲,在30秒的過程中,這個畫面在逐幀加載,這樣就可以持續進行畫面顯示//沒有這個,程序就沒有逐幀的慢速顯示,就會很快很快}if (update) {update = false;BeginBatchDraw();updateBg();//這個里面不要直接放圖片,因為我們后續還有撞出窗外的操作要實現//所以不要直接放putimage()在這里//由于玩家需要下蹲則這個代碼不行了/*putimage(heroX, heroY, &imgHero[heroIndex]);*/updateHero();updateBoold();updatezhang();updateScore();EndBatchDraw();//這個run是改變這個圖片下一次所在的位置的checkover();checkpassed();run();}//這個休眠是讓他暫停一會,要不然太快了顯示的是一個快影子//休眠的話,如果在30毫秒鐘之內按按鍵的話是不會響應得,所以這個sleep在這個小游戲里面沒有什么實質的影響,但是在大型游戲里面是有影響的/*Sleep(30);*///所以我們一般不用sleep}//定義一個死循環不斷的對圖片進行滾動//system("pause");//用于暫停觀察//int system(const char* 命令);return 0;
}
總結
接下來我們的項目就基本結束了,打包安裝需要安裝插件,感興趣的可以取收一下微軟本地的自帶插件,可以在vs管理擴展包下載,這里的源碼你直接復制會報錯,你得自己學習調節屬性和安裝插件還有文件的學習,因為天底下哪有免費的午餐