PHPでPRGゲームを作ります。サンプルソースを載せつつついけるところまでやってみようと思います。
環境
OS ubuntu22.04
Webサーバ apache2.4.52(自身のIP 192.168.19.128、公開フォルダ /var/www/html)
PHP 8.1.2-1ubuntu2.14
フィールド画面を作る
マップを作成し、マップ上を主人公が移動するところまで作成します。
とりあえず今回はゲームのイメージをつかみたいので、マップデータもテキストデータを読み込む形にしています。
ソースは次の内容を作成しました。
<!DOCTYPE html>
<html>
<head>
<style>
table,tr,th,td{
border-collapse:collapse;
border-spacing:0;
margin:0;
padding:0;
border:none
line-height: 0;
display: flex;
}
</style>
</head>
<body>
<script type="text/javascript">
<!--
function press_up_button(){
document.getElementById("do").value="up";
document.gameform.submit();
}
function press_down_button(){
document.getElementById("do").value="down";
document.gameform.submit();
}
function press_left_button(){
document.getElementById("do").value="left";
document.gameform.submit();
}
function press_right_button(){
document.getElementById("do").value="right";
document.gameform.submit();
}
function press_menu_button(){
document.getElementById("do").value="menu";
document.gameform.submit();
}
// --></script>
<?php
$data = "000000000022200000000000000000000000000000000000000000000000
000000000000000000222220000000000000000000000000000000000000
000000000000000000222000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
000000000000066666666666666666611166666666666666600000000000
000000000666655566666666666655511155555555555555556600000000
000000006655555555666666655555511555555555555555555660000000
000000066555555556665555555555115555555555555555555660000000
000000066555555556665555555551155555555555555555555660000000
000000066555555556555555555511555555555555555566666600000000
000000000066555111111555555115555555555555115600000000000000
000000000011111555551111111111111155555555505600000000000000
000000000665555555551111111111111155555555555566666000000000
000000000665555555555511111111155555555555555555566000000000
000000000665555555555551111111115555555555555555555660000000
000000000665555555555555551111155555555555775555555660000000
000000000665555555555555551111115555551115555555556600000000
000000000665555555555555555111115555115551111111111100000000
000000000665551111111555555555551111555555555555556600000000
000000000665555511155555555555551111555555555555555660000000
000000000665555555555555555555555111155555555555556666000000
000000006655555555555555555551155555555555555555560000000000
000000006655555555555555555555555555555555555566600000000000
000000000066555555555555555555555555555555556600000000000000
000000000000066555555555555555555555555555660000000000000000
000000000000006665555555555555555556666666000000000000000000
000000000000000006655555555666666660000000000000000000000000
000000000000000665555556666000000555566000000000000000000000
002220000000066555555660000000005555660000000000000000000000
022200000000066666666660000000006666666600000000000000000000
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000";
if ($_SERVER['REQUEST_METHOD'] === 'POST'
&& isset($_POST['do'])
&& isset($_POST['user_x'])
&& isset($_POST['user_y'])
&& isset($_POST['user'])) {
$do = $_POST['do'];
$user = $_POST['user'];
$userx=$_POST['user_x'];
$usery=$_POST['user_y'];
//整合性チェック
//移動先の確認
if($do === 'up'){$usery--;}
if($do === 'down'){$usery++;}
if($do === 'left'){$userx--;}
if($do === 'right'){$userx++;}
} else {
//初期場所
$userx=30;
$usery=12;
}
$rows = explode("\n", $data); // 行ごとに分割
$y = 0;
$map_wide=4;
echo '<table>';
foreach ($rows as $row) {
$y=$y+1;
if($y >= $usery-$map_wide && $y <= $usery + $map_wide){
echo '<tr>';
for ($x = 0; $x < strlen($row); $x++) {
if($x >= $userx-$map_wide && $x <= $userx + $map_wide){
echo '<td>';
if($y == $usery && $x == $userx){
echo '<img src="./img/me.jpg" width="20.px">';
}else {
echo '<img src="./img/0'.$row[$x].'.jpg" width="20.px">';
}
echo '</td>';
}
}
echo '</tr>';
}
}
echo '</table>';
echo "<form method='post' name='gameform' action=''>"; //自分自身にaction
echo 'ユーザ名<input type="text" name="user" value="user1" readonly><br>';
echo '<input type="hidden" name="pass" value="pass" readonly>';
echo 'HP<input type="text" name="hp" value="100" readonly><br>';
echo '<input type="hidden" name="user_x" value="' .$userx. '">';
echo '<input type="hidden" name="user_y" value="' .$usery. '">';
echo '<input type="hidden" name="user_map" value="1">';
echo '<input type="hidden" name="do" id="do" value="">';
echo '<table>';
echo '<tr>';
echo '<td width="30px" align="center"> </td>';
echo '<td width="23px" align="center"><input type ="button" value="↑" onclick="press_up_button();"></td>';
echo '<td width="30px" align="center"> </td>';
echo '<td width="100px" align="right"><input type ="button" name="left" value="MENU" onclick="press_menu_button();"></td>';
echo '</tr>';
echo '<tr>';
echo '<td width="30px" align="center"><input type ="button" name="left" value="←" onclick="press_left_button();"></td>';
echo '<td width="23px" align="center"> </td>';
echo '<td width="30px" align="center"><input type ="button" name="left" value="→" onclick="press_right_button();"></td>';
echo '<td width="100px" align="center"> </td>';
echo '</tr>';
echo '<tr>';
echo '<td width="30px" align="center"> </td>';
echo '<td width="23px" align="center"><input type ="button" name="left" value="↓" onclick="press_down_button();"></td>';
echo '<td width="30px" align="center"> </td>';
echo '<td width="100px" align="center"> </td>';
echo '</tr>';
echo '</table>';
echo "</form>";
?>
</body>
</html>
もう少しきれいなソースを書けるように頑張りたいと思います。(かなり強引に作っています)
● マップデータ
マップデータはテストデータなので、PHP内に直接書き込みました。いずれはDBにマップテーブルを作りたいと思っていますが、エクセルのような二次元配列テーブルを作るにはどうしようか考え中です。
マップ番号をそのままファイル名にしています。(0:海 だったら 00.jpgとしました)
画像ファイルをソースフォルダに配置すると見にくくなるので、画像ファイルは、
/var/www/html/php/rpg/img
以下に配置し、
フォルダのパーミッション 705
画像ファイルのパーミッション 604
としています。
●チート対策
メソッドをPOST限定にしているのはチート対策です。
以前作成したプログラムで、GETメソッドから不正なコードを入力されたことがあったので、GETメソッドは極力使用しないようにしています。
画面遷移後に、DBデータとの整合性チェックを行い、チート対策を行う予定です。
●画面遷移
DOというパラメータに、押されたボタンを識別する文字列を入れて自分自身をsubmitで呼び出すという方法をとりました。
この方法を使えば、一つのPHPファイルでゲームを実装できますが、ソースがスパゲッティになりやすいので注意が必要です。
実行画面
実行した画面は、こんな感じになります。
ゲームを実行した様子
十字ボタンをマウスでクリックするとキャラクタが移動します。
作り始めたばかりなので、メニューや戦闘シーンなどは実装していませんが、これからタイミングを見て実装していきたいと思います。
今回作ったプログラムはこちらから確認できます。