ワールドシミュレータの実装
ああっ! こんなことしてる場合じゃないのに!
PerlとRDBMを使って、世界をオブジェクトの塊として管理する、その現実的な手法の考察。
ゲーム世界に存在するものを、全てオブジェクトとみなす。オブジェクト指向のオブジェクトと似ているけど、一応区別する。
そのゲーム世界にいる人間、敵、アイテム、草花、家屋なども、全てオブジェクトとみなす。海のようなものはそこからほぼ無制限に塩水オブジェクトを生成する特殊な「場所」と見なして別に管理する。
オブジェクトテーブルには、世界に存在する全てのオブジェクトが登録されている。しかしここに登録されているオブジェクトの全てのパラメータを登録している訳ではない。
オブジェクトID | 名前 | 形状 | 材質 | 重量 | 体積 | 所属オブジェクト | 所属型 | 容量 |
---|---|---|---|---|---|---|---|---|
hoge | 酒 | 不定形 | 酒 | 20 | 20 | huga | in | 0 |
huga | 酒ビン | ビン | ガラス | 10 | 25 | foo | hand | 22 |
foo | マイケル | 人間 | 肉 | 500 | 400 | アララト山 | put | 15 |
上記の例は、「アララト山中に、酒の入ったビンを持った人間が(多分)飲んだくれて寝ている」ことを示している。
……もっとマシな例を思いつかないかな、俺。
my $world = World->new; # 世界とアクセス my $trash = $world->get('foo'); # 人間を取得 my @item = $trash->have; # おい、そこのクズ、何もってやがんだ。 print map { $_->name."\n" } @item; # 持ち物、ちょっと見せてみろ。な? # 結果、酒ビンのみ
まあ、そんな感じ。
んでまあ、実装的には、プログラマーの目からは普通のオブジェクトな感じなんだけど、内部では生々しいSQLバリバリだったりする訳です。はい。
$trash = $world->get('人間のクズ'); print Data::Dumper->new([$trash], ['trash'])->Dump(); # $trash = { # id=>'人間のクズ' # }=>Object
$trash->all_weight(持ち物込みでの総重量)とかやったりすると、内部では。
sub all_weight { my $invocant = shift; my $id = ref $invocant ? $invocant->id : shift; my $weight = $invocant->weight($id); $weight += $invocant->have_weight($id); return $weight; } sub weight { my $invocant = shift; my $id = ref $invocant ? $invocant->id : shift; my $sql = 'SELECT weight FROM object_table WHERE id = ?'; my $sth = $dbh->prepare($sql); $sth->execute($id); my $weight = $sth->fetch->[0]; $sth->finish; return $weight; } sub have_weight { my $invocant = shift; my $id = ref $invocant ? $invocant->id : shift; my $sql = 'SELECT id FROM object_table WHERE where_id = ?'; my $sth = $dbh->prepare($sql); $sth->execute($id); my @have = @{$sth->fetchall_arreyref([0])}; $sth->finish; my $weight = 0; map { $weight += $invocant->all_weight($_) } @have; return $weight; }
まあ、これにステートメントハンドルを使いまわす仕掛けをするんですけどね。