Unityで作る「シューティングゲーム」Vol.09

Unityで作る「シューティングゲーム」前回はプレイヤーのヒットポイントを管理する仕組みを作ってみました。
これで環境部分はだいぶ整いました。
「シューティングゲーム」には敵が必要ですよね?ということで今回は敵を作っていきたいと思います。
では早速作っていきます。

Step:1 デブリ出現数の管理

現状、デブリが発生しすぎるようなので、出現数を減らしておきましょう。
GameMangager スクリプトファイルを修正します。

void Update() 
{
    D = Random.Range(0, 2000);
    if (D == 0) 
    {
        CriateAsteroid(); 
    }
    else if (D <= 8)
    {
        CriateDebris();
    }
}

0から2000までの乱数が 8 以下の場合、 CriateDebris(); を発動してデブリを生成します。
これでだいぶ出現数が抑えられましたね?
ゲームを確認し、各自好きな数字に調整しましょう。

Step:2 敵の準備

1体目の敵は「ザコキャラ」、弱そうな画像を選んでおきましょう。
① 取得済みの素材「2D Space Kit」から「Ships and Stations」フォルダの「Fighter 2」を選択します。
 選択した素材を Hierarchy にドラッグ&ドロップで、ゲームに登場させておきます。

Unityで作る「シューティングゲーム」Vol.09

② 選択した素材がかなり小さいようなので大きくします。
 上で選択した素材の元の画像を選択して Inspector を表示させます。
「Pixcels Per Unit」を 20 にして、下の「Apply」を押します。
「Pixcels Per Unit」は1つのユニットにいくつの画像がはいるか?という数値です。
 小さいほど素材の画像が大きくなります。

Unityで作る「シューティングゲーム」Vol.09

③Hierarchy に配置した「Fighter 2」を選択し、Inspector からオブジェクトの名前を「Enemy1」に変更します。

④「Transform」コンポーネントの各パラメータの値を修正します。
 Position のY座標を 3 程度に変更(プレイヤーと重ならないように仮置き)。
 Scale のY座標の値を -1 にします。このことで「Enemy1」が下を向きます。

⑤「Sorting Layer」に作成済みの「Enemy」をセットして、背景より手前に表示させましょう。
「Enemy」を作っていなければ、「Player」の上に「Enemy」を作成します。

以下のコンポーネント、2つを追加します。

⑥「Box Collider 2D」コンポーネントを追加し、「Edit Collider」を押して Collider の大きさを調整。
 さらに「Is Trigger」の右のチェックボックスに☑(チェック)を入れます。

⑦「Rigidbody 2D」コンポーネントを追加し、「Gravity Scale」を0に、重力の効果を0にします。

⑧Projectの「02_Scripts」フォルダに新たなスクリプトファイル「Enemy1Controller」を作成し、「Enemy1」にアタッチ(ドラッグ&ドロップ)しておきます。

これで基本的なコンポーネントの準備は完成です。

Step:3 敵の動き

「Enemy1」は連隊を組んで出現させましょう。
2体1組で左右対称の動きをさせたいと思います。
まずは右側の動きを作成しますが、引数を渡すことで正反対の動きになるように工夫します。
基本的な動きは次の通り

❶1組ずつ枠外から登場し、左右対称となる任意の場所まで移動 
(移動の間はシールド等を活用し、ダメージを受けないようにします)

❷通常の動きは∞マークを描くように、ぐるぐる回ります。
 (ランダムにミサイルを撃って攻撃してくる)

今回は上記の()以外の基本の動きについて作成します。
まずは下記のコードを入力します。

float totalTime;         //時間を管理する変数
bool IsMove;             //登場と通常の動きを判定するフラグ
Rigidbody2D enemyRd2d;   //敵のRigidbody
public int appPos;       //左に出現(-1)、右に出現(1)

void Start()
{
    appPos = 1;                               //仮置き
    enemyRd2d = GetComponent<Rigidbody2D>();  //Rigidbody2D を取得
    StartCoroutine(Move0(appPos));            //コルーチンを発動
}

void Update()
{
    Move(appPos);  //通常の動き
}

//❶敵登場時の動き 引数(-1と1)で登場場所と動きを左右対称とする
IEnumerator Move0(int n)
{
    transform.position = new Vector3(18f * n, 10f, 0); //❷初期位置
    enemyRd2d.velocity = new Vector2(-3f * n, -1f);    //❸左方向に移動 
    yield return new WaitForSeconds(5);                //❹5秒継続
    enemyRd2d.velocity = transform.up * 0;             //❺移動を止める
    yield return new WaitForSeconds(0.5f);             //❻0.5秒継続
    IsMove = true;                                     //❼フラグをtrueに
}

//❽通常の動き 引数(-1と1)で画面左と画面右の動きを左右対象とする
void Move(int n)  
{
    if (IsMove)                                  //❾動きの制限
    { 
        totalTime += Time.deltaTime;             //➓totalTime を加算
        float x = Mathf.Sin(totalTime) * 7 * n;  //⓫横方向の加速
        float y = Mathf.Cos(totalTime * 2) * 10; //⓬縦方向の加速
        enemyRd2d.velocity = new Vector2(x, y);  //⓭加速値をRigidbodyに代入
    }
}

ちょっと複雑ですかね?
ポイントになる部分を説明していきます。

❶先に登場シーン、引数付きの関数、コルーチンを使って実現しています。
IEnumerator Move0(int n)引数には (1) か (-1) が渡されます。
右から登場する敵には(1)を、左から登場する敵には(-1) を指定して、正反対の動きを実現します。
コルーチンを使う際には、関数の前に修飾子 IEnumerator が必要です。
コルーチンとは指定した時間(フレーム)だけ処理を中断し、他の並列する処理を実行させる関数です。

❷  transform.position = new Vector3(18f * n, 10f, 0);
まずは初期位置の指定です。引数のnが (1) のときは x:18,y:10 に、nが(-1)のときはx:-18,y:10 になります。

❸  enemyRd2d.velocity = new Vector2(-3f * n, -1f);
Rigidbody2Dの velocity に力を与えます。
引数のnが (1) のときは、x:-3, Y:-1 の力を与え、左下の方向に動くようにします。
nが (-1) のときは、x:3, Y:-1 の力を与え、右下に動かします。

❹  yield return new WaitForSeconds(5);
reyield return new WaitForSeconds() を使って5秒待機。
他の動きは並列で進んでいますので、❸で与えた力も引き継いでEnemy1は動き続けます。

❺  enemyRd2d.velocity = transform.up * 0;
5秒のウェイト時間が解除されたタイミングで、velocity を x:0,y:0 にして、動きを止めます。
止め方はいろいろありますが、今回は [transform.up]に0 をかけて x:0,y:0 にしています。

❻  yield return new WaitForSeconds(0.5f);
❹と同じように、0.5秒待ちます。

❼  IsMove = true;
bool型の変数[IsMove ] をtrue にします。
これはこの後発動する通常の動きを実行するためのフラグになります。

❽ つづいて通常の動きですが、上で作った動きと同じように引数付き関数 void Move(int n) を作ります。

❾ 登場時には動かないように、 if (IsMove){ } で、変数[IsMove] が true のとき限定の動きにしておきましょう。

➓  totalTime += Time.deltaTime;
totalTime = totalTime + Time.deltaTime のことですね。
変数[totalTime] に1フレームごと経過時間を加算していきます。

 float x = Mathf.Sin(totalTime) * 7 * n;
変数[x] を指定して、Sin関数の周期に➓で取得した変数[totalTime] を指定、その値を7倍して横の速度を作ります。

⓬  float y = Mathf.Cos(totalTime * 2) * 10;
同じように縦の値をCos関数で作成します。
ポイントは周期を⓫の2倍にすること。
これで横に1周する間に、縦に2周する動きを実現することができます。

enemyRd2d.velocity = new Vector2(x, y);
「velocity」に⓫⓬で取得した値を代入して、Enemy1の動きを作成します。

❶はStart関数内で StartCoroutine(Move0(appPos));を指定して実現、
❽はUpdate関数で Move(appPos); を指定して動かします。

変数[appPos] は、仮の変数です。
今回は1を代入して右の敵を作ります。
実際は「GameMangager」で引数を与えて作成します。

では実際に動かしてみましょう。登場後、∞の形を描いて動き回る動き、できたでしょうか?

教室では実際に通って頂いての授業の他、Unityのオンライン授業やオンラインサポートも行っております。お困りごとのある方、ご興味がある方は、ぜひお問い合わせください。
お問い合わせは こちら から。
体験授業のお申込みは こちら から。

無料体験授業 いつでも受け付けています!

体験授業を受ける子供

スクラッチ、Unityでちょっとしたゲームを作ってみる

HTMLやCSSでWebサイト作成体験

初めてパソコンやタブレットに触れてみる

エクセルやワード、パワーポイントの学習をちょっと体験

まずは1時間程度の無料体験授業を受けて、教室の雰囲気や講師の人柄に触れて頂き、ご自身、お子様に合うのかどうかご確認ください!