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

傾けるとボールが動きます。
- JavaScriptってどう書くの?
- JavaScriptはどうやって動かすの?
- PythonのWebアプリでJavaScriptが動くんじゃない?
- JavaScriptで端末の傾きセンサー値が取得できるの?
というサッパリな状況で作っております。htmlとJavaScriptは写経。リンクは最後に貼っています。
目次
1. 実行環境
- Android(スマホ)
- Termux(Androidアプリ)
- Python3.9(Termuxでインストール)
- Pythonの外部ライブラリ
- Flask(Webアプリ作成用)
- ブラウザ(Google Chrome)
※端末の傾きをJavaScriptで取得させます。端末やブラウザによっては動かないかも知れません。
1.1 AndroidにTermuxとPythonが入ってない場合
スマホやタブレットでPythonとFlask、傾きセンサーが動く・取得できる環境があればできる(はず)。AndroidアプリならPydroid3はFlaskをインストールできるようです。QPython3やその他Pythonアプリは情報不足・不明。Flaskが駄目ならbottleで。
2. 動作の仕組み、流れ
- PythonのFlaskでAndroid端末内にサーバーを起動させます。
- 用意しておいたテンプレート
index.htmlを読み込みます。 - index.htmlは傾きセンサーの動作をJavaScriptで制御する
main.jsを読み込みます。 - ブラウザで
http://localhost:8888/を開けば、画面上にAndroidの傾きに応じて動くボールが表示されます。
2.1 ブラウザの設定
2.1.1 JavaScriptとモーションセンサー
ブラウザ上でAndroid端末の傾きセンサー値をJavaScriptで取得していますので、この2つはオンにしておきます。
Chromeでの設定
- ブラウザを開く
- ブラウザの「設定⚙️」を開く
- 「サイトの設定」を開く
- 「モーションセンサー」と「JavaScript」をオンにする。
Firefoxでの設定(不明)
傾きセンサーを設定する所が見つかりません。試したがFirefoxでは動かなかった。なぜかWebページすら表示されない。😱
3. 用意するファイル(3つ)
- app.py(Flaskを起動するpyファイル)
- index.html(ブラウザ表示用)
- 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. 実行
◆実行の手順は、
- ターミナルでapp.pyを実行(
$ python app.py) - ブラウザで
http://localhost:8888にアクセス - 画面上でオレンジ色のボールが傾きに合わせて動けば成功
◆止める時は、
- ターミナルで
Ctrl+cを入力するとFlaskサーバーが止まる。 - ブラウザのタブを閉じる。
- ブラウザの設定を元に戻す
- (JavaScriptとモーションセンサー)
おわりに
JavaScriptを動かすにはサーバーが要るのか要らないのか、ローカル保存のhtmlファイルでもJavaScriptを書いとけば動くと思っていたが動かない、ブラウザによっても挙動が違うようだ、何か分派みたいなのがメチャクチャいっぱいある、などなど。勉強大変なんじゃないか。
ジャイロセンサーの値をPCなどに送ればなんかのコントローラーとして使えそう。PC側でサーバー立ててやれば良いのかな。IoT的な方向で夢が拡がりそう。😆
【追記】
JavaScriptファイルに記されたボールの色を変えようとorangeとある部分を書き換えたのですが、変更が表示に反映されませんでした。再読込でも変わらない。
反映させるには、ブラウザ(Chromeのばあい)履歴の「キャッシュされた画像とファイル」を削除すれば出来ました。理由等は分かりません。
参考リンク
JavaScriptで端末の傾きを取得し表示する写経元です。勉強になります。ありがとうございます。 - JS:端末の傾きに応じてボールを動かす | 電脳産物
以上。