Help us understand the problem. What is going on with this article?

[PHP]ゲーム作成初心者がPHPでテト〇ス風ゲームを作ってみた

More than 1 year has passed since last update.

作ってみた

名前は TETRICE です!

image.gif

リポジトリはこちら

なんで?

どっかの質問サイトでPHPでゲームは作れますか?作るにはどうしたらいいですか?ってQに対するAが作れません or Javascript で作りますみたいな内容だらけだったのに触発されただけ。

ちなみにゲーム作ったことはほぼないです。

いきなりまとめ

使ったことないけどCUIでグラフィカルなことしたいんだったらtermbox使った方がいいと思う。
(この記事全否定)
PHPライブラリyum install -y php-pecl-termbox

スペルミスじゃないよ。
http://hot-topic-news.com/tetris-copyright

[暇な人用]にっき

以下時系列で。

標準入力のノンブロッキング化

普通にキーボードの入力受けようとするとその時点でブロックされてしまう。

(キーボード入力待ちみたいな状態)

画面垂れ流しのまま標準入力を受けようとするとnon-blockingにしないといけない。

  1. fcntl() で nonblocking にしてやろうとする
  2. dio_fcntl() 『注意: この関数は Windows 環境にはまだ実装されていません。』
  3. 色々ぐぐって stream_set_blocking(STDIN, FALSE);見つけた。
  4. 組み込んでみるもなんか動かない。
  5. 動かない報告いっぱいあった。

最終的に stream_select のタイムアウトを0にして標準入力を監視する方式にした。

src/app/Controller.php
<?php
class Controller implements LoopProcessInterface
{
    private function readNonBlock(&$data) {
        $read = [STDIN];
        $write = [];
        $except = [];

        $result = stream_select($read, $write, $except, 0);

        if($result === false) {
            throw new \Exception('stream_select failed');
        }

        // Cygwinだとここが必ず1になるから`stream_get_contents`でブロック状態になってしまう・・・
        if($result === 0) {
            return false;
        }

        $data = stream_get_contents(STDIN);

        return true;
    }

    public function loopProcess()
    {
        $data = "";
        if ($this->readNonBlock($data)) {
            echo $data;
        }
    }
}

stream_select で変更があれば 1、変更がなければ 0 が返る。
1の時に入力内容を取得してブロック状態にならないようにしたかったのだが、Cygwin上だと必ず1が返る/(^o^)\(未解決)

ユーザー入力値の制御

  • 標準入力をエンター押すまでじゃなくて押下した段階で取りたい
  • ユーザーの入力をコンソールに出さない

右とか左とかならまだしもスペースとか入力した値を表示してしまうと画面表示時にずれちゃう。なのでパスワードの入力時みたいにユーザーの入力値を非表示にしたい。

正直気持ち悪いが stty コマンド呼び出して対応・・・
shell_exec("stty -icanon -echo")

プログラム終了時に元のターミナルに戻っても適用されたままなので元に戻す処理を組み込み。
try - finally で戻す場合、開発中にexit したときとかfinallyが呼ばれない。
ただしデストラクタは呼ばれるのでそっち側に組み込んだ。

画面の描画

とりあえず画面クリアして書き込めばいいんだろとか思って clear して echo したところちらつきと出力ログ大量みたいなことになった。やりたいこととしては top コマンドに近い感じなので標準出力の内容をカーソル移動して書き換える形にした。

こんな感じでANSIエスケープシーケンスで戻って上書き可能。

sample.php
<?php
for ($i = 1; $i <= 5; $i++) {
    $str = "--- {$i}/5 ---\n";
    echo $str;

    // カーソルを一つ上にずらす
    echo "\e[1A";

    sleep(1);
}

cursor.gif

この部分書き換え+flush()を駆使することで意図通り綺麗にでるようになった。

他にもANSIエスケープシーケンスでブロックの色を表現したりした。
(スペース2つ+背景色を変更)

その他

  • ゲーム部分実装をかなりやっつけで作ってしまった感がある。
    テトリスのアルゴリズムちゃんとやるとかなりしんどそうね。
  • ブロックの種類的に1色足りなかった・・・
  • 完全にプロトタイプ作りながらなのでUnitテストがかなり後発になってしまった。
  • TravisCI + Coveralls 導入した
PruneMazui
試行錯誤の毎日 割と雑食だけどよくいるのはこの辺 ⇒ アジャイル / プロジェクトマネジメント / バックエンドアーキテクチャ / OOP / FP / RDBMS
admin-guild
「Webサービスの運営に必要なあらゆる知見」を共有できる場として作られた、運営者のためのコミュニティです。
https://admin-guild.slack.com
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした