Siki_Unity_1-5_見縫插針


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,可玩性更強一些)

   

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM