もう少し、戦車ラジコン をいじります。
M5Cameraで映した画像のどこかにQRコードがあればロックオンとしていましたが、今回は、GamePadの十字キーでちゃんと照準を合わせないと、ロックオンしないようにします。
こっちが照準が敵にあっていない状態。この状態ではまだ攻撃できません。
照準は青い丸です。
こっちが照準があっている状態。青四角で囲われていますので、この状態で攻撃できます。
毎度の通り、GitHubに上げておきました。
https://github.com/poruruba/obniz_motor
以下からもページを参照できます。
https://poruruba.github.io/obniz_motor/
仕組み
照準合わせには、DUALSHOCK 4の十字キーを使いました。
画像の再描画タイミングごとに、十字キーの押下状態と経過時間をチェックし、照準を描画しています。
そして、検出したQRコードの青四角を描画するときに、照準の位置との関係を確認し、描画するかどうかを判断します。
実装
check_direction関数で、十字キーの押下状態と経過時間のチェックを実装しています。
前回のチェック時に引き続き押下されていれば、移動フラグを立てます。
一緒に前回チェック時からの経過時間を返します。
check_direction: function(gamepad){
var direction = {};
if( !this.direction.prev ){
this.direction.prev = performance.now();
return direction;
}
var now = performance.now();
direction.diff = now - this.direction.prev;
this.direction.prev = now;
if( gamepad.buttons[12].pressed ){
if( this.direction.up )
direction.up = true;
else
this.direction.up = true;
}else{
this.direction.up = false;
}
if( gamepad.buttons[13].pressed ){
if( this.direction.down )
direction.down = true;
else
this.direction.down = true;
}else{
this.direction.down = false;
}
if( gamepad.buttons[14].pressed ){
if( this.direction.left )
direction.left = true;
else
this.direction.left = true;
}else{
this.direction.left = false;
}
if( gamepad.buttons[15].pressed ){
if( this.direction.right )
direction.right = true;
else
this.direction.right = true;
}else{
this.direction.right = false;
}
return direction;
},
配列buttonと十字キーの割り当ては、DUALSHOCK 4の場合以下の通りでした。
・12:上
・13:下
・14:左
・15:右
チェック関数の呼び出し側は、押下があった方向に、現在照準位置を移動させます。
そして、照準位置を中心に円を描きます。
var direction = this.check_direction(gamepad);
// console.log(direction);
if( direction.up )
this.aiming_y -= direction.diff * AIMING_DURATION;
if( direction.down )
this.aiming_y += direction.diff * AIMING_DURATION;
if( direction.left )
this.aiming_x -= direction.diff * AIMING_DURATION;
if( direction.right )
this.aiming_x += direction.diff * AIMING_DURATION;
if( this.aiming_x > this.qrcode_canvas.width)
this.aiming_x = this.qrcode_canvas.width;
else if( this.aiming_x < 0 )
this.aiming_x = 0;
if( this.aiming_y > this.qrcode_canvas.height)
this.aiming_y = this.qrcode_canvas.height;
else if( this.aiming_y < 0 )
this.aiming_y = 0;
this.qrcode_context.beginPath();
this.qrcode_context.arc(this.aiming_x, this.aiming_y, 10, 0 * Math.PI / 180, 360 * Math.PI / 180);
this.qrcode_context.closePath();
this.qrcode_context.stroke();
AIMING_DURATIONは、経過時間に対する照準位置の移動量です。大きくすると早く移動します。
次は、QRコードを検出したときの青四角の描画処理です。
これまでは、QRコードを検出したときには無条件に青四角を描画していましたが、今回は、照準位置がQRコードの範囲内にないと描画されないようにします。
var pos = code.location;
this.qrcode_context.beginPath();
this.qrcode_context.moveTo(pos.topLeftCorner.x, pos.topLeftCorner.y);
this.qrcode_context.lineTo(pos.topRightCorner.x, pos.topRightCorner.y);
this.qrcode_context.lineTo(pos.bottomRightCorner.x, pos.bottomRightCorner.y);
this.qrcode_context.lineTo(pos.bottomLeftCorner.x, pos.bottomLeftCorner.y);
this.qrcode_context.lineTo(pos.topLeftCorner.x, pos.topLeftCorner.y);
this.qrcode_context.closePath();
if( this.qrcode_context.isPointInPath(this.aiming_x, this.aiming_y) ){
this.lockon = true;
this.qrcode_context.stroke();
}else{
this.lockon = false;
}
canvasのcontext.isPointInPath() を呼び出しているのがみそです。
指定されたX、Y座標が、直前で作ったパスの範囲内であるかどうかを確認します。
以上