「【JavaScript】加速度を使った移動」では、猫画像を矢印キーで操作したが、画面端を過ぎると猫が見えなくなっていた。今回は猫が画面端に達したら、反対側から現れるように手を加えた。
まず、猫画像を表示するCatクラス。以前と異なるのは幅と高さを取得できるよう、width、heightゲッターを追加しているところ。
/**
* 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._rotation = 0;
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.rotate(this._rotation);
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;
}
get width() {
return this._img.width;
}
get height() {
return this._img.height;
}
get rotation() {
return this._rotation;
}
set rotation(rotation) {
this._rotation = rotation;
}
}
次に、猫を移動処理を行うBoundaryクラス。
import { Cat } from "./cat.js";
/**
* 画像の移動に加速度をつける(boundary.js)
*/
export class Boundary {
constructor() {
this._cvs = document.getElementById('canvas');
this._ctx = this._cvs.getContext('2d');
// ①キャンバスの端を表す変数を宣言
this._leftEnd = 0; // キャンバス左端
this._rightEnd = this._cvs.width; // キャンバス右端
this._topEnd = 0; // キャンバス上端
this._bottomEnd = this._cvs.height; // キャンバス下端
this._cat;
this._vx = 0;
this._vy = 0;
this._ax = 0;
this._ay = 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._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;
// ②画面端から反対側に出現させる処理
if (this._cat.x - this._cat.width / 2 > this._rightEnd) {
this._cat.x = this._leftEnd - this._cat.width / 2;
} else if (this._cat.x + this._cat.width / 2 < this._leftEnd) {
this._cat.x = this._rightEnd + this._cat.width / 2;
}
if (this._cat.y - this._cat.height / 2 > this._bottomEnd) {
this._cat.y = this._topEnd - this._cat.height / 2;
} else if (this._cat.y < this._topEnd - this._cat.height / 2) {
this._cat.y = this._bottomEnd + this._cat.height / 2;
}
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) {
this._ax = this._ay = 0;
}
}
requestAnimationFrameを使ったゲームループの実装は、「【JavaScript】requestAnimationFrameでゲームループを作る」を参照。
前回のスクリプトと異なるのは①と②の部分のみ。
①でキャンバスの上、右、下、左端の値を格納する変数を宣言し、値を代入。
②1つ目のif文は左右の端の判定をしている。画像のX座標に画像の幅の1/2を引いて、左端の位置を計算。画像幅1/2を引く理由は、猫画像はCatクラス側でコンテキストの座標を変更し、画像の中央を描画の中心にしているため。画像の左端の位置が、右端を超えれば位置を変更し、反対側から現れるようにしている。
2つ目のif文は同じことを上下で行っている。
リンク
リンク

コメント