MENU
BARREL
Auther
2019年にブログを始めました。趣味はゲームが5割、読書やらアニメ鑑賞やらが3割、残りはその都度新しい何かをやってます。

Unityで2Dシューティングを作りたかった話(挫折)

ゲームを作りたい!でも一からのコーディングではなくてUnityで手っ取り早くやりたい!

そんな思いから、今更ながら始めるUnityでの2Dシューティング制作を備忘録も兼ねて記録していきます。

速さだけを求めるのであれば、チュートリアルやアセットから改造していくほうが速く作れるはずです。が、Unity初心者はUnity本体に慣れていかなければならないため、どうせやるならプレーンから組み立ててみるのもいい勉強になるでしょう。

というわけで特にアセットやらは使用せず、2D用のプロジェクトを作成したところから始めていきます。

第一回目の記録(おしながき)

  • 自機の移動
  • 自機が持つ弾の生成
  • 敵の当たり判定

とりあえず弾を撃てて、敵に当たると弾が消えてダメージを与える(HPを減らす)ようにしていきます。

スーパー基礎の部分ではありますが、PrefabやScriptのAttach等のUnityの癖を覚えていくには良い勉強になります。

目次

自機を動かす処理

とりあえずScene上に2Dオブジェクト->スプライトを置いて適当スプライトを選択しました。

スプライトにあるKnobは元々入っているよくわからないものですが、一旦Playerとするオブジェクトに何らかの肉がついたのでこれでよしとします。

自分で絵がかける人や、既に用意してあるフリー素材などがあればそれをポイッと載せるといいかもです。

PlayerController.csを作る

Player(自機)を動かすために、キーボードからのイベントを取得するようにします。

ソースコードはAssets(作業フォルダ)内にScriptフォルダを作成し、その中にどんどん作ったものを入れていきましょう。

クラス名とファイル名は同じじゃないとエラーになるので必ず一致させます。

PlayerController.cs

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

public class PlayerController : MonoBehaviour
{
    public GameObject bulletPrefab;

    // Start is called before the first frame update
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        if (Input.GetKey(KeyCode.A))
        {
            transform.Translate(-0.05f, 0, 0);
        }
        if (Input.GetKey(KeyCode.D))
        {
            transform.Translate(0.05f, 0, 0);
        }

        if (Input.GetKeyDown(KeyCode.Space))
        {
            Instantiate(bulletPrefab, transform.position, Quaternion.identity);
        }
    }
}

if (Input.GetKey(KeyCode.A)) でキーボードのAキーが押されたら、の挙動を書いておきます。

transform.Translateにて移動させていきます。ここでは一旦、X軸だけにして左右移動のみを実装しています。

一気に移動の項目を思いつくままに実装してもいいのですが、細かくちょっとずつ作っていくのが良いです。まとめて作ってしまうとどこかでバグやエラーが起きたときに対処しづらくなってしまうので。

GetKeyは押されている間ずっと実行します。
GetKeyDownは指定のキーが押し下げられたとき(スイッチがONになったとき)に一度だけ実行されます。

なので現状はSpaceキーを押すと一度だけ弾が生成されます。

弾を撃つ処理

弾を撃つのはPlayerController.csで行います。弾が虚無から生まれるだけではなく、自機の座標から飛んでいかなくてはいけませんからね。

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

public class PlayerController : MonoBehaviour
{
    public GameObject bulletPrefab;

    // Start is called before the first frame update
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        if (Input.GetKey(KeyCode.A))
        {
            transform.Translate(-0.05f, 0, 0);
        }
        if (Input.GetKey(KeyCode.D))
        {
            transform.Translate(0.05f, 0, 0);
        }

        if (Input.GetKeyDown(KeyCode.Space))
        {
            Instantiate(bulletPrefab, transform.position, Quaternion.identity);
        }
    }
}

7行目と27-30行目に注目です。

まず、public GameObject bulletPrefab; でUnityのInspectorからオブジェクトを指定できるように宣言します。

PlayerController(スクリプト)の中にBulletPrefabありますね。そして中にはPlayerBulletを組み込みました。

弾をPrefab化するには、Scene上に一旦オブジェクトとして配置し、HierarchyからAssetsに向かってドラッグアンドドロップすればPrefabになります。Prefab化できたらBulletPrefabにAttachして準備万端。

    if (Input.GetKeyDown(KeyCode.Space))
    {
        Instantiate(bulletPrefab, transform.position, Quaternion.identity);
    }

ここ、27-30行目のところですね。

Instantiate関数はインスタンスを生成する関数で、引数にはPrefab,位置,角度を指定しておきます。
(Instantiateは引数のオプションによって挙動が変わってくるため、一旦この3つを指定します。)

transform.positionはPlayerの座標をそのまま持っています。
Quaternion.identity(クオータニオン)は角度のことで、これは角度をとくにいじらず回転などさせない記述になっています。

クオータニオンが抜けていて動かない!!!なんてケースはよくあるので、とりあえず入れておくのがいいですね。慣れてきたら細かくいじって自由に作っていくって感じで。

生まれた弾のプログラム

PlayerController.csによって、Spaceキーを押すとインスタンスが生成されます。ここで生まれるのはInspector上でBulletPrefabに指定したPrefabです。

Spaceキーによって弾が生成されたら、次は弾を移動させて当たり判定などを実装していきましょう。

PlayerBullet.cs

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

public class PlayerBullet : MonoBehaviour
{
    public float bulletSpeed = 0.1f;
    // Start is called before the first frame update
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        transform.Translate(0, bulletSpeed, 0);

        if (transform.position.y > 5)
        {
            Destroy(gameObject);
        }
    }

    void OnTriggerEnter2D()
    {
        Destroy(gameObject);
    }
}

Update内にてtransform.Translateを行い、弾が画面の上のほうへ飛んでいくような動きを実装しました。

Unity内で速度調整をして様子を見たいなと思い、bulletSpeedはpublicで宣言しています。

あとは座標指定でY軸が5を超えたら画面外にあると判定し弾を削除します。当たり判定でも同じく、弾を削除します。

void OnTriggerEnter2D()では当たり判定のisTriggerを取得し、物理演算にて衝突判定を受けたときに実行されます。

今の所引数は特に指定していませんが、OnTriggerEnter2D(Collider2D other)、other.gameObjectなどと書いておけば、何が当たったかを判定したり、当たった座標を取得したりと拡張要素が盛りだくさんあります。こちらも慣れてきたら処理の分岐などに使っていこうかなと思います。

当然ですが、PlayerBulletもPrefab化しておき、その中にPlayerBullet.csをAttachします。

当たり判定の処理

2Dの当たり判定には2D物理演算が必要です。

追加コンポーネントとして

  • ***Collider 2D
  • Rigidbody 2D

を実装します。 *** Collider 2Dは四角やら丸やらあるのでとりあえず弾の形にあわせておけばOK。

今回はCircle Collider 2Dで丸い玉の当たり判定を作ります。

トリガーにする(Is Trigger)にチェックをいれ、Rigidbodyは動的(Dynamic)、シミュレーション(Simulation)ONで設定しておきます。

敵を置いて当たり判定をつけてみる

EnemyのPrefabを作り、適当にCollider 2Dを実装し、ついでにEnemy.csを作っておきます。

Enemy1,cs

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

public class Enemy1 : MonoBehaviour
{
    public int enemyHp = 10;
    // Start is called before the first frame update
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        if(enemyHp <= 0)
        {
            Destroy(gameObject);
        }
    }

    void OnTriggerEnter2D()
    {
        --enemyHp;
    }
}

Hpは一旦10持たせておきます。これも様子を見たいのpublicで宣言しました。

Enemy1にはPlayerBulletと同様にCollider 2DとRigidbody 2Dが入っています。弾が1つ当たったらEnemy1のHpを1ずつ減算していくだけのプログラムができました。

今は弾の当たり判定しか書いていませんが、後々動きのパターンを作ろうと思いEnemy1にしました。2とか3とか、Boss1とか作っていきたいですね。

色々いじってみる

弾を連射したい!

PlayerController.cs

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

public class PlayerController : MonoBehaviour
{
    public GameObject bulletPrefab;
    public float bulletInterval = 0.0f;
    public float bulletIntervalTimer = 0.01f;
    // Start is called before the first frame update
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        if (Input.GetKey(KeyCode.A))
        {
            transform.Translate(-0.05f, 0, 0);
        }
        if (Input.GetKey(KeyCode.D))
        {
            transform.Translate(0.05f, 0, 0);
        }

        if (Input.GetKey(KeyCode.Space))
        {
            bulletInterval += bulletIntervalTimer;
            if (bulletInterval > 0.5)
            {
                Instantiate(bulletPrefab, transform.position, Quaternion.identity);
                bulletInterval = 0;
            }
        }
    }
}

ばっちり。(‘ω’)b

インターバルタイマーの数値を上げていくと連射速度が上がります(普通はタイマーの数値が低いほど連射力が上がるもんですけど。とりあえず一旦これで。)

また後日インターバルタイマーまわりは数値が低いほど連射できるように作り直します。

敵が左右に動くようにしたい!

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

public class Enemy1 : MonoBehaviour
{
    public int enemyHp = 10;
    public float enemyMoveX = 0.01f;

    // Start is called before the first frame update
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        if (enemyHp <= 0)
        {
            Destroy(gameObject);
        }
        EnemyMovement();
    }

    void OnTriggerEnter2D()
    {
        --enemyHp;
    }

    void EnemyMovement()
    {
        if (transform.position.x > 5.5)
        {
            enemyMoveX *= -1;
            transform.Translate(enemyMoveX, 0, 0);
        }
        else if (transform.position.x < -5.5)
        {
            enemyMoveX *= -1;
            transform.Translate(enemyMoveX, 0, 0);
        }
        else
        {
            transform.Translate(enemyMoveX, 0, 0);
        }
    }
}

座標が6ぐらいの場所で端にあたるため、5.5ぐらいの位置で切り替えしてシャトルランする動きになりました。

Inspector上で数字をいじれば速度を変更できます。

徐々にシューティングゲームっぽくなってきました。

次は敵の生成パターンとか、背景とか、エフェクトとか、色々やってみたいと思います。

この記事が気に入ったら
フォローしてね!

よかったらシェアしてね!
  • URLをコピーしました!

コメント

コメントする

CAPTCHA

目次