【Unity俯視角射擊】我們來做一個(gè)《元?dú)怛T士》的完整Demo(一)

作者:Yumir
Hi~我是Yumir。
今天開始一起把之前做的俯視角射擊整合成一個(gè)完整的游戲Demo吧~
目前計(jì)劃完成的內(nèi)容有:人物控制系統(tǒng)、怪物AI邏輯、地圖元素、游戲UI等等。先不做動(dòng)態(tài)生成(以后有機(jī)會(huì)的),雖然之前已經(jīng)寫過相關(guān)功能,在做Demo的時(shí)候還是有不少需要改動(dòng)的地方,為了更加隨心所欲的控制怪物所以自己寫了尋路腳本。
本篇分享我的人物控制系統(tǒng)是如何實(shí)現(xiàn)的,其他內(nèi)容后面也會(huì)慢慢整理出來,預(yù)計(jì)四篇。試著使用了Unity的新功能,把Demo上傳到網(wǎng)站,后面新的內(nèi)容完成也會(huì)持續(xù)更新:
https://connect.unity.com/mg/other/untitled-9864
一、前期準(zhǔn)備
寫這篇文章的時(shí)候想著是講人物控制系統(tǒng)但是沒有場景也不太好看,確實(shí)也需要做一些交代,元?dú)怛T士的素材包是以前在某個(gè)學(xué)習(xí)群看到下載的,不清楚是哪位大佬解出來的,這里把包分享出來:
鏈接:https://pan.baidu.com/share/init?surl=ndEqFLc_1nRDaHwi5ax1ww
提取碼:pkxq
我自己整合的圖比較隨性(混亂)等Demo做完再整理分享吧???。
地圖的繪制還是用之前用過的那個(gè)方法:
場景中還需要一些其他元素:
1、寶箱:
將素材中的寶箱貼圖拼接成一個(gè)完整的箱子,并制作相應(yīng)的動(dòng)畫,因?yàn)閷毼锩看尾煌嵌加幸粯拥膭?dòng)畫,所以新建一個(gè)空游戲物體用來制作上升動(dòng)畫并在使用時(shí)裝上寶箱持有的寶物。

2、告示牌:
告示牌比較簡單,碰撞中調(diào)用游戲管理腳本顯示或者隱藏場景中的提示板就行了,因?yàn)閿z像機(jī)都是一直跟隨人物的,所以我把提示板設(shè)置在畫面中心就可以了。

3、門:
門稍稍有點(diǎn)復(fù)雜,主要是因?yàn)閭?cè)面的門和前后的墻之間有遮擋關(guān)系,而門又是由很多很多個(gè)小柱子組成的,我是這樣處理的(結(jié)合TileMap繪制的層級(jí)劃分):


計(jì)劃里還有各種不同功能的箱子,但是還沒有做。
二、人物控制系統(tǒng)
關(guān)于人物控制我希望他能夠有以下功能:
使用”wasd“控制人物前后左右移動(dòng)。
除了移動(dòng)以外的基礎(chǔ)操作都由鼠標(biāo)左鍵操作(手游中也是這樣的)。
后期可以更換角色。
武器可以拾取更換。
------為了可以制作玩家預(yù)制體首先要有一個(gè)測試用的人物和一個(gè)測試用的武器------
1、人物
游戲中的人物和怪物動(dòng)畫基本上就三個(gè):待機(jī)、行動(dòng)、死亡。而且都是精靈圖動(dòng)畫,狀態(tài)機(jī)也基本是一樣的,但是由于是精靈圖動(dòng)畫所以并不能復(fù)用,角色狀態(tài)中還有一個(gè)被攻擊狀態(tài),我直接用了顏色動(dòng)畫。

2、武器
由于加入了武器拾取更換的功能,槍的動(dòng)畫就不能使用位移動(dòng)畫了,所以槍的位移動(dòng)畫是自己做了前后抖動(dòng)的精靈圖。

我新建了一個(gè)空物體作為玩家父物體,用來掛載玩家控制系統(tǒng)和物理碰撞系統(tǒng)。

在未運(yùn)行的狀態(tài)下該物體底下只有一個(gè)角色陰影,其他元素都是運(yùn)行時(shí)動(dòng)態(tài)生成,這個(gè)陰影除了使角色看起來立體之外,該位置還承擔(dān)如角色Buff顯示和選中狀態(tài)顯示這種功能,所以其實(shí)這個(gè)陰影也應(yīng)該是動(dòng)態(tài)生成的(只是我偷懶了- -)。

玩家持有的人物是在腳本中動(dòng)態(tài)生成準(zhǔn)備好的角色預(yù)制體到上述游戲物體中,槍則是到游戲中拾取。
myPlayer = Instantiate(playerPrefab, transform);
?
---------------------------準(zhǔn)備完畢之后是相關(guān)功能實(shí)現(xiàn)--------------------------------
1、人物移動(dòng)
人物的移動(dòng)依舊是利用在Update中獲取鍵盤輸入的"Horizontal"和"Vertical"的值,在FixedUpdate中更新角色的位置。
private void Update()
{
?? movement.x = Input.GetAxis("Horizontal");
?? movement.y = Input.GetAxis("Vertical");
?? if (movement == new Vector2(0, 0)){
????? playerAnima.SetBool("run", false);
?? }
??? else{
??????? playerAnima.SetBool("run", true);
?? }
}
private void FixedUpdate(){
??? rigidbody.MovePosition(rigidbody.position + movement * moveSpeed * Time.fixedDeltaTime);
}
?
2、人物朝向
人物朝向其實(shí)附帶功能還有武器朝向,我寫了一個(gè)Target字段現(xiàn)在賦值為鼠標(biāo)位置,有需要也可以修改(比如改為自瞄),考慮到武器種類不同的情況下瞄準(zhǔn)方式也會(huì)不一樣,所以人物的朝向和武器的朝向是各自管理的。

3、鼠標(biāo)左鍵操作邏輯
這個(gè)按鍵需要判斷四種狀態(tài):一種是玩家在可互動(dòng)物體周圍時(shí)左鍵操作為“互動(dòng)”,比如現(xiàn)在做的是撿起槍。另外則是長按、短按和抬起,不同武器在長按、短按、抬起這三個(gè)狀態(tài)下的操作是不一樣的。
為了判斷玩家是否在可互動(dòng)物體的周圍,我在Update中每幀由玩家向周圍發(fā)射射線檢測是否碰撞到可互動(dòng)物體,這里因?yàn)橹挥袠尵椭蛔隽藰尩呐袛辔催M(jìn)一步優(yōu)化。
weaponInFloor = null;
Collider2D[] cols = Physics2D.OverlapCircleAll(transform.position, 1);
if (cols.Length > 0){
?? for (int i = 0; i < cols.Length; i++){
?????? if (cols[i].CompareTag("Weapon")){
??????????? weaponInFloor = cols[i].gameObject;
?????? }
??? }
}
?
根據(jù)射線檢測的結(jié)果和按鍵的情況分別執(zhí)行對(duì)應(yīng)的操作:
if (weaponInFloor != null && fireKeyDown){
??? GetWeapon();
}
else{
???? if (fireKeyDown){
??????? if (weapon != null){ weapon.ShootButtonDown(); }
??????? else{ Debug.Log("沒有武器只能手刀撒"); }
???? }
???? else if(fireKeyPressed){
??????? if (weapon != null){ weapon.ShootButtonPressed();}
???? }
???? if(fireKeyUp){
??????? if (weapon != null){ weapon.ShootButtonUp(); }
???? }
}
?

武器的拾取需要根據(jù)玩家手上是否持有武器做不同動(dòng)作,相應(yīng)的武器身上也要有被撿起放下的兩個(gè)對(duì)應(yīng)方法:
void GetWeapon(){
??? if (weaponInFloor != null){
??????? //地上有槍就換槍
??????? if (weapon != null){
??????????? myWeapon.transform.SetParent(GameManager.instance.weaponRecycle);
??????????? weapon.PickDown();
??????? }
??????????? myWeapon = weaponInFloor;
??????????? weapon = myWeapon.GetComponent<Weapon>();
??????????? weapon.Pickup();
??????????? myWeapon.transform.SetParent(transform);
??????????? myWeapon.transform.localPosition = new Vector3(0, 0, 0);
??????????? myWeapon.transform.localRotation = Quaternion.identity;
??????????? //注冊(cè)
??????????? weapon.Initialization(gameObject.tag, gameObject.layer);
??? }
}
?
不同武器在對(duì)應(yīng)的狀態(tài)方法中編輯該狀態(tài)下的操作即可。
//例:Gun
public override void ShootButtonDown(){
??? if (Time.time - timing >=CD){
??????? timing = Time.time;
??????? GameObject bullet = Instantiate(bulletPrefab, pos.position, pos.rotation*Quaternion.AngleAxis(Random.Range(0,shake),Vector3.forward));
??????? bullet.GetComponent<Bullet>().Initialization(attack, role, bulletForce);
??????? GetComponent<Animator>().Play("Shoot");
???? }
}
public override void ShootButtonPressed(){
???? if (Time.time - timing >=CD){
?????? timing = Time.time;
?????? GameObject bullet = Instantiate(bulletPrefab, pos.position, pos.rotation*Quaternion.AngleAxis(Random.Range(0,shake),Vector3.forward));
?????? bullet.GetComponent<Bullet>().Initialization(attack, role, bulletForce);
?????? GetComponent<Animator>().Play("Shoot");
????? }
}
?
4、鏡頭跟隨
鏡頭跟隨這塊直接用了Cinemachine,跟著馬老師的視頻設(shè)置就可以啦:
【簡明UNITY教程】不用寫代碼的高級(jí)2D攝像機(jī) Cinemachine
三、湊一個(gè)小標(biāo)題(有感而發(fā))
由于中間跑去學(xué)ShaderGraph再回頭看俯視角射擊有種恍若隔世的感覺,慢慢找回寫代碼的狀態(tài)思路也更清晰了一些,但其實(shí)對(duì)自己現(xiàn)在寫的這個(gè)Demo并不是太滿意,大概會(huì)有漫長的打磨吧。
同時(shí)認(rèn)識(shí)到以前對(duì)俯視角射擊看得太簡單了,又或者說其實(shí)我寫的確實(shí)是俯視角射擊,但他離一個(gè)完整的游戲還是太遠(yuǎn)了。還需要更加努力,了解更多同質(zhì)類型的游戲,也需要學(xué)習(xí)更多類型的游戲。
望:與君共勉。
——分割線——
歡迎加入游戲開發(fā)群歡樂攪基:1082025059
對(duì)游戲開發(fā)感興趣的童鞋可戳這里進(jìn)一步了解:http://www.levelpp.com/