1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

戦車ラジコン:大砲の照準を作る

Last updated at Posted at 2020-02-11

もう少し、戦車ラジコン をいじります。

M5Cameraで映した画像のどこかにQRコードがあればロックオンとしていましたが、今回は、GamePadの十字キーでちゃんと照準を合わせないと、ロックオンしないようにします。

こっちが照準が敵にあっていない状態。この状態ではまだ攻撃できません。
照準は青い丸です。

image.png

こっちが照準があっている状態。青四角で囲われていますので、この状態で攻撃できます。

image.png

毎度の通り、GitHubに上げておきました。
 https://github.com/poruruba/obniz_motor

以下からもページを参照できます。
 https://poruruba.github.io/obniz_motor/

仕組み

照準合わせには、DUALSHOCK 4の十字キーを使いました。
画像の再描画タイミングごとに、十字キーの押下状態と経過時間をチェックし、照準を描画しています。
そして、検出したQRコードの青四角を描画するときに、照準の位置との関係を確認し、描画するかどうかを判断します。

実装

check_direction関数で、十字キーの押下状態と経過時間のチェックを実装しています。

前回のチェック時に引き続き押下されていれば、移動フラグを立てます。
一緒に前回チェック時からの経過時間を返します。

start.js
        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:右

チェック関数の呼び出し側は、押下があった方向に、現在照準位置を移動させます。
そして、照準位置を中心に円を描きます。

start.js
    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コードの範囲内にないと描画されないようにします。

start.js
    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座標が、直前で作ったパスの範囲内であるかどうかを確認します。

以上

1
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?