はじめに
こんにちは。もっちゃそです。
Weekend Engineer(WE)の10月分の開発として、2Dスクロールアクションゲームを制作しました。
WEの開発プロダクトは、今回で2個目となります。
デモ動画
以下のような流れで撮影しました。
- 敵をファイアボールで撃破しつつ普通にクリアー
- 敵に4回(ライフ0の状態で)ぶつかってゲームオーバー
- ステージから落下してゲームオーバー
きっかけ
(前回の記事と重複しますがご容赦ください・・・)
当コミュニティでは以下のステップに従って経験を積んでいきます。
- アイデア出し:渡辺さん、開発:メンバー(@Mocchaso)
- アイデア出し・開発:メンバー + 渡辺さんのヘルプ
- アイデア出し・開発:メンバー + 基本ヘルプ無し
ステップ2まで進み、いよいよ自分でアイデア出しをする段階に入りました。
来年度からゲーム制作の仕事をさせてもらえることになり、その経験を積もうと考えました。
「ゲーム制作といえばUnityが多いよな」→「前に3~4か月間触っただけだし実装しやすいゲームにするか」ということで、2Dスクロールアクションゲームを選択しました。
それだけだとオリジナリティが無いので、完全に苦し紛れですが、ストーリーを設定しました。
仕組み
ストーリー
主人公が寝坊したので、授業が始まるまでに学校へ急ぐというもの。
画像と音楽の追加まで間に合わなかったため、ゲームやっただけだと全く分かりません・・・。
ゲームのルール
ステージ右端の赤い物体に触れればクリアー、ステージから落下する or 時間切れになる or プレイヤーのライフが無くなるとゲームオーバーとなります。
操作方法は以下の通りです。
- 移動:左右の矢印キー
- ジャンプ:Spaceキー
- ファイアボール(攻撃):fキー
システム図
実装
タイトル画面
ゲーム画面だけだとゲームっぽくないと思い、作成しました。
Spaceキーを押すとゲーム画面へ移るようにしました。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class TitleManager : MonoBehaviour {
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
// Spaceキー押下でゲーム画面に遷移
if (Input.GetKey(KeyCode.Space)) {
SceneManager.LoadScene("Main");
}
}
}
ゲーム画面
ステージ上の物体(プレイヤー、敵、床など)
ゲームクリアー
ステージ右端に赤いCubeオブジェクトGoalを配置し、"Goal"
タグを付けました。
PlayerController.csでプレイヤーがGoalに触れたかどうかを検出し、GameManager.cs内のクリアーフラグを更新しています。
PlayerController.csをPlayerオブジェクトにアタッチすることで正常に動作しています。
- void OnTriggerEnter2D(Collider2D obj)
別のオブジェクトに接触した際、objにそのオブジェクトの情報が格納されます。
このメソッドで検出できるのは接触のみで、衝突などの物理現象はvoid OnCollisionEnter2D(Collision2D collision)
を使うことで検出することができます。
// 略
void OnTriggerEnter2D(Collider2D obj) {
if (obj.gameObject.tag == "Goal") { // ぶつかったオブジェクトの判別
GameManager.isGoaled = true;
}
}
}
ゲームオーバー
ステージから落下する or 時間切れになる or プレイヤーのライフが無くなる状態を、以下のように検出しました。
ステージの下部に適当なオブジェクトを配置し、プレイヤーがそのオブジェクトに衝突したら落下していると見なします。
/*
* ステージから落下する
*/
// 略
void OnCollisionEnter2D(Collision2D collision) {
if (collision.gameObject.tag == "Enemy") { // ぶつかったオブジェクトの判別
GameManager.damaged++;
} else if (collision.gameObject.tag == "GameOver") {
// 落下したらゲームオーバー
GameManager.isGameOver = true;
}
}
// 略
時間切れに関しまして、次の前半部分で1秒ごとに残り時間の表示を更新しています。
それが0秒になったら時間切れとしています。
プレイヤーのライフ切れに関しましては、PlayerController.cs
のOnCollisionEnter2D
(上記参照)で敵との衝突を検出し、その都度GameManager.cs
内のダメージ変数を更新しています。
ライフの最大値 - ダメージ変数の値 >= 0となったらライフ切れとしています。
/*
* 時間切れになる、プレイヤーのライフが無くなる
*/
void Update () {
// 残り時間のカウントダウン
countdown_timer -= Time.deltaTime;
if (countdown_timer <= 0) {
tmp_time -= 1; // 残り時間を1秒減らす
time_text.text = "TIME: " + tmp_time + " s"; // 残り時間の表示を更新
if (tmp_time == 0) {
// 残り時間が0になったらゲームオーバー
isGameOver = true;
}
countdown_timer = 1f; // タイマーのリセット
}
// 残りライフの表示を更新
if (lifemax - damaged >= 0) {
life_text.text = "LIFE: " + (lifemax - damaged);
} else {
// 残りライフが0になったらゲームオーバー
isGameOver = true;
}
if (isGameOver || isGoaled) {
// ゲームオーバー or ゲームクリア時にリザルト画面に遷移
SceneManager.LoadScene("Result");
}
}
ファイアボールを撃つ
発射のキー入力の実装は、タイトル画面のSpaceキー押下部分と概ね同じです。
fキーが押されたら、Prefab(プレハブ)化したファイアボールのゲームオブジェクトをインスタンス化します。
- Instantiate(gameObject, transform.position, transform.rotation)
transform.position
の位置、transform.rotation
の回転で、プレハブ化しているgameObjectをインスタンス化する
// このメソッドをUpdate()で呼び出している
void ShootFireBall() {
// fキー押下でファイアボールを撃つ
if (Input.GetKeyDown("f")) {
Instantiate(fireball, transform.position, transform.rotation);
}
}
プレイヤーのテクスチャの向きを対応させる(+α)
現在のプレイヤーの向きと1フレーム前のプレイヤーの向きを比較し(横方向のみ)、
向きが変わっていたらx軸方向のスケールを-1倍します。
これにより、プレイヤーが向いている向きに応じてテクスチャの向きも反転します。
※向きが変わったと判定するのは、設置している時のみに限定しています
// このメソッドをUpdate()で呼び出している
void ReversePlayerSprite() {
if (isLeft != prev_isLeft) { // 現在のプレイヤーの向きが1フレーム前と異なっていたら
Vector3 now_scale = transform.localScale;
now_scale.x *= -1;
transform.localScale = now_scale;
}
}
リザルト画面
タイトル画面と同様の経緯で作成しました。
Spaceキーを押すとタイトル画面へ移るようにしました。
実装コードはタイトル画面と同じなので割愛させていただきます。
参考にしたサイト
調べたサイトが多いため、1つのセクションとしてまとめたいと思います。
ゲームの全体像
-
【第7回、8回】2Dスクロールゲームの例とゲームの作り方
こちらのプロジェクトをベースにしました。 -
【Unity】2D横スクロールアクションゲームのキャラクター移動方法
コードを綺麗にするため、こちらのコーディングスタイルを使わせていただきました。
ゲーム画面(メインシーン)
-
Unityでマリオっぽいゲームを作るのに必要な5つのこと
Spaceキー長押しでより高くジャンプさせるための実装にて(結局できなかった)。 -
Input.GetButtonとInput.GetButtonDownの入力の違い
Spaceキー長押しでより高くジャンプさせるための実装にて(結局できなかった)。 -
Unityで特定のオブジェクトと衝突したときだけisTriggerをtrueにしたい
ファイアボールを撃った時、プレイヤーをすり抜けるように実装しました。 -
【Unity】Unityで「時間」を扱うときに注意すべきこと
残り時間のカウントダウンの実装にて。
タイトル画面、リザルト画面
-
タイトル画面を作り、タイトルからゲーム画面に移る「シーン遷移」を作ってみよう
シーン遷移の実装を復習するため拝見しました。 -
スカイボックス(Skybox)でゲームの雰囲気をガラッと変えよう
シーンの背景の初期状態を、真っ青な淡色からSkyboxに変えたかったので拝見しました。 -
Canvas Scaler(キャンバススケーラー)で解像度を変えてもUIが崩れないようにしよう&ビルドしてチェックしよう
解像度の違いで、Canvas上のテキストUIの表示揺れが起こらないようにするため拝見しました。
最後に
感想
簡単なゲームでも1人でつくるのは大変でしたが、ゲーム制作には何が必要かを入念に考えることができました。ゲーム内容の企画、デザイン、サウンドの導入、コーディング、テストプレイなど。
前回よりも時間配分に気を付けることはできましたが、研究を優先していたためビジュアルやサウンドの導入、アイテムの設置までは至りませんでした・・・。
ただ、全ての工程を1人でこなす必要があったので、力はついたような気がします。
※コード全体はこちらをご参照ください
→ Unity 2Dスクロールアクションゲーム:学校へ急ごう!
Weekend Engineerとは
渡辺大智さん (@ahpjop) 率いる開発コミュニティ。
「どんなアイデアもカタチにする」ことに焦点を置いて活動しています。
ホームページはこちら。このホームページも、WEのメンバーが制作しました。