【JavaScript】加速度を使った移動

キー等でCanvasに描いたオブジェクトを動かす時、等速ではなく加速度をつけるスクリプト。マウスでクリックした後に矢印キーで縦横に動かせる。

別ページで表示

移動に加速度をつける

まず、猫画像を表示するCatクラス(cat.js)。

/**
 * cat.js
 * 猫画像を表示
 */
export class Cat {
	constructor(parent = undefined, x = 0, y = 0) {
		if (parent !== undefined) {
			this._parent = parent;
		}
		this._x = x;
		this._y = y;
		this._img;
		
		this._init();
	}

	//////////////////////////////////
	// Private and protected
	//////////////////////////////////

	_init() {
		if (this._parent !== undefined) {
			this._ctx = this._parent;
		}
		this._img = new Image();
		this._img.src = "./cat.png";
		this.draw();
	}

	//////////////////////////////////
	// Public
	//////////////////////////////////

	draw() {
		// 現在の描画状態を保存
		this._ctx.save();
		// コンテキストの座標を変更し、キャンバス中央に移動
		this._ctx.translate(this._x, this._y);
		this._ctx.drawImage(this._img, -(this._img.width / 2), -(this._img.height / 2));
		// save()で保存した描画状態を復元
		this._ctx.restore();
	}

	//////////////////////////////////
	// Getters/Setters
	//////////////////////////////////

	get x() {
		return this._x;
	}
	set x(x) {
		this._x = x;
	}

	get y() {
		return this._y;
	}
	set y(y) {
		this._y = y;
	}
}
スポンサーリンク

次に、移動処理を行うVelosityクラス(velosity.js)。

import { Cat } from "./cat.js";

/**
 * 画像の移動に加速度をつける(velosity.js)
 */
export class Velosity {
	constructor() {
		this._cvs = document.getElementById('canvas');
		this._ctx = this._cvs.getContext('2d');
		this._cat;
		this._vx = 0;
		this._vy = 0;
		this._ax = 0; // accelerationのa
		this._ay = 0;
		this._cvs.setAttribute('tabindex', 0); // ①tabindexの指定でキーイベントを受け取れるようにする
		this._cvs.addEventListener('keydown', this._onKeydown.bind(this));
		this._cvs.addEventListener('keyup', this._onKeyUp.bind(this));
		// タイマー関連
		this._animID;
		this._isAnim = 0;
		this._FPS = 60;
		this._frame = 0;
		this._startTime;
		this._nowTime;
		
		this._init();
	}

	//////////////////////////////////
	// Private and protected
	//////////////////////////////////

	_init() {
		this._cvs.style.backgroundColor = "#eeeeee";
		this._cat = new Cat(this._ctx, this._cvs.width / 2, this._cvs.height / 2);

		this._startTime = performance.now();
		this._mainLoop();
	}

	_mainLoop() {
		this._nowTime = performance.now();
		let elapsedTime = this._nowTime - this._startTime;
		let idealTime = this._frame * (1000 / this._FPS);
		if (idealTime < elapsedTime) {
                       this._ctx.clearRect(0, 0, this._cvs.width, this._cvs.height);
                       // ②加速度を以前の速度に加算
                       this._vx += this._ax;
                       this._vy += this._ay;
                       this._cat.x += this._vx;
                       this._cat.y += this._vy;
                       this._cat.draw();

                       this._frame++;

                       if (elapsedTime >= 1000) {
				this._startTime = this._nowTime;
				this._frame = 0;
			}
		}
	
		this._animID = requestAnimationFrame(this._mainLoop.bind(this));
	}

	//////////////////////////////////
	// Handlers
	//////////////////////////////////

	_onKeydown(e) {
		// ③押されたキーを判別し、加速度を加減
		switch (e.keyCode) {
			case 37: // 左矢印キー
				this._ax = -0.2;
				break;
			case 39: // 右矢印キー
				this._ax = 0.2;
				break;
			case 38: // 上矢印キー
				this._ay = -0.2;
				break;
			case 40: // 下矢印キー
				this._ay = 0.2;
				break;
		}
	}

	_onKeyUp(e) {
		// ④矢印キーが離されたら加速度を0に
		this._ax = this._ay = 0;
	}
}

requestAnimationFrameを使ったゲームループの実装は、「【JavaScript】requestAnimationFrameでゲームループを作る」を参照。

①Canvasにキーイベントを設定するには、Canvas要素にtabindexを付与しなければならない。HTML側で指定してもよいが、ここではJavaScript側で設定している。

②速度を表す変数this._vx、this._vyに、加速度を表すthis._ax、this._ayをフレーム毎に加減。その値を猫画像のX、Y座標に代入し再描画。

③矢印キーが押されると_onKeydownイベントハンドラが呼び出され、押された矢印キーを判別して対応する向きの値を変数に代入。

④矢印キーが離されたらthis._ax、this._ayを0にリセット。

移動に加速度と角度もつける


イラスト:カクレノ(https://kotonohaworks.com/free-icons/)

別ページで表示

上のスクリプトは左右キーを角度の変更に使い、上キーでのみ進むように変えたもの。向きが判別しやすいよう、画像を猫から飛行機に変更した。

import { Plane } from "./plane.js";

/**
 * 画像の移動に角度と加速度をつける(velosity2.js)
 */
export class Velosity2 {
	constructor() {
		this._cvs = document.getElementById('canvas');
		this._ctx = this._cvs.getContext('2d');
		this._plane;
		this._vx = 0;
		this._vy = 0;
		this._vr = 0;		// 回転させる角度量
		this._thrust = 0;	// 推進力
		this._cvs.setAttribute('tabindex', 0);
		this._cvs.addEventListener('keydown', this._onKeydown.bind(this));
		this._cvs.addEventListener('keyup', this._onKeyUp.bind(this));
		// タイマー関連
		this._animID;
		this._isAnim = 0;
		this._FPS = 60;
		this._frame = 0;
		this._startTime;
		this._nowTime;
		
		this._init();
	}

	//////////////////////////////////
	// Private and protected
	//////////////////////////////////

	_init() {
		this._cvs.style.backgroundColor = "#eeeeee";
		this._plane = new Plane(this._ctx, this._cvs.width / 2, this._cvs.height / 2);

		this._startTime = performance.now();
		this._mainLoop();
	}

	_mainLoop() {
		this._nowTime = performance.now();
		let elapsedTime = this._nowTime - this._startTime;
		let idealTime = this._frame * (1000 / this._FPS);
		if (idealTime < elapsedTime) {
                        this._ctx.clearRect(0, 0, this._cvs.width, this._cvs.height);
                        // ①角度の設定
                        this._plane.rotation += this._vr;
                        let angle = this._plane.rotation;
                        let ax = Math.cos(angle) * this._thrust;
                        let ay = Math.sin(angle) * this._thrust;
                        // ②加速度を以前の速度に加算
                        this._vx += ax;
                        this._vy += ay;
                        this._plane.x += this._vx;
                        this._plane.y += this._vy;
                        this._plane.draw();
                        
                        this._frame++;

                        if (elapsedTime >= 1000) {
				this._startTime = this._nowTime;
				this._frame = 0;
			}
		}
	
		this._animID = requestAnimationFrame(this._mainLoop.bind(this));
	}

	//////////////////////////////////
	// Handlers
	//////////////////////////////////

	_onKeydown(e) {
		switch (e.keyCode) {
			case 37: // 左矢印キー
				this._vr = -0.05;
				break;
			case 39: // 右矢印キー
				this._vr = 0.05;
				break;
			case 38: // 上矢印キー
				this._thrust = 0.05;
				break;
		}
	}

	_onKeyUp(e) {
		this._vr = 0;
		this._thrust = 0;
	}
}

スクリプトの基本は「【JavaScript】マウスカーソルを追いかけるマウスストーカーを作る」で作ったカーソルを追いかけてくる矢印。そのスクリプトに加速度を導入し、自分で動かせるように改変したもの。

①角度(this._vr)を元に画像を回転させている。②加速度を画像のX、Y座標に代入。上キーを押し続けるほど推進力(this._thrust)は増加し、どんどん加速していく。

Plane.jsは読み込む画像を猫から飛行機に変えただけで同じもの。

コメント

タイトルとURLをコピーしました