<!-- css 字體設定 -->
<style>
.reveal {
font-size: 24px;
}
</style>
# 虛擬實境4-2
<!--放入主題照片 統一 =480x320 -->

[原始課程 link](https://learn.unity.com/tutorial/lesson-plan-4-2-follow-the-player?uv=2018.4&projectId=5cf96846edbc2a2bcde6d0fc#)
###### tags: `虛擬實境AA`
----
## 課程目標
- 賦予物件物理特性:`bouncy`
- 使敵人能自動追蹤玩家的位置
- 在平台上自動生成敵人
- 學習使用更高等的函式或變數,讓整體程式碼變專業且好看
----
## 新增一個敵人
----

在`Hierarchy`點擊右鍵
選取`3D Object` 點擊`Sphere`
:warning:並將球體拉離開玩家 好進行編輯的部分
----

將新物件名稱修改為`Enemy`
----

在`Inspector` `Transform`找到`Scale`
將XYZ都更改為`1.5`
----

在`Project` `Assets` `Texture` 隨機找一個與玩家物件不同的外觀款式
將其拖移至上方的`Enemy`
----

將`Enemy`的`Position`的Y軸更改為`0.15`
----

為了對抗玩家 我們也必須將敵人球體變為實體
因此在`Enemy` `Inspector` 拉到最下方
點擊`Add Component` 並搜尋`Rigidbody`
(由於上一篇ppt已有介紹 若有不清楚的地方 請自行回顧上一篇:blush::blush::blush:)
----
## 建立物理特性
----

在`Project` `Assets`點擊右鍵
點選`Create` 選取`Folder`建立一個新的資料夾
----

將此資料夾命名為`Physical Materials`
----

在`Physical Materials`資料夾點擊右鍵
點選`Create` 選取`Physical Material`
----

將檔名更改為`Bouncy`
----

將`Bouncy`拖移至上方的`player`
----

同樣的也拖移至`Enemy`
----

**(P)如何知道`player`跟`Enemy`都有`Physical Material`?(P)**
點擊`player`或`Enemy`並在右方的`Inspector`找到`Sphere Collider`
裡面的`Material`中 如果有成功加入會顯示`Bouncy`
----

點擊`Bouncy`並更改`Bounciness`為`1`
`Bounce Combine`更改為`Multiply`並測試看看會有甚麼改變
----
## 使敵人能自動追蹤玩家
----

在`Project` `Assets` `Scripts`點擊右鍵
點選`Create` 點擊建立`C# Scripts`
將檔案取名為`Enemy`後 並拖移`Enemy.cs`到`Hierarachy`的`Enemy`中
並雙擊打開
----

在`public class(){}`中打上
```csharp
public float speed = 3.0f;//給予速度變數一個數值
private Rigidbody enemyRb;//建立enemy實體變數
private GameObject player;//建立player物件變數
```
在`void Start(){}`中打上
```csharp
enemyRb = GetComponent<Rigidbody>();//拿取enemy實體變數數據
player = GameObject.Find("player");//在所有的GameObject中尋找player,並拿去player的數據
```
在`void Update(){}`打上
```csharp
enemyRb.AddForce((player.transform.position - transform.position)* speed);//給予enemy一個往player位置的力
```
----
## 程式碼debug
----
(P)在程式碼寫完後 我們可以按下撥放鍵遊玩
其中會發現 如果敵人離玩家很遠 那麼力的公式將會因為距離而不斷累加
造成敵人撞到玩家時會產生太大的力而將玩家彈飛
所以以下對於程式碼的修改 目的是為了不讓敵人的速度持續累加造成力量過大(P)
----

在`void Update(){}`更改為
```csharp
enemyRb.AddForce((player.transform.position - transform.position).normalized * speed);
```
----
## 使視野朝向前方
----
在`void Update()`打上
```csharp=
Vector3 lookDirection = (player.transform.position - transform.position).normalized;
//並將enemyRb.AddForce((player.transform.position - transform.position).normalized * speed); 修改為
enemyRb.AddForce(lookDirection * speed);
```
----
## 在平台中的隨機位置生成敵人
----

在`Project` `Assets`點擊右鍵
點選`Create` 點擊`Folder`
並取名為`Prefabs`
----

將`Hierarchy` 中的`enemy`拖移至下方剛建立的資料夾`Prefabs`中
----

將`Hierarchy` 中的`enemy` 刪除
----

在`Hierarchy` 中點擊右鍵 點選`Create Empty`
----

將新的`GameObject` 取名為`Spawn Manager`
----

在`Project` `Assets` `Scripts`點擊右鍵 建立一個新的`C# Scripts`
----

取名為`SpawnManager`
----

將剛剛建立好的`SpawnManager`拖移至上方的`Spawn Manager`
----

打開`Project` `Assets` `Scripts`中的`SpawnManager`
在`public class`中打上
```csharp
public GameObject enemyPrefab;//建立enemy prefab變數
```
在`void Start(){}`中打上
```csharp
Instantiate(enemyPrefab, new Vector3(0,0,6), enemyPrefab.transform.rotation);//將敵人建立在指定的XYZ上
```
----

點擊`Hierarchy`的`Spawn Manager`
在右方的`Inspector`
將`Project` `Prefabs`中的`Enemy`拖移至`Enemy Prefab`
----
(p)此時多次測試遊戲會發現敵人只會重生在同一個點 所以必須修改程式碼
使讓它出現在隨機的位置(p)
----

在`void Start`中打上
```csharp
float spawnPosX = Random.Range(-9,9);
float spawnPosZ = Random.Range(-9,9);//經過測量發現平台大小大約落在9x9的範圍中
Vector3 randomPos = new Vector3(spawnPosX, 0, spawnPosZ);//在此範圍產生隨機一個地方並給予其一個變數儲存位置
Instantiate(enemyPrefab, randomPos, enemyPrefab.transform.rotation);
```
----

(p)試著讓程式碼變得更專業、好看(p)
在`public class`中打上
```csharp
private float spawnRange = 9;//將void Start裡重複的9改成不被更改的變數
```
在`void Start`中打上
```csharp
float spawnPosX = Random.Range(-spawnRange, spawnRange);
float spawnPosZ = Random.Range(-spawnRange, spawnRange);//將spawnRange代入原本寫9的地方
```
----
## 利用自定義的函式使程式碼變得好看
----

在`void Start`中打上
```csharp
//GenerateSpawnPosition()是等等會寫在最下面的函式
Instantiate(enemyPrefab, GenerateSpawnPosition(), enemyPrefab.transform.rotation);
```
在`public class`中的最下面建立一個`GenerateSpawnPosition()`函式
```csharp
private Vector3 GenerateSpawnPosition()
{
float spawnPosX = Random.Range(-spawnRange, spawnRange);
float spawnPosZ = Random.Range(-spawnRange, spawnRange);
Vector3 randomPos = new Vector3(spawnPosX, 0, spawnPosZ);
return randomPos;
}
```
----
可以前往下一小節了
{"metaMigratedAt":"2023-06-15T14:32:27.394Z","metaMigratedFrom":"YAML","title":"虛擬實境4-2","breaks":true,"contributors":"[{\"id\":\"06326c0f-824e-4964-b604-fd9b52334bb2\",\"add\":6363,\"del\":626}]"}