今回の記事ではカーソルを実装します。
カーソルとは
どのようなものかはまず以下の画像を見てください。
ユニティちゃんの横に水色のオブジェクトがマウスの先にあるのが分かりますね。
このようにゲーム内でマウスに追従するポインタの役割をするオブジェクトがカーソルです。
そして今回はそのカーソルを利用して、前回の戦闘の導入ではキャラクターの正面にしか飛ばせなかった攻撃を、カーソルに向かって攻撃を飛ばせるようにしましょう!
カーソルの導入手順
カーソルの導入手順は以下の通りです。
- MouseCursorオブジェクトの作成
- レイヤー"Player"と"Attack"を追加し、プレイヤープレハブと攻撃の球プレハブを設定
- CursorManageScriptを作成し、MouseCursorオブジェクトにセット
- CharacterControlScriptを変更
MouseCursorオブジェクトのInspectorビュー
カーソルは見た目上分かりやすいように水色のCursorMatというmatファイルを作成し、Materialsに適用しています。
"Player"、"Attack"レイヤーの追加と設定
以下の画像のように新規のUser Layerを追加します。
ユニティちゃんのPrefabのLayerを"Player"に、攻撃の球オブジェクトのLayerを"Attack"に設定します。
CursorManageScript.csのソースコード
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
using UnityEngine; using System.Collections; public class CursorManageScript : MonoBehaviour { void Update() { //カメラからマウスがある場所に向かってRayを発射 RaycastHit hit; //layer8と9の"Player"と"Attack"には当たらないためのマスク int layerMask = ~(1 << 8 | 1 << 9); Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition); if (Physics.Raycast(ray, out hit, Mathf.Infinity, layerMask)) { //Rayが当たった所にカーソルを移動させる transform.position = hit.point; } } } |
カメラからマウスカーソルがある方向にRayを飛ばし、Rayが当たった場所にカーソルを動かすようにしています。
普通のゲームではキャラクターや攻撃にカーソルは乗らないので、layerMaskでUser Layer 8の"Player"レイヤーとUser Layer 9の”Attack”レイヤーのオブジェクトにはRayが当たらないようにしています。
なのでプレイヤーと攻撃のオブジェクトのレイヤーが違う番号であればlayerMaskの数字を書き換えてください。
CharacterControlScript.csの変更後ソースコード
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 |
using System.Collections; using System.Collections.Generic; using UnityEngine; public class CharacterControlScript : MonoBehaviour { //オンライン化に必要なコンポーネントを設定 public PhotonView myPV; public PhotonTransformView myPTV; private Camera mainCam; //移動処理に必要なコンポーネントを設定 public Animator animator; //モーションをコントロールするためAnimatorを取得 public CharacterController controller; //キャラクター移動を管理するためCharacterControllerを取得 //移動速度等のパラメータ用変数(inspecterビューで設定) public float speed; //キャラクターの移動速度 public float jumpSpeed; //キャラクターのジャンプ力 public float rotateSpeed; //キャラクターの方向転換速度 public float gravity; //キャラにかかる重力の大きさ Vector3 targetDirection; //移動する方向のベクトル Vector3 moveDirection = Vector3.zero; //戦闘用変数&状態フラグ管理 public GameObject BallPrefab; //ボールPrefab bool MoveLock = false; //移動ロックフラグ bool AttackLock = false; //連射防止用攻撃ロックフラグ bool invincible = false; //無敵フラグ bool Deadflag = false; //死亡フラグ //マウスカーソルの位置取得用 Transform Cursor; // Start関数は変数を初期化するための関数 void Start () { if (myPV.isMine) //自キャラであれば実行 { //MainCameraのtargetにこのゲームオブジェクトを設定 mainCam = Camera.main; mainCam.GetComponent<CameraScript>().target = this.gameObject.transform; //マウスカーソルのTransformを設定 Cursor = GameObject.Find("MouseCursor").transform; } } // Update関数は1フレームに1回実行される void Update () { //自キャラでなければ操作しないためreturn if (!myPV.isMine) { return; } //移動ロックONまたは死亡フラグONであれば移動、攻撃をさせない if (!MoveLock && !Deadflag) { moveControl(); //移動用関数 RotationControl(); //旋回用関数 } //攻撃ロックがかかっていなければ攻撃できる if (!AttackLock) { //攻撃処理 AttackControl(); } //最終的な移動処理 //(これが無いとCharacterControllerに情報が送られないため、動けない) controller.Move(moveDirection * Time.deltaTime); //スムーズな同期のためにPhotonTransformViewに速度値を渡す Vector3 velocity = controller.velocity; myPTV.SetSynchronizedValues(velocity, 0); } void moveControl() { //★進行方向計算 //キーボード入力を取得 float v = Input.GetAxisRaw("Vertical"); //↑↓の入力 float h = Input.GetAxisRaw("Horizontal"); //←→の入力 //カメラの正面方向ベクトルからY成分を除き、正規化してキャラが走る方向を取得 Vector3 forward = Vector3.Scale(Camera.main.transform.forward, new Vector3(1, 0, 1)).normalized; Vector3 right = Camera.main.transform.right; //カメラの右方向を取得 //カメラの方向を考慮したキャラの進行方向を計算 targetDirection = h * right + v * forward; //★地上にいる場合の処理 if (controller.isGrounded) { //移動のベクトルを計算 moveDirection = targetDirection*speed; //Jumpボタンでジャンプ処理 if (Input.GetButton("Jump")) { moveDirection.y = jumpSpeed; } } else //空中操作の処理(重力加速度等) { float tempy = moveDirection.y; //(↓の2文の処理があると空中でも入力方向に動けるようになる) //moveDirection = Vector3.Scale(targetDirection, new Vector3(1, 0, 1)).normalized; //moveDirection *= speed; moveDirection.y = tempy - gravity * Time.deltaTime; } //★走行アニメーション管理 if (v > .1 || v < -.1 || h > .1 || h < -.1) //(移動入力があると) { animator.SetFloat("Speed", 1f); //キャラ走行のアニメーションON } else //(移動入力が無いと) { animator.SetFloat("Speed", 0f); //キャラ走行のアニメーションOFF } } void RotationControl() //キャラクターが移動方向を変えるときの処理 { Vector3 rotateDirection = moveDirection; rotateDirection.y = 0; //それなりに移動方向が変化する場合のみ移動方向を変える if (rotateDirection.sqrMagnitude > 0.01) { //緩やかに移動方向を変える float step = rotateSpeed * Time.deltaTime; Vector3 newDir = Vector3.Slerp(transform.forward, rotateDirection, step); transform.rotation = Quaternion.LookRotation(newDir); } } //ボール攻撃 void AttackControl() { if (Input.GetButtonDown("Fire1")) { //カーソル方向に向く transform.LookAt(Cursor); //攻撃ロック開始 AttackLock = true; StartCoroutine(_ballattack(1f)); } } IEnumerator _ballattack(float pausetime) { //RPCでボール生成 myPV.RPC("BallInst", PhotonTargets.AllViaServer, transform.position + transform.up, transform.rotation); //攻撃硬直のためpausetimeだけ待つ yield return new WaitForSeconds(pausetime); //攻撃ロック解除 AttackLock = false; } [PunRPC]//ボール生成 void BallInst(Vector3 instpos, Quaternion instrot, PhotonMessageInfo info) { //ボールを生成 GameObject Ball = Instantiate(BallPrefab, instpos, instrot) as GameObject; Ball.GetComponent<BallManageScript>().Attacker = info.sender; //ボールに自分のPhotonPlayer情報を乗せる } #region 被弾関連処理 void OnTriggerEnter(Collider col) { //自キャラ以外なら処理しない if (!myPV.isMine) { return; } if (Deadflag || invincible) //死亡時または無敵時は処理しない { return; } PhotonPlayer colAttacker = col.GetComponent<BallManageScript>().Attacker; //当たった物がボールではないまたは自分が生成したボールならなにもしない if (!col.CompareTag("Ball")||colAttacker.IsLocal) { return; } else { //ダメージを与える LocalVariables.currentHP -= 20; //攻撃側プレイヤーのkillcount++処理 if (LocalVariables.currentHP > 0) { myPV.RPC("Damaged", PhotonTargets.AllViaServer); //被弾処理RPC StartCoroutine(_rigor(.5f)); //被弾硬直処理 } else { myPV.RPC("Dead", PhotonTargets.AllViaServer); //死亡処理RPC StartCoroutine(_revive(3.5f)); //復活処理 } } } //被弾処理同期用RPC [PunRPC] void Damaged() { MoveLock = true; //硬直のため移動ロックON animator.SetTrigger("DamagedTrigger"); //ダメージアニメーション } //ヒット時硬直処理 IEnumerator _rigor(float pausetime) { yield return new WaitForSeconds(pausetime); //倒れている時間 MoveLock = false; //移動ロック解除 } //死亡処理同期用RPC [PunRPC] void Dead() { Deadflag = true; //死亡フラグON AttackLock = true; //攻撃ロックON MoveLock = true; //移動ロックON animator.SetTrigger("DeathTrigger"); //死亡アニメーションON } //復活コルーチン IEnumerator _revive(float pausetime) { yield return new WaitForSeconds(pausetime); //倒れている時間 //復活 Deadflag = false; //死亡解除 AttackLock = false; //攻撃ロック解除 MoveLock = false; //移動ロック解除 invincible = true; //死亡後無敵開始 LocalVariables.currentHP = 100; //HP回復 yield return new WaitForSeconds(5f); //死亡後無敵時間 invincible = false; //無敵解除 } #endregion } |
CharacterControlScript.cs自体が長くなってきてややこしく思うかもしれませんが、今回追加したスクリプトはマークされている6行のみです。
カーソルのTransformを常に取得しておき、攻撃時にカーソルのPositionの方向をキャラクターが向くようにしています。
実際に動かしてみましょう!
カーソルのオブジェクトがマウスに追従し、攻撃はカーソル方向に発射していることが分かります。
今までは攻撃の方向を操作するのが難しかったですが、簡単になりました!
次回予告!!
次回は色々なUIの設置について書きたいと思います。
お楽しみに!!