1-5 見縫插針
任務1:資源下載
任務2:案例演示
任務3:創建工程和場景
Project Name:StickPin
import素材,為兩張png圖
創建各個分類文件夾Scenes/ Prefabs/ Scripts
修改Main Camera的Clear Flags為Solid Color
Background顏色到小清新的卡其色
任務4:創建小球和分數顯示
2D游戲 -- 勾選Scene上的2D標識
創建小球:
將Image里的Circle拖入Hierarchy面板
調整位置到中偏上,scale為0.7
顏色為黑
計分板:
UI->Text 用於顯示分數
刪除自動創建的EventSystem,因為不需要用到事件
Text居中(reset Rect Transform即可)
文字水平居中豎直居中,字體白色,大小變大
Canvas的渲染模式Render Mode改為World Space
這樣就可以將UI縮小到和游戲開發環境一樣,便於設計大小
Canvas的Event Camera選擇為Main Camera;共用同一個Camera即可
Canvas的大小設置為100*100(因為Text的是100*100)
但是Canvas和Circle比較還是很大,-> scale 0.01 (之前是1pixel=1m,現在是100pixels=1m)
將Canvas的位置放在Circle圓心(Position值相同即可)
運行游戲,手動改變分數,發現100分時候只顯示10分
勾選Text的best fit,自適應大小
任務5:控制小球旋轉
圍繞圓心順時針勻速旋轉 -- 圍繞z軸旋轉
transform.Rotate(new Vector3(0, 0, -1) * speed * Time.deltaTime);
speed 設置為90; // 每秒鍾旋轉90°
任務6:針的Prefab預制體
創建針 Image->Pin
顏色為黑,大小放大到接近Circle的直徑,方向從下往上
創建針頭 Image->Circle
成為Pin的子物體
顏色為黑,改變大小,放在針的下端
給針頭Circle添加碰撞器Circle Collider 2D
做成Prefab
任務7:開發GameManager生成針(實例化)
創建空物體StartPoint,放置於針准備發射的位置
創建空物體SpawnPoint,放置於針實例化的位置(在屏幕外部)
創建空物體GameManager,用於管理針的實例化
創建GameManager.cs
控制針的發射:
得到兩個點的位置:
private Transform startPoint;
private Transform spawnPoint;
startPoint = GameObject.Find("StartPoint").transform;
spawnPoint = GameObject.Find("SpawnPoint").transform;
得到Prefab:
public GameObject pinPrefab; // 拖拽賦值
實例化針:
GameObject.Instantiate( pinPrefab, spawnPoint.position, pinPrefab.transform.rotation);
public class GameManager : MonoBehaviour { public GameObject pinPrefab;private Transform spawnPoint; // Use this for initialization void Start() { spawnPoint = GameObject.Find("SpawnPoint").transform; SpawnPin(); } private void SpawnPin() { GameObject.Instantiate(pinPrefab, spawnPoint.position, pinPrefab.transform.rotation); } }
任務8&9&10:控制針移動到准備位置 & 針的插入 & 判斷針到達表面
給Pin添加腳本PinMovement.cs來控制針的初始運動
Pin的運動分為兩段:1. 准備階段;2. 插針階段
用bool hasReachedStartPoint = false; 來判斷是否到達StartPoint
用bool isInserting = false; 來判斷是否在插針階段
1. 准備階段
private Transform startPoint; // 獲取該Transform與上任務相同
邏輯思路:
if(isInserting == false) {
if(hasReachedStartPoint == false) { // 准備階段
transform.position = Vector3.MoveTowards
(transform.position, startPoint.position, speed * Time.deltaTime);
// MoveTowards(起點,終點,速度) 返回一個Vector3的位置信息
}
}
2. 判斷是否到達StartPoint
Vector3.Distance(transform.position, startPoint.position) < 0.05f;
// Vector3.Distance(兩點坐標),返回的是兩點之間的距離
如果到達,hasReachedStartPoint = true;
3. 插針階段
檢測鼠標左鍵的按下
Input.GetMouseButtonDown(0);
發射針:
private PinMovement currentPin;
實例化的時候currentPin得到Pin的實體(賦值給currentPin即可)
currentPin = GameObject.Instantiate(..).GetComponent<PinMovement>();
currentPin.StartInsert();
StartInsert() {
isInserting = true;
hasReachedStartPoint = true;
}
朝着Circle運動:
得到Circle的位置 private Transform... = GameObject.Find(...);
transform.position = Vector3.MoveTowards(...);
運行,點擊鼠標,Pin insert了,但是在一個奇怪的位置停住了
發現針頭的名字也是Circle,懷疑得到的是這個Circle的坐標,將其改為PinHead
還是不對,將腳本中Circle設置為public,運行游戲,雙擊Unity里的public Circle,發現這個Circle的屬性和PinHead的屬性相同,但是不知道怎么改。。。故使用FindGameObjectWithTag("Circle");實現
成功運行了。但是將代碼改回Find("Circle")后發現,也成功運行了。不知道為何。有點懵逼。
4. 判斷是否到達目標位置(是否插入Circle)
同樣用Vector3.Distance()判斷
在Unity中手動計算針在到達小球表面時候針和小球原點的距離
private Vector3 targetPosition = circleTransform.position - Vector3(0, diff,0);
if(Vector3.Distance(transform.position, targetPosition) < 0.05f) {
transform.position = targetPosition; // 最后位置的到達
transform.parent = circle; // 讓針隨着小球轉動
isInserting = false;
}
void Update () { if (isInserting == false) { if (hasReachedStartPoint == false) { // 准備階段 transform.position = Vector3.MoveTowards(transform.position, startPoint.position, speed * Time.deltaTime); // MoveTowards(起點,終點,速度) 返回一個Vector3的位置信息 if (Vector3.Distance(startPoint.position, transform.position) < 0.05f) { transform.position = startPoint.position; hasReachedStartPoint = true; // 到達以后transform就不變了,除非isInserting == true } } } else { // 插針階段 transform.position = Vector3.MoveTowards(transform.position, targetPosition, speed * Time.deltaTime); if (Vector3.Distance(transform.position, targetPosition) < 0.05f) { transform.position = targetPosition; // 最后位置的到達 transform.parent = circleTransform; // 讓針隨着小球轉動 isInserting = false; // 到達小球表面,isInserting == false; hasReached == true; 不會執行代碼 } } } public void StartInsert() { isInserting = true; hasReachedStartPoint = true; }
任務10:針的連環發射
在點擊鼠標左鍵的時候,StartInsert();之后進行SpawnPin();即可
針的運動速度有點慢,修改為15
void Update() { // GameManager.csif (Input.GetMouseButtonDown(0)) { currentPin.StartInsert(); SpawnPin(); } }
任務11:針頭的碰撞和游戲結束
觸發檢測
針頭有了Collider,但是沒有剛體組件
添加Rigidbody2D,重力Gravity Scale設置為0
並使用Trigger模式(不想讓碰撞影響運動)
如果兩個針頭碰撞,游戲結束
給PinHead添加Tag "PinHead",方便Trigger的檢測
PinHeadCollision.cs
void OnTriggerEnter2D(Collider2D collier) {
if(collider.tag == "PinHead") {
// 調用GameManager的方法
GameObject.Find("GameManager").
GetComponent<GameManager>().GameOver();
}
}
GameManager.GameOver():
// 因為每個PinHead上都會有PinHeadCollision的腳本,所以Collision發生的時候會執行多次GameOver(),而實際上執行一次即可
private bool isGameOver = false;
public void GameOver() {
if(isGameOver) return;
// 游戲結束后小球不旋轉了
GameObject.Find("Circle").GetComponent<RotateSelf>().enabled = false;
isGameOver = true;
}
在Update()中,游戲結束后就不能控制Pin了
Update() {
if(isGameOver) return;
...
}
任務12:控制分數的顯示
private int score = 0;
public Text scoreText; // using UnityEngine.UI;
// 在按下鼠標的時候加分
scoreText.text = score.ToString();
void Update() { // GameManager.cs if (isGameOver) return; if (Input.GetMouseButtonDown(0)) { currentPin.StartInsert(); score++; scoreText.text = score.ToString(); SpawnPin(); } }
任務13:游戲結束動畫的顯示
思路:
游戲背景顏色改變
Camera size變小(畫面變近)
GameManager.cs
IEnumerator GameOverAnimation() { // using System.Collections;
while(true) {
mainCamera.backgroundColor =
Color.Lerp(mainCamera.backgroundColor, Color.red, speed * Time.deltaTime);
mainCamera.orthographicSize =
Mathf.Lerp(mainCamera.orthographicSize, 4, speed * Time.deltaTime);
if(Mathf.Abs(mainCamera.orthographicSize - 4) < 0.01f) break; // 判斷是否到達目標值
yield return 0;
}
yield return new WaitForSeconds(0.5f); // 暫停0.5s(因為播放完動畫會自動重新開始游戲)
// using UnityEngine.SceneManagement
SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex); // 重載游戲
}
// Lerp(起始值,目標值,改變速度) -- 漸變
在GameOver()中加入StartCoroutine(GameOverAnimation());調用;
(將circle旋轉速度改為140,可玩性更強一些)