LoginSignup
3
4

More than 1 year has passed since last update.

PyScriptでぷよぷよ

Last updated at Posted at 2022-05-15

PyScriptが面白そうって話を聞いたので PyScriptでぷよぷよ作ってみる。
内容は Elmで作ったものと同じものを目指す。

PyScript

AnacondaがリリースしたWebブラウザ上でpythonが実行できるフレームワークらしい。

公式からスクリプト読み込むだけで実行できるのでめちゃめちゃお手軽

<link rel="stylesheet" href="https://pyscript.net/alpha/pyscript.css" />
<script defer src="https://pyscript.net/alpha/pyscript.js"></script>

※ CORSエラーが出る時があったのでローカルにbuildしておくのもいいかも。

使い方

大体は↓に書いてある。

pythonのコードを <py-script> タグに入れるだけでいいらしい。

<py-script>
  実行したいコード
</py-script>

ここではゲーム作成の肝になるテンプレートタグイベントリスナーイベントループだけ紹介。
※ ドキュメントがあまり無いので、サンプルみて作ることになりそう。

テンプレートタグ

まずはpython側からhtmlの要素を取得する話。
id指定の場合は↓で要素を取得できる

...
<divid="grid-container">
</div>
...
<py-script>
grid_container = Element("grid-container")
</py-script>

そして、要素の操作や追加は↓のようにjavascriptみたいに可能

# 追加
grid_container.element.appendChild(puyo_html.element)

# 変更 (イメージの変更)
puyo_html = Element("puyo-blue")
puyo_html_img =  puyo_html.select("img")
puyo_html_img.element.src = "hoge.img"

そしてtemplateタグを使う場合はcloneを利用する。

...
    <template id="puyo-template">
      <div class="view-cell" style="position: static">
        <img src="" class="puyo">
      </div>
    </template>
...
<py-script>
# スタイルとイメージを変更し、要素を追加
puyo_html = puyo_template.clone('puyo-template', to=grid_container)
puyo_html.element.style = "position: absolute;"
puyo_html_img =  puyo_html.select("img")
puyo_html_img.element.src = c.img
grid_container.element.appendChild(puyo_html.element)
</py-script>

これでViewの更新、変更はなんとかなりそう。

イベントリスナー

ゲーム作るならキーボード入力がないとってことでイベントリスナー。
この辺はpyodideを見ないとダメッぽい。

結論から、↓でキーイベントを取得できる。

from pyodide import create_proxy

async def key_down(event):
    # ...なにかやりたい処理
    pass

game_panel = document.querySelector("body")
game_panel.addEventListener("keydown", create_proxy(key_down))

ほぼjavascriptの書き方だが、addEventListenerで特定のイベントを取得し、create_proxyでpythonの関数にproxyする。
↑の場合はevent.keyとかでキーコードが取得できる。

イベントループ

asyncioのイベントループが使えるみたい。

async def tick():
  while True:
    try:
        # ...なにかの処理
        await asyncio.sleep(1)
        print(tock)
    except Exception as e:
        break

pyscript.run_until_complete(tick())

run_until_complete以外は試してない。使えるのだろうか...

ぷよぷよを作る

あとは作るだけ。
処理内容は以前elmで作ったものと変わらず

テンプレートでぷよを定義して、それをひたすら動かしていく。
空のボード・操作するぷよ・次のぷよ・ゲームのステータスを初期状態として定義し、イベントループ/イベントリスナーで盤面を更新する。
更新毎にupdate_view()で画面に盤面を反映。

    def __init__(self):
        self.board = [[Puyo.Empty for i in range(COL)] for i in range(ROW)]
        self.gripped_puyo = [
            { 'position': {'row': 0, 'col': 1}, 'color': Puyo.random_choice()},
            { 'position': {'row': 1, 'col': 1}, 'color': Puyo.random_choice()}
        ]
        for p in self.gripped_puyo:
            self.board[p['position']['row']][p['position']['col']] = p['color']
        self.next_puyo = [
            [Puyo.random_choice(), Puyo.random_choice()],
            [Puyo.random_choice(), Puyo.random_choice()],
        ]
        self._status = Status.Normal
        self.init_view()

    def update_view(self):
        count = 0
        for r in self.board[1:]:
            for c in r:
                puyo_html = Element("puyo-" + str(count))
                puyo_html_img =  puyo_html.select("img")
                puyo_html_img.element.src = c.img
                count += 1

    def init_view(self):
        pos = [0,0]
        count = 0
        for r in self.board:
            if pos[0] == 0:
                pos[0] = pos[0] + 1
                continue
            pos[1] = 0
            for c in r:
                puyo_html = puyo_template.clone('puyo-'+str(count), to=grid_container)
                puyo_html.element.style = "position: absolute; top: " + str(25 * (pos[0]-1)) + "px; left: " + str(25 * (pos[1]+1)) + "px;"
                puyo_html_img =  puyo_html.select("img")
                puyo_html_img.element.src = c.img
                grid_container.element.appendChild(puyo_html.element)
                pos[1] = pos[1] + 1
                count += 1
            pos[0] = pos[0] + 1
        self.update_next_view()

    def update_next_view(self):
        count = 0
        for pair in self.next_puyo:
            for c in pair:
                puyo_html = Element('next-puyo-'+str(count))
                puyo_html_img =  puyo_html.select("img")
                puyo_html_img.element.src = c.img
                count += 1

出来上がり。

puyo-demo.gif

pyscript-gamesみたいなプロジェクトもできるのかな

3
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
4