この記事は新歓ブログリレー45日目の記事です。
はじめに
21Bのさばにしです。普段はたまにお絵描きしています。
去年一年間はそれなりに忙しかったのですが、大学一年生の春休みという物はリアルが充実していない私のような人間にとっては、かなり暇です。毎日だらだらとお絵描き・読書・スマホの無限ループを続けるのもつまらないものです。
そのため、何か生産的な事をしようと、約4週間で2本のゲームを制作したのでご紹介いたします。
制作物
作ったゲームのURLです。ぜひ遊んでね。
一本目『百鬼夜行記』
二本目『どったんばったんきりたんパズル』
一本目[百鬼夜行記]について
ゲーム紹介
このゲームは同じサークルに所属しているtakeさんとの共同制作です。私はプログラム担当です。
魔法使い(?)の女の子が魑魅魍魎を倒してまわる横スクロールシューティングゲームです。
ストーリーは特に考えてなかったのでありません。
難易度は自称東方Normalシューターの私でもクリアできるぐらいなので、多分誰でもクリアできるようになっていると思います[要出典]。
制作期間等
2/19(土)〜3/5(日)の15日間。
サークル内イベントの『ichigojam』にて制作しました。
雑記
私の担当はプログラムだったと述べましたが、フルスクラッチ[1]ではなくUnityを用いて制作しました。
Unityでの制作はフルスクラッチに比べて手間がかからず、難易度もそれほど高くありません。だからこそ2週間という短期間で作れたのかも? (余談ですが、高校の頃javaで作ったSTGは今回と同程度のボリュームですが、完成までに半年かかりました。一日あたりの作業時間が違うので一概に比較はできませんが...)
シューティングゲームは、初心者向けゲーム制作サイトでおすすめされているゲームジャンルの鉄板であると言えるでしょう。しかし、Unityで作るとなると少し難易度が高いかな?という印象を受けます。というのもシューティングゲームはUnityのシステムに頼りづらいからです。ですが、ゲーム作りの基礎を学べるとは思うので、そういう意味では初めて作るジャンルとしてアリかもしれません。
二本目[どったんばったん(ry]について
ゲーム紹介
東北きりたん[2]の二次創作アクションパズルゲームです。全30面。きりたんを操作してゴールまで導くタイプのパズルです。
今回は一人で作ったので、趣味全開です。キリタンカワイイヤッター!
私はパズルゲーム下手くそですが、作る場合は自分が解けないような問題も作れてしまうと、今回のゲームを通じて実感しました。一応難しくなりすぎないように注意したので、多分クリア不可能な難易度ではないと思います。
制作期間等
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さんです。楽しみ〜。