練手的第一個(gè)游戲

《計(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í))

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末卵惦,一起剝皮案震驚了整個(gè)濱河市阻肿,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌沮尿,老刑警劉巖丛塌,帶你破解...
    沈念sama閱讀 206,482評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異畜疾,居然都是意外死亡赴邻,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,377評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門啡捶,熙熙樓的掌柜王于貴愁眉苦臉地迎上來姥敛,“玉大人,你說我怎么就攤上這事瞎暑⊥玻” “怎么了?”我有些...
    開封第一講書人閱讀 152,762評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵了赌,是天一觀的道長臊泌。 經(jīng)常有香客問我,道長揍拆,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,273評(píng)論 1 279
  • 正文 為了忘掉前任茶凳,我火速辦了婚禮嫂拴,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘贮喧。我一直安慰自己筒狠,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,289評(píng)論 5 373
  • 文/花漫 我一把揭開白布箱沦。 她就那樣靜靜地躺著辩恼,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上灶伊,一...
    開封第一講書人閱讀 49,046評(píng)論 1 285
  • 那天疆前,我揣著相機(jī)與錄音,去河邊找鬼聘萨。 笑死竹椒,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的米辐。 我是一名探鬼主播胸完,決...
    沈念sama閱讀 38,351評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼翘贮!你這毒婦竟也來了赊窥?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,988評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤狸页,失蹤者是張志新(化名)和其女友劉穎锨能,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體肴捉,經(jīng)...
    沈念sama閱讀 43,476評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡腹侣,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,948評(píng)論 2 324
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了齿穗。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片傲隶。...
    茶點(diǎn)故事閱讀 38,064評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖窃页,靈堂內(nèi)的尸體忽然破棺而出跺株,到底是詐尸還是另有隱情,我是刑警寧澤脖卖,帶...
    沈念sama閱讀 33,712評(píng)論 4 323
  • 正文 年R本政府宣布乒省,位于F島的核電站,受9級(jí)特大地震影響畦木,放射性物質(zhì)發(fā)生泄漏袖扛。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,261評(píng)論 3 307
  • 文/蒙蒙 一十籍、第九天 我趴在偏房一處隱蔽的房頂上張望蛆封。 院中可真熱鬧,春花似錦勾栗、人聲如沸惨篱。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,264評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽砸讳。三九已至琢融,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間簿寂,已是汗流浹背漾抬。 一陣腳步聲響...
    開封第一講書人閱讀 31,486評(píng)論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留陶耍,地道東北人奋蔚。 一個(gè)月前我還...
    沈念sama閱讀 45,511評(píng)論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像烈钞,于是被迫代替她去往敵國和親泊碑。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,802評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容