??前言:
這款簡易版的球球大作戰是博主耗時兩天半完成的,玩家需要控制坤坤在游戲界面上移動,來躲避游戲界面上方不斷掉下來的籃球。本游戲使用C語言和easyx圖形庫編寫,旨在幫助初學者了解游戲開發的基本概念和技巧。
在開始編寫代碼之前,我們需要先了解一下游戲的基本規則和功能:
游戲界面:游戲界面是一個矩形區域,玩家可以在這個區域內控制球的移動。
坤坤:玩家控制的坤坤可以在游戲界面內自由移動,按下特定的按鍵后可以跳躍。
籃球:籃球在游戲界面的正上方源源不斷地生成,并下降。
坤坤觸碰籃球:當坤坤觸碰到上方掉下來的籃球時,坤坤的血量就會降低一格,一共五格血量降完為止。
接下來,我們將通過以下幾個步驟來實現這個游戲:
1. 初始化游戲界面和模型的信息。
2. 處理鍵盤輸入,實現玩家控制坤坤的移動和跳躍。
3. 生成足夠數量的籃球。
4. 生成籃球,并控制其移動。
5. 檢測籃球與坤坤之間的觸碰關系,并減少相應的血量。
通過學習這個游戲的開發過程,初學者將能夠掌握C語言編程和easyx圖形庫的基本技巧。
1. 前期準備
第一步:我們需要在easyx官網下載好easyx圖形庫。(具體操作可以去b站搜索相關視頻)
第二步:按照下圖的步驟將字符集改為多節字符集,因為如果使用的字符集只包含有限數量的字符,可能無法支持所有需要的字符,導致無法正確加載圖像。因此,將字符集改為多字符集可以確保包含所有可能需要的字符,從而避免加載圖像時出現錯誤或亂碼問題。
2. 游戲的背景設置
游戲界面的長和寬根據背景圖片的長寬(右鍵點擊圖片的屬性可以查看)來設置,這里的背景圖片有兩張一張是游戲界面,另一張是游戲結束的圖片。這里首先需要聲明一個IMAGE類型的變量來存儲加載的圖片數據。這是后續對圖片進行處理的基礎,利用函數loadimage可以從本地文件中加載圖片(盡量將游戲所需要的素材放在和代碼的同一個目錄里),最后利用putimage可以將圖片繪制到窗口上來。
int main()
{Init();Itset();//設置窗口的長寬initgraph(Wide, Hight);//緩沖BeginBatchDraw();while (1){show();//刷新FlushBatchDraw();}closegraph;return 0;
}
//聲明IMAGE類型的變量
IMAGE img[2];
//加載圖片
loadimage(&img[0], "resource/微信圖片_20240222202456.jpg");
loadimage(&img[1], "resource/微信圖片_20240303132408.jpg");
//繪制圖片
putimage(0, 0, &img[Img]);
3. 初始模型的信息
在這里籃球和坤坤的模型都是球,只是后面用圖片覆蓋而已。首先在游戲游戲界面的正上方生成多個球(具體數量自己定),然后在游戲的下方生成一個玩家控制的球,最后就是加載圖片了。
初始化小球?
void Itset()
{//for (int i = 0; i < Ball_num; i++){Enemy[i].x = Wide / 2;Enemy[i].y = 10;Enemy[i].r = 10;}//玩家Player.x = Wide / 2;Player.r = 10;Player.y = Hight - Player.r * 4;
}
加載圖片
因為loadimage函數只能加載圖片,加載不了視頻或者動圖,所以我們需要將視頻一幀一幀的加載上去,然后用循環繪制圖片,這樣就產生了一個動圖的效果。
IMAGE kunkun[58];
IMAGE ball[Ball_num];loadimage(&kunkun[0], "resource/2月22日.png", 34, 34);loadimage(&kunkun[1], "resource/2月22日(1).png", 34, 34);loadimage(&kunkun[2], "resource/2月22日(2).png", 34, 34);loadimage(&kunkun[3], "resource/2月22日(3).png", 34, 34);loadimage(&kunkun[4], "resource/2月22日(4).png", 34, 34);loadimage(&kunkun[5], "resource/2月22日(5).png", 34, 34);loadimage(&kunkun[6], "resource/2月22日(6).png", 34, 34);loadimage(&kunkun[7], "resource/2月22日(7).png", 34, 34);loadimage(&kunkun[8], "resource/2月22日(8).png", 34, 34);loadimage(&kunkun[9], "resource/2月22日(9).png", 34, 34);loadimage(&kunkun[10], "resource/2月22日(10).png", 34, 34);loadimage(&kunkun[11], "resource/2月22日(11).png", 34, 34);loadimage(&kunkun[12], "resource/2月22日(12).png", 34, 34);loadimage(&kunkun[13], "resource/2月22日(13).png", 34, 34);loadimage(&kunkun[14], "resource/2月22日(14).png", 34, 34);loadimage(&kunkun[15], "resource/2月22日(15).png", 34, 34);loadimage(&kunkun[16], "resource/2月22日(16).png", 34, 34);loadimage(&kunkun[17], "resource/2月22日(17).png", 34, 34);loadimage(&kunkun[18], "resource/2月22日(18).png", 34, 34);loadimage(&kunkun[19], "resource/2月22日(19).png", 34, 34);loadimage(&kunkun[20], "resource/2月22日(20).png", 34, 34);loadimage(&kunkun[21], "resource/2月22日(21).png", 34, 34);loadimage(&kunkun[22], "resource/2月22日(22).png", 34, 34);loadimage(&kunkun[23], "resource/2月22日(23).png", 34, 34);loadimage(&kunkun[24], "resource/2月22日(24).png", 34, 34);loadimage(&kunkun[25], "resource/2月22日(25).png", 34, 34);loadimage(&kunkun[26], "resource/2月22日(26).png", 34, 34);loadimage(&kunkun[27], "resource/2月22日(27).png", 34, 34);loadimage(&kunkun[28], "resource/2月22日(28).png", 34, 34);loadimage(&kunkun[29], "resource/2月22日(29).png", 34, 34);loadimage(&kunkun[30], "resource/2月22日(30).png", 34, 34);loadimage(&kunkun[31], "resource/2月22日(31).png", 34, 34);loadimage(&kunkun[32], "resource/2月22日(32).png", 34, 34);loadimage(&kunkun[33], "resource/2月22日(33).png", 34, 34);loadimage(&kunkun[34], "resource/2月22日(34).png", 34, 34);loadimage(&kunkun[35], "resource/2月22日(35).png", 34, 34);loadimage(&kunkun[36], "resource/2月22日(36).png", 34, 34);loadimage(&kunkun[37], "resource/2月22日(37).png", 34, 34);loadimage(&kunkun[38], "resource/2月22日(38).png", 34, 34);loadimage(&kunkun[39], "resource/2月22日(39).png", 34, 34);loadimage(&kunkun[40], "resource/2月22日(40).png", 34, 34);loadimage(&kunkun[41], "resource/2月22日(41).png", 34, 34);loadimage(&kunkun[42], "resource/2月22日(42).png", 34, 34);loadimage(&kunkun[43], "resource/2月22日(43).png", 34, 34);loadimage(&kunkun[44], "resource/2月22日(44).png", 34, 34);loadimage(&kunkun[45], "resource/2月22日(45).png", 34, 34);loadimage(&kunkun[46], "resource/2月22日(46).png", 34, 34);loadimage(&kunkun[47], "resource/2月22日(47).png", 34, 34);loadimage(&kunkun[48], "resource/2月22日(48).png", 34, 34);loadimage(&kunkun[49], "resource/2月22日(49).png", 34, 34);loadimage(&kunkun[50], "resource/2月22日(50).png", 34, 34);loadimage(&kunkun[51], "resource/2月22日(51).png", 34, 34);loadimage(&kunkun[52], "resource/2月22日(52).png", 34, 34);loadimage(&kunkun[53], "resource/2月22日(53).png", 34, 34);loadimage(&kunkun[54], "resource/2月22日(54).png", 34, 34);loadimage(&kunkun[55], "resource/2月22日(55).png", 34, 34);loadimage(&kunkun[56], "resource/2月22日(56).png", 34, 34);for (int i = 0; i < Ball_num; i++){loadimage(&ball[i], "resource/5459.png_860.png", 36, 36);}
4. 繪制圖片
圖片是需要根據球來移動的,所以putimage函數的格式應該為:
putimage(x, y, Wide, Hight, &kunkun[a], 0, 0,SRCAND);
x, y
:圖像左上角在窗口中的坐標。Wide, Hight
:要繪制的圖像的寬度和高度。&kunkun[a]
:指向圖像數據數組的指針,a
是數組中圖像數據的索引。0, 0
:源圖像中要復制的區域的左上角坐標。
這樣圖片的位置就可以根據球的為止移動了。?
void show()
{srand((unsigned)time(NULL));//清屏函數cleardevice();//setbkcolor(WHITE);putimage(0, 0, &img[Img]);putimage(0, 0, &Heal[Health], SRCAND);for (int i = 0; i < Ball_num; i++){setfillcolor(RGB(229, 124, 77));solidcircle(Enemy[i].x, Enemy[i].y, Enemy[i].r);}putimage(Player.x - 14, Player.y - 14, Wide, Hight, &kunkun[a], 0, 0,SRCAND);for (int i = 0; i < Ball_num; i++){putimage(Enemy[i].x - 18, Enemy[i].y - 18, Wide, Hight, &ball[i], 0, 0, SRCAND);}
}
?5. 籃球的移動
隨機生成8個隨機數,然后根據這八個隨機數在執行向下移動的同時執行向左或向右的指令。為了防止籃球的移動速度太快,我們需要加一個Sleep(10)函數給它降速。當籃球移動出游戲界面的時候我們讓它重新生成。
void Enemy_move()
{srand((unsigned)time(NULL));for (int i = 0; i < Ball_num; i++){int direction = rand() % 8;if (direction == 0){Enemy[i].y++;Enemy[i].x--;}else if (direction == 1){Enemy[i].y++;Enemy[i].x++;}else if (direction == 2){Enemy[i].y += 2;Enemy[i].x += 2;}else if (direction == 3){Enemy[i].y += 2;Enemy[i].x -= 2;}else if (direction == 4){Enemy[i].y += 3;Enemy[i].x += 3;}else if (direction == 5){Enemy[i].y += 3;Enemy[i].x -= 3;}else if (direction == 6){Enemy[i].y += 4;Enemy[i].x -= 4;}else if (direction == 7){Enemy[i].y += 4;Enemy[i].x += 4;}if (Enemy[i].x <0 || Enemy[i].x>Wide || Enemy[i].y > Hight - Player.r * 3){Enemy[i].x = Wide / 2;Enemy[i].y = 10;Enemy[i].r = 10;}}
}
6.?玩家與球碰撞
生成游戲血條,每碰撞一次血條減少,并且重新生成籃球。
IMAGE Heal[6];loadimage(&Heal[5], "resource/微信圖片_20240303142935.jpg");loadimage(&Heal[4], "resource/微信圖片_20240303142958.jpg");loadimage(&Heal[3], "resource/微信圖片_20240303142931.jpg");loadimage(&Heal[2], "resource/微信圖片_20240303142926.jpg");loadimage(&Heal[1], "resource/微信圖片_20240303142922.jpg");
//玩家與球碰撞
void collide()
{for (int i = 0; i < Ball_num; i++){if (Distance(Player.x, Player.y, Enemy[i].x, Enemy[i].y) < Player.r + Enemy[i].r && Health > 0){Health--;Enemy[i].x = Wide / 2;Enemy[i].y = 10;Enemy[i].r = 10;}}}
7. 人物的移動?
在這里需要用到GetAsyncKeyState(vk virtual key)函數獲取異步按鍵狀態,其中vk virtual key是虛擬鍵值,如果接受到這個虛擬鍵值,它會返回真。VK_UP、VK_LEFT、VK_RIGHT、0x20、0x41、0x44、0x57分別是上箭頭鍵、左箭頭鍵、右箭頭鍵、空格鍵、a、d、w的虛擬鍵值。最后這里比較難處理的就是跳躍的這個動作了,我在這里設置人物跳躍后最高上升60個像素格,然后通過while循環循環上升每次上升5個像素個,如果是直接上升60個像素格的話,就是閃現了達不到跳躍的效果,在人物上升的同時其他動作是任然要進行的,所以我們還需要將這些動作函數打包放到這個人物跳躍的while循環當中。值得注意的是我們還需要在這個while循環中加一個Sleep(20)調節循環速度,使這里運動速度與主函數的while循環的運動速度一致。
void player_move()
{if (GetAsyncKeyState(VK_LEFT)|| GetAsyncKeyState(0x41)){if (Player.x > 0)Player.x -= Player_sleep;}if (GetAsyncKeyState(VK_RIGHT)|| GetAsyncKeyState(0x44)){if (Player.x < Wide)Player.x += Player_sleep;}if (Player.y == Hight - Player.r * 4){if (GetAsyncKeyState(0x20) || GetAsyncKeyState(0x57)|| GetAsyncKeyState(VK_UP)){BeginBatchDraw();while (Player.y > Hight - Player.r * 4 - 60){Sleep(20);Player.y -= 5;player_move();Enemy_move();show();collide();FlushBatchDraw();}}if (Health == 0){printf("\a");system("pause");exit(0);}}
}
效果展示:
坤坤的籃球回避秀
源碼:
#include<stdio.h>
#include<easyx.h>
#include<time.h>
#include<windows.h>
#include<mmsystem.h>
#include<math.h>
#pragma comment(lib,"winmm.lib")
#define Wide 1280
#define Hight 720
#define Wide1 780
#define Hight1 286
#define Ball_num 20
#define Player_sleep 5
int Health = 5;
int sleep = 1;
int Img = 0;
struct Ball
{float x = 0;int y = 0;float r = 0;};
struct Ball Enemy[Ball_num];
struct Ball Player;
IMAGE img[2];
IMAGE kunkun[58];
IMAGE ball[Ball_num];
IMAGE Heal[6];
int a = 0;
//加載圖片
void Init()
{loadimage(&img[0], "resource/微信圖片_20240222202456.jpg");loadimage(&img[1], "resource/微信圖片_20240303132408.jpg");loadimage(&Heal[5], "resource/微信圖片_20240303142935.jpg");loadimage(&Heal[4], "resource/微信圖片_20240303142958.jpg");loadimage(&Heal[3], "resource/微信圖片_20240303142931.jpg");loadimage(&Heal[2], "resource/微信圖片_20240303142926.jpg");loadimage(&Heal[1], "resource/微信圖片_20240303142922.jpg");loadimage(&kunkun[0], "resource/2月22日.png", 34, 34);loadimage(&kunkun[1], "resource/2月22日(1).png", 34, 34);loadimage(&kunkun[2], "resource/2月22日(2).png", 34, 34);loadimage(&kunkun[3], "resource/2月22日(3).png", 34, 34);loadimage(&kunkun[4], "resource/2月22日(4).png", 34, 34);loadimage(&kunkun[5], "resource/2月22日(5).png", 34, 34);loadimage(&kunkun[6], "resource/2月22日(6).png", 34, 34);loadimage(&kunkun[7], "resource/2月22日(7).png", 34, 34);loadimage(&kunkun[8], "resource/2月22日(8).png", 34, 34);loadimage(&kunkun[9], "resource/2月22日(9).png", 34, 34);loadimage(&kunkun[10], "resource/2月22日(10).png", 34, 34);loadimage(&kunkun[11], "resource/2月22日(11).png", 34, 34);loadimage(&kunkun[12], "resource/2月22日(12).png", 34, 34);loadimage(&kunkun[13], "resource/2月22日(13).png", 34, 34);loadimage(&kunkun[14], "resource/2月22日(14).png", 34, 34);loadimage(&kunkun[15], "resource/2月22日(15).png", 34, 34);loadimage(&kunkun[16], "resource/2月22日(16).png", 34, 34);loadimage(&kunkun[17], "resource/2月22日(17).png", 34, 34);loadimage(&kunkun[18], "resource/2月22日(18).png", 34, 34);loadimage(&kunkun[19], "resource/2月22日(19).png", 34, 34);loadimage(&kunkun[20], "resource/2月22日(20).png", 34, 34);loadimage(&kunkun[21], "resource/2月22日(21).png", 34, 34);loadimage(&kunkun[22], "resource/2月22日(22).png", 34, 34);loadimage(&kunkun[23], "resource/2月22日(23).png", 34, 34);loadimage(&kunkun[24], "resource/2月22日(24).png", 34, 34);loadimage(&kunkun[25], "resource/2月22日(25).png", 34, 34);loadimage(&kunkun[26], "resource/2月22日(26).png", 34, 34);loadimage(&kunkun[27], "resource/2月22日(27).png", 34, 34);loadimage(&kunkun[28], "resource/2月22日(28).png", 34, 34);loadimage(&kunkun[29], "resource/2月22日(29).png", 34, 34);loadimage(&kunkun[30], "resource/2月22日(30).png", 34, 34);loadimage(&kunkun[31], "resource/2月22日(31).png", 34, 34);loadimage(&kunkun[32], "resource/2月22日(32).png", 34, 34);loadimage(&kunkun[33], "resource/2月22日(33).png", 34, 34);loadimage(&kunkun[34], "resource/2月22日(34).png", 34, 34);loadimage(&kunkun[35], "resource/2月22日(35).png", 34, 34);loadimage(&kunkun[36], "resource/2月22日(36).png", 34, 34);loadimage(&kunkun[37], "resource/2月22日(37).png", 34, 34);loadimage(&kunkun[38], "resource/2月22日(38).png", 34, 34);loadimage(&kunkun[39], "resource/2月22日(39).png", 34, 34);loadimage(&kunkun[40], "resource/2月22日(40).png", 34, 34);loadimage(&kunkun[41], "resource/2月22日(41).png", 34, 34);loadimage(&kunkun[42], "resource/2月22日(42).png", 34, 34);loadimage(&kunkun[43], "resource/2月22日(43).png", 34, 34);loadimage(&kunkun[44], "resource/2月22日(44).png", 34, 34);loadimage(&kunkun[45], "resource/2月22日(45).png", 34, 34);loadimage(&kunkun[46], "resource/2月22日(46).png", 34, 34);loadimage(&kunkun[47], "resource/2月22日(47).png", 34, 34);loadimage(&kunkun[48], "resource/2月22日(48).png", 34, 34);loadimage(&kunkun[49], "resource/2月22日(49).png", 34, 34);loadimage(&kunkun[50], "resource/2月22日(50).png", 34, 34);loadimage(&kunkun[51], "resource/2月22日(51).png", 34, 34);loadimage(&kunkun[52], "resource/2月22日(52).png", 34, 34);loadimage(&kunkun[53], "resource/2月22日(53).png", 34, 34);loadimage(&kunkun[54], "resource/2月22日(54).png", 34, 34);loadimage(&kunkun[55], "resource/2月22日(55).png", 34, 34);loadimage(&kunkun[56], "resource/2月22日(56).png", 34, 34);for (int i = 0; i < Ball_num; i++){loadimage(&ball[i], "resource/5459.png_860.png", 36, 36);}
}
//初始化小球的信息
void Itset()
{//for (int i = 0; i < Ball_num; i++){Enemy[i].x = Wide / 2;Enemy[i].y = 10;Enemy[i].r = 10;}//玩家Player.x = Wide / 2;Player.r = 10;Player.y = Hight - Player.r * 4;
}
void Enemy_move()
{srand((unsigned)time(NULL));for (int i = 0; i < Ball_num; i++){int direction = rand() % 8;if (direction == 0){Enemy[i].y++;Enemy[i].x--;}else if (direction == 1){Enemy[i].y++;Enemy[i].x++;}else if (direction == 2){Enemy[i].y += 2;Enemy[i].x += 2;}else if (direction == 3){Enemy[i].y += 2;Enemy[i].x -= 2;}else if (direction == 4){Enemy[i].y += 3;Enemy[i].x += 3;}else if (direction == 5){Enemy[i].y += 3;Enemy[i].x -= 3;}else if (direction == 6){Enemy[i].y += 4;Enemy[i].x -= 4;}else if (direction == 7){Enemy[i].y += 4;Enemy[i].x += 4;}if (Enemy[i].x <0 || Enemy[i].x>Wide || Enemy[i].y > Hight - Player.r * 3){Enemy[i].x = Wide / 2;Enemy[i].y = 10;Enemy[i].r = 10;}}
}
void show()
{srand((unsigned)time(NULL));cleardevice();putimage(0, 0, &img[Img]);putimage(0, 0, &Heal[Health], SRCAND);for (int i = 0; i < Ball_num; i++){setfillcolor(RGB(229, 124, 77));solidcircle(Enemy[i].x, Enemy[i].y, Enemy[i].r);}putimage(Player.x - 14, Player.y - 14, Wide, Hight, &kunkun[a], 0, 0,SRCAND);for (int i = 0; i < Ball_num; i++){putimage(Enemy[i].x - 18, Enemy[i].y - 18, Wide, Hight, &ball[i], 0, 0, SRCAND);}
}
//距離
int Distance(int x, int y, int x1, int y1)
{return sqrt((x - x1) * (x - x1) + (y - y1) * (y - y1));
}
//玩家與球碰撞
void collide()
{for (int i = 0; i < Ball_num; i++){if (Distance(Player.x, Player.y, Enemy[i].x, Enemy[i].y) < Player.r + Enemy[i].r && Health > 0){Health--;Enemy[i].x = Wide / 2;Enemy[i].y = 10;Enemy[i].r = 10;}}}
void player_move()
{if (GetAsyncKeyState(VK_LEFT)|| GetAsyncKeyState(0x41)){if (Player.x > 0)Player.x -= Player_sleep;}if (GetAsyncKeyState(VK_RIGHT)|| GetAsyncKeyState(0x44)){if (Player.x < Wide)Player.x += Player_sleep;}if (Player.y == Hight - Player.r * 4){if (GetAsyncKeyState(0x20) || GetAsyncKeyState(0x57)|| GetAsyncKeyState(VK_UP)){BeginBatchDraw();while (Player.y > Hight - Player.r * 4 - 60){Sleep(20);Player.y -= 5;player_move();Enemy_move();show();collide();FlushBatchDraw();}}if (Health == 0){printf("\a");system("pause");exit(0);}}
}
int main()
{Init();Itset();initgraph(Wide, Hight);BeginBatchDraw();while (1){Sleep(20);if (a <= 56){a++;}if (a > 56){a = 0;}if (Player.y < Hight - Player.r * 4){Player.y += 2;}if (sleep > 0){sleep--;}if (Health == 0)Img = 1;show();FlushBatchDraw();Enemy_move();player_move();collide();}closegraph;return 0;
}