マップチップのアイテムブロック処理(プログラムでマリオを作る第33回)

今回は、アイテムブロックの処理を書きます。
アイテムブロックを叩いた時に、コインを取得できるようにします。

まず、マップチップエディタを起動して、アイテム用のマップチップを配置しましょう。
一番左にあるマップチップをコイン用のマップチップとします。

このコイン用のアイテムマップチップを叩いた時にコインが取得できるような処理を書きます。
マップチップ番号は80になります。

まず、マップチップを入れ替えるので、main.jsを開いてください。

main.js

現在のマップチップの真ん中部分を64から80に入れ替えましょう。

var gMapChip = [
  [255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255],
  [255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255],
  [255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255],
  [255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255],
  [255,255,255,255,255,255,255,255,255,255,255,255,255,64,255,255,255,255,255,64,255,255,255,255,255,255,255,64,255,255,255,255,255,255,255,64,64,64,64,64,255,255,64,64,64,64,64,255,255,64,64,64,64,64,255,255,64,255,255,255,255,255,64,255,255,255,255,255,255,255,64,255,255,255,255,255,255,255,64,64,64,64,64,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255],
  [255,255,255,255,255,255,255,255,255,255,255,255,255,64,64,255,255,255,64,64,255,255,255,255,255,255,64,255,64,255,255,255,255,255,255,64,255,255,255,64,255,255,255,255,64,255,255,255,255,64,255,255,255,64,255,255,64,64,255,255,255,64,64,255,255,255,255,255,255,64,255,64,255,255,255,255,255,255,64,255,255,255,64,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255],
  [255,255,255,255,255,33,33,33,255,255,255,255,255,64,255,64,255,64,255,64,255,255,255,255,255,64,255,255,255,64,255,255,255,255,255,64,255,255,255,64,255,255,255,255,64,255,255,255,255,64,255,255,255,64,255,255,64,255,64,255,64,255,64,255,255,255,255,255,64,255,255,255,64,255,255,255,255,255,64,255,255,255,64,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255],
  [255,255,255,255,255,255,255,255,255,255,255,255,255,64,255,255,64,255,255,64,255,255,255,255,64,255,255,255,255,255,64,255,255,255,255,64,64,64,64,64,255,255,255,255,64,255,255,255,255,64,255,255,255,64,255,255,64,255,255,64,255,255,64,255,255,255,255,64,255,255,255,255,255,64,255,255,255,255,64,64,64,64,64,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255],
  [255,255,255,255,255,255,255,255,255,255,255,255,255,64,255,255,255,255,255,64,255,255,255,64,64,64,64,64,64,64,64,64,255,255,255,64,255,255,64,255,255,255,255,255,64,255,255,255,255,64,255,255,255,64,255,255,64,255,255,255,255,255,64,255,255,255,64,64,64,64,64,64,64,64,64,255,255,255,64,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255],
  [255,255,255,255,64,80,80,80,64,255,255,255,255,64,255,255,255,255,255,64,255,255,64,255,255,255,255,255,255,255,255,255,64,255,255,64,255,255,255,64,255,255,64,64,64,64,64,255,255,64,64,64,64,64,255,255,64,255,255,255,255,255,64,255,255,64,255,255,255,255,255,255,255,255,255,64,255,255,64,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,64],
  [255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255],
  [255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255],
  [255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255],
  [112,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,114],
  [128,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,130]
];

次にcollisionUtilsにコインのマップチップか判定する関数
アイテムブロックを空のアイテムブロックに入れ替える関数を書きます。

collisionUtils.js

/**
  coinブロックか判定する
  mapNumber : マップチップ番号

*/
function isCoinBlock(mapNumber){
  if(mapNumber == 80){
    return true;
  }
  return false;
}

/**
  対象のマップチップを空のボックスに入れ替える
*/
function replaceEmptyBoxMap(map,mapX,mapY){
  map[mapY][mapX] = EMPTY_BOX_MAP;
}

次に、const.jsに先ほど定義した定数を定義しましょう。

空の箱はマップエディタで81なので、81を代入します。

const.js

// chapter33
var EMPTY_BOX_MAP = 81;
var MAX_MAP_BLOCK = 2;
var MAX_BLOCK_COIN_FRAME = 20;

まとめて、今後使う定数も定義しています。

MAX_MAP_BLOCKはアニメーションさせるマップブロックの最大個数です。

MAX_BLOCK_COIN_FRAMEはアニメーションフレームの最大数です。

続いて、コインブロックと当たり判定が起こった時に、
アニメーションさせるように、mario.jsに処理を追加します。

mario.js

まず、マリオのメンバー変数を追加します。
2つ同時にコインを叩く場合があるので、アニメーション用の
変数を2つ持ちます

// chapter33
// ブロックコインアニメーション開始フラグ
this.isBlockCoinAnim = [false,false];
// ブロックコインのフレーム
this.blockCoinFrame = [0,0];
// ブロックコインのX座標
this.blockCoinX = [0,0];
// ブロックコインのY座標
this.blockCoinY = [0,0];

続いて、マリオがブロックコインのマップチップとぶつかった時に、
コインを出現させる処理を書きます。

まずは、ブロックコインの当たり判定を行うコードまで書きます。

既存のように当たり判定を|| や &&で重ねてしまうと、長くて、読みにくいコードになってしまうので、
配列に置き換えています。

ただ毎回変数を生成するのは、効率が悪いので、メンバー変数として保持する方がゲームではいいでしょう。

Mario.prototype.collisionY = function(map,posY){
	this.updateMapPositionY(posY);
  // マップ座標xを配列で保管する
  var mapsX = [this.rightMapX,this.leftMapX];
  for(var i = 0;i < MAX_MAP_BLOCK;++i){
    // マリオの上側に当たった場合
    if(isObjectMap(map[this.upMapY][mapsX[i]])){
       // コインブロックだった場合
       if(isCoinBlock(map[this.upMapY][mapsX[i]])){

       }
    }
  }

続いて、ブロックマップアニメーションを開始するために、
flagを立てる関数を作ります。

/**
  ブロックコインのアニメーション処理のセット
  index : coinBlockの配列index
*/
Mario.prototype.setBlockCoinMapAnim = function(index,posX,posY){
  this.isBlockCoinAnim[index] = true;
  this.blockCoinFrame[index] = 0;
  this.blockCoinX[index] = posX;
  this.blockCoinY[index] = posY;
}

材料がそろったので、当たり判定関数の続きを書きます。

/**
	chapter20
	オブジェクトとの当たり判定Y
*/
Mario.prototype.collisionY = function(map,posY){
	this.updateMapPositionY(posY);
  // マップ座標xを配列で保管する
  var mapsX = [this.rightMapX,this.leftMapX];
  for(var i = 0;i < MAX_MAP_BLOCK;++i){
    // マリオの上側に当たった場合
    if(isObjectMap(map[this.upMapY][mapsX[i]])){
       // コインブロックだった場合
       if(isCoinBlock(map[this.upMapY][mapsX[i]])){
          // コインブロック用のアニメーションをセットする
          var coinX = mapsX[i] * MAP_SIZE;
          // ひとつ上にセット鶴
          var coinY = (this.upMapY - 1) * MAP_SIZE;
          this.setBlockCoinMapAnim(i,coinX,coinY);
          // ボックスを空にする
          replaceEmptyBoxMap(map,mapsX[i],this.upMapY);
          // coin取得
          this.getCoin();
       }
   		// (加算される前の)中心点からの距離をみる
   		var vecY = Math.abs((this.posY + HALF_MAP_SIZE) - ((this.upMapY * MAP_SIZE) + HALF_MAP_SIZE));
   		// Yの加算量調整
   		this.addPosY = Math.abs(MAP_SIZE - vecY);
   		// 落下させる
   		this.jumpPower = 0;
    }
  }

	// マリオの下側
	if(isObjectMap(map[this.downMapY][this.rightMapX]) || isObjectMap(map[this.downMapY][this.leftMapX])){
		// (加算される前の)中心点からの距離を見る
		var vecY = Math.abs((this.posY + HALF_MAP_SIZE) - ((this.downMapY * MAP_SIZE) + HALF_MAP_SIZE));
		// Yの加算量調整
		this.addPosY = Math.abs(MAP_SIZE - vecY);
		// 地面についた
		this.posY += this.addPosY;
		this.addPosY = 0;
		this.jumpPower = 0;
		this.isJump = false;
		// リセットアニメーション
		this.animOffsetX = 0;
	}
}

続いて、animation flagが立った時にアニメーションさせる関数を書きます。

/**
  ブロックコインのアニメーション処理
*/
Mario.prototype.animateBlockCoin = function(){
  for(var i = 0;i < MAX_MAP_BLOCK;++i){
    if(this.isBlockCoinAnim[i]){
      // コインを上昇させる
      this.blockCoinY[i] -= 1;
      if(this.blockCoinFrame[i]++ >= MAX_BLOCK_COIN_FRAME){
        this.isBlockCoinAnim[i] = false;
      }
    }
  }
}

続いて、animation flagが立ったらブロックコインを描画する処理を書くので、
main.jsを開いてください。

main.js

/**
  アイテムブロックから出現したコインの描画
*/
function drawBlockCoin(){
  for(var i = 0;i < MAX_MAP_BLOCK;++i){
    if(gMario.isBlockCoinAnim[i]){
      g_Ctx.drawImage(gMapTex,32,64,MAP_SIZE,MAP_SIZE,gMario.blockCoinX[i] - gMario.mapScrollX,gMario.blockCoinY[i],MAP_SIZE,MAP_SIZE);
    }
  }
}

drawImageの32,64はマップチップ画像の切り出し位置でしたね。

gMario.mapScrollXを引いているのは、スクロールした際に画面外からコインを消すためです。

この描画関数をDraw関数の内で呼びます。
そのあとにmario.jsで定義したblockcoinをアニメーションさせる関数も呼びましょう。

/*
	Draw
	描画
*/
function Draw(){
  // 背景
  drawMap(gBackGroundMapChip);
  // オブジェクト
  drawObjectMap(gMapChip);
	gMario.draw(g_Ctx,gMarioTex);
  gKuribo.draw(g_Ctx,gKuriboTex,gMario.mapScrollX);

  drawCoin(630,10,gMario.coinNum);
  drawBlockCoin();
  changeMapAnim();
  gMario.animateBlockCoin();
}

今回は、Drawつまり描画メソッドでアニメーションさせる関数を呼んでいますが、
本来描画と動きをするような処理は別個にすべきなので、animationを行う部分の関数は、
別に定義するべきですが、今回はこのままで。

これで、マップチップのブロックコインアニメーションが完成したので、実行してみましょう。

全体のソースコードはgithubで確認ください