RPGクラス
<?php
// RPGクラス
class tuwGameUtl
{
// 魔物番号
private $Monster = 2;
// 粉砕可能画像の先頭番号
private $crushIndex = 3;
// マップのセルサイズ
private $ChipSize = 66;
// 魔物URLリスト
private $Devils = array(
"./media/npc/mst01.png"
, "./media/npc/mst02.png"
, "./media/npc/mst03.png"
, "./media/npc/mst04.png"
, "./media/npc/mst05.png"
);
// 経路探索未訪問リスト
private $oHash = array();
// 経路探索訪問済リスト
private $cHash = array();
// 生成
public function __construct()
{
}
// プロパティ設定
public function __set($key, $value)
{
if ($key == "Monster")
$this->Monster = $value;
else if ($key == "crushIndex")
$this->crushIndex = $value;
else if ($key == "ChipSize")
$this->ChipSize = $value;
else
throw new Exception('Undefined Property['.$key."]");
}
// プロパティ取得
public function __get($key)
{
if ($key == "Monster")
return $this->Monster;
else if ($key == "crushIndex")
return $this->crushIndex;
else if ($key == "ChipSize")
return $this->ChipSize;
else
throw new Exception('Undefined Property['.$key."]");
}
// 魔物をランダムに得る
public function GetDevil()
{
$idx = array_rand($this->Devils);
return $this->Devils[$idx];
}
// RPG 地図ランダム生成
// 0:地べた
// 1:粉砕後(ここでは設定しない)
// 2:魔物
// 3:粉砕対象(3以上)
// $rows = マップの行数
// $cols = マップの列数
// $num = 宝箱の種類数
public function CreateMap($rows, $cols, $num)
{
// マップの中央
$cpx = floor($cols / 2);
$cpy = floor($rows / 2);
// マップ配列
$map = array();
// 障害物、宝箱、魔物等の地べた以外の配列
$mst = array();
// 行ループ
for ($row = 0; $row < $rows; $row++) {
$map[] = array();
// 列ループ
for ($col = 0; $col < $cols; $col++) {
// マップの中央は必ず地べたにする
if ($row == $cpy && $col == $cpx)
$map[$row][$col] = 0;
else {
$flg = mt_rand(0, 1);
// 地べたと置物分岐
if ($flg == 0) {
$map[$row][$col] = $flg;
$mst[] = array('r' => $row, 'c' => $col);
}
else {
// 粉砕対象がでたら10個に1個の割合で宝箱にする
if (mt_rand(1, 10) == 10) {
$box = mt_rand(1, $num);
$map[$row][$col] = $this->crushIndex + $box;
}
else
$map[$row][$col] = $this->crushIndex;
}
}
}
}
// 魔物を配置する(マップに1匹)
$idx = array_rand($mst);
$map[$mst[$idx]['r']][$mst[$idx]['c']] = $this->Monster;
// 結果を返す
return $map;
}
// 経路上のノード生成
private function NewNode($parent, $row, $col)
{
$key = substr('0000'.$row, -4).substr('0000'.$col, -4);
$new = array('key' => $key, 'row' => $row, 'col' => $col, 'cost' => 0, 'parent' => $parent);
return $new;
}
// ノードを登録する
private function putNode($node, $flgOpen)
{
if ($flgOpen)
$this->oHash[$node['key']] = $node;
else
$this->cHash[$node['key']] = $node;
}
// 推定コスト計算 ヒューリスティック関数
// 二つの指定ノードの推定コストを計算する
// この関数が最短経路を選択する肝になる
private function getHeuristicCost($node, $next)
{
// 二つのノードの行列の差を得る
$a = $node['row'] - $next['row'];
$b = $node['col'] - $next['col'];
// 二つのノードのコストを計算する
$c = sqrt(($a * $a) + ($b * $b));
// 結果を返す
return $c;
}
// 最小コストのノードを得る
private function getMinCostNode()
{
$mNode = null;
// Openリストがあるなら...
if (count($this->oHash) > 0) {
// ダミーノードを生成する
$mNode = $this->NewNode(null, 0, 0);
$mNode['cost'] = PHP_INT_MAX;
// コストの最小値を探索する
foreach($this->oHash as $node) {
if ($node['cost'] < $mNode['cost'])
$mNode = $node;
}
// ハッシュを削除
unset($this->oHash[$mNode['key']]);
}
// 結果を返す
return $mNode;
}
// 最短経路の取得
public function GetShortcutRoute($StRow, $StCol, $EdRow, $EdCol, $map)
{
// 隣接ノード間の最長距離コスト(障害物)
$ObstacleCost = $this->ChipSize * $this->ChipSize;
// 1.初期化 出発点ノードとゴールノードを作成する
$sNode = $this->NewNode(null, $StRow, $StCol);
$gNode = $this->NewNode($sNode, $EdRow, $EdCol);
// 2.出発点ノードをOpenリストに追加する、このとき g*(S) = 0 であり f*(S) = h*(S) となる
$sNode['cost'] = $this->getHeuristicCost($sNode, $gNode);
$this->putNode($sNode, true);
// 3.Openリストが空になるまでループ
while (count($this->oHash) > 0) {
// Openリストに格納されているノードの内、最小の距離コストを持つノード n を取り出す。
$node = $this->getMinCostNode();
// ゴールであるなら探索を終了する
if ($node['row'] == $EdRow && $node['col'] == $EdCol) {
$gNode = $node;
break;
}
// ゴール以外の場合は n を Close リストに移す。
$this->putNode($node, false);
// n に隣接している全てのノード(時計回り8方向の隣接ノードを m とおく)に対して以下の操作を行う
for ($v = 0; $v < 8; $v++) {
// 着目ノードの座標を得る
$r = $node['row'];
$c = $node['col'];
// 北、北東、北西
if ($v == 0 || $v == 1 || $v == 7)
$r--;
// 南東、南、南西
if ($v == 3 || $v == 4 || $v == 5)
$r++;
// 北東、東、南東
if ($v == 1 || $v == 2 || $v == 3)
$c++;
// 南西、西、北西
if ($v == 5 || $v == 6 || $v == 7)
$c--;
// マップ範囲内にあるならば...
if (isset($map[$r]) && isset($map[$r][$c])) {
$m = $this->NewNode($node, $r, $c);
// $mCost = 累積距離コスト + COST(n,m) を計算する
// 累積距離コスト=現在着目しているノードのコスト=$node['cost']
// $aCost = COST(n,m) = ノード n から m へ移動するときのコスト
$aCost = $this->getHeuristicCost($node, $m);
$mCost = $node['cost'] + $aCost;
// m がゴールでなく障害物ならコストを大きくする
if (($r != $EdRow || $c != $EdCol) && $map[$r][$c] >= $this->Monster)
$mCost += $ObstacleCost;
// m の状態に応じて以下の操作を行う
if (!isset($this->oHash[$m['key']]) && !isset($this->cHash[$m['key']])) {
// m が Openリストにも Closeリストにも含まれていない場合 f*(m) = f'(m)
$m['cost'] = $mCost;
// m を 登録する
$this->putNode($m, true);
}
else if (isset($this->oHash[$m['key']])) {
// m が Openリストにある場合登録済み m を得る
$m = $this->oHash[$m['key']];
// f'(m) < f*(m) であるなら
if ($mCost < $m['cost']) {
// f*(m) = f'(m) に置き換える
$m['cost'] = $mCost;
// m の親を n にする
$m['parent'] = $node;
// m を 置き換える
$this->putNode($m, true);
}
}
else if (isset($this->cHash[$m['key']])) {
// m が Closeリストにある場合登録済み m を得る
$m = $this->cHash[$m['key']];
// f'(m) < f*(m) であるなら
if ($mCost < $m['cost']) {
// m を Closeリストから削除
unset($this->cHash[$m['key']]);
// f*(m) = f'(m) とする
$m['cost'] = $mCost;
// m の親を n にする
$m['parent'] = $node;
// m を Openリストに追加する
$this->putNode($m, true);
}
}
}
}
}
// 経路結果変数
$route = array();
// 4.探索終了後、親を順次たどっていくと G から S までの最短経路が得られる。
while (isset($gNode['parent'])) {
$route[] = array('row' => $gNode['row'], 'col' => $gNode['col']);
$gNode = $gNode['parent'];
}
// 結果を返す
return $route;
}
}
?>