您好,登錄后才能下訂單哦!
這篇文章主要介紹“C++怎么利用easyx圖形庫實現天天酷跑小游戲”,在日常操作中,相信很多人在C++怎么利用easyx圖形庫實現天天酷跑小游戲問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”C++怎么利用easyx圖形庫實現天天酷跑小游戲”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!
1.創建項目
2.導入素材
3.創建游戲界面
從用戶界面入手
選擇圖形庫或者其他引擎,酷跑是基于“easyx”圖形庫的
1)創建游戲窗口
2)設計游戲背景
a.三重背景不同的速度移動
b.循環滾動背景的實現
3)實現游戲背景
a.加載背景資源
b.渲染(實現打印圖片的效果)背景知識:坐標
遇到的問題:背景圖片的png格式圖片出現黑色
4.實現玩家奔跑
5.實現玩家跳躍
6.實現隨機小烏龜
7.創建結構體結構類型
8.使用障礙物結構體后重新初始化
9.封裝后多個障礙物的顯示
10.實現玩家的下蹲技能
11.添加柱子障礙物
//#undef UNICODE //#undef _UNICODE #include <stdio.h> #include <graphics.h> #include <conio.h> #include <vector> //c++ 長度可變的數組 #include "tools.h" using namespace std; //聲明命名空間 #define WIN_SCORE 10 #define WIN_WIDTH 1012 //定義宏 便于后期維護與處理 #define WIN_HEIGHT 396 #define OBSTACLE_COUNT 10 IMAGE imgBgs[3];//背景圖片——創建圖片數組 int bgX[3];//背景圖片的X坐標(不斷變化) int bgSpeed[3] = { 1,2,4 };//控制3個背景不同速度 IMAGE imgHeros[12];//人物不斷奔跑的實現 int heroX;//玩家的X坐標 int heroY;//玩家的Y坐標 int heroIndex;//玩家奔跑的圖片幀序號 bool heroJump;//表示玩家正在跳躍 int jumpHeightMax;//跳躍的最大高度 int heroJumpOff;//跳躍偏移量 int update;//表示是否需要馬上刷新畫面 //IMAGE imgTortoise; //小烏龜 //int torToiseX; //小烏龜的水平坐標 //int torToiseY; //小烏龜的豎直坐標 //bool torToiseExist; //當前窗口是否有小烏龜 int heroBlood; //定義玩家血量 int score; typedef enum { TORTOISE, //烏龜 0 LION, //獅子 1 HOOK1, HOOK2, HOOK3, HOOK4, OBSTACLE_TYPE_COUNT //邊界 6 }obstacle_type; // 相當于 IMAGE obstacleImgs[3][5] vector<vector<IMAGE>>obstacleImgs; //二維數組 存放所有障礙物的各個圖片 typedef struct obstacle { int type; //障礙物的類型 int imgIndex; //當前顯示的圖片的序號 int x, y; //障礙物的坐標 int speed; int power; //殺傷力 bool exist; bool hited; //表示是否已經發生碰撞 bool passed;//表示是否已經被通過 }obstacle_t; obstacle_t obstacles[OBSTACLE_COUNT]; int lastObsIndex;//解決障礙物bug(柱子與獅子在一起) IMAGE imgHeroDown[2]; bool heroDown; //表示玩家是否處于下蹲狀態 IMAGE imgSZ[10]; //游戲的初始化 void init() { //創建游戲窗口 initgraph(WIN_WIDTH, WIN_HEIGHT, EW_SHOWCONSOLE); //加載背景資源 char name[64]; for (int i = 0; i < 3; i++) { //路徑 "res/bg001.png" "res/bg002.png" "res/bg003.png" sprintf(name, "res/bg%03d.png",i+1);//%03d占3位,不足3位自動補0 //#undef _UNICODE loadimage(&imgBgs[i], name);//把3個圖片加載到了圖片數組的位置 bgX[i] = 0; } //加載Hero奔跑的圖片幀素材 for (int i = 0; i < 12; i++) { sprintf(name, "res/hero%d.png", i + 1); loadimage(&imgHeros[i], name); } //設置玩家的初始位置 heroX = WIN_WIDTH * 0.5 - imgHeros[0].getwidth() * 0.5;//X坐標:屏幕寬度的一半減去人物寬度的一半 heroY = 345 - imgHeros[0].getheight();//Y坐標:腳底坐標減去人物高度 heroIndex = 0; heroJump = false; jumpHeightMax = 345 - imgHeros[0].getheight() - 120; heroJumpOff = -4; update = true; 加載小烏龜素材 //loadimage(&imgTortoise, "res/t1.png"); //torToiseExist = false; //torToiseY = 345 - imgTortoise.getheight() + 5; IMAGE imgTort; loadimage(&imgTort, "res/t1.png"); vector<IMAGE>imgTortArray; imgTortArray.push_back(imgTort);//添加圖片 obstacleImgs.push_back(imgTortArray); IMAGE imgLion; vector<IMAGE>imgLionArray; for (int i = 0; i < 6; i++) { sprintf(name, "res/p%d.png", i + 1); loadimage(&imgLion, name); imgLionArray.push_back(imgLion); } obstacleImgs.push_back(imgLionArray); //初始化障礙物池 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/h%d.png", i + 1); loadimage(&imgH, name, 63, 250, true); // 圖片進行縮化 imgHookArray.push_back(imgH); obstacleImgs.push_back(imgHookArray); } heroBlood = 100; //預加載音效 preLoadSound("res/hit.mp3"); //背景音樂 mciSendString("play res/bg.mp3 repeat", 0, 0, 0); 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].imgIndex = 0; //obstacles[i].type = (obstacle_type)(rand() % OBSTACLE_TYPE_COUNT); 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 += rand() % 4; //0-3 } obstacles[i].x = WIN_WIDTH; obstacles[i].y = 345 + 5 - obstacleImgs[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 = 1; 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 + imgHeros[heroIndex].getwidth() - off; a2y = heroY + imgHeros[heroIndex].getheight(); } else { a1x = heroX + off; a1y = 345 - imgHeroDown[heroIndex].getheight(); a2x = heroX + imgHeroDown[heroIndex].getwidth() - off; a2y = 345; } IMAGE img = obstacleImgs[obstacles[i].type][obstacles[i].imgIndex]; //當前障礙物類型(的第幾張圖片) 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() - 10; if (rectIntersect(a1x, a1y, a2x, a2y, b1x, b1y, b2x, b2y)) { heroBlood -= obstacles[i].power; printf("血量剩余 %d\n", heroBlood); playSound("res/hit.mp3"); obstacles[i].hited = true; } } } } //讓背景動起來 void run() { for (int i = 0; i < 3; i++) { bgX[i] -= bgSpeed[i];//3個背景移動的速度不同 if (bgX[i] < -WIN_WIDTH) { bgX[i] = 0; } } //實現跳躍 if (heroJump) { if (heroY < jumpHeightMax) //達到最大跳躍高度 跳躍偏移量為正 向下跳躍 { heroJumpOff = 4; } heroY += heroJumpOff; if (heroY > 345 - imgHeros[0].getheight()) //到達地面 跳躍結束 { heroJump = false; heroJumpOff = -4; // 偏移量初始化 } } else if (heroDown) { //人物下蹲 static int count = 0; int delays[2] = { 8,30 }; //設置下蹲的時間不一樣 count++; if (count >= delays[heroIndex]) { count = 0; heroIndex++; if (heroIndex >= 2) { heroIndex = 0; heroDown = false; } } } else{ //不跳躍 heroIndex = (heroIndex + 1) % 12; //12張圖片循環播放完成一系列動作 } //創建障礙物 static int frameCount = 0; static int enemyFre = 50; frameCount++; if (frameCount > enemyFre){ frameCount = 0; //if (!torToiseExist) { //避免屏幕同時出現多個小烏龜 // torToiseExist = true; // torToiseX = WIN_WIDTH; // enemyFre=rand()%301+200; //每200-500幀隨機出現一只龜 //} enemyFre = rand() % 50 + 50; creatObstacle(); } //if (torToiseExist) { // //更新小烏龜位置 // torToiseX -= bgSpeed[2]; // if (torToiseX < -imgTortoise.getwidth()) { // torToiseExist = false; // } //} //更新所有障礙物的坐標 for (int i = 0; i < OBSTACLE_COUNT; i++) { if (obstacles[i].exist) { obstacles[i].x -= obstacles[i].speed + bgSpeed[2]; if (obstacles[i].x < -obstacleImgs[obstacles[i].type][0].getwidth() * 2) { obstacles[i].exist = false; } int len = obstacleImgs[obstacles[i].type].size(); obstacles[i].imgIndex = (obstacles[i].imgIndex + 1) % len; } } //玩家和障礙物的“碰撞檢測”處理 checkHit(); } //渲染“游戲背景” void updateBg() { //調整背景圖片位置 putimagePNG2(bgX[0], 0, &imgBgs[0]); putimagePNG2(bgX[1], 119, &imgBgs[1]); putimagePNG2(bgX[2], 330, &imgBgs[2]); } //實現跳躍 void jump() { heroJump = true; update = true; //未處于刷新時也能跳躍 } void down() { update = true; heroDown = true; heroIndex = 0; } //處理用戶按鍵的輸入 void keyEvent() { //char c; //scanf("%c", &c); 會直接阻塞程序的執行 if (GetAsyncKeyState(VK_UP)){ //虛擬鍵 jump(); /* if(kbhit()) //kbhit()判斷有無鍵盤輸入。若有按鍵按下,則kbhit()返回 TRUE { char ch = _getch();//不需要按下回車即可直接讀取 if (ch == ' ') {//按下空格跳躍 jump(); } */ } else if (GetAsyncKeyState(VK_DOWN)) { down(); } } void updateEnemy() { //渲染小烏龜 /*if (torToiseExist) { putimagePNG2(torToiseX, torToiseY, WIN_WIDTH, &imgTortoise); }*/ for (int i = 0; i < OBSTACLE_COUNT; i++) { if (obstacles[i].exist) { putimagePNG2(obstacles[i].x, obstacles[i].y, WIN_WIDTH, &obstacleImgs[obstacles[i].type][obstacles[i].imgIndex]); } } } void updateHero() { if (!heroDown) { //不處于下蹲狀態——奔跑跳躍 putimagePNG2(heroX, heroY, &imgHeros[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/over.png"); FlushBatchDraw();//刷新 mciSendString("stop res / bg.mp3", 0, 0, 0);//關掉背景音樂 system("pause"); //暫停之后,充幣復活或者直接開始下一局 heroBlood = 100; score = 0; mciSendString("play res / bg.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].x + obstacleImgs[obstacles[i].type][0].getwidth() < heroX && obstacles[i].hited == false) { score++; obstacles[i].passed = true; printf("score:%d\n", score); } } } 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/win.png"); FlushBatchDraw(); mciSendString("stop res/bg.mp3", 0, 0, 0); system("pause"); heroBlood = 100; score = 0; mciSendString("play res/bg.mp3 repeat", 0, 0, 0); } } int main(void) { init(); //顯示初始化面 loadimage(0, "res/over.png"); system("pause"); int timer = 0; while (1) { keyEvent(); timer += getDelay();//此函數返回距離上一次調用間隔的時間,第一次返回0 if (timer > 30) { //30毫秒刷新時間 timer = 0; update = true; } if (update) { update = false; BeginBatchDraw();//這個函數用于開始批量繪圖。執行后,任何繪圖操作都將暫時不輸出到繪圖窗口上,直到執行 FlushBatchDraw 或 EndBatchDraw 才將之前的繪圖輸出。 updateBg(); //putimagePNG2(heroX, heroY, &imgHeros[heroIndex]); updateHero(); updateEnemy(); updateBloodBar(); updateScore(); checkWin(); EndBatchDraw();//這個函數用于結束批量繪制,并執行未完成的繪制任務。 這兩個函數主要為了消除閃爍。 checkOver(); checkScore(); run(); } //Sleep(30); //休眠 } system("pause"); return 0; } ## tool頭文件 ```javascript #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); }
到此,關于“C++怎么利用easyx圖形庫實現天天酷跑小游戲”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注億速云網站,小編會繼續努力為大家帶來更多實用的文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。