さて#1の続編として、動く障害物を実装する例を紹介します。
#1で大まかにUnityを使ったゲーム開発の流れ・仕組みがわかったと思います。
●シーンにオブジェクトを配置して、
各種機能をもつコンポーネント、
プログラミング制御するスクリプトをアタッチする。
●ゲームの画面、ステージの数だけ、シーンを作成し、遷移させる。
という仕組みです。
さらにゲームを作り込み、個性を出していくために
本記事の内容にも、 ぜひチャレンジしてみてください^^
動く障害物の実装
ゲームオブジェクトが自動的に動くようにする方法は、
・スクリプトで制御する方法
・アニメーションを設定する方法
・物理挙動の赴くままに任せる方法
があります。
ここでは、 よりC#プログラミング学習のためになる
スクリプトで制御する方法を紹介します。
この制御方法について理解できれば、
あなたの数学力をどのようにゲーム開発に活かせるかがなんとなくわかるかも!?
(数学的に美しいゲームを作る第一歩...)
早速、障害物(ここではObstacleと呼ぶ)が動くように、
スクリプトObstacle.csに次のコードを追記します。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class Obstacle : MonoBehaviour
{
[SerializeField] GameObject gameoverText;
[SerializeField] GameObject retryBtn;
// ここからObstacleを動かすコード
Vector3 startPosition;
[SerializeField] Vector3 movementVector;
float movementFactor;
[SerializeField] float period = 2f;
void Start()
{
startPosition = transform.position;
}
void Update()
{
if (period <= Mathf.Epsilon)
{
return;
} //およそ0なら動かないようにする
float cycles = Time.time / period; // 時間を数値で割る(periodが大きいほど、動きが遅くなる)
const float tau = Mathf.PI * 2;
float rawSinWave = Mathf.Sin(cycles * tau); // 時間経過でSinの()内の値は増えていくが、Sinなので-1~1を超えることはない)
movementFactor = (rawSinWave +1f) / 2f; // 0~1の間を増減するものに変換
Vector3 offset = movementVector * movementFactor;
transform.position = startPosition + offset; // Obstacleを動かす
}
// ここまで
void OnTriggerEnter(Collider other)
{
if(other.CompareTag("Player"))
{
gameoverText.GetComponent<Text>().text = "GAME OVER";
gameoverText.GetComponent<Text>().color = new Color(0,0,255);
gameoverText.SetActive(true);
retryBtn.SetActive(true);
Time.timeScale = 0;
}
}
}
プログラミングのコードで表現すると複雑そうに見えますが、
数学的には大したものではありません^^;
MathfはC#で用意された数学的な機能です。
Mathf.PI(円周率π)やMathf.sin()をここでは使っています。
オブジェクトに往復するような動きを実装する場合、
Mathf.sinやMathf.cosがおすすめです。
なぜなら、sinなどの三角関数は、必ず-1〜1の間の値をとるからです。
sinの()の値は、2πをかけることで、角度に変換され、必ず-1≦sin()≦1となります。
時間の経過によって、Mathf.sin()が-1〜1を往復するようにするには、
Mathf.sinの引数において
時間の経過で増える数Time.timeを、
Inspectorから自由に値を設定できるperiodで割り、
(ここではcycleという変数に代入)
2π(ここではtauという関数内で変更不可な定数として使用)を掛けるようにします。
さらに、それ(rawSinWave)に1を足して2で割れば、
0〜1を往復するようになります(movementFactorに代入)。
そのmovementFactorを、Vector3であるMovementVectorに計算してきたmovementFactor(0~1)をかけて移動する方向と移動量を決定します。
それを元のオブジェクトの位置(startPosition)に足して、動かしていくという寸法です。
なお、このObstacle.csでInspectorから
MovementVectorで動く範囲・方向を自由に設定できるようになります。
(動きの速さに影響を与えるperiodもその1つ)
これで、Obstacleごとに、異なる動きに設定できます。
その他、Obstacleを回転させたい場合は、次のコードを追記します。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class Obstacle : MonoBehaviour
{
[SerializeField] GameObject gameoverText;
[SerializeField] GameObject retryBtn;
Vector3 startPosition;
[SerializeField] Vector3 movementVector;
float movementFactor;
[SerializeField] float period = 2f;
// 回転させるコードpt.1
[SerializeField] float xAngle = 0;
[SerializeField] float yAngle = 0;
[SerializeField] float zAngle = 0;
void Start()
{
startPosition = transform.position;
}
void Update()
{
// 回転させるコードpt.2
transform.Rotate(xAngle,yAngle,zAngle);
if (period <= Mathf.Epsilon)
{
return;
}
float cycles = Time.time / period;
const float tau = Mathf.PI * 2;
float rawSinWave = Mathf.Sin(cycles * tau);
movementFactor = (rawSinWave +1f) / 2f;
Vector3 offset = movementVector * movementFactor;
transform.position = startPosition + offset;
}
void OnTriggerEnter(Collider other)
{
if(other.CompareTag("Player"))
{
gameoverText.GetComponent<Text>().text = "GAME OVER";
gameoverText.GetComponent<Text>().color = new Color(0,0,255);
gameoverText.SetActive(true);
retryBtn.SetActive(true);
Time.timeScale = 0;
}
}
}
1フレームごとに設定した値(角度)分だけ、
回転させるシンプルなコードです。
x軸回転なのか、y軸回転なのか、z軸回転なのか
設定できます。
回転という動きそのものが、繰り返す動きなので、
特にMathfを用いることもなく、実装が簡単ですね^^
というわけで、
オブジェクトが自動的に動くようになったはずです。
こういった数式を活用したスクリプトで、
数学およびゲーム開発をどんどん楽しんでいきましょう^^