solar2Dというゲームエンジンで、アナログスティックの入力を角度で取得する方法
event.axis
solar2Dは以下のように
1 2 3 4 5 |
function scene:show(event) if event.phase == "did" then Runtime:addEventListener("axis", inputHandler) end end |
eventListenerのaxisにセットした関数から、axisイベントを取得できる。
しかし注意したいのは、このeventListener、どうやら値に変化があった時のみトリガーされる。
さらに、このevent、x軸か、y軸の、どちらか一方しか含んでいない。
x、yの両方を取得して角度を算出するのがやりたいことだが、結論から言うとライブラリの都合上、これをevent発火のlistener内部で行うことができない。
ちなみに、nw.js (node.js)では
1 2 3 |
let gamePad = navigator.getGamepads()[0] gamePad.axes[0] -- x gamePad.axes[1] -- y |
という風に、同時に取得できる。
何が問題か
問題なのは、例えば、アナログスティックを下向きにずっと入力する、などの場合、イベントがずっと下向きの入力を補足して発火し続ける、ことがない。
下向きの入力の、初めの一度しか発火しない。
ボタン系ならそれで充分だが、基本的にずっとぐりぐりしているはずのアナログスティックは、これでは対応できない。
解決方法
eventは基本的に値が変更されたときに発火されるようなので、この値を保持し、enterFrameのイベントでこの値を監視し、そこからアナログスティックの発火を行う。
1 2 3 4 5 |
if event.axis.number == 1 then axisPoint.x = event.normalizedValue elseif event.axis.number == 2 then axisPoint.y = event.normalizedValue end |
まず上記のようにevent.axis.numberでx、yを振り分けて保存しておく。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
-- enterFrameイベントリスナーでaxisPoint.xとaxisPoint.yを監視する関数 local function onEnterFrame(event) if math.abs(axisPoint.x) >= 0.2 or math.abs(axisPoint.y) >= 0.2 then local angle = math.deg(math.atan2(axisPoint.y, axisPoint.x)) if angle < 0 then angle = angle + 360 -- 角度を0-360度の範囲に補正 end -- 角度を引数にして発火 doSomething(angle) end end -- enterFrameイベントをリスナーに追加 Runtime:addEventListener("enterFrame", onEnterFrame) |
そしてenterFrameに対して、監視を設定する。
アナログスティックは、ちょっと傾いているだけでも入力を保持するため、デッドゾーンと呼ばれる無視する領域を設定する必要がある。上記の場合、0.2にしてある。
こうすることで、0.2以上の動きがある時、そちらの方向に入力が発生していることとなり、ずっと下向き、の入力が可能になる。