電脳ヨーグルト

プログラミングの備忘録と私生活を

Unityで3Dシューティングゲームを作ってみた

f:id:at25250410:20180930124137p:plain

Unity初心者ですが、本を参考にしながら3Dのシューティングゲームを作ってみました。

地球を外周する宇宙ゴミを打ち落とすというものです。

自分の勉強のためにメモ的な感じで書いていきます。

一応作ったゲームを動画としてYoutubeにアップロードしてみたので良かったら見てください!

プログラムとか興味がない方は概要の部分だけ読んで頂ければ充分です。

www.youtube.com

www.prog-ganbaru.com

www.prog-ganbaru.com

www.prog-ganbaru.com

概要

・3Dシューティングゲーム
地球の周りの宇宙空間を浮遊する宇宙ゴミを撃ち落とすというコンセプトのゲームです。
(実際はクリックしたら消えるというだけでシンプルな感じですが・・・)

・製作時間は4~5時間くらい
ゲーム自体の製作時間です。なにもかも手探りなので、そのあとの動画編集に地味に時間が掛かりました。

・使用言語はC#
一応UnityはJavascriptとC#が使えるらしいのですが、最近はUnity公式がC#押しらしく、Javascriptに対する風当たりはきつくなています。

ゲームで使用した地球の画像などの素材はこちらのサイトからダウンロードしました。

ほんきで学ぶUnityゲーム開発入門 Unity5対応 ダウンロード|翔泳社の本

Tips

・OnMouseDown関数は、オブジェクトがタップまたはクリックされたときの処理を加えるときに使う。


・プレハブ(Prefab)は一般化したオブジェクトで型みたいなイメージです。プログラムでいうクラスみたいな。


・スクリプトからプレハブを作成する。

Instantiate(debri, transform.position, Quaternion.identity);


・コルーチンを使用すると、Update関数よりも簡単に時間の流れの処理を記述できる。



以下C#スクリプト

球体を回転させるスクリプト

using System.Collections;
using UnityEngine;

public class Rotation : MonoBehaviour {
public Vector3 angle; // Vector3型のangleという変数を宣言する

	void Start () {
	
        }
	// Update is called once per frame
	void Update () {
                transform.Rotate(angle * Time.deltaTime); //angleと経過時間をかけて回転させる。
	}
}

地球の周りを宇宙ゴミに回らせるスクリプト

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

public class Debri : MonoBehaviour {

	// 1秒あたりの回転角度
	public float angle = 30F;
	// 破壊時の得点
	public int score = 10;

	// 回転の中心左表
	private Vector3 targetPos;
	// Use this for initialization
	void Start () {
		Transform target = GameObject.Find("Earth").transform;

		targetPos = target.position;
		// 宇宙ゴミの正面の向きをEarthの方向に向ける
		transform.LookAt(target);
		// 宇宙ゴミを0から360の範囲でz軸を中心に回転させておく
		transform.Rotate(new Vector3(0, 0, Random.Range(0, 360)), Space.World);
	}

	// Update is called once per frame
	void Update () {
		// Earthを中心に宇宙ゴミの現在の上方向に 毎秒angle分だけ回転する
		Vector3 axis = transform.TransformDirection(Vector3.up);
		transform.RotateAround(targetPos, axis, angle * Time.deltaTime);
	}

	void OnMouseDown(){
		// クリックされたら宇宙ゴミを消す
		Destroy(gameObject);
	}
}

f:id:at25250410:20180929190059g:plain

定期的に宇宙ゴミを発生させるスクリプト

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

public class SpawnPoint : MonoBehaviour {
	// 宇宙ゴミ プレハブ
	public GameObject debri;
	// 宇宙ゴミ発生間隔
	public float interval = 1F;

	// Use this for initialization
	void Start () {
		StartCoroutine("SpawnDebris");
	}

	IEnumerator SpawnDebris() {
		while(true) {
			Instantiate(debri, transform.position, Quaternion.identity);
				yield return new WaitForSeconds(interval);
			}
		}
	}

f:id:at25250410:20180929193232p:plain

その他詳細設定

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

public class GameController : MonoBehaviour {

		// タイトル画像
		public Image guiTitle;
		// タイムアップ画像
		public Image guiTimeup;

		// ゲームの状態定義
		public enum GameState {
			TITLE,
			PLAYING,
			TIMEUP,
			TIMEUP_TO_TITLE,
		}

		// ゲームの状態
		private GameState state;

		// SpawnPointゲームオブジェクト
		private GameObject spawnPoint;
		// Scoreゲームオブジェクト
		private GameObject score;
		// Timerコンポーネント
		private Timer timer;

	// ゲームの初期化
	void Start () {
		// 状態をタイトルに
		state = GameState.TITLE;
		// タイトル画像を表示
		guiTitle.enabled = true;
		// タイムアップ画像表示
		guiTimeup.enabled = false;

		// SpawnPointゲームオブジェクトを取得する
		spawnPoint = GameObject.Find("SpawnPoint");
		score = GameObject.Find("Score");
		// TimerゲームオブジェクトのTimerコンポーネントを取得
		timer = GameObject.Find("Timer").GetComponent<Timer>();
	}

	// Update is called once per frame
	void Update () {
		switch (state) {
		case GameState.TITLE:
			// タイトル状態でマウスで左クリックされたらプレイ状態へ
			if (Input.GetMouseButtonUp(0)) {
				state = GameState.PLAYING;
				spawnPoint.SendMessage("StartSpawn");
				score.SendMessage("InitScore");
				timer.StartTimer();
				// タイトル画像非表示
				guiTitle.enabled = false;
			}
			break;

			case GameState.PLAYING:
			if (timer.GetTimeRemaining() == 0) {
				state = GameState.TIMEUP;
				spawnPoint.SendMessage("StopSpawn");
				timer.StopTimer();
				DestroyAllDebris();
				guiTimeup.enabled = true;
			}
			break;

		case GameState.TIMEUP:
		if (Input.GetMouseButtonUp(0)) {
			state = GameState.TIMEUP_TO_TITLE;
			StartCoroutine("ShowTitleDelayed", 3f);
		}
		break;

	}
}

void DestroyAllDebris() {
	GameObject[] debris = GameObject.FindGameObjectsWithTag("debri");
	foreach (GameObject debri in debris) {
			Destroy(debri);
	}
}

IEnumerator ShowTitleDelayed(float delayTime) {
	yield return new WaitForSeconds(delayTime);
	state = GameState.TITLE;
	timer.ResetTimer();
	guiTitle.enabled = true;
	guiTimeup.enabled = false;
	}
}