概要
前回、unity公式チュートリアルの2Dシューティングゲームの第四回でSpaceshipクラスを作り、その後修正を加えてオブジェクト指向っぽい作りにしました。
unityでオブジェクト指向な作り方ってなんなの\(^o^)/ その2
unityでオブジェクト指向な作り方ってなんなの\(^o^)/ その2.5
今回はチュートリアル第五回の当たり判定を作っていくぞー!…と意気込んでいたのですが、少々困ったことに…
[チュートリアル第五回 当たり判定とアニメーションイベントとレイヤー]
(https://github.com/unity3d-jp-tutorials/2d-shooting-game/wiki/%E7%AC%AC05%E5%9B%9E-%E5%BD%93%E3%81%9F%E3%82%8A%E5%88%A4%E5%AE%9A%E3%81%A8%E3%82%A2%E3%83%8B%E3%83%A1%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E3%82%A4%E3%83%99%E3%83%B3%E3%83%88%E3%81%A8%E3%83%AC%E3%82%A4%E3%83%A4%E3%83%BC)
当たり判定処理について
第五回のチュートリアルで、
「スクリプトからトリガーの当たり判定を取得するには「OnTriggerEnter2D」「OnTriggerStay2D」「OnTriggerExit2D」の3つを使用します。」
と、書かれていますが、本当にスクリプトにそのメソッドを書くだけで処理が行われるんですねーこれはびっくりです。
しかもチュートリアルを進めていくと、タグとレイヤーで制御、つまりunity状のプロジェクトの設定で色々出来ちゃうみたいで…つまり何が言いたいかというとあまりオブジェクト指向な書き方をしようとするとunity自体の機能も使えなくなりそうで色々変更出来なかったのです。
その結果がこちらです。
プレイヤークラス
using UnityEngine;
using System.Collections;
[RequireComponent(typeof(MoveObject))]
[RequireComponent(typeof(SpaceShip))]
public class Player : MonoBehaviour {
private MoveObject moveObject;
private SpaceShip spaceShip;
void Awake() {
moveObject = GetComponent<MoveObject> ();
spaceShip = GetComponent<SpaceShip> ();
}
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
float x = Input.GetAxisRaw ("Horizontal");
float y = Input.GetAxisRaw ("Vertical");
//移動する向きを求める
Vector2 direction = new Vector2 (x, y);
moveObject.Move (direction);
if (Input.GetKey (KeyCode.Z)) {
//プレイヤーと同じ位置/角度で発射
StartCoroutine(spaceShip.Shot(transform));
}
}
// ぶつかった瞬間に呼び出される
private void OnTriggerEnter2D (Collider2D c)
{
// レイヤー名を取得
string layerName = LayerMask.LayerToName(c.gameObject.layer);
// レイヤー名がBullet (Enemy)の時は弾を削除
if( layerName == "Bullet(Enemy)")
{
// 弾の削除
Destroy(c.gameObject);
}
// レイヤー名がBullet (Enemy)またはEnemyの場合は爆発
if( layerName == "Bullet(Enemy)" || layerName == "Enemy")
{
// 爆発する
spaceShip.Explosion();
// プレイヤーを削除
Destroy (gameObject);
}
}
}
敵クラス
using UnityEngine;
using System.Collections;
[RequireComponent(typeof(MoveObject))]
[RequireComponent(typeof(SpaceShip))]
public class Enemy : MonoBehaviour {
private MoveObject moveObject;
private SpaceShip spaceShip;
void Awake() {
moveObject = GetComponent<MoveObject> ();
spaceShip = GetComponent<SpaceShip> ();
}
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
Vector2 direction = new Vector2 (1, 1);
moveObject.Move (direction);
StartCoroutine(spaceShip.Shot(transform));
}
private void OnTriggerEnter2D (Collider2D c)
{
// レイヤー名を取得
string layerName = LayerMask.LayerToName(c.gameObject.layer);
// レイヤー名がBullet (Player)以外の時は何も行わない
if( layerName != "Bullet(Player)") return;
// 弾の削除
Destroy(c.gameObject);
// 爆発
spaceShip.Explosion();
// エネミーの削除
Destroy(gameObject);
}
}
うーんこれは色々ひどいような…まず個人的に思ったこととして
- プレイヤー、敵クラスに処理を書いて、弾クラスには何も書かないの?
- 処理内で微妙に同じ処理あるやん!まとめんのかい!(レイヤー名取得とか)
- このOnTrigger(ry関数ってゲーム開始してずっと呼ばれてるんだったらすごい重そう…
1,2はオブジェクト指向としてどうなんでしょう…一部のクラスに任せっきりになってる気がしてならないです。依然作ったMoveObjectコンポーネントにOnTriggerEnter2D関数を書こうと思ったのですが、それも正しいのかがはっきりと分からず、手が止まってしまいました。そもそもこの関数は継承や合成して使っても良いものなのか…?
ステージ内のキャラの衝突などを管理するStageクラスのようなものがないせいで、そういう風に感じるのでしょうか?
仕方ないのでこのままで行こうと思います…ただレイヤー名をそのまま書いてるのは良くないのでLayerNameクラスのようなものを作ってそこに名前を付け足す感じにはするつもりです。
3に関してはunityの関数の問題なのでこれも何とも言えないですね…コライダーが表示しっぱなしだと重い、Destroyを頻繁に使うと重い など色んな記事をよく見ますが、この辺はもう少し勉強しないといけないです。
まとめ(感想と次回に向けて)
急に雲行きが怪しくなってきましたが、今回はここまで。勉強、技術、経験全て不足しているせいで色々自分の中で混乱していますが、なんとか整理したいですね。
次回は第6回で背景作りですが、そこはあまりオブジェクト指向とは無関係な感じだったので、その次の回のWave作りを進めていきます。
この回は以上です。
この時点でアドバイスがあればお願い致します!