今回は、マリオをクラス化します。
クラス化をすることで、処理を独立させ、他のソースと干渉させることを
防ぎ、部品として扱えるようにします。
以後、マリオの処理を書く時には、マリオクラスを経由して処理を書いていきます。
今回は、前回書いた移動処理と描画処理をマリオクラスに追加し、
以前書いた処理をマリオクラスのそれと置き換えます。
クラスとは
クラスとは独立した部品のことです。
クラス内には、メンバー変数と呼ばれる変数を定義することができます。
メンバー変数には、マリオを操作する時に使用する変数を定義します。
今回は位置を保持するposX,posYを定義しますが、
今後、使いたい変数が増えたら逐次追加していきます。
メンバー変数を定義する他に、関数も定義することができます。
このような関数をメンバー関数と呼びします。
メンバー関数には、移動する関数であるmoveXなどを定義していきます。
クラスの関数の定義方法
クラスの関数を定義するには、prototypeキーワードを使用します。
draw関数を定義する際には、
Mario.prototype.draw
と書いていますが、このようにprototypeキーワードを使ってclassの関数を定義していきます。
クラス内メンバー変数はthisを使って参照する
クラス内にはメンバー変数を定義することができますが、
メンバー変数であることを示すためにthisキーワードを使用します。
動画解説
今回は、マリオオブジェクトのクラス化をしたいと思います。
クラス化をすることで、処理を独立させ、他のソースと干渉させることを
防ぎ、部品として扱えるようにします。
まず、mario.jsクラスを作成します。
mario.jsを作成する
function Mario(posX,posY){
// 表示X座標
this.posX = posX;
// 表示Y座標
this.posY = posY;
}
thisをつけることで、クラス内のメンバーであるということを示しています。
クラスのメンバー変数にアクセスする際はthisという接頭語を記述します。
描画関数
/*
描画関数
ctx:context
texture:img class
*/
Mario.prototype.draw = function(ctx,texture){
ctx.drawImage(texture,0,0,24,24,this.posX,this.posY,24,24);
}
後から変更するかもしれませんが、とりあえずこの形にします。
つづいて、移動関数です。
Mario.prototype.moveX = function(moveX){
this.posX += moveX;
}
これで、マリオクラスの定義を終えたので、
処理の変更に対応するためにmain.jsの変更をします。
main.jsを変更する
まず、マリオクラスを定義します
var gMario;
マリオクラスを新しく定義したので、ポジションを保持していた変数を削除します。
続いて、
マリオクラスを生成します。
gMario = new Mario(0,64);
newキーワードによってobjectを生成できます
続いて、draw関数を変更します。
gMario.draw(g_Ctx,gMarioTex);
マリオクラスのdraw関数を使います
続いて、move関数を変更します。
function move(){
// 左キーが押されている状態
if(gLeftPush){
gMario.moveX(-4);
}
// →キーが押されている状態
if(gRightPush){
gMario.moveX(4);
}
}
move関数を使って左に移動させます。
index.htmlを変更する
最後にhtmlファイルに作成したmairoクラスを読み込ませます。
<script lang="JavaScript" src=mario.js></script>
mairo.jsを読み込ませます。
では実行してみましょう。
マリオクラスに置き換えても正常に実行できました。
今回変更・追加したソースファイル
mairo.js
function Mario(posX,posY){
this.posX = posX;
this.posY = posY;
}
/*
描画関数
ctx:context
texture:img class
*/
Mario.prototype.draw = function(ctx,texture){
ctx.drawImage(texture,0,0,32,32,this.posX,this.posY,32,32);
}
Mario.prototype.moveX = function(moveX){
this.posX += moveX;
}
main.js
var g_Canvas;
var g_Ctx;
// fps
var g_LastAnimationFrameTime = 0;
var g_LastFpsUpdateTime = 0;
var g_FpsElement;
var gMarioTex;
// key
var gSpacePush = false; // space
var gLeftPush = false; // 左
var gRightPush = false; // 右
var gUpPush = false; // 上
var gDownPush = false; // 下
// keyの定義
var SPACE_KEY = 32;
var LEFT_KEY = 37;
var RIGHT_KEY = 39;
var UP_KEY = 38;
var DOWN_KEY = 40;
// マリオ
var gMario;
/**
onload
最初に呼び出される関数
*/
onload = function () {
// キャンバスに代入
g_Canvas = document.getElementById('id_canvas');
g_FpsElement = document.getElementById("fps");
// cavasに対応していない
if (!g_Canvas || !g_Canvas.getContext) {
alert("html5に対応していないので、実行できません");
return false;
}
g_Ctx = g_Canvas.getContext('2d'); // cox
loadTexture();
gMario = new Mario(0,64);
// キーの登録
window.addEventListener("keydown",keyDown, true);
window.addEventListener("keyup",keyUp, true);
requestNextAnimationFrame(animate); // loopスタート
};
/*
テクスチャのロード
*/
function loadTexture(){
gMarioTex = new Image();
gMarioTex.src = "resource/main.png";
}
function animate(now) {
// fps
calculateFps(now);
move();
// 描画
Draw();
requestNextAnimationFrame(animate);
}
/*
60fps毎に処理を実行
*/
window.requestNextAnimationFrame =
(function () {
var originalWebkitRequestAnimationFrame = undefined,
wrapper = undefined,
callback = undefined,
geckoVersion = 0,
userAgent = navigator.userAgent,
index = 0,
self = this;
// Workaround for Chrome 10 bug where Chrome
// does not pass the time to the animation function
if (window.webkitRequestAnimationFrame) {
// Define the wrapper
wrapper = function (time) {
if (time === undefined) {
time = +new Date();
}
self.callback(time);
};
// Make the switch
originalWebkitRequestAnimationFrame = window.webkitRequestAnimationFrame;
window.webkitRequestAnimationFrame = function (callback, element) {
self.callback = callback;
// Browser calls the wrapper and wrapper calls the callback
originalWebkitRequestAnimationFrame(wrapper, element);
}
}
// Workaround for Gecko 2.0, which has a bug in
// mozRequestAnimationFrame() that restricts animations
// to 30-40 fps.
if (window.mozRequestAnimationFrame) {
// Check the Gecko version. Gecko is used by browsers
// other than Firefox. Gecko 2.0 corresponds to
// Firefox 4.0.
index = userAgent.indexOf('rv:');
if (userAgent.indexOf('Gecko') != -1) {
geckoVersion = userAgent.substr(index + 3, 3);
if (geckoVersion === '2.0') {
// Forces the return statement to fall through
// to the setTimeout() function.
window.mozRequestAnimationFrame = undefined;
}
}
}
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function (callback, element) {
var start,
finish;
window.setTimeout( function () {
start = +new Date();
callback(start);
finish = +new Date();
self.timeout = 1000 / 60 - (finish - start);
}, self.timeout);
};
}
)
();
function move(){
// 左キーが押されている状態
if(gLeftPush){
gMario.moveX(-4);
}
// 右キーが押されている状態
if(gRightPush){
gMario.moveX(4);
}
}
/*
Draw
描画
*/
function Draw(){
g_Ctx.fillStyle = "rgb(255,0,0)"; // 赤に設定
g_Ctx.fillRect(0,0,640,480); // 塗りつぶす
// context.drawImage(img,sx,sy,swidth,sheight,x,y,width,height);
gMario.draw(g_Ctx,gMarioTex);
}
/*
fpsの計算
*/
function calculateFps(now) {
// 1秒間に何回実行されているか
var fps = 1000 / (now - g_LastAnimationFrameTime);
g_LastAnimationFrameTime = now;
// 1秒経過
if (now - g_LastFpsUpdateTime > 1000) {
g_LastFpsUpdateTime = now;
// 要素にfps値を代入する
g_FpsElement.innerHTML = fps.toFixed(0) + ' fps';
}
}
/*
キーを押した時の処理
*/
function keyDown(event){
// どのキーが押されたか
var code = event.keyCode;
switch(code){
case SPACE_KEY:
// スクロールさせないため
event.returnValue = false;
event.preventDefault();
gSpacePush = true;
break;
// 左キー
case LEFT_KEY:
gLeftPush = true;
break;
// 右キー
case RIGHT_KEY:
gRightPush = true;
break;
// 上キー
case UP_KEY:
// スクロールさせないため
event.returnValue = false;
event.preventDefault();
gUpPush = true;
break;
// 下キー
case DOWN_KEY:
// スクロールさせないため
event.returnValue = false;
event.preventDefault();
gDownKey = true;
break;
}
}
/*
キーを離した時のイベント
*/
function keyUp(event){
// どのキーが押されたか
var code = event.keyCode;
switch(code){
case SPACE_KEY:
gSpacePush = false;
break;
// 左キー
case LEFT_KEY:
gLeftPush = false;
break;
// 右キー
case RIGHT_KEY:
gRightPush = false;
break;
// 上キー
case UP_KEY:
gUpPush = false;
break;
// 下キー
case DOWN_KEY:
gDownKey = false;
break;
}
}
index.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<link rel="stylesheet" href="main.css">
<script lang="JavaScript" src=mario.js></script>
<script lang="JavaScript" src=main.js></script>
</head>
<body>
<div id="fps"></div>
<div id="canvas_wrapper">
<canvas id="id_canvas" width="640" height="480"></canvas>
</div>
</body>
</html>