c语言大作业_2018 C语言大作业--21_Ekko制作教程
同學們實現的效果:
https://www.zhihu.com/video/1066249425780809728以下是開發同學的相關文檔:
《Ekko》設計報告
本組設計并編寫的游戲《Ekko》,是一款引用了當下紅火的網絡游戲《英雄聯盟》中的游戲角色Ekko為主角,由本組三名成員使用C語言編寫的一款橫屏動作闖關游戲。
一 設計思路
在選取游戲題材作為最終的課程設計目標時,一如許多組的同學一樣,我們曾考慮過將一個現成的游戲拿來改編,但最后我們決定自己做一款游戲。而我們要做的第一步,則是明確我們要做一款什么樣的游戲。受一款動作游戲《Super Hot》靈感,本組成員想要做一款主角擁有控制時間能力的動作游戲。
在《Super Hot》中,玩家操控的角色擁有一種令人著迷的能力:放慢時間,讓原本正常的世界的時間流動速度變慢,從而擁有更強、更從容的反應能力來應對敵人。我們認為這是一個非常酷炫的游戲概念,并想要做一款能體現這一游戲概念的游戲。
受限于我們的知識儲備,我們只能使用C語言來編寫游戲,而與此同時,我們也只能用EasyX來進行繪圖。因此,我們最終決定設計一款2D的動作游戲,而這款游戲能展現出令人著迷的控制時間的能力。
而在設計我們的主角的時候,我們亦曾想過做一個“能控制時間的忍者”,而之后我們注意到了在現今的網絡游戲中大紅大紫的競技游戲《英雄聯盟》之中,就有一個類似的能控制時間的角色:艾克(Ekko)。艾克是一名生長于名為祖安的城市的少年,擁有控制時間的能力,并利用這個能力懲奸除惡,踐行自己的價值觀,守護著祖安城。艾克的人設展現出令人欽佩的人性光彩,和他桀驁不羈的個性。我們幾乎一拍即合,決定采用Ekko作為我們游戲的主角。
而在游戲構架的構思中,我們為了最大程度體現“控制時間”這一能力,決定設計一種關卡難度極大的游戲——需要玩家細膩的操作,并且正確地使用“時間暫停”這一能力。
談及動作游戲的難度,最容易想到的有兩點:1、地圖的復雜性;2、敵人攻擊的危險性。因此,在最初的構思中,我們決定給予主角僅僅一條生命——如同《超級馬里奧》一般,被敵人的攻擊命中,便會死亡。同時,我們會設計復雜而多變的地形,以及大量的敵人、更大量的彈幕。
而我們不能只關注游戲難度是否夠高,而應同時關注玩家的游戲體驗。所以我們必須將主角的操作細節設計得足夠細膩——以回應玩家細膩的操作。
綜上,我們的游戲的基本雛形便構建完畢——在祖安城內,一位名為Ekko的少年,在大量的敵人面前把玩著自己的控制時間的能力,靈巧地躲避敵人的各種攻擊并前進,這就是我們想做出來的一款原創跑酷游戲。
二 功能描述
在我們組的《Ekko》的設計中,由我來擔任Ekko的運動的編寫,以及Ekko與地圖中各種各樣的互動。
以下為艾克——這名酷炫的時間刺客,需要具有什么樣的基礎功能,以及什么樣的“畫龍點睛”,才能給玩家一個不錯的游戲體驗。
1:顯示素材。不可否認的是,對于計科專業的同學來說,期末課設最為直接的素材收集方式為搜索互聯網。但是這對于我們組而言不可行——因為我們要做的游戲中,需要的元素大部分在網上找不到,原因則為我們游戲雖題材非原創,但游戲方式與界面卻與原素材的相去甚遠(比如英雄聯盟中的3D建模下的艾克是無法應用在我們的游戲中的)。因此,我們組只能自己去繪制我們的素材。
此外,繪制好的素材需要放在特定文件夾內,以便編程時用代碼讀取這些素材;此外,我們組還需要學會如何利用EasyX,在游戲中顯示透明的圖層。
2:人物移動。在課程中,我們學習了最基本的人物移動方法:利用getchar函數和幾個簡單的判斷,來實現人物坐標的改變。但這對于我們的Ekko是不夠的——這個函數的讀取模式存在著“第一次和第二次之間存在停頓”的問題。因此,我需要尋求更加優秀的算法來實現人物的移動。
3:與場景的碰撞。在許多簡單的游戲中,與場景的碰撞可以簡單的歸結為“和一兩個物體之間的碰撞判定”,但這個判定方式在一個更加復雜的地圖中時不成立的——我們需要編寫大量碰撞判斷,這讓代碼變得冗雜,難以閱讀和編寫,容易出錯,且不易調試。因此,我需要寫一套“碰撞法則”,以方便后期的地圖編寫。如此,只需要一套法則,就可以應對各種各樣的地圖而不易出現問題。
4:時間暫停。這個功能是我們的游戲中的亮點。Ekko正是因為能夠控制自己的時間,才能成為“撕裂時空的少年”。這一功能的實現方法很多。
5:正確的死亡。我需要編寫艾克在合何時會死亡的代碼。
三 分步驟實現方法
第一階段:繪制素材,準備好人物圖片與對應的遮罩圖;
第二階段:架構基本游戲框架,采用不同的源文件以封裝不同的功能。利用掩碼圖將人物放入,調試直至能夠正常的演示圖片,并加入最簡單的人物移動功能。為了使游戲運行更加順暢,我花費了大量的時間來構建人物的移動,代碼量多達一千行左右。以下為代碼的一部分:
if ((GetAsyncKeyState(0x41) & 0x8000)) // a
{
if (Ekko_Speed_x >= -2.5)
{
Acceleration_x = -0.1;//獲得加速度
Ekko_Speed_x += Acceleration_x;
}
else if (Ekko_Speed_x <= -3)
{
Acceleration_x = 0.8;
Ekko_Speed_x += Acceleration_x;
}
if (Crash_Wall())//如果要撞墻
{
Acceleration_x = 0;
Ekko_Speed_x = 0;
goto loop1;
}
if (Ekko_Face == 1)//變換方向
{
Ekko_Face = -1;
}
Ekko_x += Ekko_Speed_x;
if (DropOrNot == 0)
{
Status_check_i = 1;
}
else if (DropOrNot == 1)//檢測空中是否按過AD
{
AD_in_Air = 1;
}
}
需要注意的是,單獨的這一段代碼并不能看出什么直接意義。這些變量的功能穿插于許許多多的函數中,牽一發而動全身。許多變量不僅用來記錄數據,還用來記錄狀態。
第三階段:優化人物移動,加入人物和環境的碰撞的法則并測試。這一階段的完成,意味著地圖編寫工作可以正式開始;然而該階段為開發過程最為艱難的部分之一。沒有現成的物理引擎的支持,自己從頭開始寫,并非一件容易的事情,需要大量的耐心、細心,以及長時間的測試,同時這個階段面臨的BUG是最多的。
以下為碰撞代碼的核心內容:
int ABS(float A, float B) //float型絕對值。單獨定義并且用在下面的函數中
{
float C;
C = A - B;
if (C >= 0)
{
return C;
}
else
{
C = (-1)*C;
return C;
}
}
int Crash_Wall()//判斷是否即將和地形碰撞。即將 碰撞 返還 1 ,否則返還 0
{
for (int i = 0; i < Block_Number; i++)
{
if (Ekko_Speed_x > 0)
{
if (
Ekko_x + Ekko_Width / 2 <= Land_Left[i] && Ekko_x + Ekko_Speed_x + Ekko_Width / 2 > Land_Left[i]
&&
Ekko_y + Ekko_High / 2 > Land_Top[i] && Ekko_y - Ekko_High / 2 < Land_Bottom[i]
)
{
LockedOne_x = i;
return 1;
//break;
}
else if (i == LockedOne_x && ABS(Land_Left[i], Ekko_x + Ekko_Width / 2) < 4)
{
return 1;
}
else
continue;
}
else if (Ekko_Speed_x < 0)
{
if (
Ekko_x - Ekko_Width / 2 >= Land_Right[i] && Ekko_x + Ekko_Speed_x - Ekko_Width / 2 < Land_Right[i]
&&
Ekko_y + Ekko_High / 2 > Land_Top[i] && Ekko_y - Ekko_High / 2 < Land_Bottom[i]
)
{
LockedOne_x = i;
return 1;
//break;
}
else if (i == LockedOne_x && ABS(Ekko_x - Ekko_Width / 2, Land_Right[i]) < 3)
{
return 1;
}
else
continue;
}
}
return 0;
}
int Crash_Ground()//判斷和地面是否碰撞,即將碰撞返還1,否則返還0 加入了踩到地刺的判定
{
for (int i = 0; i < Block_Number; i++)
{
if (Ekko_Speed_y > 0)
{
if (
Ekko_y + Ekko_High / 2 <= Land_Top[i] && Ekko_y + Ekko_Speed_y + 0.06 + Ekko_High / 2 > Land_Top[i] //0.06是Y軸方向加速度
&&
Ekko_x + Ekko_Width / 2 > Land_Left[i] && Ekko_x - Ekko_Width / 2 < Land_Right[i]
)
{
LockedOne_y = i;
if (LockedOne_y == 6||LockedOne_y == 7 || LockedOne_y == 8 || LockedOne_y == 11 || LockedOne_y == 12 || LockedOne_y == 44 || LockedOne_y == 45 || LockedOne_y == 46 || LockedOne_y == 64 || LockedOne_y == 65 || LockedOne_y == 66)
DeadOrNot = 1;
return 1;
//break;
}
else
continue;
}
else if (DropOrNot == 1 && Ekko_Speed_y == 0)//懸空時速度為0
{
return 0;
}
else if (DropOrNot == 0 && Ekko_Speed_y == 0 && LockedOne_y == i && (Ekko_x + Ekko_Width / 2 < Land_Left[i] || Ekko_x - Ekko_Width / 2 > Land_Right[i]))//落地后速度為0但是踩空
{
return 1;
}
else if (DropOrNot == 0 && Ekko_Speed_y == 0 && LockedOne_y == i && (Ekko_x - Ekko_Width / 2 < Land_Right[i] && Ekko_x + Ekko_Width / 2 > Land_Left[i]))//落地后速度為0,踩實
{
return 0;
}
else if (Ekko_Speed_y < 0)
{
return 0;
}
}
return 0;
}
int Crash_Top()
{
for (int i = 0; i < Block_Number; i++)
{
if (Ekko_Speed_y < 0)
{
if (
Ekko_y - Ekko_High / 2 >= Land_Bottom[i] && Ekko_y + Ekko_Speed_y - Ekko_High / 2 < Land_Bottom[i]
&&
Ekko_x + Ekko_Width / 2 > Land_Left[i] && Ekko_x - Ekko_Width / 2 < Land_Right[i]
)
{
LockedOne_y = i;
return 1;
//break;
}
}
else
break;
}
return 0;
}
簡而言之,這些代碼實現了主角和任意設置好的矩形都能發生正確的碰撞,使得地圖的開發變得簡單——只需要記錄各個地圖板塊的坐標即可。
第四階段:測試人物和地圖的碰撞,并加入沖刺能力、時間減緩能力,并測試。
沖刺代碼:
static float SIN, COS;//記錄角度
AD_in_Air=0;
MOUSEMSG mouse;
mouse.uMsg = false;
if (MouseHit())
{
mouse = GetMouseMsg();
}
if (mouse.uMsg== WM_RBUTTONDOWN && Dash_Check == 0&&Dash_limit==0) //準備沖刺
{
Dash_Speed = 11;
COS = ((mouse.x - Screen_Center_x) / sqrt((mouse.y - Screen_Center_y)*(mouse.y - Screen_Center_y) + (mouse.x - Screen_Center_x)*(mouse.x - Screen_Center_x)));
SIN= ((mouse.y - Screen_Center_y) / sqrt((mouse.y - Screen_Center_y)*(mouse.y - Screen_Center_y) + (mouse.x - Screen_Center_x)*(mouse.x - Screen_Center_x)));
Ekko_Speed_x = Dash_Speed * COS;//鼠標位置決定沖刺方向
Ekko_Speed_y = Dash_Speed * SIN;
Dash_Check = 1;
Dash_limit = 1;
if (!Crash_Wall()&&!Crash_Top()&&!Crash_Ground())
{
Ekko_x += Ekko_Speed_x;
Ekko_y += Ekko_Speed_y;
}
else
{
Ekko_Speed_x = 0;
Ekko_Speed_y = 0;
Dash_Check = 0;
Dash_limit = 0;
}
if (Dash_Check==1)
{
Status_check_i = 3;//圖形演示變為沖刺
if (Ekko_Speed_x > 0)
Ekko_Face = 1;
else
Ekko_Face = -1;
DropOrNot = 1;
w_check = 1;
JumpOrNot = 1;
jump_limit_check = 1;
}
}
else if (Dash_Check == 1) //沖刺過程不可控
{
if (Dash_Speed > 3)
{
Dash_Speed -= 0.2;
}
Ekko_Speed_x = Dash_Speed * COS;
Ekko_Speed_y = Dash_Speed * SIN;
if (Crash_Wall())
{
Ekko_Speed_x = 0;
Dash_Check = 0;
}
if (Crash_Top())
{
Ekko_Speed_y = 0;
Dash_Check = 0;
}
if (Crash_Ground())
{
Ekko_Speed_y = 0;
Dash_Check = 0;
Dash_limit = 0;
}
if(Dash_Speed<=5)
{
Dash_Check = 0;
}
Ekko_x += Ekko_Speed_x;
Ekko_y += Ekko_Speed_y;
}
else //非沖刺的情況
... ...(其他功能)
第五階段:加入人物的死亡功能——被敵人的子彈擊中時死亡,墜入地底時也會死亡,碰到地刺的時候亦會死亡。
第六階段:優化、加入與Ekko語音的音樂素材。
四 體會與總結
在最后完成游戲的一瞬間,心中固然有著千般喜悅,但苦澀感依然無法散去。這一個月的開發過程并不總是一帆風順,在面對眾多的BUG和技術難關時,自己知識的匱乏徹徹底底地暴露出來了,這也迫使自己進一步去學習新的知識。
令我高興的是,游戲的效果不錯——擁有著相當流暢的游戲體驗、自己制作的素材活靈活現地展現在游戲中、游戲本身有著諸多趣味等等,依然會讓我會心一笑。在這樣的過程中,我領悟到了編程帶來的無窮樂趣,以及編程的深奧。這樣寶貴的經歷,必將促使我進行更加深入的學習,以做出讓自己更為滿意的作品!
分步驟代碼、素材、開發難點講解視頻、報告文檔,可以從百度網盤下載:
https://pan.baidu.com/s/15lDd1bAwBjsZm6oUi5NHhA?pan.baidu.com 創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎總結
以上是生活随笔為你收集整理的c语言大作业_2018 C语言大作业--21_Ekko制作教程的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: jwt获取token_Koa开发之koa
- 下一篇: 十三岁的际遇原文赏析(苏教版初一)