2018年11月20日 星期二

教學範例 (1): Unity 做上下移動控制及 4 個本地多人遊玩的分割畫面

這樣的教學範例會延伸一系列文章,記載「遊戲設計社」社團課程中所教的專題內容及方法。

目標:

  1.  本地多人畫面遊玩
  2.  設定 4 組外接搖桿做控制 (以 Xbox Controller 為主,但因手邊沒有,無法詳盡介紹)
  3.  四個角色都能被控制
  4.  畫面切割線


實際畫面:




分割四個畫面的設定


要分割四個畫面,等於是只要 4 個不同的攝影機進行控制,我們先看看一個攝影機的情況,如何調整為 1/4 的畫面,且保持在平面座標第二象限。


在攝影機的 Component 設定中,有個 Viewport Rect,這是一個 Component 參數,而且型別是 Rect,其中可以直接在 Inspector 中調整 x,y, 寬度比, 高度比,然後就會置中在如下畫面 (若是在遊戲起動時拖曳,會有殘影):


程式碼部分:


GameObject camera_1 = new GameObject();
camera_1.AddComponent<Camera>();
camera_1.GetComponent<Camera>().rect = new Rect(0,0.5f,0.5f,0.5f);
camera_1.name = "Camera Player 1";

於是,這個攝影機就會在開始遊戲時,自己生產一個攝影機遊戲物件,然後預設調整其 Rect。

*此腳本(init.cs)請在 start 中寫入該程式,並且將腳本套用到一個空物件上。

加入至遊玩角色物件底下


我們期望在 Hierarchy 中可以把 Camera 變成跟 Player 之間的父子關係,因此套用 4 個攝影機分別到四個玩家座標上,然後把攝影機位置往後往上拉,目的是可以在 Player 移動的時候,原座標也會相同。


其中使用綁定的程式碼是將子物件的 transform 其中一參數 (transform.parent) 指定為父物件的 Transform 型別,因為一個子物件只會有一個父物件。

然後在子物件中欲想設定座標,請注意在繼承關係下的物件,座標會轉換本地座標 (local position),所以在 Inspector 上顯示的 transform position x,y,z 座標也會是 local position (本地座標),在設定遊戲物件座標時,要使用 transform.localPosition 而不是 transform.position。

程式碼部分(init.cs):

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Init : MonoBehaviour {

 public GameObject player1;
 public GameObject player2;
 public GameObject player3;
 public GameObject player4;

 

 // Use this for initialization
 void Start () {
  GameObject camera_1 = new GameObject();
  camera_1.AddComponent<Camera>();
  camera_1.GetComponent<Camera>().rect = new Rect(0,0.5f,0.5f,0.5f);
  camera_1.name = "Camera Player 1";
  camera_1.transform.parent = player1.transform; //指定父物件是誰
  camera_1.transform.Rotate(new Vector3(30,0,0)); //攝影機旋轉位置
  camera_1.transform.localPosition = new Vector3(0,1.5f,-2); //攝影機位置向後看


  GameObject camera_2 = new GameObject();
  camera_2.AddComponent<Camera>();
  camera_2.GetComponent<Camera>().rect = new Rect(0.5f,0.5f,0.5f,0.5f);
  camera_2.name = "Camera Player 2";
  camera_2.transform.parent = player2.transform;
  camera_2.transform.Rotate(new Vector3(30,0,0));
  camera_2.transform.localPosition = new Vector3(0,1.5f,-2);


  GameObject camera_3 = new GameObject();
  camera_3.AddComponent<Camera>();
  camera_3.GetComponent<Camera>().rect = new Rect(0.5f,0,0.5f,0.5f);
  camera_3.name = "Camera Player 3";
  camera_3.transform.parent = player3.transform;
  camera_3.transform.Rotate(new Vector3(30,0,0));
  camera_3.transform.localPosition = new Vector3(0,1.5f,-2);


  GameObject camera_4 = new GameObject();
  camera_4.AddComponent<Camera>();
  camera_4.GetComponent<Camera>().rect = new Rect(0,0,0.5f,0.5f);
  camera_4.name = "Camera Player 4";
  camera_4.transform.parent = player4.transform;
  camera_4.transform.Rotate(new Vector3(30,0,0));
  camera_4.transform.localPosition = new Vector3(0,1.5f,-2);
 }
 
}

*此程式腳本尚未完整,請自行加入螢幕分割的程式。


玩家角色物件控制


在控制角色移動時,會碰到兩個問題:

  1.  多個控制器如何控制各自的不同物件
  2.  同一個腳本如何區分不同的物件進行控制

我們得解決第一個問題,事實上我們一般使角色在 x,y 座標下移動,使用 WASD 或上下左右的程式會像這樣:

void Update () {
    float x = Input.GetAxis("Horizontal"),y = Input.GetAxis("Vertical");
    transform.Translate(x,y,0);
}

而在 Input.GetAxis 中的字串,其實是 Unity 中 Input Setting 的參數設定,有 Horizontal, Vertical 兩個設定涵蓋了鍵盤中 WASD, 上下左右的定義。

功能選項位於 Edit -> Project Settings -> Input。


在功能中,你可以看到有 Horizontal, Vertical 這兩個設定,而下面的 Joy Num (如下圖)其實就是指 Joystick(可以想成是不同的搖桿控制器),只要指定到 N 個控制器,就可以區分玩家了。


如果要設定 4 個玩家,那就對預設的 Horizontal, Vertical 兩個參數,右鍵複製(如下圖):


複製後更改名稱,則就是在 Input.GetAxis 中需要的參數,這裡就複製 4 個 horizontal, 4 個 vertical 改為 player1x, player1y, player2x, player2y,.....


程式中,按照 Player 1 - 4 來做區分,則定義一個 enum 來區別個項設定:


最好是能夠在 Component 中做選擇,會比較方便。

程式碼(PlayerControl.cs):

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerControl : MonoBehaviour {

 public enum playerType { player1, player2, player3, player4 };

 public playerType playerNumber;


 // Use this for initialization
 void Start () {
  
 }
 
 // Update is called once per frame
 void Update () {
  float x = 0,y = 0;
  
  //for player 1
  if(playerNumber.Equals(playerType.player1)){
   x = Input.GetAxis("Player1x");
   y = Input.GetAxis("Player1y");
  }

  //for player 2
  if(playerNumber.Equals(playerType.player2)){
   x = Input.GetAxis("Player2x");
   y = Input.GetAxis("Plater2y");
  }
  
  transform.Translate(x,y,0);
  
 }
}

不詳列 player 1- 4 之內容,請自行新增。

*此腳本(PlayerControl.cs)請套用至各角色的 GameObject 中,然後請設定 Component 參數。


在螢幕畫分割線


在螢幕中做分割線有很多做法,在此只用最粗糙的方式完成:

程式碼(init.cs),請自行加入在 update(){} 結束之後。

void OnGUI(){
    GUI.Box(new Rect(Screen.width / 2, 0, 1, Screen.height),"");
    GUI.Box(new Rect(0, Screen.height / 2, Screen.width, 1),"");
}

Reference:
https://docs.unity3d.com/ScriptReference/Transform-localPosition.html
https://docs.unity3d.com/ScriptReference/GUI.Box.html



沒有留言:

張貼留言

© Mac Taylor, 歡迎自由轉貼。
Background Email Pattern by Toby Elliott
Since 2014