一、新建項目
新建項目,並在Assets下右鍵Import Package ->Custom Package導入資源。如下圖所示。
二、地形設計
地形工具的使用可以參考Unity官方文檔
2.1創建地形
在Hierarchy中右鍵創建Terrain(地形),同時在Assets中會出現New Terrain(保存的是地形相關數據),將其重命名爲Terrain Data並將其放入創建的Terrain文件夾中。
2.2 調整地形的長度和寬度
在Hierarchy視圖中選中Terrain,可以在Inspector視圖中看到Terrain遊戲物體的組件Terrain,這時點擊齒輪(Terrain Settings),在其中可以設置許多地形相關屬性。找到Terrain Width 和Terrain Length以及Terrain Height(地形的最大高度),將他們的值設爲50,每一個在修改後,按下回車將會生效。如下圖所示。
2.3 Raise or Lower Terrain(升高或降低地形)
其中
Brush size:用來調整刷子尺寸的
Opacity:地形強度,當Opacity越大時,地形升高的越快。
按住shift鍵並且用刷子刷地形可以降低地形。
詳細的可以參考Unity官方文檔
2.4 Smooth Height
此工具可以將地形設計的更加平滑。
2.5 Paint Texture
使用 Paint Texture 工具可將紋理(如草、雪或沙)添加到地形。如下圖所示。
詳情請參考Unity官方文檔的Paint Texture和地形圖層
2.6 Paint Trees
通過點擊Paint Trees圖標可以在地形上擺放一些樹,如下圖所示。
詳細請參考Unity官方文檔
2.7 Paint Details
通過點擊Paint Details圖標,可以對草和其他一些細節進行處理,如下圖所示。
詳細的請參考Unity官方文檔
三、古蹟探險地形設計
此處自由發揮,就不描述了。
由於太亮,所以需要**調節光的強度。**如下圖所示。
最終效果類似於如下圖。
四、相機和當前視野保持一致
讓相機和當前視野保持一致。選擇Main Camera -> GameObject -> Align With View。如下圖所示。
五、剛體
在場景中創建球體,運行遊戲發現球體在半空中並沒有掉落,這時就需要給球體遊戲對象添加Rigidbody(剛體)組件來實現物理效果。
Mass:對象的質量(默認爲千克)
Drag:阻力
Angular Drag:旋轉時的阻力
Use Gravity:是否受重力影響
Freeze Position:鎖定剛體沿世界 X、Y 和 Z 軸的移動。
Freeze Rotation:鎖定剛體圍繞局部 X、Y 和 Z 軸旋轉。
有關剛體的更多信息,請參考Unity官方文檔
六、碰撞器
碰撞器組件定義對象的形狀以便用於物理碰撞。如下圖所示,當禁用球體的碰撞器(Sphere Collider)後,球體會直接穿過地面,而沒禁用碰撞器時,則會與地面發送物理碰撞效果,也就不會穿過地面。
注意:碰撞發生的條件,兩個物體必須都有碰撞體(Collider),並且其中一個需要有剛體(Rigidbody)。
關於碰撞器的詳細信息可以查看Unity官方文檔
6.1 碰撞檢測的方法
在Assets下創建Scripts文件夾,在Scripts中創建命名爲Sphere的C#腳本,並將腳本掛載到Sphere遊戲物體上。如下圖所示。
可以使用以下方法(詳情可以參考Unity官方文檔)來進行碰撞檢測,這些方法都是由Unity調用的:
//當該碰撞體/剛體已開始接觸另一個剛體/碰撞體時,調用 OnCollisionEnter。(碰撞發生時調用)
private void OnCollisionEnter(Collision collision) {
}
//當該碰撞體/剛體已停止接觸另一個剛體/碰撞體時,調用 OnCollisionExit。(碰撞結束時調用)
private void OnCollisionExit(Collision collision) {
}
//對應正在接觸剛體/碰撞體的每一個碰撞體/剛體,每幀調用一次 :ref::OnCollisionStay。(碰撞過程中調用)
private void OnCollisionStay(Collision collision) {
}
6.2 碰撞信息的獲取
//當該碰撞體/剛體已開始接觸另一個剛體/碰撞體時,調用 OnCollisionEnter。(碰撞發生時調用)
private void OnCollisionEnter(Collision collision) {
//獲取我們和哪一個碰撞器發生了碰撞
print(collision.collider);
//獲取我們碰撞的遊戲物體的名字
print(collision.collider.name);
//獲取我們碰撞的遊戲物體的標籤
print(collision.collider.tag);
}
6.3 觸發檢測
有時候我們需要做一些機關,當角色靠近機關時會觸發一些效果,這時我們就可以將碰撞器設置爲觸發器(勾選 Is Trigger)。如下圖所示。可以創建一個Cube,移除掉Mesh Filter和Mesh Renderer組件。
或者直接創建一個空遊戲物體(Create Empty),然後給它添加碰撞器(Collider),並將碰撞器的Is Trigger勾選。並可以使用Edit Collider圖標對Collider範圍進行調節。如下圖所示。
6.4 觸發檢測的方法
可以使用以下方法來進行觸發檢測,詳情參考Unity官方文檔
//當一個遊戲物體開始進入到另一個遊戲物體觸發區域時,調用OnTriggerEnter
private void OnTriggerEnter(Collider other) {
}
//當一個遊戲物體離開另一個遊戲物體觸發區域時,調用OnTriggerExit
private void OnTriggerExit(Collider other) {
}
//當一個遊戲物體正在另一個遊戲物體觸發區域時,調用OnTriggerStay
private void OnTriggerStay(Collider other) {
}
6.5 觸發信息的獲取
//當一個遊戲物體開始進入到另一個遊戲物體觸發區域時,調用OnTriggerEnter
private void OnTriggerEnter(Collider other) {
//獲取觸發器
print(other);
//獲取觸發器所在遊戲物體的名字
print(other.name);
//獲取觸發器所在遊戲物體的標籤
print(other.tag);
}
七、Unity中四種燈光
關於光源的詳細信息可以參考Unity官方文檔
7.1 Directional Light
方向光對於在場景中創建諸如陽光的效果非常有用。方向光在許多方面的表現很像太陽光,可視爲存在於無限遠處的光源。方向光沒有任何可識別的光源位置,因此光源對象可以放置在場景中的任何位置。
7.2 Point Light
點光源位於空間中的一個點,並在所有方向上均勻發光。照射到表面的光線的方向是從接觸點返回到光源對象中心的線。強度隨着遠離光源而衰減,在到達指定距離時變爲零。點光源可用於模擬場景中的燈和其他局部光源。還可以用點光源逼真地模擬火花或爆炸照亮周圍環境。
7.3 Spot Light
像點光源一樣,聚光燈具有指定的位置和光線衰減範圍。不同的是聚光燈有一個角度約束,形成錐形的光照區域。錐體的中心指向光源對象的發光 (Z) 方向。聚光燈錐體邊緣的光線也會減弱。加寬該角度會增加錐體的寬度,並隨之增加這種淡化的大小,稱爲“半影”。
聚光燈通常用於人造光源,例如手電筒、汽車前照燈和探照燈。
7.4 Area Light
面光源是通過空間中的矩形來定義的。光線在表面區域上均勻地向所有方向上發射,但僅從矩形的所在的面發射。無法手動控制面光源的範圍,但是當遠離光源時,強度將按照距離的平方呈反比衰減。由於光照計算對處理器性能消耗較大,因此面光源不可實時處理,只能烘焙到光照貼圖中。
八、給場景添加火堆
8.1 給場景添加光源
給場景添加光源,並對光的顏色做一些設置。
8.2 添加火堆
給火堆添加光源,並將其設爲Prefab(預製體)。
九、Lightmapping
當我們在場景中不使用光照貼圖的話,光對場景的影響是需要實時計算的,這樣比較耗費性能。如果視野Lightmapping的話,會提前將光照信息計算好,然後烘焙成一個貼圖,並將貼圖貼到模型上,這樣在實際運行中就不需要進行重複計算了。
由於火光會有動畫效果,一閃一閃的,如果用Backed的話,效果是不變的。所以火堆這裏需要用Mixed。
觀察Scene視圖,發現其中沒有陰影。
十、使用粒子系統創建火焰
選擇Bonfire預製體,創建粒子系統。
調整形狀。
調整Start LifeTime和Start Speed
比較詳細的過程可以去看siki學院的視頻
最終效果,如下圖所示。
十一、給燈光添加閃爍效果
創建動畫
給燈光添加運動動畫效果,讓火苗左右搖擺。
整個動畫效果,如下圖所示。
十二、導航系統(尋路系統)
要使用導航系統需要進行導航網格的烘焙,在烘焙之前需要確定Environment的static是勾選上的(確保Navigation Static勾選上就行了)。
12.1 生成導航網格
在Navigation -> Bake ->Bake按鈕。可通過Agent Radius來調節代理半徑(類似於在障礙物的範圍不可進行導航)。
對於草之類的,角色應該是可以通過的,我們需要將其Navigation Static勾選取消掉,然後再重新進行烘焙。
對於不能到達的,要選中物體->Navigation->Object->AI->Navigation Area->Not Walkable。
12.2 添加導航組件
想要控制角色在網格上行走,需要給角色添加導航組件Nav Mesh Agent,可通過Radius和Height調整寬度和高度。
12.3 通過導航組件控制角色的移動
通過鼠標點擊地面,獲取鼠標點擊的點,將這個點設置爲目的地,然後讓角色到達目的地。
在Scripts文件夾下創建Hero腳本,並將其掛載到Hero遊戲物體上。
12.3.1 射線檢測
void Update() {
//鼠標左鍵按下
if (Input.GetMouseButtonDown(0)) {
//射線檢測
//ScreenPointToRay:將屏幕座標轉換爲射線
//Input.mousePosition:鼠標位置
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
//用於從射線投射獲取信息的結構。
RaycastHit hit;
//Physics.Raycast():向場景中的所有碰撞體投射射線,並返回有關命中對象的詳細信息,信息保存在hit中。
if (Physics.Raycast(ray, out hit)) {
print(hit.point);
}
}
}
12.3.2 控制角色到達目的地
在Hero腳本中定義屬性public NavMeshAgent agent;
並將組件Nav Mesh Agent拖入。如下圖所示。
在判斷代碼中用agent調用SetDestination()方法
if (Physics.Raycast(ray, out hit)) {
//print(hit.point);
//設置目的地
agent.SetDestination(hit.point);
}
效果,如下圖所示。
完整代碼:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;
public class Hero : MonoBehaviour {
public NavMeshAgent agent;
// Start is called before the first frame update
void Start() {
}
// Update is called once per frame
void Update() {
//鼠標左鍵按下
if (Input.GetMouseButtonDown(0)) {
//射線檢測
//ScreenPointToRay:將屏幕座標轉換爲射線
//Input.mousePosition:鼠標位置
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
//用於從射線投射獲取信息的結構。
RaycastHit hit;
//Physics.Raycast():向場景中的所有碰撞體投射射線,並返回有關命中對象的詳細信息,信息保存在hit中。
if (Physics.Raycast(ray, out hit)) {
//print(hit.point);
//設置目的地
agent.SetDestination(hit.point);
}
}
}
}
十三、控制攝像機的跟隨
調節相機到合適的角度,創建FollowTarget腳本,並將其掛載到Main Camera遊戲物體上。
在FollowTarget腳本中定義屬性public Transform hero;
保存,並在Unity中將Hero賦給hero。如下圖所示。
代碼:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class FollowTarget : MonoBehaviour {
//因爲跟隨目標,只需要目標的位置
public Transform hero;
//位置的偏移
private Vector3 offset;
// Start is called before the first frame update
void Start() {
//當前遊戲物體位置減去角色hero的位置
offset = transform.position - hero.position;
}
// Update is called once per frame
void Update() {
//相機跟隨
transform.position = offset + hero.position;
}
}
效果:
十四、控制角色的動畫播放
創建Animator Controller。
編輯狀態機。
在腳本中設置參數的值進行動畫的切換。
代碼:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;
public class Hero : MonoBehaviour {
public NavMeshAgent agent;
public Animator anim;
// Start is called before the first frame update
void Start() {
}
// Update is called once per frame
void Update() {
//鼠標左鍵按下
if (Input.GetMouseButtonDown(0)) {
//射線檢測
//ScreenPointToRay:將屏幕座標轉換爲射線
//Input.mousePosition:鼠標位置
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
//用於從射線投射獲取信息的結構。
RaycastHit hit;
//Physics.Raycast():向場景中的所有碰撞體投射射線,並返回有關命中對象的詳細信息,信息保存在hit中。
if (Physics.Raycast(ray, out hit)) {
//print(hit.point);
//設置目的地
agent.SetDestination(hit.point);
}
}
//agent.velocity.magnitude:速度的大小
anim.SetFloat("speed",agent.velocity.magnitude);
}
}