コードを整理する
前回は、ひとまず完成したということで、全ソースコードを載せました。
しかし、このコードは正直綺麗なものではないと思います。そこで、コードを整理していきましょう。ひとまずは、球やラケット、Areaなどをクラス化して、コードを整理します。
四角形クラスを追加する
ラケットやArea(弾が動き回る範囲)は四角形(長方形)なので、まずはそれを扱うクラスを作りました。
/**
* 四角形を表すクラス
*/
class Rect {
/**
* 四角形の中心のX座標
*/
public X: number;
/**
* 四角形の中心のY座標
*/
public Y: number;
/**
* 四角形の横幅
*/
public Width: number;
/**
* 四角形の高さ
*/
public Height: number;
/**
* コンストラクタ
* 点(X1,Y1)と点(X2,Y2)を対角線上の頂点とする四角形を作る。
* @param x1 1つ目の頂点のX座標
* @param y1 1つ目の頂点のY座標
* @param x2 2つ目の頂点のX座標
* @param y2 2つ目の頂点のY座標
*/
constructor(x1: number, y1: number, x2: number, y2: number) {
this.X = (x1 + x2) / 2;
this.Y = (y1 + y2) / 2;
this.Width = Math.abs(x2 - x1);
this.Height = Math.abs(y2 - y1);
}
/**
* 四角形の左辺のX座標
*/
public get Left() { return this.X - this.Width / 2; }
/**
* 四角形の右辺のX座標
*/
public get Right() { return this.X + this.Width / 2; }
/**
* 四角形の上辺のY座標
*/
public get Top() { return this.Y - this.Height / 2; }
/**
* 四角形の下辺のY座標
*/
public get Bottom() { return this.Y + this.Height / 2; }
}
内部的には長方形の中心座標を(X,Y)として持ち、幅と高さを(Width,Height)として持つことにします。
四角形の座標として、今回のように中心座標を保持する形だけでなく、左上座標を保持する形も考えられます。(実際、前のコードのAreaの(X,Y)は左上座標である。)
しかしラケットや弾を中心座標で管理してきたので、Areaの(X,Y)も中心座標になるように統一していくことにしました。
それ以外は、よくある実装なので特に説明する必要はないでしょう。
AreaをRectで宣言する
/**
* 球が移動できる範囲
*/
let Area = new Rect(10, 10, 310, 310);
/**
* ゲームCANVASを描画する。
*/
function DrawGameCanvas() {
let cvsGame = document.getElementById("game") as HTMLCanvasElement;
if (cvsGame) {
let width = cvsGame.width;
let height = cvsGame.height;
let context = cvsGame.getContext("2d");
if (context && width > 0 && height > 0) {
// Areaの描画以外のコードは省略している
// Areaの範囲を白で描画
context.strokeStyle = "white";
context.strokeRect(Area.Left, Area.Top, Area.Width, Area.Height);
//旧コードだと下のようになっていた(比較のための記載している)
//context.strokeRect(Area.X, Area.Y, Area.Width, Area.Height);
}
}
}
AreaをRectクラスを使って記述するとこうなります。
球やラケットの描画や衝突処理などでもArea.XやArea.Yを参照していたので他にも修正点はありますがが、同様の修正になるので説明は省略します。
ラケットをクラス化する
次にラケットをクラス化します。ラケットは四角なので内部的にRectの形で座標などを保持します。
/**
* ラケットを表すクラス
*/
class Racket {
/**
* ラケット本体の四角
*/
private _body: Rect;
/**
* コンストラクタ
*/
constructor() {
this._body = new Rect(0, 0, 40, 10);
}
/**
* ゲーム開始時の初期化処理
*/
public Init() {
// X座標:初期値はAreaの横幅の真ん中
this._body.X = Area.X;
// Y座標:初期値はAreaの下辺からラケットの縦幅の半分だけ上
this._body.Y = Area.Bottom - this._body.Height / 2
// 幅は40
this._body.Width = 40;
}
/**
* 状態更新
*/
public Update() {
let left = Area.Left + this._body.Width / 2;
let right = Area.Right - this._body.Width / 2;
// ラケットの移動先と現在値との距離
let distance = RacketDestinationX - this._body.X;
// 距離に応じて、X軸の変化速度を変更する。
let vx = distance / 5;
// ラケットを移動する。
let x = this._body.X + vx;
if (x < left) {
x = left;
}
else if (x > right) {
x = right;
}
this._body.X = x;
// ラケットの幅をScoreに応じて短くする。
let width = 40 - 2 * Math.floor(Score / 20);
if (width < 10) {
width = 10;
}
this._body.Width = width;
}
/**
* CANVASへ描画する
* @param context
*/
public DrawCanvas(context: CanvasRenderingContext2D) {
context.fillStyle = "yellowgreen";
context.fillRect(this._body.Left, this._body.Top, this._body.Width, this._body.Height);
}
}
クラス化する前のコードでは、ラケットの状態の初期化はInitGameSituation()の中で、CANVASに描画する処理はDrawGameCanvas()の中で他の(弾やAreaの)処理と一緒に行なっていました。それらの処理はクラスメソッドとして行うように変更しています。
Update()は以前のUpdateRacket()の処理をほぼそのまま使っています。(Racket.Widthだったのがthis._body.Widthに変わっているといった違いはもちろんあります。)
ただし、AreaやScoreなどのグローバル変数をじかに参照するのはあまり綺麗ないコードではないでしょう。このあたりもゆくゆくは整理したいところです。
円クラスを追加する
次に球をクラス化したい…のですが、その前に円を表すクラスを追加します。
/**
* 円を表すクラス
*/
class Circle {
/**
* 円の中心のX座標
*/
public X: number;
/**
* 円の中心のY座標
*/
public Y: number;
/**
* 円の半径
*/
public Radius: number;
/**
* コンストラクタ
* 点(x,y)を中心とする半径Rの円を作る。
* @param x 中心のX座標
* @param y 中心のY座標
* @param r 中心の半径
*/
constructor(x: number, y: number, r: number) {
this.X = x;
this.Y = y;
this.Radius = Math.abs(r);
}
/**
* 円の最も元も左のX座標
*/
public get Left() { return this.X - this.Radius; }
/**
* 円の最も右のX座標
*/
public get Right() { return this.X + this.Radius; }
/**
* 円の最も上のY座標
*/
public get Top() { return this.Y - this.Radius; }
/**
* 円の最も下のY座標
*/
public get Bottom() { return this.Y + this.Radius; }
}
今回はWidthやHeightは作っていませんが、今後必要なら追加します。
次は球のクラス化ですが、コードの修正量が多くなるので、今回はここまで。
コメント