Pyxelでマウスカーソルの表示/非表示を制御したい
Pyxelには、mouse関数という、マウスカーソルの表示・非表示を制御する関数があります。
mouse(visible)
visibleがTrueならマウスカーソルを表示し、Falseなら非表示にします。マウスカーソルが非表示でも座標は更新されます。
( pyxel/docs/README.ja.md at main · kitao/pyxel より引用)
Pyxelでクリック系のゲームを作成した場合、この関数を使ってマウスカーソルを表示することで画面上での自身の現在位置を把握することができます。
これはPCならば便利ですが、スマホやタブレットなどの画面タッチたんまつからゲームを起動した場合は、画面タップのたびにマウスカーソルがタップされた位置に飛び飛びで表示されてしまいます。
本記事では、端末のOSを判定してマウスカーソルの表示・非表示を制御してみます。
(なお、手動でマウスカーソルの表示・非表示を切り替える設定画面等を作成する、というのが一番確実ではあるのですが、ここではそれは考えないことにします)
環境
Pyxelのバージョンは2.2.8で実施しています。
ローカル実行する場合
ローカル環境からPyxelを実行する場合(コマンドだとpyxel run {pyファイル}
)、pythonのplatformモジュールを使用することで、OSを取得することができます。
イメージ的には以下のような感じです。
import pyxel
import platform
class App:
def __init__(self):
pyxel.init(160, 120)
# PC(非タップ端末)からの実行時のみマウスカーソルを表示する
os_name = platform.system()
is_pc = os_name == "Windows" or os_name == "Darwin" or os_name == "Linux"
pyxel.mouse(is_pc)
pyxel.run(self.update, self.draw)
def update(self)
...
def draw(self)
...
App()
Web Launcherから起動する場合
Web Launcher上では上記のplatform.system()で取得できる文字列は"Emscripten"の固定文字列となってしまいます。
そのため別の方法を使用する必要があるのですが、WebLauncherからの起動の場合、Pyodideの機能である、JavaScriptの実行が可能になるので、それを使用します。
具体的には、jsモジュールのnavigatorオブジェクトからユーザーエージェント情報を取得し、解析することでPCかスマホかを判定します。
以下、実装イメージです。
import pyxel
import js
class App:
def __init__(self):
pyxel.init(160, 120)
# PC(非タップ端末)からの実行時のみマウスカーソルを表示する
user_agent = navigator.userAgent.lower()
is_pc = not ("android" in user_agent or "iphone" in user_agent or "ipad" in user_agent)
pyxel.mouse(is_pc)
pyxel.run(self.update, self.draw)
def update(self)
...
def draw(self)
...
App()
両方考慮する場合
上記のjsモジュールですが、WebLauncherからの実行以外ではモジュールインポート時に例外が発生してしまいます。
そのため、pyxel runによる実行とWeb Launcherからの実行の両方を考慮する場合は、例外発生も考慮したコーディングが必要となります。
具体例として、以下のようなOS判定用モジュールを作成する方法があります。
import platform
# from js はEmscripten環境以外では例外発生するのでcatchして環境を判定する
try:
from js import navigator
is_web_launcher = True
except ImportError:
is_web_launcher = False
class DeviceChecker:
def __init__(self):
if is_web_launcher:
# Web launcherから起動している場合、js関数でOS判定する
self.user_agent = navigator.userAgent.lower()
self.os_pc = not ("android" in self.user_agent or "iphone" in self.user_agent or "ipad" in self.user_agent)
else:
# ローカルから起動している場合、platformから判定する
self.os_name = platform.system()
self.os_pc = self.os_name == "Windows" or self.os_name == "Darwin" or self.os_name == "Linux"
def is_pc(self):
return self.os_pc
def is_web_launcher(self):
return is_web_launcher
OS判定用モジュールをPyxelのコードで使用するイメージとしては、以下のような感じになります。
import pyxel
from device_checker import DeviceChecker
class App:
def __init__(self):
pyxel.init(160, 120)
# PC(非タップ端末)からの実行時のみマウスカーソルを表示する
self.deviceChecker = DeviceChecker()
px.mouse(self.deviceChecker.is_pc())
pyxel.run(self.update, self.draw)
def update(self)
...
def draw(self)
...
App()
補足
中華ゲーム機だとどうなるのかが未検証です。
plumOSを使用する場合、pyxappファイルを配置すると思うので、 platform.system()
の戻り値を調べてそれをハンドリングすれば良さそうです。
実装例
試しに簡単なクリックゲームを作ってみました。
pyxappを直接実行しても、Web Launcherから実行しても、PCからだとマウスカーソルが表示され、スマホ(画面タッチ端末)からだとマウスカーソルが非表示になるはずです。
GitHubリンク:
IgarashisanT/tap-numbers
WebLauncherリンク:
TAP NUMBERS
注意事項
Web Launcherからの起動の場合、更新直後はキャッシュが効いていてソースコードの変更が反映されない場合があるようです。
更新が反映されていないと思ったら、キャッシュクリアを試してみると良いです。
参考URL
pyxel/docs/README.ja.md at main · kitao/pyxel
Pyodideは今どれくらいできるのか #Python - Qiita
Pythonが実行されている環境のOSやバージョン情報などを取得 | note.nkmk.me
Pyxel(ブラウザ版)でJavaScriptの機能をいろいろ使う|frenchbread