2025/04/01

ゲーム「一網打尽」の開発始めました

目次

ゲーム紹介

新しいゲーム「一網打尽」を去年の10月ごろから開発を始め、最低限の遊びが出来上がったのでプレビュー公開します。
このゲームは、マップ上に次々登場する敵を上手く誘導し、ここぞというタイミングで仕掛けておいた罠を発動して、出来るだけたくさんの敵を倒すゲームになります。
現バージョンではまだ、たくさんの敵を一気に倒したときのボーナスなどは実装されていないのでご了承ください。

サイズが大きく、今後のバージョンでダウンサイジングしたいところ

操作方法

キーボード

マウス

余談

ゲームエンジンの話になるのですが、今まではUnreal Engine (UE)を使っていました。
UEは3Dゲームを作れ、光の描写なども優れていて、ブループリントというビジュアル言語(私にとっては使いやすい)が使える良いゲームエンジンだと思います。
ただしその分、色々と細かくてややこしい仕様(カメラ周りでは、Orient Rotation to Movement、後は忘れた)があったり、3Dアセット(キャラクターメッシュ、アニメーション、環境、ライティング)を無料で調達するのが難しかったりしました。
没入感、迫力、(あとは3Dに対する憧れ)を入れたくなったら使うと思いますが今のところ、遊びを表現するなら2Dゲームで十分といった印象です。

今回はゲームエンジンにEbitengineを採用しています。
Ebitengineは2Dゲームのみ作れるゲームエンジンです。
2D空間(X, Y座標)を表現すればいいだけなので、計算量(PCの負荷)を大きく減らせ、開発者側もより遊びの実装に集中できます。
とは言いつつ、今回は大半の期間をEbitengineを自分仕様に拡張していく作業に費やしています。
(本末転倒という言葉が聞こえてきそうですが、今回は初めてEbitengineを使うのと、拡張していく作業自体が楽しく、かなり学びにもなったという言い訳で逃げさせていただきます(笑))

Ebitengineを使う際、Go言語もまた使うことになりまして、よりGo言語が好きになってしまいました。
昔の記事(忘年会2022)では、コンパイルが速い、不必要なimportがあればコンパイルエラーになるとか、表面的なメリットだけを書いておいて、他の言語をボロクソに言っていた時期があり、私も若かったです。
Goをより使ってみて現時点で感じたことは、とにかくインターフェース周りの恩恵がでかい感じです。
他のオブジェクト指向言語では、継承という考え方があり、クラスBがクラスAを継承したら、B=Bであり、B=Aである考え方で、Aの情報をすべて持ってくれるし、Aそのものになれたわけです。
対してGoは、継承はないが代わりに組み込みができます。
構造体Bに構造体Aを組み込むと、AがメンバA1を持っていたとして、B.A1のような感じでアクセス可能になります。
ただし、B≠Aのため、あくまでも継承ではないです。
ではどうやってAとBの共通部分を生み出すかというと、その役割を担うのがインターフェースなわけです。
インターフェースは空メソッド(メソッド名、引数・返値の並び、個数、型)の集合体で、記述されている全ての空メソッド、メソッドの処理を構造体が実装していたら、インターフェースを実装しているとみなされます。
つまり、インターフェースαを定義しておけば、A=α、B=αになり、A=B的になります。
こうすることで、Bに引き継がせたくないメソッドをシャットアウトでき、各構造体がより必要な情報しか持たないようにできます。
よく考えられています。
あとはジェネリクスもよく考えられている感じで、型パラメータが引数や返値の型と連動できるので、その場合は呼び出し側で明示的な型指定を省略できたりします。
例えば、スライスから特定の要素を削除する関数の場合、

func RemoveSliceItem[T comparable](slice []T, item T) []T {
	i := slices.Index(slice, item)
	if i == -1 {
		return slice
	}

	return slices.Delete(slice, i, i+1)
}

var targets []utility.MovableCollider = "スライス"
var t utility.MovableCollider = "削除する要素"

targets = utility.RemoveSliceItem(targets, t)

みたいな感じで書けたりします。
わざわざ、targets = utility.RemoveSliceItem[utility.MovableCollider](targets, t)と書く必要はないんですよね。
他にも細かなところまで丁寧に作りこまれている言語で、理不尽さがなく、ストレスなくプログラミングできるのは本当に嬉しかったりします。
逆にGoで使いにくいのはリフレクションな気がするが、そもそもあまり使う機会がなく、今回はTiledで作られたマップデータをEbitengineに取り込むのに使ったぐらいですかね。
便利な反面、命名規則、関数呼び出しならシグネチャを統一しなければいけないという大きな制限がかかる、諸刃の剣的なところは他言語と同じです。


コメントはこちらにどうぞ!
タグ:ゲーム一網打尽