HSP3Dish.jsでセンサー値を取得
目次
今回やること
HSP3Dish.js でJavaScriptを実行する方法については、前回説明しました。 今回はその続きとして、JavaScript側で取得した値をHSP3側で受け取り、使ってみる方法について書いてみます。
まずはdevicemotion
イベントを使用して加速度を取得してみます。
また、加速度(重力を含む)、角速度の取得に加え、deviceorientation
イベントを用いてデバイスの向きも取得します。
あ。requestPermission
を使っていないので、iOS (Safari)では動きません。Androidスマホでお試しください。
今回の内容は、HSP3.7β9、β10が対象です。
センサ値の取得(JavaScript)
JavaScriptでセンサーデータを取得する方法を確認します。
HTMLとJavaScriptでの実装例がこちらです。
実装例:sensor01.html
こちらの実装例はiOS (Safari)では動作しません。動作させるためにはrequestPermission
を入れる必要があるのですが、今回は調べてないので見送りです。
動かしてみると、小数点1桁までしか値が取得できていません。ブラウザの制限でしょうか?このあたりについても調べきれてないので今回は見送り。このままいきます。
JavaScriptで作成したプログラム部分はこのようになっています。
JavaScript
// 値の受け取り用グローバル変数
var acc = { x: 0, y: 0, z: 0};
var accg = { x: 0, y: 0, z: 0};
var rot = { alpha: 0, beta: 0, gamma: 0};
var orient = { alpha: 0, beta: 0, gamma: 0};
// デバイスモーションイベントのリスナーを追加
window.addEventListener('devicemotion', function(event) {
// 加速度
var acceleration = event.acceleration;
acc.x = acceleration.x;
acc.y = acceleration.y;
acc.z = acceleration.z;
// 加速度 (重力を含む)
var accelerationIncludingGravity = event.accelerationIncludingGravity;
accg.x = accelerationIncludingGravity.x;
accg.y = accelerationIncludingGravity.y;
accg.z = accelerationIncludingGravity.z;
// 角速度
var rotationRate = event.rotationRate;
rot.alpha = rotationRate.alpha;
rot.beta = rotationRate.beta;
rot.gamma = rotationRate.gamma;
});
// デバイスオリエンテーションイベントのリスナーを追加
window.addEventListener('deviceorientation', function(event) {
// デバイスの方向
orient.alpha = event.alpha;
orient.beta = event.beta;
orient.gamma = event.gamma;
});
変数 acc
、accg
、rot
、orient
にセンサーの値を格納します。
イベントリスナーを設定し、センサーの値が更新されるたびに値を取得する処理を実行しています。
stringToUTF8Array関数を使った値の受け取り
JavaScript側からHSP3へ値を渡すには、stringToUTF8Array
関数を使用します。
この関数はHSP3Dish.js内で定義されており、以下のように使用します。
(そういえばセーブの話をした際にもstringToUTF8Array
は使ったんでしたね。復習です。)
stringToUTF8Array(文字列, Module.HEAP8, HSP3側の受け取り用変数のポインタ, HSP側の変数のバッファサイズ)
パラメータ | 説明 |
---|---|
文字列 | HSP3側に渡したい文字列を指定します。 |
Module.HEAP8 | 固定値(意味は分かりません。) |
HSP3側の受け取り用変数のポインタ | HSP3側で値を受け取る変数のポインタを指定します。実行直前にvarptr 命令で取得して使います。 |
HSP側の変数のバッファサイズ | sdim 命令で確保したサイズ以下か、varsize 命令で確認したサイズ以下を指定します。sdim 命令で事前に確保したサイズ以上を指定していけません。 |
HSP3の変数のポインタを渡す必要があるので、HSP3側での実装が必要です。
HSP3
sdim strBox, 64
ptrBox = varptr( strBox )
exec "stringToUTF8Array('文字列', Module.HEAP8, " + ptrBox + ", 64)"
この方法では文字列のみ受け渡し可能です。
数値を渡す場合は、文字列に変換したものを受け取り、HSP3側で double
関数などを使用して数値に変換する必要があります。
ちょっと面倒ですね。
HSP3でのセンサーデータ取得
ここからは、加速度を取得する方法を例にHSP3Dish.jsでの実装例を作ってみます。
JavaScript側の準備をします。加速度を取得するスクリプトをHTMLファイルに追加します。 ヘルパーでHTMLファイルを出力後に以下の内容を追記します。 hsp3dish.jsを呼び出した後ぐらいがいいと思います。
HTML
<script async type="text/javascript" src="hsp3dish.js"></script>
<script>
var acc = { x: 0, y: 0, z: 0};
function updateSensorAcc(ptrX, ptrY, ptrZ) {
if( !!ptrX && (acc.x !== null) ){ stringToUTF8Array(acc.x.toFixed(5), Module.HEAP8, ptrX, 64); }
if( !!ptrY && (acc.y !== null) ){ stringToUTF8Array(acc.y.toFixed(5), Module.HEAP8, ptrY, 64); }
if( !!ptrZ && (acc.z !== null) ){ stringToUTF8Array(acc.z.toFixed(5), Module.HEAP8, ptrZ, 64); }
}
window.addEventListener('devicemotion', function(event) {
// 加速度
var acceleration = event.acceleration;
acc.x = acceleration.x;
acc.y = acceleration.y;
acc.z = acceleration.z;
});
</script>
HSP3側の実装は、updateSensorAcc
関数を呼び出すだけです。
#include "hsp3dish.as"
; 読み込み用バッファ
sdim strAcceleration_x, 64
sdim strAcceleration_y, 64
sdim strAcceleration_z, 64
exec_text = ""
;-------------------------------------------------------------------------------
*main
redraw 1
exec exec_text
redraw 0 : color 10,10,10 : boxf : color 255, 255, 255 : pos 0,0
; 取得値を数値に変換
; 取得した値は文字列なので、使いやすいように数値に変換します。
acceleration_x = double( strAcceleration_x )
acceleration_y = double( strAcceleration_y )
acceleration_z = double( strAcceleration_z )
; 描画
mes "acc X = " + acceleration_x
mes "acc Y = " + acceleration_y
mes "acc Z = " + acceleration_z
; センサー値を取得
ptrAcc_x = varptr( strAcceleration_x )
ptrAcc_y = varptr( strAcceleration_y )
ptrAcc_z = varptr( strAcceleration_z )
exec_text = "updateSensorAcc( " + ptrAcc_x + ", " + ptrAcc_y + ", " + ptrAcc_z + ");"
goto *main
ほとんどJavaScript側で実装してしまったので、HSP3側はシンプルに記述できました。
サンプル
同じ要領で、加速度(重力含む)、角速度も取得してみます。ついでにデバイスの向きについても取得してみます。 実装例です。
スマートフォン(Android)などのセンサーが内蔵されたデバイスで実行してください。 デスクトップPCのブラウザにはセンサーがないため、反応しません。iOS(Safari)も非対応です。
デバイスを動かすことで、棒グラフや数値が動的に変化する様子を確認できるはずです。
sensor.jsについて
サンプルの中身を見ていきます。 まずはJavaScript側の実装から。加速度や角速度、デバイスの向きなどを取得するためのスクリプトが必要です。
JavaScript側で取得するセンサー情報は、次のものです。
- 加速度 …
devicemotion
イベントのacceleration
プロパティ - 加速度(重力含む) …
devicemotion
イベントのaccelerationIncludingGravity
プロパティ - 角速度 …
devicemotion
イベントのrotationRate
プロパティ - デバイスの向き …
deviceorientation
イベントのevent
オブジェクト
これらを取得するJavaScriptのプログラムを書く必要があります。長くなりそうですね。毎度HTMLに何行も追記するのは面倒です。 これに限らずスクリプトは長くなりがちなので別ファイルに書くべきでしょう。今回は sensor.js という名前のファイルにまとめてHTML側から呼び出す形にします。
JavaScript
// sensor.js
// 値の受け取り用グローバル変数
var acc = { x: 0, y: 0, z: 0};
var accg = { x: 0, y: 0, z: 0};
var rot = { alpha: 0, beta: 0, gamma: 0};
var orient = { alpha: 0, beta: 0, gamma: 0};
function updateSensorAcc(ptrX, ptrY, ptrZ) {
if( !!ptrX && (acc.x !== null) ){ stringToUTF8Array(acc.x.toFixed(5), Module.HEAP8, ptrX, 64); }
if( !!ptrY && (acc.y !== null) ){ stringToUTF8Array(acc.y.toFixed(5), Module.HEAP8, ptrY, 64); }
if( !!ptrZ && (acc.z !== null) ){ stringToUTF8Array(acc.z.toFixed(5), Module.HEAP8, ptrZ, 64); }
}
function updateSensorAccg(ptrX, ptrY, ptrZ) {
if( !!ptrX && (accg.x !== null) ){ stringToUTF8Array(accg.x.toFixed(5), Module.HEAP8, ptrX, 64); }
if( !!ptrY && (accg.y !== null) ){ stringToUTF8Array(accg.y.toFixed(5), Module.HEAP8, ptrY, 64); }
if( !!ptrZ && (accg.z !== null) ){ stringToUTF8Array(accg.z.toFixed(5), Module.HEAP8, ptrZ, 64); }
}
function updateSensorRot(ptrA, ptrB, ptrG) {
if( !!ptrA && (rot.alpha !== null) ){ stringToUTF8Array(rot.alpha.toFixed(5), Module.HEAP8, ptrA, 64); }
if( !!ptrB && (rot.beta !== null) ){ stringToUTF8Array(rot.beta.toFixed(5), Module.HEAP8, ptrB, 64); }
if( !!ptrG && (rot.gamma !== null) ){ stringToUTF8Array(rot.gamma.toFixed(5), Module.HEAP8, ptrG, 64); }
}
function updateSensorOrient(ptrA, ptrB, ptrG) {
if( !!ptrA && (orient.alpha !== null) ){ stringToUTF8Array(orient.alpha.toFixed(5), Module.HEAP8, ptrA, 64); }
if( !!ptrB && (orient.beta !== null) ){ stringToUTF8Array(orient.beta.toFixed(5), Module.HEAP8, ptrB, 64); }
if( !!ptrG && (orient.gamma !== null) ){ stringToUTF8Array(orient.gamma.toFixed(5), Module.HEAP8, ptrG, 64); }
}
// デバイスモーションイベントのリスナーを追加
window.addEventListener('devicemotion', function(event) {
// 加速度
var acceleration = event.acceleration;
acc.x = acceleration.x;
acc.y = acceleration.y;
acc.z = acceleration.z;
// 加速度 (重力を含む)
var accelerationIncludingGravity = event.accelerationIncludingGravity;
accg.x = accelerationIncludingGravity.x;
accg.y = accelerationIncludingGravity.y;
accg.z = accelerationIncludingGravity.z;
// 角速度
var rotationRate = event.rotationRate;
rot.alpha = rotationRate.alpha;
rot.beta = rotationRate.beta;
rot.gamma = rotationRate.gamma;
});
// デバイスオリエンテーションイベントのリスナーを追加
window.addEventListener('deviceorientation', function(event) {
// デバイスの方向
orient.alpha = event.alpha;
orient.beta = event.beta;
orient.gamma = event.gamma;
});
以下は、HTMLファイル側からsensor.jsを読み込む例です。
<script src="sensor.js"></script>
の部分で読み込んでいます。
htmlを出力した後に、この要領で修正を行ってください。
…
</script>
<script async type="text/javascript" src="hsp3dish.js"></script>
<script src="sensor.js"></script>
<p><font size="2" color="#404040">powered by …</font></p>
</body>
</html>
この方法を使うと、HTML側での修正は1行だけで済み、センサー値取得機能のアップデートも簡単に行えます。
hsp3での実装例
センサー値を取得する関数が準備できたら、HSP3側で値を受け取るスクリプトを作成します。
HSP3
; スマホ向けHSP3Dishのサンプル
#include "hsp3dish.as"
#include "d3m.hsp"
#module
; バー
#deffunc drawBar double p_max, double p_val
r = ginfo_r
g = ginfo_g
b = ginfo_b
px = ginfo_cx
py = ginfo_cy
h = 10
w = 120
color 200,200,200
boxf px - w, py, px + w, py + h
v = p_val / p_max
ww = v * w
if ww >= 0 {
color 250, 0, 0
} else {
color 0, 0, 250
}
boxf px, py, ww + px, py + h
pos px, py+h
color r,g,b
return
; 画像を使用したフォント表示準備
; mod_picfont.asを流用
#deffunc picfont int _p1, int _p2, int _p3, int _p4, int _p5
sx=_p2:if sx=0 : sx=16
sy=_p3:if sy=0 : sy=16
mode=_p4:id=_p1
ofsx=_p5
celdiv id, sx, sy;, sx/2, sy/2
return
; 画像を使用したフォント表示
#deffunc picfprt str _p1
x=ginfo_cx:xs=x
y=ginfo_cy
i=0:gmode mode,sx,sy
st=_p1
repeat
a1=peek(st,i):i++:if a1=0 : break
if a1 = 13 {
a1 = peek(st,i)
if a1=10 : i++
x=xs : y+=sy : continue ; 改行
} else {
pos x,y
celput id, a1
}
x+=sx+ofsx
loop
pos xs,y+sy
return
#global
;-------------------------------------------------------------------------------
; プラットフォームを確認
getreq idPlatform, SYSREQ_PLATFORM
; フォントを準備
widFont = 1
celload "fontchr.png", widFont
picfont widFont,16,16,2,-4 ; Dishだとgmode 2が効いてない。
; 読み込み用バッファ
sdim strAcceleration_x, 64
sdim strAcceleration_y, 64
sdim strAcceleration_z, 64
sdim strAccelerationIncludingGravity_x, 64
sdim strAccelerationIncludingGravity_y, 64
sdim strAccelerationIncludingGravity_z, 64
sdim strRotationRate_alpha, 64
sdim strRotationRate_beta, 64
sdim strRotationRate_gamma, 64
sdim strOrientation_alpha, 64
sdim strOrientation_beta, 64
sdim strOrientation_gamma, 64
exec_text = ""
;-------------------------------------------------------------------------------
*main
redraw 1
if idPlatform = PLATFORM_WEBGL {
; hsp3dish.js(WebGL/JavaScript)版
exec exec_text
} else {
; Windows版など他環境
await 16
}
redraw 0 : color 10,10,10 : boxf : color 255, 255, 255 : pos 0,0
picfprt "" + d3getfps() + " fps"
; 取得値を数値に変換
; 取得した値は文字列なので、使いやすいように数値に変換します。
acceleration_x = double( strAcceleration_x )
acceleration_y = double( strAcceleration_y )
acceleration_z = double( strAcceleration_z )
accelerationIncludingGravity_x = double( strAccelerationIncludingGravity_x )
accelerationIncludingGravity_y = double( strAccelerationIncludingGravity_y )
accelerationIncludingGravity_z = double( strAccelerationIncludingGravity_z )
rotationRate_alpha = double( strRotationRate_alpha )
rotationRate_beta = double( strRotationRate_beta )
rotationRate_gamma = double( strRotationRate_gamma )
orientation_alpha = double( strOrientation_alpha )
orientation_beta = double( strOrientation_beta )
orientation_gamma = double( strOrientation_gamma )
; 描画
cx = ginfo_winx / 2
pos cx, 10
m = 10.0
s = "acceleration_x" : v = acceleration_x : gosub *l_draw
s = "acceleration_y" : v = acceleration_y : gosub *l_draw
s = "acceleration_z" : v = acceleration_z : gosub *l_draw
s = "accelerationIncludingGravity_x" : v = accelerationIncludingGravity_x : gosub *l_draw
s = "accelerationIncludingGravity_y" : v = accelerationIncludingGravity_y : gosub *l_draw
s = "accelerationIncludingGravity_z" : v = accelerationIncludingGravity_z : gosub *l_draw
m = 30.0
s = "rotationRate_alpha" : v = rotationRate_alpha : gosub *l_draw
s = "rotationRate_beta " : v = rotationRate_beta : gosub *l_draw
s = "rotationRate_gamma" : v = rotationRate_gamma : gosub *l_draw
m = 360.0
s = "orientation_alpha " : v = orientation_alpha : gosub *l_draw
m = 90.0
s = "orientation_beta " : v = orientation_beta : gosub *l_draw
s = "orientation_gamma " : v = orientation_gamma : gosub *l_draw
; 値を取得
; JavaScriptを使用して、各種センサーの値を取得します。
; 次の名用のスクリプトを実行します。updateSensor~関数は、sensor.jsファイル内で定義しています。
;
; }
; updateSensorAcc( ptrX, ptrY, ptrZ )
; updateSensorAccg( ptrX, ptrY, ptrZ )
; updateSensorRot( ptrA, ptrB, ptrG )
; updateSensororient( ptrA, ptrB, ptrG )
; }
ptrAcc_x = varptr( strAcceleration_x )
ptrAcc_y = varptr( strAcceleration_y )
ptrAcc_z = varptr( strAcceleration_z )
ptrAccg_x = varptr( strAccelerationIncludingGravity_x )
ptrAccg_y = varptr( strAccelerationIncludingGravity_y )
ptrAccg_z = varptr( strAccelerationIncludingGravity_z )
ptrRot_a = varptr( strRotationRate_alpha )
ptrRot_b = varptr( strRotationRate_beta )
ptrRot_g = varptr( strRotationRate_gamma )
ptrOrient_a = varptr( strOrientation_alpha )
ptrOrient_b = varptr( strOrientation_beta )
ptrOrient_g = varptr( strOrientation_gamma )
exec_text = "{"
exec_text+= "updateSensorAcc( " + ptrAcc_x + ", " + ptrAcc_y + ", " + ptrAcc_z + ");"
exec_text+= "updateSensorAccg( " + ptrAccg_x + ", " + ptrAccg_y + ", " + ptrAccg_z + ");"
exec_text+= "updateSensorRot( " + ptrRot_a + ", " + ptrRot_b + ", " + ptrRot_g + ");"
exec_text+= "updateSensorOrient( " + ptrOrient_a + ", " + ptrOrient_b + ", " + ptrOrient_g + ");"
exec_text+= "}"
goto *main
;------------------------------
; 奇麗に配置して値を描画
;------------------------------
*l_draw
x1 = ginfo_cx
y1 = ginfo_cy
pos cx - 120
picfprt "" + v
pos x1, y1
picfprt s
drawBar m, v
pos , ginfo_cy+4+5
return
値の取得は簡単になったのですが、データを表示する部分が少し複雑になっています。 数字が動いているだけでは、センサー値が正常に取得されているかがわかりません。そのため、棒グラフを使って視覚的に変化を表示しています。
また、項目名称と取得したセンサー値を確認できるようにするため、文字で表示するようにしています。mes
命令ではパフォーマンスに問題があるため、画像フォントを使用しています。
その他への活用
今回は加速度センサーや角速度センサーを用いてデータを取得しましたが、 ブラウザのAPIには、GPS位置情報を取得する機能などもあります。 その他にも、ブラウザならではの機能を活用する方法が存在します。(するはず。)
今後、HSP3で他のブラウザ機能を使えるか試してみたいところですが、 手間がかかるため、本音は誰か調べてほしい…。
最新バージョン(HSP3.7β10)の紹介
この記事を書いている間に、先日(2025/1/27)HSP3.7β10が公開されました。
この最新バージョンでは、加速度(ginfo_accel*
)とジャイロセンサー値(ginfo_gyro*
)の取得に対応しました。
加速度かジャイロが必要な場合は、このページで紹介したやり方よりもginfo_accel*
命令かginfo_gyro*
命令の利用を推奨します。
exec
命令を使わないで済むならそれに越したことはありません。
var sensor_button = 1;
とすることで使えるようになるようです。こっちはiOS (Safari)にも対応しているみたいです。