feature image

2022年4月22日 | ブログ記事

え!! 一ヶ月で2本のゲーム制作を!?

出来らぁっ!

この記事は新歓ブログリレー45日目の記事です。

はじめに

21Bのさばにしです。普段はたまにお絵描きしています。
去年一年間はそれなりに忙しかったのですが、大学一年生の春休みという物はリアルが充実していない私のような人間にとっては、かなり暇です。毎日だらだらとお絵描き・読書・スマホの無限ループを続けるのもつまらないものです。
そのため、何か生産的な事をしようと、約4週間で2本のゲームを制作したのでご紹介いたします。



制作物

作ったゲームのURLです。ぜひ遊んでね。
一本目『百鬼夜行記』
二本目『どったんばったんきりたんパズル』



一本目[百鬼夜行記]について

ゲーム紹介

このゲームは同じサークルに所属しているtakeさんとの共同制作です。私はプログラム担当です。
魔法使い(?)の女の子が魑魅魍魎を倒してまわる横スクロールシューティングゲームです。
ストーリーは特に考えてなかったのでありません。
難易度は自称東方Normalシューターの私でもクリアできるぐらいなので、多分誰でもクリアできるようになっていると思います[要出典]。

画像 図1 『百鬼夜行記』のプレイ画面

制作期間等

2/19(土)〜3/5(日)の15日間。
サークル内イベントの『ichigojam』にて制作しました。

雑記

私の担当はプログラムだったと述べましたが、フルスクラッチ[1]ではなくUnityを用いて制作しました。
Unityでの制作はフルスクラッチに比べて手間がかからず、難易度もそれほど高くありません。だからこそ2週間という短期間で作れたのかも? (余談ですが、高校の頃javaで作ったSTGは今回と同程度のボリュームですが、完成までに半年かかりました。一日あたりの作業時間が違うので一概に比較はできませんが...)
シューティングゲームは、初心者向けゲーム制作サイトでおすすめされているゲームジャンルの鉄板であると言えるでしょう。しかし、Unityで作るとなると少し難易度が高いかな?という印象を受けます。というのもシューティングゲームはUnityのシステムに頼りづらいからです。ですが、ゲーム作りの基礎を学べるとは思うので、そういう意味では初めて作るジャンルとしてアリかもしれません。



二本目[どったんばったん(ry]について

ゲーム紹介

東北きりたん[2]の二次創作アクションパズルゲームです。全30面。きりたんを操作してゴールまで導くタイプのパズルです。
今回は一人で作ったので、趣味全開です。キリタンカワイイヤッター!
私はパズルゲーム下手くそですが、作る場合は自分が解けないような問題も作れてしまうと、今回のゲームを通じて実感しました。一応難しくなりすぎないように注意したので、多分クリア不可能な難易度ではないと思います。

画像 図2 『どったんばったん(以下略)』のプレイ画面

制作期間等

3/7(月)〜3/20(土)の13日間。
一作目と同様に15日で作る予定でしたが、前倒しで完成に漕ぎ着けました。

雑記

このゲーム、最初は軽めのゲーム作ろう!みたいなノリで作り始めましたが、作っているうちにどんどんのめり込んでいき、規模が大きくなっていきました。その分結構苦労して作ったので、思い入れがあります。だからより多くの人に遊んで欲しいな〜って思ってます。そのため、らん☆ぷろ[3]で紹介してみました。私は人前で話す事が苦手[4]なのですが。発表って難しいね。



共同制作と個人制作の違いについて

今回、2本のゲームをそれぞれ複数人、個人で作ったので、両方をやってみて感じたメリット・デメリットについて軽くまとめます。

共同制作

個人制作

個人制作は自由にやれる代わりにケツを叩いてくれる人がいないため、制作意欲がないと完成しません。エタります。共同制作はその逆です。



技術的な話

記事内容が薄い気がするので、少しUnityに関する小話をします。興味がない方は飛ばしてください。

オブジェクトプール

オブジェクトプールという概念があります。その名の通り、オブジェクト(物体)をプール(備蓄)しておくという意味です。オブジェクトの生成、破壊はコスト(演算時間)がかかります。とくにシューティングゲームのような大量の弾を発射するゲームにおいては、そのコストが嵩みます。そのため、オブジェクトを使い回す事により、その計算コストを削減します。

一般的なオブジェクト生成・破壊

Unityにはプレハブとよばれる機能があります。簡単にいうと、複製したいオブジェクトの設計図・見本のような物です。あらかじめこのプレハブを用意しておく事で、これを複製できます。より詳しく知りたい方はググってください。このプレハブを使う事で、オブジェクトを簡単に生成できます。

Sample.cspublic class Sample:MonoBehavior
{
    [Serializefield]private GameObject prefab;//プレハブの設定
    
    //毎フレーム呼び出されるメソッド
    private void Update()
    {
        GameObject hoge = Instantiate(prefab);
    }
}

実際にオブジェクトを生成しているのは8行目です。上の例では、毎フレーム一つのオブジェクトが生成されます。


ところで、画面外に出た弾をいつまでもそのままにしておくのは無駄です。なので、消します。以下の例では、弾のオブジェクトにアタッチ[5]されるBulletクラスの例を示します。

Bullet.cspublic class Bullet:MonoBahavior
{
    private void Update()
    {
        if(Utils.IsOut(tranform.position)//もしオブジェクトが画面外なら
        {
            Destroy(gameObject);
        }
    }
}

5行目の説明は省略します。その説明をする前にUtilsクラスについて理解する必要があり、少し長くなるからです。Updateメソッドで画面外かどうかを毎フレーム判定し、もし画面外ならオブジェクトを破壊している事だけ理解してもらえば問題ありません。

改良版生成・破壊

さて、以上が標準的なUnityでのオブジェクト生成、破壊の手順なのですが、この処理は結構重いです。なので、なるべく生成、破壊の回数を減らしたいです。

Bullet.cspublic class Bullet:MonoBehavior
{
    private void Update()
    {
        if(Utils.IsOut(transform.position)
        {
            gameObject.SetActive(false);
        }
    }
}

BulletManager.cspublic class BulletM<anager
{
    private List<Bullet> bulletStock=new List<Bullet>(); //注1
    
    private Bullet CreateBulletDeal(BulletBelongEnum belongEnum, BulletImageEnum imageEnum, TrajectoryEnum trajectoryEnum, Vector3 pos)
    {
        Sprite sprite = BulletImages[(int)imageEnum];
        Trajectory trajectory = CreateTrajectory(trajectoryEnum);

        foreach (var _bullet in bulletStock) //注2a
        {
            if (!_bullet.gameObject.activeSelf) //注2b
            {
                _bullet.gameObject.SetActive(true); //注3
                _bullet.Initialize(belongEnum, imageEnum, sprite, pos, trajectory);

                return _bullet; //注4
            }
        }

        GameObject bulletObject = Instantiate(BulletPrefab, transform); //注5
        Bullet bullet = bulletObject.GetComponent<Bullet>();
        bullet.Initialize(belongEnum, imageEnum, sprite, pos, trajectory);
        bulletStock.Add(bullet); //注6
        return bullet;
    }
}

上のソースコードは制作したゲームから一部抜粋した物です。全部説明したら日が暮れてしまいますのでオブジェクトプールに関係ある部分のみに絞ります。
まず、Bulletクラスの変更点から。7行目のみ変更されています。
gameObject.SetAvtive(false)は自身の活動を停止させるようなイメージです。破壊ではないので処理が軽いです。
次にBulletManagerクラスについて。実際にはこのクラス内のCreateBulletメソッドを他のオブジェクト(敵など)が呼び出す事により弾を発射させます。BulletManagerクラスは弾を製造する工場のような役割を果たします。
注1は弾を備蓄するリストの宣言です。
注2の処理によりこのリストの中身を調べ、activeSelf(Bulletクラスでfalseにした物)がfalseになっている弾を調べます。もしこれが存在するならば、注3によりそれをtrueにし、初期化処理を施したのちに、注4によりそのオブジェクトを返します。この一連の処理は普通に弾を生成するより軽い処理です。
さて、注5以降の処理は弾の備蓄リストにactiveSelがfalseのオブジェクトが一つもなかった場合のみに実行されます[6]。その場合は、注5により弾が生成されます。ここは最初に紹介したサンプルと同じですね。その後、初期化処理の後に、このオブジェクトは注6によりリストに追加されます。
こうして、必要最低限の弾のみを生成する事ができます。


最後に、これを実行したサンプルのご紹介。

画面中央のBullet(Clone)の文字が薄くなったり濃くなったりしている事、画面左上において画面外に出た弾が見えなくなっている(activeSelfがfalseになっている)事が確認できると思います。



まとめ

最後までお読みいただきありがとうございます。ゲーム制作は、人生という死ぬまでの暇つぶしにちょうどいい物であると、私は考えています。ぜひ皆さんも、ゲーム制作を始めてみませんか?
ゲームは意外と簡単に作れますよ。


明日の新歓ブログリレー担当者は@Fourmsushiさんです。楽しみ〜。


  1. システムをイチから自作する事。 ↩︎

  2. 東北地方応援キャラクター。
    声優「茜屋日海夏」の声を元に制作した、落ち着いていながらも可愛らしい声が特徴の入力文字読み上げソフト、『VOICEROID+ 東北きりたんEX』が発売されています。詳しくはこちら↩︎

  3. traP内での簡単な進捗報告会のようなもの。詳しくはこちら↩︎

  4. 私、吃音症なので... ↩︎

  5. オブジェクトとスクリプト(ソースコード)を紐付ける事。 ↩︎

  6. もし一つでもtrueがあれば注4により値が返されて処理が中断されるため、後の処理は実行されません。 ↩︎

sabanishi icon
この記事を書いた人
sabanishi

21Bです。 お絵描きとゲ制してまーす。

この記事をシェア

このエントリーをはてなブックマークに追加
共有

関連する記事

2022年4月7日
traPグラフィック班の活動紹介
annin icon annin
2021年4月2日
DXライブラリで重力パズルゲームを作る
Macky1_2 icon Macky1_2
2022年9月16日
5日でゲームを作った #tararira
Komichi icon Komichi
2022年4月5日
アーキテクチャとディレクトリ構造
mazrean icon mazrean
2022年3月29日
課題・レポートの作成、何使う?【新歓ブログリレー2022 21日目】
aya_se icon aya_se
2021年7月8日
じゃぱりぱーく・おんらいん
suzushiro icon suzushiro
記事一覧 タグ一覧 Google アナリティクスについて