《計算機游戲開發》期末課題實驗報告
北京郵電大學數字媒體與設計藝術學院
2017年6月24日
一、游戲簡介:
《夢游大逃殺》是一款基于UNITY3D開發制作的第三人稱視角射擊生存類游戲,其游戲背景是一個畫風非常卡通的小朋友,在夢游過程中拿著假想的槍支和自己的毛絨玩具們展開了逃跑或是追殺(依關卡難度而定),游戲本身的每一個關卡均沒有固定的結束機制(例如到達安全屋或者殺掉足夠數量的敵人)而是更加類似于FPS游戲中的生存模式,玩家可以根據關卡的設定制定不同的策略與戰術,并在逐漸增多的敵人面前存活盡可能長的時間。
二、游戲規則:
由于所學知識的限制和素材原因,我并不能在短時間內制作出豐富的劇情,但是游戲本身擁有四個關卡和開始界面五個場景素材,且主角人物和敵人均設定了動作動畫。游戲內所有模型(人物,地形,環境)均有碰撞檢測,并為地方單位受到攻擊時添加了粒子效果。游戲本身擁有循環的背景音樂,且開槍,受到傷害,死亡均設計了獨立音效。考慮到內存和模型的原因,在槍支的設定上并未采用子彈設定,而是從槍管方向添加了一條很長的ShootRay,在主色調偏暗的游戲場景內也更容易瞄準。
游戲開始界面如下:
其中Stage Select部分由四個關卡代表的按鈕組成,點擊每個按鈕就可以進入該關卡,如果點擊Start按鈕則直接進入第一個關卡。此外還在右下角設置了音量按鈕,可以在游戲開始前調節游戲內部的音量(0-100)
開始游戲后以第三關舉例:
游戲視角跟隨持槍的主角,屏幕正上方的是分數,其中三種敵人:
僵尸兔子分值20;僵尸小熊分值30,僵尸大象分值80,擊殺難度/造成傷害也隨著分值相應不同,在擊殺的時候處理優先級也根據游戲關卡不同而不同。
游戲左下角是生命值,根據每個關卡的難度/機制而不同,例如第三關的敵人傷害較高,且人物射速較低,因此生命值為300(相比于第一關的100和第三關的500略有不同,但是數值具體僅經過了初步平衡,游戲具體的難度體驗因人而異);在人物受到攻擊時屏幕會出現紅色,提醒玩家注意規避:
在生命數值歸零后,游戲會結束,播放玩家死亡音效,敵人停止追逐玩家并且玩家不能繼續進行射擊和移動,在1秒后進入游戲結束畫面:
玩家再次點擊屏幕后,回到游戲的開始界面進行關卡選擇。
游戲的關卡設計了四關,分別叫Late Night(夜半);Nightmare(噩夢);Dawn(黎明);Polar(極圈);四關的游戲機制如下:
夜半是游戲的初始關卡,難度較低,設定上人物移動速度較快,且槍支的射速較快(對應的傷害較低,但總體DPS比較平衡,適合不熟悉控制的人熟悉瞄準機制),三種敵人刷新速度也較慢,兩種血量較低的敵人(兔子和熊)刷新時間為3秒,大象刷新時間為5秒。此外,對應30每發/每秒10發的射速,擊殺小型敵人所需時間很短,因此主要難度是利用地形和走位規避傷害并盡可能多的擊殺大象。
噩夢和夜半類似,是難度較高的夜半,例如敵人的傷害變高(通過提高攻擊間隔,單次傷害實現),血量變高,但控制人物的血量沒變,但相應提高了槍的傷害(例如擊殺大象原來需要17發,現在需要14發),相應的存活時間也會降低,因此難度較高,但同時人物的射速與單發傷害與第一關并無區別,玩家只需要一直按住左鍵然后向敵人反方向跑就可以了。
黎明的設計理念與前兩關不同,如果說前兩關的武器是輕型自動步槍,這關的武器則是狙擊槍。單發傷害提升到170意味著可以單發擊殺100血量的兔子,200血量的熊需要兩槍,500血量的大象需要三槍。相應的,人物的血量也提高為300,同時射速被削減到了0.5發每秒。此外,在該關卡中玩家的移動速度被提高到了8.0f(前兩關為6.0f),可以拉開距離進行遠距離的精確瞄準,由于設定時為地形中的障礙設計了碰撞檢測(設計navigation時烘培了所有模型),敵人無法穿過的模型子彈也無法穿過,因此關卡難度也很大。
極圈的設計類似于上世紀的游戲搶灘登陸等的理念,玩家的移動速度被極大限制但是射速和傷害被極大提高,在該關卡中人物移動速度僅為1.0f,但射速,單發傷害極高,對應的敵人刷新速度也很快且個人血量也很高,因此該關卡下玩家只需要站在原地然后擊退一波又一波的敵人即可。
三.設計理念:
1.UI設計思路:
游戲本身由兩類場景組成:開始界面和游戲關卡,其中開始界面的設計難點在于UI的布置,不同場景之間的連接和控件功能的實現;游戲關卡的設計難點在于人物動作之間的銜接,主角和敵方人物的移動控制和武器的命中判定。
游戲的UI為了契合游戲本身的卡通風格,因此大部分使用了較為活潑的字體和顏色設計,例如游戲從標題,關卡選擇到游戲結束使用的均是這種叫LUCKIEST-GUY的字體,但同時作為一個打僵尸的游戲,背景音樂設定上采用了比較陰森但是較為清澈的打擊樂。
在界面設計中,由于游戲本身色調偏暗,因此背景使用了紫色,但標題采用了鮮艷的顏色(手調的黃色和淺藍色,不一定好看
之后為Dream-Walking使用Animation功能添加了動畫效果,讓開始界面顯得不那么突兀。此外,為了增加標題的層次感,為兩段text分別添加了陰影,經過調整后藍色字體添加了黑色陰影,黃色字體添加了深黃色陰影,看起來比較像3D制作的標題。
同理,在關卡選擇部分的UI設計也為了整體的一致性采用了同樣的字體:
圖標本身使用了UI中的button選項,并為每一個按鈕的image組件添加了關卡的截圖。在設計時考慮到unity的button都是圓角按鈕,為了整體的美觀性想把關卡按鈕也做成圓角的,但是采用圖片作為按鈕背景時無論圖片是否是圓角圖片,保存成jpg格式后導入到texture中的結果都是矩形圖片(圓角圖片導入后會留下四個白色的角);查閱資料發現需要使用shader組件進行代碼控制,但在這版本的游戲中還沒有實現。
UI部分代碼實現思路:
游戲中用到的UI設計主要包含以下三部分:關卡切換,玩家信息顯示,音量調節;分別用一段代碼進行實現。
I. 關卡切換部分:
利用Load Level/Load Scene函數均可實現,為了避免bug加入了Debug.Log函數;完成代碼后在界面中的Button組件中使用OnBtnClick方法調用,并將每個關卡和代碼關聯即可。
關卡切換部分代碼如下:
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. 關卡中對人物的信息顯示:
屏幕中主要需要顯示人物的分數和血量,和游戲結束后的Game Over界面;
分數實現非常簡單,只需要構建一個Text文件然后設置每個敵方單位的得分并相加即可。
分數的代碼實現:
publicstaticintscore;
Texttext;
voidAwake()
{
text = GetComponent ();
score = 0;
}
voidUpdate()
{
text.text ="Score: "+ score;
}
}
III.人物血量的顯示:
血量的代碼實現稍后人物生命值部分會講解,只需要將人物血量顯示到已經在代碼中聲明過的Health Slider中即可,此處粘貼一下該部分代碼:
publicvoidTakeDamage (intamount)
{
damaged =true;
currentHealth -= amount;
healthSlider.value = currentHealth;
playerAudio.Play ();
if(currentHealth <= 0 && !isDead)
{
Death ();
}
}
IV. 游戲通關界面:
人物死亡后的Game Over動畫的實現也非常簡單,只需要在Animation中構建三部分:藍色背景的透明-----不透明,分數的高亮(大小變大再變小)和Game Over字樣的顯示。
在Animation中構建完成后只需要在代碼中調用該Animation組件即可。
代碼如下:
Animatoranim;
voidAwake()
{
anim = GetComponent();
}
V. 音量調節部分:
需要首先創建一個Slider,之后向Slider中添加Audio Source組件,并將背景音樂和該組件關聯。
之后向該Slider中添加代碼即可。該部分代碼實現如下:
usingSystem.Collections;
usingSystem.Collections.Generic;
usingUnityEngine;
usingUnityEngine.UI;
publicclassMusicAdministor:MonoBehaviour
{
publicSliderVolume;
publicvoidOnVolume()
{
GetComponent().volume = Volume.value;
}
}
2. 對第一人稱人物的設計:
I.控制人物的設計思路:
從代碼實現角度講分三部分實現:人物的移動;人物的傷害判定;人物的射擊判定。
從人物模型的角度講同樣分三部分實現:人物模型/動作的關聯(Animator組件),人物模型移動的判定(對地表模型的烘培,navigation模塊),人物開槍的動作設計
II.控制人物移動的設計:
人物的移動核心代碼如下:
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方法獲得來自鍵盤/鼠標的控制系數,Horizontal和Vertical是獲得鍵盤上下/左右鍵按下時觸發的,后面調用人物旋轉時使用的Mouse X,Mouse Y同理,獲得的是鼠標沿著屏幕的橫/縱軸進行移動時獲得的長度。
之后設置人物的移動面為X和Z(可以在人物模型的剛體組件內進行如下修改:
設置人物可以在XZ軸內進行平移)
之后對人物的移動設置一個三維數組movement,將Y值設置為0,并在代碼開始定義人物的移動速度:public float speed = 6.0f ,便于之后各關卡對人物的移動速度進行調節。
之后設置人物的位置為原位置+速度x時間,并每幀調用一次該函數即可。
III.人物的方向控制設計:
人物的旋轉函數與之類似:
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);
}
}
獲取人物鼠標位置的方法如上,創建三維數組后定義PlayerToMouse初始位置為玩家位置面向鼠標位置,旋轉角度的改變量為地面位置-改變位置,同樣每幀調用一次該方法。
IV.人物的動畫銜接設計:
之后對人物的動畫銜接進行設置:首先從Animator窗口對人物動作進行綁定:
提取到的動畫模組有三個:Move(移動),Idle(發呆),Death(死亡)。
之后對Conditions中添加兩個變量作為三種模組之間的轉換:
控制Idle-Move/Move-Idle的判定情況:Is Walking;是Bool型變量,Is True情況下轉為Move動畫,Is False情況下轉為Idle動畫。
控制Any State-Death的判定情況:Is Dead;是Trigger型變量,觸發時結束所有當前動作并進入Death動畫。
完成調節后對時間軸的切換點進行設置,因為進入Idle狀態需要一點時間的動畫延續以防止人物動作過于僵硬,因此將Move動畫稍微延長一段,并勾選Has Exit Time選項。而另外一邊的開始移動如果使用Has Exit Time就會在人物開始移動時位置出現平移而沒有動畫效果,所以需要取消掉Has Exit Time選項。
voidAnimating(floath,floatv)
{
boolwalking = h != 0f || v != 0f;
anim.SetBool("IsWalking", walking);
}
利用該代碼判定人物是否在移動(通過對水平/垂直平面的坐標進行判定),并修改Is Walking模組的數據。
voidDeath ()
{
isDead =true;
playerShooting.DisableEffects ();
anim.SetTrigger ("Die");
playerAudio.clip = deathClip;
playerAudio.Play ();
playerMovement.enabled =false;
playerShooting.enabled =false;
}
利用該代碼判定人物是否存活(通過人物的血量判斷是否存活,若死亡則停止人物的射擊和移動動畫),并修改Is Alive模組的數據。
V.人物的射擊判定:
因為人物的射擊通過ShootRay思路進行實現,所以對開火的設計如下:
1.設置單發傷害
2.設置開火間隔
3.設置射擊有效距離
4.將開火時的粒子效果/光效/音效在代碼中進行定義,并在Unity中進行綁定
5.利用代碼設置:左鍵按下判定開火;若距離上一發開火時間>開火間隔則設計,否則不射擊
6.定義射擊方向:從槍口開始,做一條長度為開火距離,角度為鼠標指向/人物角度的射線
7.定義射擊傷害判定:若射線和模型collider發生碰撞,且目標具有生命值(考慮到可能會射擊到地形/墻面/地形上)則造成傷害
控制射擊部分的代碼如下:
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.設定人物的生命上限,
2.將人物生命值投射到UI中的slider中,
3.通過生命值對Is Alive(上文中提到的判定模組)進行判斷,以對人物的動畫進行設置。
4.設置敵人的傷害參數(此處只是定義變量,后面設置敵人的攻擊代碼時會填入參數)
5.為了傷害效果逼真,在人物受到傷害時讓屏幕變紅,實現方法為在游戲關卡的UI中添加一個和屏幕一樣大的紅色image,平常透明度為0,若受到傷害則講透明度重置為100%,0.5秒后回復。該方法中利用color.lerp函數對圖片的顏色進行設置。
6.設置人物如果生命值降低至0時,觸發Death動畫,并在0.5秒內播放Game Over界面(和受傷的紅色界面類似,需要在外界通過animation和UI進行設計,但是在游戲中只需要調用觸發函數)
7.Game Over后調用Load Scene函數,回到主界面選擇重新開始。
代碼實現如下:
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);
}
}
關卡結束部分代碼:
voidUpdate()
{
if(playerHealth.currentHealth <= 0)
{
anim.SetTrigger("GameOver");
restartTimer +=Time.deltaTime;
if(restartTimer >= restartDelay)
{
Application.LoadLevel(Application.loadedLevel);
}
}
}
3.敵方單位設計思路:
和控制人物類似,對敵方單位的設計也從以下方面著手:敵人血量,敵人移動,敵人傷害,和敵人的動畫構建,和人物不同的是由于動畫素材限制,敵人沒有遠程攻擊(只有近戰,對應的也利用Animator進行不同動畫的關聯),并且敵人需要設置Navigation組件以智能的尋找玩家位置。
I.對敵人移動方式的設計:
1.設置敵人的基本移動速度;
2.將敵人的位置命名為一個三維數組;并定義敵人的新位置為原位置+速度x Delta.time,每幀執行一次。
3.為敵人設計碰撞檢測;以便后面對敵人的攻擊玩家/地形碰撞進行處理;
4.判定玩家的血量和敵人本身的血量,若血量>0則利用nav函數表達敵人的方向為面向玩家位置。
敵人移動的代碼實現如下:
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. 對敵人的血量設計:
1.設置敵人的初始血量(因敵人的不同而異),并設計擊殺后尸體消失的時間和增加的分值
2.定義敵人遭到攻擊時的粒子特效,聲效。
3.設置尸體消失的動畫:由于Animation中可以看出敵人死后是平躺的,所以不需要加入旋轉函數,只需要在Z軸上對敵人尸體進行平移即可,Z坐標為原坐標+尸體消失速度x Delta Time,每幀調用一次。
4.設置敵人遭到攻擊(在人物開槍的代碼中定義過傷害判定,此處只需要定義血量削減函數并通過get component調用受傷時的粒子特效和音效即可。
敵人血量的代碼設計如下:
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);
}
}
此外,和人物死亡動畫類似,敵人死亡也需要調用Death----Idle的Animator模組,此處也是定義一個Trigger變量Death,和人物死亡一樣----取消Exit Time并在代碼中調用該段動畫。
敵人的animator如下:
三.對敵人的攻擊設計
敵人對玩家的攻擊動作和人物射擊敵人的設計方式類似,步驟如下:
1.設置敵人的攻擊間隔和攻擊傷害(作為全局public變量,便于拖入敵人的prefab后修改數值,以改變敵人的難度)
2.調用玩家人物,作為敵人的移動方向和攻擊目標(此處同樣調用人物的血量以判定人物是否存活)
3.進行碰撞檢測(此處的碰撞檢測和敵人與地形碰撞檢測并不一樣,此處是判定敵人的攻擊區域內是否存在玩家----若存在則運行攻擊玩家的方法)
4.判定玩家人物的血量,若血量在0+且進入了敵人的攻擊范圍則進行一次攻擊判定(并開始計算敵人的攻擊動作的冷卻時間)
攻擊設計的代碼實現如下:
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);
}
}
}
四.設計步驟:
由于游戲本身內容復雜,為了較為形象的解釋該游戲從空場景到可以構建為成熟場景的過程,在此處簡要的解釋一下該游戲設計過程中的主要步驟:
1.構建一個游戲場景,并導入下載好的環境prefab文件(此處包含燈光設計)
2.導入玩家的人物模型,并在Animator中導入人物的不同動畫,并創建變量來規范動作間的變換觸發點和持續時間
3.對人物模型進行優化,首先對人物的槍支進行設計,加入開火的特效,并添加腳本對開火行為進行構建
槍支的Inspector界面最后如下圖:
4.對人物的移動進行設計,其中包括鏡頭的跟隨,人物的移動旋轉和移動動畫的觸發,并在代碼中對各個功能進行實現
人物本身的Animator最后如下:
人物本身的Inspector最后如下:
5.完成對玩家控制人物的調試后,對敵人的角色進行設計;首先將敵人的模型導入到游戲中;
6.對敵人的Animator進行控制,將各種動畫通過添加變量的方式進行關聯,并在代碼中對各個變量的作用時間分別進行定義。
敵人的Animator窗口如下:
7.對敵人的移動方式進行控制,通過代碼實現敵人的移動和攻擊,并設定敵人對地形的碰撞體積和對玩家進行攻擊的碰撞體積。
設計完成后敵人的Inspector窗口如下:
8.完成敵人移動的設計后需要對場景進行Navigation的烘培,對地形的角度/人物模型進行對比后將臺階等設置進行平衡,最后點擊烘培
烘培后的地形效果如下:
藍色部分為可移動平面。
9.將單個敵人保存為Prefab,并將同樣的腳本內容賦值給三種不同的模型(對動畫效果重新進行綁定),并修改人物的屬性(移動速度,單次傷害,傷害間隔,血量等)
10.設置怪物刷新的位置,并使用相應的代碼進行實現
11.對游戲場景進行相應的細化,例如燈光,鏡頭遠近,背景音樂設置等
12.完成游戲場景的布置后對場景進行build,并以此類推進行以下幾個游戲關卡的設計
13.完成游戲關卡的設計后開始進行UI界面的設計,對每關人物的血量/分數等利用代碼進行調用,并完成Game Over動畫的實現。
14.對游戲開始界面的GUI進行設計,包括關卡切換/音量調節等,并利用相關的代碼進行關卡切換等功能的實現。
15.對所有場景進行build操作,并對游戲進行基本測試,完成后導出游戲素材。
五.后記
本游戲參考了Unity官方教程https://unity3d.com/cn/learn/tutorials/projects/survival-shooter-tutorial
該教程從
12個方面對游戲設計進行了講解,是我在unity官網完成的第五部游戲開發教程,整個視頻課程約300分鐘,我從該視頻課程中受益匪淺,學到了相當多Unity中各方面的開發知識和前端代碼的實現與程序構建。
視頻的播放列表鏈接如下:
https://unity3d.com/cn/learn/tutorials/projects/survival-shooter/camera-setup?playlist=17144
本游戲非本人制作的部分如下:
游戲關卡的地形場景;游戲中玩家和敵人的模型;模型使用的動畫;游戲UI中使用的字體。
參考了教程中的部分如下:
游戲中玩家和敵人的運動代碼參考了部分視頻中給出的案例;
游戲內燈光的布置和設計;
游戲內Navigation地形的渲染設置。
獨立設計部分:
游戲機制,人物開火動畫,關卡,開始界面UI,分數判定等。
游戲素材內包含以下部分,如果需要檢查素材可以按以下方式檢查:
代碼部分:
分為玩家,敵人,攝像機,游戲機制四部分:
游戲內場景部分:
包括Level 00(開始界面)和Level 01-04(游戲關卡)
游戲內環境材質:
(來自素材包)
游戲內Prefab:
包括環境,槍和受傷的粒子特效,光效和玩家/敵人的模型。
游戲內材質球:
(來自素材包)
游戲內字體:
游戲內聲音素材:
游戲內人物受傷/死亡音效;背景音樂等
(來自素材包)
游戲內動畫效果素材:
主界面UI的動畫效果,游戲結束效果和設計時槍口的動畫效果
六.組員信息:
模型設計,動畫設計,關卡設計,人物設計,配樂,游戲機制設計,代碼設計,動畫組件設計,等等等等
游戲設計時間:大約30小時(包括寫報告時間5小時,海報制作2小時,看視頻10小時和獨立制作10小時)