發(fā)布時(shí)間:2023-11-27 04:57:43 瀏覽量:118次
每天一個(gè)C語言小項(xiàng)目,提升你的編程能力!
【第一版】
花了一天時(shí)間,用 easyx 做了一個(gè)小游戲,程序中所有的類函數(shù)都是內(nèi)聯(lián)函數(shù),大約 300 行。
【第二版】
主要做了代碼優(yōu)化,加強(qiáng)可讀性。
同時(shí)改了操作方式,玩家和敵人都可以在 x、y 方向上移動(dòng),敵人每隔一段時(shí)間會(huì)隨機(jī)換向。
游戲運(yùn)行截圖如下:
操作方式
玩家通過方向鍵移動(dòng),z 鍵射擊,左 Shift 進(jìn)入低速移動(dòng)模式提高操作精度。
代碼說明
關(guān)于無阻塞延時(shí),首先,先要 ctime 創(chuàng)建一個(gè) clock_t 變量 a,初始化為 clock(),貌似是自從 1970 年到現(xiàn)在的毫秒數(shù)。
我們要每隔 0.5 秒執(zhí)行函數(shù) func() 一次。
那么創(chuàng)建主循環(huán) while(1),調(diào)用前用 clock() - a;如果 clock() - a > 500,那么執(zhí)行 func(),并把 a 重新賦值為 clock()。
如果使用 Sleep(500) 的話,這個(gè)循環(huán)就只能執(zhí)行 func 函數(shù)了,在此期間什么也做不了。
(直接上源碼,大家可以看注釋)
/* 作者:STF(QQ:2292683261)*/
#include <easyx.h>
#include <cstdlib>
#include <ctime>
void hp_bar();
void show_player();
void show_enemy();
void move_enemy();
void draw_background();
int generate_line(); // 若返回 -1,表示生成線條失敗
int create_p_b(); // 創(chuàng)建自機(jī)的子彈
int create_e_b(); // 創(chuàng)建敵機(jī)的子彈
int destroy_p_b(int index);
int destroy_e_b(int index); // 刪除一個(gè)子彈
#define FRAMERATE 20 // 畫面刷新的周期(ms)
#define FIRERATE 350 // 射擊間隔時(shí)間
#define E_FIRERATE 350 // 敵人射擊間隔
#define BLEED_TIME 150 // 受傷閃爍時(shí)間
#define BACKGROUND 80 // 繪制背景線條的周期
#define MAX_LINES 75 // 最多同屏背景線條數(shù)目
#define MAX_PLAYER_BULLETS 40 // 最多同屏自機(jī)子彈數(shù)目
#define MAX_ENEMY_BULLETS 40 // 最多同屏敵機(jī)子彈數(shù)目
int player_pos[2] = { 30,30 }; // 自機(jī)位置xy
int enemy_bullet[MAX_ENEMY_BULLETS][2]; // 敵人的子彈位置
int player_bullet[MAX_PLAYER_BULLETS][2]; // 自機(jī)的子彈位置
int enemy_pos[2] = { 580,240 }; // 敵機(jī)位置
bool p_b_slots[MAX_PLAYER_BULLETS] = { false }; // 用于判斷 player_bullet 的某個(gè)位置是否可用
bool e_b_slots[MAX_ENEMY_BULLETS] = { false };
int number_p_b = 0, number_e_b = 0; // 記錄自機(jī)和敵機(jī)的子彈數(shù),減少遍歷壓力
int player_health = 100, enemy_health = 100;
bool isBleeding_p = false, isBleeding_e = false; // 用于實(shí)現(xiàn)命中后的閃爍效果
int background_line[MAX_LINES][3]; // 背景的線條,三個(gè)參數(shù)分別是 x、y、長度
bool line_slots[MAX_LINES] = { false };
int number_lines = 0; // 記錄背景線條數(shù)目
clock_t begin_time = 0;
int main()
{
initgraph(640, 550, 4);
srand((unsigned)time(NULL));
settextcolor(RGB(0, 254, 0));
settextstyle(30, 0, L"微軟雅黑");
outtextxy(50, 200, L"方向鍵移動(dòng), Z 攻擊, 左 Shift 切換低速模式");
bool win = false, dead = false;
clock_t firerate = clock(); // 射擊控制
clock_t e_firerate = clock(); // 控制敵機(jī)的射擊
clock_t runtime = clock(); // 用于控制畫面刷新頻率
clock_t bleed_p = clock(), bleed_e = clock(); // 用于實(shí)現(xiàn)受傷閃爍
clock_t backgroundline_generate = clock(); // 用于生成背景線條
Sleep(3000);
BeginBatchDraw();
bool leftshift = false;
begin_time = clock();
while (true)
{
if (clock() - runtime >= FRAMERATE)
{
runtime = clock();
cleardevice();
draw_background();
hp_bar();// 畫血條
show_player();
show_enemy();
int n_p_b = 1, n_e_b = 1; // 計(jì)數(shù),遍歷子彈,刷新位置
int p_b_toprocess = number_p_b, e_b_toprocess = number_e_b; // 需要處理的子彈數(shù)
for (int i = 0; i < MAX_PLAYER_BULLETS && (n_p_b <= p_b_toprocess || n_e_b <= e_b_toprocess); ++i)
{
if (n_p_b <= p_b_toprocess) // 如果子彈已經(jīng)處理完就不處理了
{
if (p_b_slots[i] == true)
{
++n_p_b;
player_bullet[i][0] += 3;
setfillcolor(RGB(150, 180, 210));
if (player_bullet[i][0] >= 635)
{
destroy_p_b(i); // 到達(dá)了屏幕最右端
}
// 碰撞檢測,兩個(gè)矩形
if ((player_bullet[i][0] + 5 >= enemy_pos[0] - 20 && player_bullet[i][0] - 5 <= enemy_pos[0] + 20) && (player_bullet[i][1] - 5 < enemy_pos[1] + 40 && player_bullet[i][1] + 5 > enemy_pos[1] - 40))
// 擊中敵人
{
destroy_p_b(i);
enemy_health -= 8;
isBleeding_e = true;
bleed_e = clock();
}
fillrectangle(player_bullet[i][0] - 5, player_bullet[i][1] - 5, player_bullet[i][0] + 5, player_bullet[i][1] + 5); // 畫子彈
}
}
if (n_e_b <= e_b_toprocess) // 敵人的子彈
{
if (e_b_slots[i] == true)
{
++n_e_b;
enemy_bullet[i][0] -= 3;
setfillcolor(RGB(255, 180, 20));
if (enemy_bullet[i][0] < 5)
{
destroy_e_b(i);
}
// 碰撞檢測,兩個(gè)矩形
if (enemy_bullet[i][0] - 5 < player_pos[0] + 25 && enemy_bullet[i][0] + 5 > player_pos[0] - 25 && enemy_bullet[i][1] - 5 < player_pos[1] + 25 && enemy_bullet[i][1] + 5 > player_pos[1] - 25)
{
// 擊中自機(jī)
isBleeding_p = true;
destroy_e_b(i);
player_health -= 8;
bleed_p = clock();
}
fillrectangle(enemy_bullet[i][0] - 5, enemy_bullet[i][1] - 5, enemy_bullet[i][0] + 5, enemy_bullet[i][1] + 5);
}
}
}
if (win || dead)
break;
FlushBatchDraw();
move_enemy();
if (player_health <= 0)
dead = true;
if (enemy_health <= 0)
{
win = true;
}
if (GetAsyncKeyState(VK_LSHIFT) & 0x8000) // 按住 Shift 減速
{
leftshift = true;
}
else
{
leftshift = false;
}
if (GetAsyncKeyState(VK_UP) & 0x8000)
// 玩家移動(dòng)
{
if (player_pos[1] >= 28)
if (leftshift)
player_pos[1] -= 2; // y 的正方向是向下的
else
player_pos[1] -= 5;
}
if (clock() - firerate >= FIRERATE && GetAsyncKeyState('Z') & 0x8000)
// 玩家開火
{
firerate = clock();
create_p_b();
}
if (GetAsyncKeyState(VK_DOWN) & 0x8000)
// 玩家移動(dòng)
{
if (player_pos[1] <= 452)
if (leftshift)
player_pos[1] += 2;
else
player_pos[1] += 5;
}
if (GetAsyncKeyState(VK_LEFT) & 0x8000)
// 玩家移動(dòng)
{
if (player_pos[0] >= 30)
if (leftshift)
player_pos[0] -= 2;
else
player_pos[0] -= 5;
}
if (GetAsyncKeyState(VK_RIGHT) & 0x8000)
// 玩家移動(dòng)
{
if (player_pos[0] <= 320)
if (leftshift)
player_pos[0] += 2;
else
player_pos[0] += 5;
}
if (clock() - e_firerate >= E_FIRERATE)
{
e_firerate = clock();
create_e_b();
}
if (clock() - bleed_p >= BLEED_TIME) // 受傷時(shí)間結(jié)束后關(guān)閉受傷閃爍效果
{
isBleeding_p = false;
}
if (clock() - bleed_e >= BLEED_TIME) // 受傷時(shí)間結(jié)束后關(guān)閉受傷閃爍效果
{
isBleeding_e = false;
}
if (clock() - backgroundline_generate >= BACKGROUND)
{
backgroundline_generate = clock();
generate_line();
}
}
}
if (win)
{
settextcolor(RGB(0, 254, 0));
settextstyle(35, 0, L"黑體");
outtextxy(150, 200, L"你打敗了boss!你贏了??!");
}
else
{
settextcolor(RGB(254, 0, 0));
settextstyle(35, 0, L"黑體");
outtextxy(140, 200, L"你被boss打敗了!");
}
FlushBatchDraw();
Sleep(5000);
EndBatchDraw();
return 0;
}
void hp_bar()
{
setlinecolor(RGB(255, 255, 255));
line(0, 481, 640, 481); // 一條分割線
settextstyle(20, 0, L"黑體");
outtextxy(10, 485, L"BOSS的生命值:");
outtextxy(10, 520, L"玩家的生命值:");
setfillcolor(RGB(0, 255, 1));
setlinecolor(WHITE);
rectangle(160, 515, 560, 540); // 血條外框
setfillcolor(RGB(0, 255, 1));
setlinecolor(RGB(255, 255, 255));
if (player_health > 0)
fillrectangle(160, 515, 160 + player_health * 4, 540); // 玩家血條
setlinecolor(WHITE);
rectangle(160, 485, 560, 510); // 敵人血條外框
setfillcolor(RGB(230, 0, 1));
setlinecolor(RGB(255, 255, 255));
if (enemy_health > 0)
fillrectangle(160, 485, 160 + enemy_health * 4, 510); // 敵人血條
}
void show_player()
{
if (isBleeding_p)
setfillcolor(RGB(255, 0, 0));
else
setfillcolor(RGB(150, 180, 210));
fillrectangle(player_pos[0] - 25, player_pos[1] - 25, player_pos[0] + 25, player_pos[1] + 25);
setfillcolor(RGB(100, 200, 180));
fillrectangle(player_pos[0], player_pos[1] + 5, player_pos[0] + 40, player_pos[1] - 5);
}
void show_enemy()
{
if (isBleeding_e)
setfillcolor(RGB(255, 0, 0));
else
setfillcolor(RGB(0, 130, 125));
fillrectangle(enemy_pos[0] - 20, enemy_pos[1] - 40, enemy_pos[0] + 20, enemy_pos[1] + 40);
setfillcolor(RGB(100, 200, 180));
fillrectangle(enemy_pos[0], enemy_pos[1] + 5, enemy_pos[0] - 40, enemy_pos[1] - 5);
}
void move_enemy()
{
static bool angle_v; // 控制敵機(jī)的豎直移動(dòng)方向,true 為向上,到邊緣就換向
static bool angle_h; // 控制敵機(jī)的水平移動(dòng)方向,true 為向左,到邊緣就換向
static clock_t interval; // 定時(shí)隨機(jī)換向
if (clock() - interval >= 2000)
{
interval = clock();
if (rand() % 2) // 一般的概率換向
angle_v = !angle_v;
if (rand() % 2)
angle_h = !angle_h;
}
if (angle_v == true) // 到了地圖邊緣就調(diào)頭
enemy_pos[1] -= 3;
else
enemy_pos[1] += 3;
if (angle_h == true)
enemy_pos[0] -= 3;
else
enemy_pos[0] += 3;
if (enemy_pos[1] >= 440)
angle_v = true;
else if (enemy_pos[1] <= 40)
angle_v = false;
if (enemy_pos[0] >= 580)
angle_h = true;
else if (enemy_pos[0] <= 380)
angle_h = false;
}
void draw_background()
{
setlinecolor(WHITE);
int n_b_l = number_lines; // 待處理線條數(shù)目
for (int i = 0; i < MAX_LINES && (n_b_l > 0); ++i)
{
if (line_slots[i] == true)
{
if (background_line[i][0] + background_line[i][2] <= 0) // 說明線條出了屏幕
{
--number_lines;
line_slots[i] = false;
}
else
{
background_line[i][0] -= 10; // 線條移動(dòng)
line(background_line[i][0], background_line[i][1], background_line[i][0] + background_line[i][2], background_line[i][1]);
}
--n_b_l;
}
}
}
int generate_line()
{
if (number_lines >= MAX_LINES)
return -1;
++number_lines;
for (int i = 0; i < MAX_LINES; ++i)
{
if (line_slots[i] == false)
{
line_slots[i] = true;
background_line[i][0] = 640; // 線條出現(xiàn)于屏幕最右邊
background_line[i][1] = rand() % 480; // 線條高度隨機(jī)
background_line[i][2] = 10 + rand() % 50; // 線條長度隨機(jī)在 10-50 像素之間
break;
}
}
return 0;
}
int create_p_b()
{
if (number_p_b > MAX_PLAYER_BULLETS) // 空間不夠
return -1;
for (int i = 0; i < MAX_PLAYER_BULLETS; ++i) // 搜索 slots,尋找空位
{
if (p_b_slots[i] == false)
{
p_b_slots[i] = true;
player_bullet[i][0] = player_pos[0] + 45;
player_bullet[i][1] = player_pos[1]; // 創(chuàng)建子彈
++number_p_b;
break;
}
}
return 0;
}
int create_e_b()
{
if (number_e_b > MAX_ENEMY_BULLETS) // 空間不夠
return -1;
for (int i = 0; i < MAX_ENEMY_BULLETS; ++i) // 搜索 slots,尋找空位
{
if (e_b_slots[i] == false)
{
e_b_slots[i] = true;
enemy_bullet[i][0] = enemy_pos[0] - 45;
enemy_bullet[i][1] = enemy_pos[1]; // 創(chuàng)建子彈
++number_e_b;
break;
}
}
return 0;
}
int destroy_p_b(int index)
{
if (index > MAX_PLAYER_BULLETS - 1)
return -2;
if (p_b_slots[index] == false)
return -1;
p_b_slots[index] = false;
--number_p_b;
return 0;
}
int destroy_e_b(int index)
{
if (index > MAX_ENEMY_BULLETS - 1)
return -2;
if (e_b_slots[index] == false)
return -1;
e_b_slots[index] = false;
--number_e_b;
return 0;
}
大家趕緊去動(dòng)手試試吧!
此外,我也給大家分享我收集的其他資源,從最零基礎(chǔ)開始的教程到C語言C++項(xiàng)目案例,幫助大家在學(xué)習(xí)C語言的道路上披荊斬棘!
編程學(xué)習(xí)書籍分享:
編程學(xué)習(xí)視頻分享:
整理分享(多年學(xué)習(xí)的源碼、項(xiàng)目實(shí)戰(zhàn)視頻、項(xiàng)目筆記,基礎(chǔ)入門教程)最重要的是你可以在群里面交流提問編程問題哦!
對(duì)于C/C++感興趣可以關(guān)注小編在后臺(tái)私信我:【編程交流】一起來學(xué)習(xí)哦!可以領(lǐng)取一些C/C++的項(xiàng)目學(xué)習(xí)視頻資料哦!已經(jīng)設(shè)置好了關(guān)鍵詞自動(dòng)回復(fù),自動(dòng)領(lǐng)取就好了!
熱門資訊
探討游戲引擎的文章,介紹了10款游戲引擎及其代表作品,涵蓋了RAGE Engine、Naughty Dog Game Engine、The Dead Engine、Cry Engine、Avalanche Engine、Anvil Engine、IW Engine、Frostbite Engine、Creation引擎、Unreal Engine等引擎。借此分析引出了游戲設(shè)計(jì)領(lǐng)域和數(shù)字藝術(shù)教育的重要性,歡迎點(diǎn)擊咨詢報(bào)名。
2. 手機(jī)游戲如何開發(fā)(如何制作傳奇手游,都需要準(zhǔn)備些什么?)
?如何制作傳奇手游,都需要準(zhǔn)備些什么?提到傳奇手游相信大家都不陌生,他是許多80、90后的回憶;從起初的端游到現(xiàn)在的手游,說明時(shí)代在進(jìn)步游戲在更新,更趨于方便化移動(dòng)化。而如果我們想要制作一款傳奇手游的
3. B站視頻剪輯軟件「必剪」:免費(fèi)、炫酷特效,小白必備工具
B站視頻剪輯軟件「必剪」,完全免費(fèi)、一鍵制作炫酷特效,適合新手小白??靵碓囋嚕?/span>
4. Steam值得入手的武俠游戲盤點(diǎn),各具特色的快意江湖
游戲中玩家將面臨武俠人生的掙扎抉擇,戰(zhàn)或降?殺或放?每個(gè)抉定都將觸發(fā)更多愛恨糾葛的精彩奇遇?!短烀嬗肪哂卸嗑€劇情多結(jié)局,不限主線發(fā)展,高自由...
5. Bigtime加密游戲經(jīng)濟(jì)體系揭秘,不同玩家角色的經(jīng)濟(jì)活動(dòng)
Bigtime加密游戲經(jīng)濟(jì)模型分析,探討游戲經(jīng)濟(jì)特點(diǎn),幫助玩家更全面了解這款GameFi產(chǎn)品。
6. 3D動(dòng)漫建模全過程,不是一般人能學(xué)的會(huì)的,會(huì)的多不是人?
步驟01:面部,頸部,身體在一起這次我不準(zhǔn)備設(shè)計(jì)圖片,我從雕刻進(jìn)入。這一次,它將是一種純粹關(guān)注建模而非整體繪畫的形式。像往常一樣,我從Sphere創(chuàng)建它...
7. 3D動(dòng)畫軟件你知道幾個(gè)?3ds Max、Blender、Maya、Houdini大比拼
當(dāng)提到3D動(dòng)畫軟件或動(dòng)畫工具時(shí),指的是數(shù)字內(nèi)容創(chuàng)建工具。它是用于造型、建模以及繪制3D美術(shù)動(dòng)畫的軟件程序。但是,在3D動(dòng)畫軟件中還包含了其他類型的...
?三昧動(dòng)漫對(duì)于著名ARPG游戲《巫師》系列,最近CD Projekt 的高層回應(yīng)并不會(huì)推出《巫師4》。因?yàn)椤段讕煛废盗性诓邉澋臅r(shí)候一直定位在“三部曲”的故事框架,所以在游戲的出品上不可能出現(xiàn)《巫師4》
9. 3D打印技巧揭秘!Cura設(shè)置讓你的模型更堅(jiān)固
想讓你的3D打印模型更堅(jiān)固?不妨嘗試一下Cura參數(shù)設(shè)置和設(shè)計(jì)技巧,讓你輕松掌握!
10. Unity3D入門:手把手帶你開發(fā)一款坦克大戰(zhàn)的游戲
Unity工程創(chuàng)建完成后如圖所示: 接下來應(yīng)該導(dǎo)入此項(xiàng)目所需的Unity Package文件,要用到的Unity package文件大家可以去Unity3D的官方網(wǎng)站下載(地址:ht...
最新文章
同學(xué)您好!