こんにちは、ナレコム前川です。
今回は、Amazon Sumerian の公式チュートリアルの
DOM Event Listeners を進めていきたいと思います。
今回は、ユーザーのクリックやドラッグ、タッチに応答するインタラクティブなシーンを作成するのに役立ちます。
JavaScript のイベントリスナーを使用することによってユーザーの入力を操作することができます。
ここでは、ユーザーがマウスを使用してエンティティを回転させるためのスクリプトを作成します。
それでは、進めていきましょう。
1. シーンの作成
① ダッシュボードからDefault Lightingを選択。
① ダッシュボードからDefault Lightingを選択。
② シーン名を「DOM Event Listeners」に設定し、作成。
③ Create Entity から Box を追加。
※ 3D の別のエンティティ(例えば、球とか)でも構いません。
④ Box の色を変更。(Hex の 232F3E に設定しました。)
⑤ Box に Script Component を追加し、Custom を追加。
⑥ スクリプト名を「Spinner」に設定。
⑦ Create Entity から Fixed Cam を追加。
⑧ Fixed Cam を選択し、Main Camera と Follow Editor Camera にチェックを入れる。
これで、シーンの設定は終わりです。
2. JavaScript Event Listeners を理解する
イベントハンドラに要素(例えば、div とか)や document, window をアタッチすることができます。
以下のコードは、mousedown イベントリスナーを window オブジェクトに追加する方法を示しています。
1window.addEventListener('mousedown', function(evt) {2 console.log('Mouse down event triggered!', evt);3});evt は、イベントが発生した座標などのプロパティを保持します。
それでは、evt についてコンソールを開いて確認してみてください。
マウスをクリックするとマウスの位置が表示されます。
3. Event Listeners の追加と削除
イベントリスナーを使用する上で気にかけることがいくつかあります。
まず、setup 関数については、イベントリスナーを追加するのに最適な関数です。
しかし、追加したリスナーを cleanup 関数で削除する必要があります。
削除するにあたって、格納されたリスナーのハンドルが必要となります。
また、イベントリスナーのカスタマイズや作業を容易にするために、優れたスクリプト構造を持つことが大切です。
それでは、実際に編集して実行していきましょう。
1var setup = function(args, ctx) {23 ctx.evtListeners = {4 mousedown: function(evt) {5 console.log('mousedown!', evt);6 },7 mouseup: function(evt) {8 console.log('mouseup!', evt);9 }10 };1112 for (var handle in ctx.evtListeners) {13 // The canvas element can be reached through ctx.domElement14 ctx.domElement.addEventListener(handle, ctx.evtListeners[handle]);15 }1617 };1819 var cleanup = function(args, ctx) {20 for (var handle in ctx.evtListeners) {21 ctx.domElement.removeEventListener(handle, ctx.evtListeners[handle]);22 }23 };上記のプログラムをスクリプトに追加・保存し、シーンを実行してみてください。
コンソールを確認すると、以下のように表示されます。
3. 回転に速度をつける
ここでは、mousedown, mouseup, mousemove のイベントを組み合わせたスクリプトを作成していきたいと思います。
① 以下のスクリプトを setup 関数の一番上に書く。
1ctx.dragging=false;ctx.velocity=0;ctx.lastX=0;ctx.currentX=0;② 2 つのパラメータを設定するため、以下のコードを追加する。
1var parameters = [2 {3 key: 'sensitivity',4 name: 'Sensitivity',5 type: 'float',6 control: 'slider',7 min: 0.01,8 max: 1.00,9 default: 0.0510 },11 {12 key: 'damping',13 name: 'Damping',14 type: 'float',15 control: 'slider',16 min: 0,17 max: 1,18 default: 0.0519 }20 ];sensitivity は、マウスのドラッグ距離に関連して回転速度を制御します。
damping は、Box が永遠に回転しないようにするものです。
③ 実際の動作を制御する関数を追加する。
1var startDrag = function(ctx, x) {2 ctx.dragging = true;3 ctx.currentX = x;4 };56 var stopDrag = function(ctx) {7 ctx.dragging = false;8 };910 var drag = function(ctx, x) {11 if (ctx.dragging) {12 // Record the x position from the last update13 ctx.lastX = ctx.currentX;14 // Update the current x position15 ctx.currentX = x;16 // Use the dragged distance since last update to add velocity17 ctx.velocity += ctx.currentX - ctx.lastX;18 }19 };2021 var update = function(args, ctx) {22 // Use the accumulated velocity to add rotation around the y axis.23 // Apply the elapsed time to to be frame rate independent.24 ctx.entity.addRotation(0, args.sensitivity * ctx.velocity * ctx.world.tpf, 0);25 // Apply damping26 ctx.velocity *= (1-args.damping);27 };④ setup 関数のイベントリスナーを以下のようにする。
1ctx.evtListeners = {2 mousedown: function(evt) {3 startDrag(ctx, evt.clientX);4 },5 mouseup: function() {6 stopDrag(ctx);7 },8 mouseout: function() {9 stopDrag(ctx);10 },11 mousemove: function(evt) {12 drag(ctx, evt.clientX);13 },14 touchstart: function(evt) {15 startDrag(ctx, evt.touches[0].clientX);16 },17 touchend: function() {18 stopDrag(ctx);19 },20 touchmove: function(evt) {21 drag(ctx, evt.touches[0].clientX);22 }23};これで、スクリプトの作成は完了です。
実行して確認してみてください。
もしうまくいかない場合は、以下のコードと置き換えてください。
以下は、完成版のスクリプトです。
1var setup = function(args, ctx) {2 ctx.dragging = false;3 ctx.velocity = 0;4 ctx.lastX = 0;5 ctx.currentX = 0;67 ctx.evtListeners = {8 mousedown: function(evt) { startDrag(ctx, evt.clientX); },9 mouseup: function() { stopDrag(ctx); },10 mouseout: function() { stopDrag(ctx); },11 mousemove: function(evt) { drag(ctx, evt.clientX); },12 touchstart: function(evt) { startDrag(ctx, evt.touches[0].clientX); },13 touchend: function() { stopDrag(ctx); },14 touchmove: function(evt) { drag(ctx, evt.touches[0].clientX);}15 };1617 for (var l in ctx.evtListeners) {18 ctx.domElement.addEventListener(l, ctx.evtListeners[l]);19 }20};2122var cleanup = function(args, ctx) {23 for (var l in ctx.evtListeners) {24 ctx.domElement.removeEventListener(l, ctx.evtListeners[l]);25 }26};2728var startDrag = function(ctx, x) {29 ctx.dragging = true;30 ctx.currentX = x;31};3233var stopDrag = function(ctx) {34 ctx.dragging = false;35};3637var drag = function(ctx, x) {38 if (ctx.dragging) {39 ctx.lastX = ctx.currentX;40 ctx.currentX = x;41 ctx.velocity += ctx.currentX - ctx.lastX;42 }43};4445var update = function(args, ctx) {46 ctx.entity.addRotation(0, args.sensitivity * ctx.velocity * ctx.world.tpf, 0);47 ctx.velocity *= (1-args.damping);48};4950var parameters = [{51 key: 'sensitivity',52 name: 'Sensitivity',53 type: 'float',54 control: 'slider',55 min: 0.01,56 max: 1.00,57 default: 0.0558},{59 key: 'damping',60 name: 'Damping',61 type: 'float',62 control: 'slider',63 min: 0,64 max: 1,65 default: 0.0566}];今回のチュートリアルは以上です。
お疲れ様でした。