《計(jì)算機(jī)游戲開發(fā)》
期末課題實(shí)驗(yàn)報(bào)告
姓名:李基銘
班級(jí):2014211602
學(xué)號(hào):2014212123
指導(dǎo)教師:李學(xué)明
北京郵電大學(xué)數(shù)字媒體與設(shè)計(jì)藝術(shù)學(xué)院
一、游戲簡介:
《夢游大逃殺》是一款基于UNITY3D開發(fā)制作的第三人稱視角射擊生存類游戲黑忱,其游戲背景是一個(gè)畫風(fēng)非持洌卡通的小朋友西雀,在夢游過程中拿著假想的槍支和自己的毛絨玩具們展開了逃跑或是追殺(依關(guān)卡難度而定),游戲本身的每一個(gè)關(guān)卡均沒有固定的結(jié)束機(jī)制(例如到達(dá)安全屋或者殺掉足夠數(shù)量的敵人)而是更加類似于FPS游戲中的生存模式饮潦,玩家可以根據(jù)關(guān)卡的設(shè)定制定不同的策略與戰(zhàn)術(shù)南捂,并在逐漸增多的敵人面前存活盡可能長的時(shí)間。
二缸兔、游戲規(guī)則:
由于所學(xué)知識(shí)的限制和素材原因日裙,我并不能在短時(shí)間內(nèi)制作出豐富的劇情,但是游戲本身擁有四個(gè)關(guān)卡和開始界面五個(gè)場景素材惰蜜,且主角人物和敵人均設(shè)定了動(dòng)作動(dòng)畫昂拂。游戲內(nèi)所有模型(人物,地形抛猖,環(huán)境)均有碰撞檢測政钟,并為地方單位受到攻擊時(shí)添加了粒子效果路克。游戲本身擁有循環(huán)的背景音樂樟结,且開槍养交,受到傷害,死亡均設(shè)計(jì)了獨(dú)立音效瓢宦∷榱考慮到內(nèi)存和模型的原因,在槍支的設(shè)定上并未采用子彈設(shè)定驮履,而是從槍管方向添加了一條很長的ShootRay鱼辙,在主色調(diào)偏暗的游戲場景內(nèi)也更容易瞄準(zhǔn)。
游戲開始界面如下:
其中Stage Select部分由四個(gè)關(guān)卡代表的按鈕組成玫镐,點(diǎn)擊每個(gè)按鈕就可以進(jìn)入該關(guān)卡倒戏,如果點(diǎn)擊Start按鈕則直接進(jìn)入第一個(gè)關(guān)卡。此外還在右下角設(shè)置了音量按鈕恐似,可以在游戲開始前調(diào)節(jié)游戲內(nèi)部的音量(0-100)
開始游戲后以第三關(guān)舉例:
游戲視角跟隨持槍的主角杜跷,屏幕正上方的是分?jǐn)?shù),其中三種敵人:
僵尸兔子分值20矫夷;僵尸小熊分值30葛闷,僵尸大象分值80,擊殺難度/造成傷害也隨著分值相應(yīng)不同双藕,在擊殺的時(shí)候處理優(yōu)先級(jí)也根據(jù)游戲關(guān)卡不同而不同淑趾。
游戲左下角是生命值,根據(jù)每個(gè)關(guān)卡的難度/機(jī)制而不同忧陪,例如第三關(guān)的敵人傷害較高扣泊,且人物射速較低,因此生命值為300(相比于第一關(guān)的100和第三關(guān)的500略有不同嘶摊,但是數(shù)值具體僅經(jīng)過了初步平衡延蟹,游戲具體的難度體驗(yàn)因人而異);在人物受到攻擊時(shí)屏幕會(huì)出現(xiàn)紅色更卒,提醒玩家注意規(guī)避:
在生命數(shù)值歸零后等孵,游戲會(huì)結(jié)束,播放玩家死亡音效蹂空,敵人停止追逐玩家并且玩家不能繼續(xù)進(jìn)行射擊和移動(dòng)俯萌,在1秒后進(jìn)入游戲結(jié)束畫面:
玩家再次點(diǎn)擊屏幕后,回到游戲的開始界面進(jìn)行關(guān)卡選擇上枕。
游戲的關(guān)卡設(shè)計(jì)了四關(guān)咐熙,分別叫Late Night(夜半);Nightmare(噩夢)辨萍;Dawn(黎明)棋恼;Polar(極圈)返弹;四關(guān)的游戲機(jī)制如下:
夜半是游戲的初始關(guān)卡,難度較低爪飘,設(shè)定上人物移動(dòng)速度較快义起,且槍支的射速較快(對(duì)應(yīng)的傷害較低,但總體DPS比較平衡师崎,適合不熟悉控制的人熟悉瞄準(zhǔn)機(jī)制)默终,三種敵人刷新速度也較慢,兩種血量較低的敵人(兔子和熊)刷新時(shí)間為3秒犁罩,大象刷新時(shí)間為5秒齐蔽。此外,對(duì)應(yīng)30每發(fā)/每秒10發(fā)的射速床估,擊殺小型敵人所需時(shí)間很短含滴,因此主要難度是利用地形和走位規(guī)避傷害并盡可能多的擊殺大象。
噩夢和夜半類似丐巫,是難度較高的夜半谈况,例如敵人的傷害變高(通過提高攻擊間隔,單次傷害實(shí)現(xiàn))鞋吉,血量變高鸦做,但控制人物的血量沒變,但相應(yīng)提高了槍的傷害(例如擊殺大象原來需要17發(fā)谓着,現(xiàn)在需要14發(fā))泼诱,相應(yīng)的存活時(shí)間也會(huì)降低,因此難度較高赊锚,但同時(shí)人物的射速與單發(fā)傷害與第一關(guān)并無區(qū)別治筒,玩家只需要一直按住左鍵然后向敵人反方向跑就可以了。
黎明的設(shè)計(jì)理念與前兩關(guān)不同舷蒲,如果說前兩關(guān)的武器是輕型自動(dòng)步槍耸袜,這關(guān)的武器則是狙擊槍。單發(fā)傷害提升到170意味著可以單發(fā)擊殺100血量的兔子牲平,200血量的熊需要兩槍堤框,500血量的大象需要三槍。相應(yīng)的纵柿,人物的血量也提高為300蜈抓,同時(shí)射速被削減到了0.5發(fā)每秒。此外昂儒,在該關(guān)卡中玩家的移動(dòng)速度被提高到了8.0f(前兩關(guān)為6.0f)沟使,可以拉開距離進(jìn)行遠(yuǎn)距離的精確瞄準(zhǔn),由于設(shè)定時(shí)為地形中的障礙設(shè)計(jì)了碰撞檢測(設(shè)計(jì)navigation時(shí)烘培了所有模型)渊跋,敵人無法穿過的模型子彈也無法穿過腊嗡,因此關(guān)卡難度也很大着倾。
極圈的設(shè)計(jì)類似于上世紀(jì)的游戲搶灘登陸等的理念,玩家的移動(dòng)速度被極大限制但是射速和傷害被極大提高燕少,在該關(guān)卡中人物移動(dòng)速度僅為1.0f卡者,但射速,單發(fā)傷害極高棺亭,對(duì)應(yīng)的敵人刷新速度也很快且個(gè)人血量也很高虎眨,因此該關(guān)卡下玩家只需要站在原地然后擊退一波又一波的敵人即可。
三.設(shè)計(jì)理念:
1.UI設(shè)計(jì)思路:
游戲本身由兩類場景組成:開始界面和游戲關(guān)卡镶摘,其中開始界面的設(shè)計(jì)難點(diǎn)在于UI的布置,不同場景之間的連接和控件功能的實(shí)現(xiàn)岳守;游戲關(guān)卡的設(shè)計(jì)難點(diǎn)在于人物動(dòng)作之間的銜接凄敢,主角和敵方人物的移動(dòng)控制和武器的命中判定。
游戲的UI為了契合游戲本身的卡通風(fēng)格湿痢,因此大部分使用了較為活潑的字體和顏色設(shè)計(jì)涝缝,例如游戲從標(biāo)題,關(guān)卡選擇到游戲結(jié)束使用的均是這種叫LUCKIEST-GUY的字體譬重,但同時(shí)作為一個(gè)打僵尸的游戲拒逮,背景音樂設(shè)定上采用了比較陰森但是較為清澈的打擊樂。
在界面設(shè)計(jì)中臀规,由于游戲本身色調(diào)偏暗滩援,因此背景使用了紫色,但標(biāo)題采用了鮮艷的顏色(手調(diào)的黃色和淺藍(lán)色塔嬉,不一定好看)
之后為Dream-Walking使用Animation功能添加了動(dòng)畫效果玩徊,讓開始界面顯得不那么突兀。此外谨究,為了增加標(biāo)題的層次感恩袱,為兩段text分別添加了陰影,經(jīng)過調(diào)整后藍(lán)色字體添加了黑色陰影胶哲,黃色字體添加了深黃色陰影畔塔,看起來比較像3D制作的標(biāo)題。
同理鸯屿,在關(guān)卡選擇部分的UI設(shè)計(jì)也為了整體的一致性采用了同樣的字體:
圖標(biāo)本身使用了UI中的button選項(xiàng)澈吨,并為每一個(gè)按鈕的image組件添加了關(guān)卡的截圖。在設(shè)計(jì)時(shí)考慮到unity的button都是圓角按鈕碾盟,為了整體的美觀性想把關(guān)卡按鈕也做成圓角的棚辽,但是采用圖片作為按鈕背景時(shí)無論圖片是否是圓角圖片,保存成jpg格式后導(dǎo)入到texture中的結(jié)果都是矩形圖片(圓角圖片導(dǎo)入后會(huì)留下四個(gè)白色的角)冰肴;查閱資料發(fā)現(xiàn)需要使用shader組件進(jìn)行代碼控制屈藐,但在這版本的游戲中還沒有實(shí)現(xiàn)榔组。
UI部分代碼實(shí)現(xiàn)思路:
游戲中用到的UI設(shè)計(jì)主要包含以下三部分:關(guān)卡切換,玩家信息顯示联逻,音量調(diào)節(jié)搓扯;分別用一段代碼進(jìn)行實(shí)現(xiàn)。
I. 關(guān)卡切換部分:
利用Load Level/Load Scene函數(shù)均可實(shí)現(xiàn)包归,為了避免bug加入了Debug.Log函數(shù)锨推;完成代碼后在界面中的Button組件中使用OnBtnClick方法調(diào)用,并將每個(gè)關(guān)卡和代碼關(guān)聯(lián)即可公壤。
關(guān)卡切換部分代碼如下:
publicclassGameStartManager:MonoBehaviour{
publicButtonStartButton;
publicvoidOpenScene00()
{
Debug.Log("Game Started");
Application.LoadLevel("Level 00");
}
publicvoidOpenScene01()
{
Debug.Log("Game Started");
Application.LoadLevel("Level 01");
}
publicvoidOpenScene02()
{
Debug.Log("Game Started");
Application.LoadLevel("Level 02");
}
publicvoidOpenScene03()
{
Debug.Log("Game Started");
Application.LoadLevel("Level 03");
}
publicvoidOpenScene04()
{
Debug.Log("Game Started");
Application.LoadLevel("Level 04");
}
}
II. 關(guān)卡中對(duì)人物的信息顯示:
屏幕中主要需要顯示人物的分?jǐn)?shù)和血量换可,和游戲結(jié)束后的Game Over界面;
分?jǐn)?shù)實(shí)現(xiàn)非常簡單厦幅,只需要構(gòu)建一個(gè)Text文件然后設(shè)置每個(gè)敵方單位的得分并相加即可沾鳄。
分?jǐn)?shù)的代碼實(shí)現(xiàn):
publicstaticintscore;
Texttext;
voidAwake()
{
text = GetComponent ();
score = 0;
}
voidUpdate()
{
text.text ="Score: "+ score;
}
}
III.人物血量的顯示:
血量的代碼實(shí)現(xiàn)稍后人物生命值部分會(huì)講解,只需要將人物血量顯示到已經(jīng)在代碼中聲明過的Health Slider中即可确憨,此處粘貼一下該部分代碼:
publicvoidTakeDamage (intamount)
{
damaged =true;
currentHealth -= amount;
healthSlider.value = currentHealth;
playerAudio.Play ();
if(currentHealth <= 0 && !isDead)
{
Death ();
}
}
IV. 游戲通關(guān)界面:
人物死亡后的Game Over動(dòng)畫的實(shí)現(xiàn)也非常簡單译荞,只需要在Animation中構(gòu)建三部分:藍(lán)色背景的透明-----不透明,分?jǐn)?shù)的高亮(大小變大再變行萜)和Game Over字樣的顯示吞歼。
在Animation中構(gòu)建完成后只需要在代碼中調(diào)用該Animation組件即可。
代碼如下:
Animatoranim;
voidAwake()
{
anim = GetComponent();
}
V. 音量調(diào)節(jié)部分:
需要首先創(chuàng)建一個(gè)Slider塔猾,之后向Slider中添加Audio Source組件篙骡,并將背景音樂和該組件關(guān)聯(lián)。
之后向該Slider中添加代碼即可桥帆。該部分代碼實(shí)現(xiàn)如下:
usingSystem.Collections;
usingSystem.Collections.Generic;
usingUnityEngine;
usingUnityEngine.UI;
publicclassMusicAdministor:MonoBehaviour
{
publicSliderVolume;
publicvoidOnVolume()
{
GetComponent().volume = Volume.value;
}
}
2. 對(duì)第一人稱人物的設(shè)計(jì):
I.控制人物的設(shè)計(jì)思路:
從代碼實(shí)現(xiàn)角度講分三部分實(shí)現(xiàn):人物的移動(dòng)医增;人物的傷害判定;人物的射擊判定老虫。
從人物模型的角度講同樣分三部分實(shí)現(xiàn):人物模型/動(dòng)作的關(guān)聯(lián)(Animator組件)叶骨,人物模型移動(dòng)的判定(對(duì)地表模型的烘培,navigation模塊)祈匙,人物開槍的動(dòng)作設(shè)計(jì)
II.控制人物移動(dòng)的設(shè)計(jì):
人物的移動(dòng)核心代碼如下:
floath =Input.GetAxisRaw("Horizontal");
floatv =Input.GetAxisRaw("Vertical");
voidMove(floath,floatv)
{
movement.Set(h, 0f, v);
movement = movement.normalized * speed *Time.deltaTime;
playerRigidbody.MovePosition(transform.position + movement);
}
首先利用input.getaxisraw方法獲得來自鍵盤/鼠標(biāo)的控制系數(shù)忽刽,Horizontal和Vertical是獲得鍵盤上下/左右鍵按下時(shí)觸發(fā)的,后面調(diào)用人物旋轉(zhuǎn)時(shí)使用的Mouse X夺欲,Mouse Y同理跪帝,獲得的是鼠標(biāo)沿著屏幕的橫/縱軸進(jìn)行移動(dòng)時(shí)獲得的長度。
之后設(shè)置人物的移動(dòng)面為X和Z(可以在人物模型的剛體組件內(nèi)進(jìn)行如下修改:
設(shè)置人物可以在XZ軸內(nèi)進(jìn)行平移)
之后對(duì)人物的移動(dòng)設(shè)置一個(gè)三維數(shù)組movement些阅,將Y值設(shè)置為0伞剑,并在代碼開始定義人物的移動(dòng)速度:public float speed = 6.0f ,便于之后各關(guān)卡對(duì)人物的移動(dòng)速度進(jìn)行調(diào)節(jié)市埋。
之后設(shè)置人物的位置為原位置+速度x時(shí)間黎泣,并每幀調(diào)用一次該函數(shù)即可恕刘。
III.人物的方向控制設(shè)計(jì):
人物的旋轉(zhuǎn)函數(shù)與之類似:
voidTurning()
{
RaycamRay =Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHitfloorHit;
if(Physics.Raycast (camRay,outfloorHit, camRayLength, floorMask))
{
Vector3playerToMouse = floorHit.point - transform.position;
playerToMouse.y = 0f;
QuaternionnewRotation =Quaternion.LookRotation(playerToMouse);
playerRigidbody.MoveRotation(newRotation);
}
}
獲取人物鼠標(biāo)位置的方法如上,創(chuàng)建三維數(shù)組后定義PlayerToMouse初始位置為玩家位置面向鼠標(biāo)位置抒倚,旋轉(zhuǎn)角度的改變量為地面位置-改變位置褐着,同樣每幀調(diào)用一次該方法。
IV.人物的動(dòng)畫銜接設(shè)計(jì):
之后對(duì)人物的動(dòng)畫銜接進(jìn)行設(shè)置:首先從Animator窗口對(duì)人物動(dòng)作進(jìn)行綁定:
提取到的動(dòng)畫模組有三個(gè):Move(移動(dòng))托呕,Idle(發(fā)呆)含蓉,Death(死亡)。
之后對(duì)Conditions中添加兩個(gè)變量作為三種模組之間的轉(zhuǎn)換:
控制Idle-Move/Move-Idle的判定情況:Is Walking项郊;是Bool型變量馅扣,Is True情況下轉(zhuǎn)為Move動(dòng)畫,Is False情況下轉(zhuǎn)為Idle動(dòng)畫呆抑。
控制Any State-Death的判定情況:Is Dead岂嗓;是Trigger型變量,觸發(fā)時(shí)結(jié)束所有當(dāng)前動(dòng)作并進(jìn)入Death動(dòng)畫鹊碍。
完成調(diào)節(jié)后對(duì)時(shí)間軸的切換點(diǎn)進(jìn)行設(shè)置,因?yàn)檫M(jìn)入Idle狀態(tài)需要一點(diǎn)時(shí)間的動(dòng)畫延續(xù)以防止人物動(dòng)作過于僵硬食绿,因此將Move動(dòng)畫稍微延長一段侈咕,并勾選Has Exit Time選項(xiàng)。而另外一邊的開始移動(dòng)如果使用Has Exit Time就會(huì)在人物開始移動(dòng)時(shí)位置出現(xiàn)平移而沒有動(dòng)畫效果器紧,所以需要取消掉Has Exit Time選項(xiàng)耀销。
voidAnimating(floath,floatv)
{
boolwalking = h != 0f || v != 0f;
anim.SetBool("IsWalking", walking);
}
利用該代碼判定人物是否在移動(dòng)(通過對(duì)水平/垂直平面的坐標(biāo)進(jìn)行判定),并修改Is Walking模組的數(shù)據(jù)铲汪。
voidDeath ()
{
isDead =true;
playerShooting.DisableEffects ();
anim.SetTrigger ("Die");
playerAudio.clip = deathClip;
playerAudio.Play ();
playerMovement.enabled =false;
playerShooting.enabled =false;
}
利用該代碼判定人物是否存活(通過人物的血量判斷是否存活熊尉,若死亡則停止人物的射擊和移動(dòng)動(dòng)畫),并修改Is Alive模組的數(shù)據(jù)掌腰。
V.人物的射擊判定:
因?yàn)槿宋锏纳鋼敉ㄟ^ShootRay思路進(jìn)行實(shí)現(xiàn)狰住,所以對(duì)開火的設(shè)計(jì)如下:
1.設(shè)置單發(fā)傷害
2.設(shè)置開火間隔
3.設(shè)置射擊有效距離
4.將開火時(shí)的粒子效果/光效/音效在代碼中進(jìn)行定義,并在Unity中進(jìn)行綁定
5.利用代碼設(shè)置:左鍵按下判定開火齿梁;若距離上一發(fā)開火時(shí)間>開火間隔則設(shè)計(jì)催植,否則不射擊
6.定義射擊方向:從槍口開始,做一條長度為開火距離勺择,角度為鼠標(biāo)指向/人物角度的射線
7.定義射擊傷害判定:若射線和模型collider發(fā)生碰撞创南,且目標(biāo)具有生命值(考慮到可能會(huì)射擊到地形/墻面/地形上)則造成傷害
控制射擊部分的代碼如下:
publicintdamagePerShot = 20;
publicfloattimeBetweenBullets = 0.3f;
publicfloatrange = 100f;
floattimer;
RayshootRay =newRay();
RaycastHitshootHit;
intshootableMask;
ParticleSystemgunParticles;
LineRenderergunLine;
AudioSourcegunAudio;
LightgunLight;
floateffectsDisplayTime = 0.2f;
voidAwake()
{
shootableMask =LayerMask.GetMask ("Shootable");
gunParticles = GetComponent ();
gunLine = GetComponent ();
gunAudio = GetComponent();
gunLight = GetComponent ();
}
voidUpdate()
{
timer +=Time.deltaTime;
if(Input.GetButton ("Fire1") && timer >= timeBetweenBullets &&Time.timeScale!=0
{
Shoot ();
}
if(timer >= timeBetweenBullets * effectsDisplayTime)
{
DisableEffects ();
}
}
voidShoot ()
{
timer = 0f;
gunAudio.Play();
gunLight.enabled =true;
gunParticles.Stop ();
gunParticles.Play ();
gunLine.enabled =true;
gunLine.SetPosition (0, transform.position);
shootRay.origin = transform.position;
shootRay.direction = transform.forward;
if(Physics.Raycast (shootRay,outshootHit, range, shootableMask))
{
EnemyHealthenemyHealth = shootHit.collider.GetComponent ();
if(enemyHealth !=null)
{
enemyHealth.TakeDamage (damagePerShot, shootHit.point);
}
gunLine.SetPosition (1, shootHit.point);
}
else
{
gunLine.SetPosition (1, shootRay.origin + shootRay.direction * range);
}
}
}
VI.人物的生命值判定:
控制人物的生命判定如下:
1.設(shè)定人物的生命上限,
2.將人物生命值投射到UI中的slider中省核,
3.通過生命值對(duì)Is Alive(上文中提到的判定模組)進(jìn)行判斷稿辙,以對(duì)人物的動(dòng)畫進(jìn)行設(shè)置。
4.設(shè)置敵人的傷害參數(shù)(此處只是定義變量气忠,后面設(shè)置敵人的攻擊代碼時(shí)會(huì)填入?yún)?shù))
5.為了傷害效果逼真邻储,在人物受到傷害時(shí)讓屏幕變紅赋咽,實(shí)現(xiàn)方法為在游戲關(guān)卡的UI中添加一個(gè)和屏幕一樣大的紅色image,平常透明度為0芥备,若受到傷害則講透明度重置為100%冬耿,0.5秒后回復(fù)。該方法中利用color.lerp函數(shù)對(duì)圖片的顏色進(jìn)行設(shè)置萌壳。
6.設(shè)置人物如果生命值降低至0時(shí)亦镶,觸發(fā)Death動(dòng)畫,并在0.5秒內(nèi)播放Game Over界面(和受傷的紅色界面類似袱瓮,需要在外界通過animation和UI進(jìn)行設(shè)計(jì)缤骨,但是在游戲中只需要調(diào)用觸發(fā)函數(shù))
7.Game Over后調(diào)用Load Scene函數(shù),回到主界面選擇重新開始尺借。
代碼實(shí)現(xiàn)如下:
usingUnityEngine;
usingUnityEngine.UI;
usingSystem.Collections;
usingUnityEngine.SceneManagement;
publicclassPlayerHealth:MonoBehaviour
{
publicintstartingHealth = 100;
publicintcurrentHealth;
publicSliderhealthSlider;
publicImagedamageImage;
publicAudioClipdeathClip;
publicfloatflashSpeed = 5f;
publicColorflashColour =newColor(1f, 0f, 0f, 0.1f);
Animatoranim;
AudioSourceplayerAudio;
PlayerMovementplayerMovement;
PlayerShootingplayerShooting;
boolisDead;
booldamaged;
voidAwake()
{
anim = GetComponent ();
playerAudio = GetComponent ();
playerMovement = GetComponent ();
playerShooting = GetComponentInChildren ();
currentHealth = startingHealth;
}
voidUpdate()
{
if(damaged)
{
damageImage.color = flashColour;
}
else
{
damageImage.color =Color.Lerp (damageImage.color,Color.clear, flashSpeed *Time.deltaTime);
}
damaged =false;
}
publicvoidTakeDamage (intamount)
{
damaged =true;
currentHealth -= amount;
healthSlider.value = currentHealth;
playerAudio.Play ();
if(currentHealth <= 0 && !isDead)
{
Death ();
}
}
voidDeath ()
{
isDead =true;
playerShooting.DisableEffects ();
anim.SetTrigger ("Die");
playerAudio.clip = deathClip;
playerAudio.Play ();
playerMovement.enabled =false;
playerShooting.enabled =false;
}
publicvoidRestartLevel ()
{
SceneManager.LoadScene(0);
}
}
關(guān)卡結(jié)束部分代碼:
voidUpdate()
{
if(playerHealth.currentHealth <= 0)
{
anim.SetTrigger("GameOver");
restartTimer +=Time.deltaTime;
if(restartTimer >= restartDelay)
{
Application.LoadLevel(Application.loadedLevel);
}
}
}
3.敵方單位設(shè)計(jì)思路:
和控制人物類似绊起,對(duì)敵方單位的設(shè)計(jì)也從以下方面著手:敵人血量,敵人移動(dòng)燎斩,敵人傷害虱歪,和敵人的動(dòng)畫構(gòu)建,和人物不同的是由于動(dòng)畫素材限制栅表,敵人沒有遠(yuǎn)程攻擊(只有近戰(zhàn)笋鄙,對(duì)應(yīng)的也利用Animator進(jìn)行不同動(dòng)畫的關(guān)聯(lián)),并且敵人需要設(shè)置Navigation組件以智能的尋找玩家位置怪瓶。
I.對(duì)敵人移動(dòng)方式的設(shè)計(jì):
1.設(shè)置敵人的基本移動(dòng)速度萧落;
2.將敵人的位置命名為一個(gè)三維數(shù)組;并定義敵人的新位置為原位置+速度x Delta.time洗贰,每幀執(zhí)行一次找岖。
3.為敵人設(shè)計(jì)碰撞檢測;以便后面對(duì)敵人的攻擊玩家/地形碰撞進(jìn)行處理敛滋;
4.判定玩家的血量和敵人本身的血量许布,若血量>0則利用nav函數(shù)表達(dá)敵人的方向?yàn)槊嫦蛲婕椅恢谩?/p>
敵人移動(dòng)的代碼實(shí)現(xiàn)如下:
usingUnityEngine;
usingSystem.Collections;
usingUnityEngine.AI;
publicclassEnemyMovement:MonoBehaviour
{
publicfloatenemySpeed = 100.0f;
Transformplayer;
PlayerHealthplayerHealth;
EnemyHealthenemyHealth;
NavMeshAgentnav;
Vector3enemyMovement;
RigidbodyenemyRigidbody;
voidAwake()
{
player =GameObject.FindGameObjectWithTag("Player").transform;
playerHealth = player.GetComponent();
enemyHealth = GetComponent();
nav = GetComponent();
enemyRigidbody = GetComponent();
}
voidMove(floath,floatv)
{
enemyMovement.Set(h, 0f, v);
enemyMovement = enemyMovement.normalized * enemySpeed *Time.deltaTime;
enemyRigidbody.MovePosition(transform.position + enemyMovement);
}
voidUpdate()
{
if(enemyHealth.currentHealth > 0 && playerHealth.currentHealth > 0)
{
nav.SetDestination(player.position);
}
else
{
nav.enabled =false;
}
}
}
II. 對(duì)敵人的血量設(shè)計(jì):
1.設(shè)置敵人的初始血量(因敵人的不同而異),并設(shè)計(jì)擊殺后尸體消失的時(shí)間和增加的分值
2.定義敵人遭到攻擊時(shí)的粒子特效矛缨,聲效爹脾。
3.設(shè)置尸體消失的動(dòng)畫:由于Animation中可以看出敵人死后是平躺的,所以不需要加入旋轉(zhuǎn)函數(shù)箕昭,只需要在Z軸上對(duì)敵人尸體進(jìn)行平移即可灵妨,Z坐標(biāo)為原坐標(biāo)+尸體消失速度x Delta Time,每幀調(diào)用一次落竹。
4.設(shè)置敵人遭到攻擊(在人物開槍的代碼中定義過傷害判定泌霍,此處只需要定義血量削減函數(shù)并通過get component調(diào)用受傷時(shí)的粒子特效和音效即可。
敵人血量的代碼設(shè)計(jì)如下:
usingUnityEngine;
usingUnityEngine.Events;
publicclassEnemyHealth:MonoBehaviour
{
publicintstartingHealth = 100;
publicintcurrentHealth;
publicfloatsinkSpeed = 2.5f;
publicintscoreValue = 10;
publicAudioClipdeathClip;
Animatoranim;
AudioSourceenemyAudio;
ParticleSystemhitParticles;
CapsuleCollidercapsuleCollider;
boolisDead;
boolisSinking;
voidAwake()
{
anim = GetComponent ();
enemyAudio = GetComponent ();
hitParticles = GetComponentInChildren ();
capsuleCollider = GetComponent ();
currentHealth = startingHealth;
}
voidUpdate()
{
if(isSinking)
{
transform.Translate (-Vector3.up * sinkSpeed *Time.deltaTime);
}
}
publicvoidTakeDamage (intamount,Vector3hitPoint)
{
if(isDead)
return;
enemyAudio.Play ();
currentHealth -= amount;
hitParticles.transform.position = hitPoint;
hitParticles.Play();
if(currentHealth <= 0)
{
Death ();
}
}
publicvoidStartSinking ()
{
GetComponent ().enabled =false;
GetComponent ().isKinematic =true;
isSinking =true;
ScoreManager.score += scoreValue;
Destroy (gameObject, 2f);
}
}
此外,和人物死亡動(dòng)畫類似朱转,敵人死亡也需要調(diào)用Death----Idle的Animator模組蟹地,此處也是定義一個(gè)Trigger變量Death,和人物死亡一樣----取消Exit Time并在代碼中調(diào)用該段動(dòng)畫藤为。
敵人的animator如下:
三.對(duì)敵人的攻擊設(shè)計(jì)
敵人對(duì)玩家的攻擊動(dòng)作和人物射擊敵人的設(shè)計(jì)方式類似怪与,步驟如下:
1.設(shè)置敵人的攻擊間隔和攻擊傷害(作為全局public變量,便于拖入敵人的prefab后修改數(shù)值缅疟,以改變敵人的難度)
2.調(diào)用玩家人物分别,作為敵人的移動(dòng)方向和攻擊目標(biāo)(此處同樣調(diào)用人物的血量以判定人物是否存活)
3.進(jìn)行碰撞檢測(此處的碰撞檢測和敵人與地形碰撞檢測并不一樣,此處是判定敵人的攻擊區(qū)域內(nèi)是否存在玩家----若存在則運(yùn)行攻擊玩家的方法)
4.判定玩家人物的血量存淫,若血量在0+且進(jìn)入了敵人的攻擊范圍則進(jìn)行一次攻擊判定(并開始計(jì)算敵人的攻擊動(dòng)作的冷卻時(shí)間)
攻擊設(shè)計(jì)的代碼實(shí)現(xiàn)如下:
usingUnityEngine;
usingSystem.Collections;
publicclassEnemyAttack:MonoBehaviour
{
publicfloattimeBetweenAttack = 0.5f;
publicintattackDamage = 10;
Animatoranim;
GameObjectplayer;
PlayerHealthplayerHealth;
EnemyHealthenemyHealth;
boolplayerInRange;
floattimer;
voidAwake()
{
player =GameObject.FindGameObjectWithTag ("Player");
playerHealth = player.GetComponent ();
enemyHealth = GetComponent();
anim = GetComponent ();
}
voidOnTriggerEnter(Colliderother)
{
if(other.gameObject == player)
{
playerInRange =true;
}
}
voidOnTriggerExit(Colliderother)
{
if(other.gameObject == player)
{
playerInRange =false;
}
}
voidUpdate()
{
timer +=Time.deltaTime;
if(timer >= timeBetweenAttack && playerInRange && enemyHealth.currentHealth > 0)
{
Attack ();
}
if(playerHealth.currentHealth <= 0)
{
anim.SetTrigger ("PlayerDead");
}
}
voidAttack ()
{
timer = 0f;
if(playerHealth.currentHealth > 0)
{
playerHealth.TakeDamage (attackDamage);
}
}
}
四.設(shè)計(jì)步驟:
由于游戲本身內(nèi)容復(fù)雜耘斩,為了較為形象的解釋該游戲從空?qǐng)鼍暗娇梢詷?gòu)建為成熟場景的過程,在此處簡要的解釋一下該游戲設(shè)計(jì)過程中的主要步驟:
1.構(gòu)建一個(gè)游戲場景桅咆,并導(dǎo)入下載好的環(huán)境prefab文件(此處包含燈光設(shè)計(jì))
2.導(dǎo)入玩家的人物模型括授,并在Animator中導(dǎo)入人物的不同動(dòng)畫,并創(chuàng)建變量來規(guī)范動(dòng)作間的變換觸發(fā)點(diǎn)和持續(xù)時(shí)間
3.對(duì)人物模型進(jìn)行優(yōu)化岩饼,首先對(duì)人物的槍支進(jìn)行設(shè)計(jì)荚虚,加入開火的特效,并添加腳本對(duì)開火行為進(jìn)行構(gòu)建
槍支的Inspector界面最后如下圖:
4.對(duì)人物的移動(dòng)進(jìn)行設(shè)計(jì)籍茧,其中包括鏡頭的跟隨曲管,人物的移動(dòng)旋轉(zhuǎn)和移動(dòng)動(dòng)畫的觸發(fā),并在代碼中對(duì)各個(gè)功能進(jìn)行實(shí)現(xiàn)
人物本身的Animator最后如下:
人物本身的Inspector最后如下:
5.完成對(duì)玩家控制人物的調(diào)試后硕糊,對(duì)敵人的角色進(jìn)行設(shè)計(jì);首先將敵人的模型導(dǎo)入到游戲中腊徙;
6.對(duì)敵人的Animator進(jìn)行控制简十,將各種動(dòng)畫通過添加變量的方式進(jìn)行關(guān)聯(lián),并在代碼中對(duì)各個(gè)變量的作用時(shí)間分別進(jìn)行定義撬腾。
敵人的Animator窗口如下:
7.對(duì)敵人的移動(dòng)方式進(jìn)行控制螟蝙,通過代碼實(shí)現(xiàn)敵人的移動(dòng)和攻擊,并設(shè)定敵人對(duì)地形的碰撞體積和對(duì)玩家進(jìn)行攻擊的碰撞體積民傻。
設(shè)計(jì)完成后敵人的Inspector窗口如下:
8.完成敵人移動(dòng)的設(shè)計(jì)后需要對(duì)場景進(jìn)行Navigation的烘培胰默,對(duì)地形的角度/人物模型進(jìn)行對(duì)比后將臺(tái)階等設(shè)置進(jìn)行平衡,最后點(diǎn)擊烘培
烘培后的地形效果如下:
藍(lán)色部分為可移動(dòng)平面漓踢。
9.將單個(gè)敵人保存為Prefab牵署,并將同樣的腳本內(nèi)容賦值給三種不同的模型(對(duì)動(dòng)畫效果重新進(jìn)行綁定),并修改人物的屬性(移動(dòng)速度喧半,單次傷害奴迅,傷害間隔,血量等)
10.設(shè)置怪物刷新的位置挺据,并使用相應(yīng)的代碼進(jìn)行實(shí)現(xiàn)
11.對(duì)游戲場景進(jìn)行相應(yīng)的細(xì)化取具,例如燈光脖隶,鏡頭遠(yuǎn)近,背景音樂設(shè)置等
12.完成游戲場景的布置后對(duì)場景進(jìn)行build暇检,并以此類推進(jìn)行以下幾個(gè)游戲關(guān)卡的設(shè)計(jì)
13.完成游戲關(guān)卡的設(shè)計(jì)后開始進(jìn)行UI界面的設(shè)計(jì)产阱,對(duì)每關(guān)人物的血量/分?jǐn)?shù)等利用代碼進(jìn)行調(diào)用,并完成Game Over動(dòng)畫的實(shí)現(xiàn)块仆。
14.對(duì)游戲開始界面的GUI進(jìn)行設(shè)計(jì)构蹬,包括關(guān)卡切換/音量調(diào)節(jié)等,并利用相關(guān)的代碼進(jìn)行關(guān)卡切換等功能的實(shí)現(xiàn)榨乎。
15.對(duì)所有場景進(jìn)行build操作怎燥,并對(duì)游戲進(jìn)行基本測試,完成后導(dǎo)出游戲素材蜜暑。
五.后記
本游戲參考了Unity官方教程https://unity3d.com/cn/learn/tutorials/projects/survival-shooter-tutorial
該教程從
12個(gè)方面對(duì)游戲設(shè)計(jì)進(jìn)行了講解铐姚,是我在unity官網(wǎng)完成的第五部游戲開發(fā)教程,整個(gè)視頻課程約300分鐘肛捍,我從該視頻課程中受益匪淺隐绵,學(xué)到了相當(dāng)多Unity中各方面的開發(fā)知識(shí)和前端代碼的實(shí)現(xiàn)與程序構(gòu)建。
視頻的播放列表鏈接如下:
https://unity3d.com/cn/learn/tutorials/projects/survival-shooter/camera-setup?playlist=17144
本游戲非本人制作的部分如下:
游戲關(guān)卡的地形場景拙毫;游戲中玩家和敵人的模型依许;模型使用的動(dòng)畫;游戲UI中使用的字體缀蹄。
參考了教程中的部分如下:
游戲中玩家和敵人的運(yùn)動(dòng)代碼參考了部分視頻中給出的案例峭跳;
游戲內(nèi)燈光的布置和設(shè)計(jì);
游戲內(nèi)Navigation地形的渲染設(shè)置缺前。
獨(dú)立設(shè)計(jì)部分:
游戲機(jī)制蛀醉,人物開火動(dòng)畫,關(guān)卡衅码,開始界面UI拯刁,分?jǐn)?shù)判定等。
游戲素材內(nèi)包含以下部分逝段,如果需要檢查素材可以按以下方式檢查:
代碼部分:
分為玩家垛玻,敵人,攝像機(jī)奶躯,游戲機(jī)制四部分:
游戲內(nèi)場景部分:
包括Level 00(開始界面)和Level 01-04(游戲關(guān)卡)
游戲內(nèi)環(huán)境材質(zhì):
(來自素材包)
游戲內(nèi)Prefab:
包括環(huán)境帚桩,槍和受傷的粒子特效,光效和玩家/敵人的模型巫糙。
游戲內(nèi)材質(zhì)球:
(來自素材包)
游戲內(nèi)字體:
游戲內(nèi)聲音素材:
游戲內(nèi)人物受傷/死亡音效朗儒;背景音樂等
(來自素材包)
游戲內(nèi)動(dòng)畫效果素材:
主界面UI的動(dòng)畫效果,游戲結(jié)束效果和設(shè)計(jì)時(shí)槍口的動(dòng)畫效果
六.組員信息:
游戲設(shè)計(jì)人:
14級(jí)數(shù)媒技術(shù)2班 李基銘?
負(fù)責(zé)工作:
模型設(shè)計(jì),動(dòng)畫設(shè)計(jì)醉锄,關(guān)卡設(shè)計(jì)乏悄,人物設(shè)計(jì),配樂恳不,游戲機(jī)制設(shè)計(jì)檩小,代碼設(shè)計(jì),動(dòng)畫組件設(shè)計(jì)烟勋,等等等等
游戲設(shè)計(jì)時(shí)間:大約30小時(shí)(包括寫報(bào)告時(shí)間5小時(shí)规求,海報(bào)制作2小時(shí),看視頻10小時(shí)和獨(dú)立制作10小時(shí))