enchant.jsを勉強する4 hit_testとPad対応
リリースされてからまだ日がたっていないenchant.jsですが、どんどん作品を作ってる人がいます。
これは手軽にゲームが作れるという証拠でしょうか。実際面倒な処理はスクリプト側でやってくれるのでとても助かります。
さて、アクションでもRPGでも重要なのに衝突判定があります。
これはオブジェクトとオブジェクトが衝突する判定は以前にやりましたが、マップのデータとオブジェクトの衝突の判定はこれとは違う形式になっています。
あらかじめマップデータに衝突判定のデータを入れておくことで、マップの一つ一つを判定しなくてもいいということになります。
では早速実装したいと思います。
*その前にiphone等で使えるようにパッドに対応の準備もしたいと思います。
制作中のフォルダにui.enchant.js、chara0.gif、pad.png、icon.gifをコピーして
index.htmlのファイルを開いてenchant.jsを読み込んだ次の行に
<script type="text/javascript" src="ui.enchant.js"></script>
を追加します。
マップを動くサンプル
enchant(); window.onload = function() { var game = new Game(320, 400); var tile = 16;//タイルのサイズ game.preload('map1.gif','chara0.gif','pad.png','icon.gif'); game.onload = function() { var m_data = new Array(); //表示用マップ領域 var m_hit = new Array(); //衝突判定用マップ領域 //マップの初期化 for (i = 0; i < 19; i++){ m_data[i] = new Array(); m_hit[i] = new Array(); for (ii = 0; ii < 19; ii++){ var flag=2; if(i>0 && i<18 && ii>0 && ii<18){ if(i%2 || ii%2){ flag=1; } } m_data[i][ii] = flag; m_hit[i][ii] = flag-1; //壁の時1、壁以外の時0を入れる。 } } //迷路作成 dx = [1,0,-1,0]; dy = [0,1,0,-1]; for(i = 2;i < 18; i+=2){ for(ii = 2;ii < 18; ii+=2){ var r=3; if(i==2){r=4;} //一番上のみ上の方向を追加。 var rand = Math.floor(Math.random()*r); m_data[i+dy[rand]][ii+dx[rand]] = 2; m_hit[i+dy[rand]][ii+dx[rand]] = 1; //指定した方向の通路を壁で埋める。 } } var map = new Map(16, 16); map.image = game.assets['map1.gif']; map.loadData(m_data); map.collisionData = m_hit; game.rootScene.addChild(map); //Pad設定 var pad = new Pad(); // Padを追加 pad.x = 0; // x座標 pad.y = 305; // y座標 game.rootScene.addChild(pad); // シーンに追加 //プレイヤーの初期化 var player = new Sprite(16, 24); player.image = game.assets['chara0.gif']; player.x = tile*1; player.y = 8; game.rootScene.addChild(player); player.direction = 0; player.walk=0; var p_spd = 1; //プレイヤーの移動スピード var a_spd = 3; //プレイヤーのアニメーションスピード player.addEventListener('enterframe', function(e) { this.xx = this.x; this.yy = this.y; if (game.input.left){this.xx = this.x - p_spd;this.direction = 1;} if (game.input.right){this.xx = this.x + p_spd;this.direction = 2;} if (game.input.up) {this.yy = this.y - p_spd;this.direction = 3;} if (game.input.down){ this.yy = this.y + p_spd;this.direction = 0;} //移動予定地this.xx,this.yyが壁かどうかを調べる。 var asobi = 4; //遊び幅 if(!map.hitTest(this.xx+asobi,this.yy+8+asobi)&&!map.hitTest(this.xx+15-asobi,this.yy+8+asobi)&&!map.hitTest(this.xx+asobi,this.yy+23-asobi)&&!map.hitTest(this.xx+15-asobi,this.yy+23-asobi)){this.x=this.xx;this.y=this.yy;} if (!(game.frame % a_spd)){this.walk++;} if(this.walk == 3){this.walk = 0;} this.frame = this.direction*6 + this.walk; }); var score = 0; //点数の初期化 var state = new Label(); state.text = "Score:0"; state.color = "#000000"; state.x = 200; state.y = 310; game.rootScene.addChild(state); } game.start(); }
game.preload(‘map1.gif’,’chara0.gif’,’pad.png’,’icon.gif’);
使う画像が増えたので読み込みます。
m_hit[i][ii] = flag-1; //壁の時1、壁以外の時0を入れる。
m_hit[i+dy[rand]][ii+dx[rand]] = 1;
新しく、壁の衝突判定のために配列を追加しています。
壁の時に1をそれ以外の時に0をいれています。
map.collisionData = m_hit;
マップの衝突チェック(HitTest)用の配列をロードします。
//Pad設定
var pad = new Pad(); // Padを追加
pad.x = 0; // x座標
pad.y = 305; // y座標
game.rootScene.addChild(pad); // シーンに追加
新しくパッドオブジェクトを作成して下に配置します。
//プレイヤーの初期化
以前作成したのと同じようにプレイヤーを作成します。
this.xx = this.x; this.yy = this.y; if (game.input.left){this.xx = this.x - p_spd;this.direction = 1;} if (game.input.right){this.xx = this.x + p_spd;this.direction = 2;} if (game.input.up) {this.yy = this.y - p_spd;this.direction = 3;} if (game.input.down){ this.yy = this.y + p_spd;this.direction = 0;}
以前は、直接座標を移動していましたが、今回はマップの衝突判定のために移動予定座標XXとYYに代入します。
//移動予定地this.xx,this.yyが壁かどうかを調べる。 var asobi = 4; //遊び幅 if(!map.hitTest(this.xx+asobi,this.yy+8+asobi)&&!map.hitTest(this.xx+15-asobi,this.yy+8+asobi)&&!map.hitTest(this.xx+asobi,this.yy+23-asobi)&&!map.hitTest(this.xx+15-asobi,this.yy+23-asobi)){this.x=this.xx;this.y=this.yy;}
マップの衝突判定をします。
移動しようとした先の座標が、事前に設定されていた壁の属性をもっていた場合は、Trueを返します。
今回は移動先のオブジェクトの四隅に少し遊び幅を持たせた4点の座標と衝突判定を行い。全ての判定が偽の場合壁がないと判断して移動しています。
var score = 0; //点数の初期化 var state = new Label(); state.text = "Score:0"; state.color = "#000000"; state.x = 200; state.y = 310; game.rootScene.addChild(state);
今回はまだつかってません。いずれ使う予定の得点です。
さて、次回は得点アイテムの表示をしたいと思います。
今回のサンプルです。