よちよちpython

独習 python/Qpython/Pydroid3/termux/Linux

【PythonのFlask、JavaScript】端末の傾きに応じてボールを動かすアプリを作る

PythonのFlaskとJavaScriptを使って、Android端末の傾きに応じてブラウザ上でボールを動かすプログラムを試します。メモ。

動作中のキャプチャ画像

f:id:chayarokurokuro:20210304183536j:plain


傾けるとボールが動きます。



というサッパリな状況で作っております。htmlとJavaScriptは写経。リンクは最後に貼っています。



目次



1. 実行環境

※端末の傾きをJavaScriptで取得させます。端末やブラウザによっては動かないかも知れません。


1.1 AndroidにTermuxとPythonが入ってない場合

スマホタブレットPythonとFlask、傾きセンサーが動く・取得できる環境があればできる(はず)。AndroidアプリならPydroid3はFlaskをインストールできるようです。QPython3やその他Pythonアプリは情報不足・不明。Flaskが駄目ならbottleで。



2. 動作の仕組み、流れ

  1. PythonのFlaskでAndroid端末内にサーバーを起動させます。
  2. 用意しておいたテンプレートindex.htmlを読み込みます。
  3. index.htmlは傾きセンサーの動作をJavaScriptで制御するmain.jsを読み込みます。
  4. ブラウザでhttp://localhost:8888/を開けば、画面上にAndroidの傾きに応じて動くボールが表示されます。



2.1 ブラウザの設定

2.1.1 JavaScriptモーションセンサー

ブラウザ上でAndroid端末の傾きセンサー値をJavaScriptで取得していますので、この2つはオンにしておきます。

Chromeでの設定

  1. ブラウザを開く
  2. ブラウザの「設定⚙️」を開く
  3. 「サイトの設定」を開く
  4. 「モーションセンサー」と「JavaScript」をオンにする。



Firefoxでの設定(不明)

傾きセンサーを設定する所が見つかりません。試したがFirefoxでは動かなかった。なぜかWebページすら表示されない。😱



3. 用意するファイル(3つ)

  1. app.py(Flaskを起動するpyファイル)
  2. index.html(ブラウザ表示用)
  3. main.js(センサー取得用)



3.1 ディレクトリ構成

$ tree

.
├── app.py
├── static/
│   └── js/
│       └── main.js
├── templates/
   └── index.html


3 directories, 3 files


Flaskは、

  • indexテンプレートファイルを
    • templates/フォルダ内。
  • js、css、imageファイル等を
    • static/フォルダ内の各フォルダ内。

に入れてあげないと、どうやらファイルが読み込まれない(たぶん)。ディレクトリ構成が決まっているようなので注意します。



4. 実装

ファイルを3つ作ります。
それぞれは上記のディレクトリ構成でフォルダに保存してあげる。



4.1 app.py(Flask用)

from flask import Flask, render_template

app = Flask(__name__)

@app.route('/')
def index():
    return render_template('index.html')

if __name__ == "__main__":
    app.run(debug=True, port=8888, threaded=True)


※ブラウザでlocalhostのポート8888番にアクセスすると、index.htmlが表示される。



4.2 index.html(テンプレートファイル)

app.pyと同じ階層にtemplates/フォルダを作り、その中のこのファイルを保存する。
※このファイルはほぼ写経です。リンクは最後に貼っています。

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1.0">
    <title>端末の傾きに応じてボールを動かす</title>
    <script src="static/js/main.js" type="text/javascript"></script>
    <style>*{margin:0; padding:0;}</style>
</head>
<body>
    <canvas id="canvas" width="" height=""></canvas>
</body>
</html>


javascriptファイルのパスをapp.pyからの相対でscriptタグに書いておくだけで読み込んでくれる。



4.3 main.js(傾き取得用)

app.pyと同じ階層にstatic/フォルダを作り、更にその中にjs/フォルダを作った中にこのファイルを保存する。
このファイルも写経です。リンクは最後に。

/*
 * 端末の傾きに応じてボールを動かす
 */

/*
 * 定数
 */
const SCREEN_WIDTH = 480;       // キャンバス幅(ピクセル)
const SCREEN_HEIGHT = 480;  // キャンバス高さ(ピクセル)

/*
 * グローバル変数
 */
var canvas = null;      // キャンバス
var g = null;               // コンテキスト
var vec = {x: 0, y: 0 };    // 加速度センサー値格納用
var ball = null;            // 表示するボール

/*
 * ボールクラス
 */
class Ball{
    constructor(x, y, r){
        this.x = x; // x座標
        this.y = y; // y座標
        this.r = r; // 半径
    }
    draw(){
        // 位置を計算
        this.x += vec.x;
        this.y += vec.y;
        // 円を描画(塗りつぶし円)
        g.beginPath();
        g.fillStyle = "orange";
        g.arc(this.x, this.y, this.r, 0, Math.PI*2, false);
        g.fill();
    };
};

/*
 * ゲームループ
 */
function mainLoop(){
    // 画面クリア
    g.fillStyle = "#ddd";
    g.fillRect(0, 0, canvas.width, canvas.height);

    // ボールを描く
    ball.draw();

    // 再帰呼び出し
    requestAnimationFrame(mainLoop);
}

/*
 * 加速度センサーの値を取得
 */
window.addEventListener("deviceorientation", function(e){
    vec.x = e.gamma / 5;    // x方向の移動量: そのままでは大きい為、小さくする
    vec.y = e.beta / 5;     // y方向の移動量:         〃
}, false);

/*
 * 起動処理
 */
window.addEventListener("load", function(){
    // キャンバス情報取得
    canvas = document.getElementById("canvas");
    g = canvas.getContext("2d");

    // キャンバスサイズ設定
    canvas.width = SCREEN_WIDTH;
    canvas.height = SCREEN_HEIGHT;

    // ボールを一つ生成
    ball = new Ball(SCREEN_WIDTH/2, SCREEN_HEIGHT/2, 20);

    // メインループ実行
    mainLoop();
});

Pythonでセンサー値の取得が簡単に出来れば良いんだけどなぁ。

よし、3つのファイルがそろった。実行する\\\٩( 'ω' )و ////



5. 実行

◆実行の手順は、

  1. ターミナルでapp.pyを実行($ python app.py)
  2. ブラウザでhttp://localhost:8888にアクセス
  3. 画面上でオレンジ色のボールが傾きに合わせて動けば成功

◆止める時は、

  • ターミナルでCtrl+cを入力するとFlaskサーバーが止まる。
  • ブラウザのタブを閉じる。
  • ブラウザの設定を元に戻す



おわりに

JavaScriptを動かすにはサーバーが要るのか要らないのか、ローカル保存のhtmlファイルでもJavaScriptを書いとけば動くと思っていたが動かない、ブラウザによっても挙動が違うようだ、何か分派みたいなのがメチャクチャいっぱいある、などなど。勉強大変なんじゃないか。



ジャイロセンサーの値をPCなどに送ればなんかのコントローラーとして使えそう。PC側でサーバー立ててやれば良いのかな。IoT的な方向で夢が拡がりそう。😆

【追記】
JavaScriptファイルに記されたボールの色を変えようとorangeとある部分を書き換えたのですが、変更が表示に反映されませんでした。再読込でも変わらない。
反映させるには、ブラウザ(Chromeのばあい)履歴の「キャッシュされた画像とファイル」を削除すれば出来ました。理由等は分かりません。



参考リンク

JavaScriptで端末の傾きを取得し表示する写経元です。勉強になります。ありがとうございます。 - JS:端末の傾きに応じてボールを動かす | 電脳産物



以上。