マケプレ、著書等あったりします!!

マケプレ作品は絶対におススメです!!!!

グリッド管理に便利 PackedInt32Array 化して「1セル=1整数」にする設計メモ【Godot備忘録】

1レベル10×10マスのパズルとかで、グリッドの管理をいちいち詳細な情報を持たせて作ると大変だし、じゃあ各オブジェクトを.tresにしてインスペでチマチマ貼るのもしんどい。
100面あるパズルゲームでそんなことしたら死んじゃうので。試しにPackedInt32Arrayでグリッドのセルに整数だけ持たせてシーン構築時に展開すると楽ちんだったのでメモメモ。

PackedInt32ArrayはInt32を並べるもので、要素1個=4バイトらしい。

Int32は符号付なので、上位ビットをガンガン使うと負の値になってバグるかもなんで不注意に過剰使用するとバグのもとになりそう。まぁ、注意して使えば20億くらい情報を詰めれるので、そこまで怖がらんでも…。いまはいいでしょ。

情報を詰める時

これを、例えば10×10のステージなら要素100個の整数をぶち込んで、シーン生成のタイミングで展開していけばいいってこと。

例えば下位8ビットに、コンベアの種類、次の2~3ビット(4方位なら2bit、8方位にしたければ3bitに増やす)に向きを詰めておけば、読み取って展開可能。

例えばあるセルをコンベアタイプ8、向き西とかにしたいって場合に
00000000 00000000 000011 00001000
こんな感じになればいいとして、これを整数にすると向きが768、タイプが8で、足して776を入れておけばいいって感じ。

[gd_resource type="Resource" script_class="LevelDef" format=3 uid="uid://"]

[ext_resource type="Script" uid="uid://cs1hgtxx8uo0c" path="res://scripts/def/level_def.gd" id="1_5mpnl"]

[resource]
script = ExtResource("1_5mpnl")
width = 4
height = 4
cells = PackedInt32Array(257, 258, 258, 259, 772, 770, 770, 515, 516, 261, 258, 262, 0, 0, 0, 5)
metadata/_custom_type_script = "uid://"

↑のは4×4だけど、同じようにすればいい。これなら100面作るのもかなり楽。

展開する時

じゃあ776からどうやって展開するかなんだけど、ざっくり言うと、設計したビットのまとまりごとに取り出して対応をチェックして、あとは判定に投げる感じ。

static func unpack_type(v: int) -> int:
	return v & 0xFF

こんな感じに255にマスクすればタイプはmatchで探せるし、

static func unpack_rot(v: int) -> int:
	return (v >> 8) & 3

こんな感じで右シフトで下位の8ビットを切り取って、3ビットをマスクで取り出せば向きもmatchで探せるって寸法。

const TYPE_BITS := 8
const TYPE_MASK := (1 << TYPE_BITS) - 1 # 0xFF

# 4方向なら 2bit、8方向なら 3bit に
const ROT_BITS := 2
const ROT_MASK := (1 << ROT_BITS) - 1  # 0b11

static func pack_cell(cell_type: int, rot: int) -> int:
    return (cell_type & TYPE_MASK) | ((rot & ROT_MASK) << TYPE_BITS)

static func unpack_type(v: int) -> int:
    return v & TYPE_MASK

static func unpack_rot(v: int) -> int:
    return (v >> TYPE_BITS) & ROT_MASK

例としてこんな感じになる。

まとめ

PackedInt32Arrayは32bitで、編集が楽になるのでつよつよになります。ただし、人間が直接手で数値を書くのは事故りやすいので、pack/unpack関数を必ず経由するのが望ましいかな。

データの手動生成って大変で、外部エディタとかでガンガン作らないと一生終わらないので、こういうちょっとでも楽になる方法は試していかないと寿命が先に来ちゃう…。たぶんゲーム開発では一般的な手法なのでいいお勉強になりました。

また、32ビットなので、まだまだ使ってない上位ビットがあって、2セル詰めるとか、PackedByteArrayを2つ使って上手くやるとか、もっと勉強すればいい方法はあるけど、最適化のタイミングでまた考えましょうぞ。

てなわけで、ゲーム開発がんばりましょー( *˙ω˙*)و

コメント