マリオ隠しブロック

マリオと隠しブロック1upキノコの実装(プログラミングでマリオを作る第49回)

今回は、実装したほうがよいであろう隠しブロック1up処理を書きたいと思います。

実行結果は以下のようになります。

マリオと隠しブロック処理

隠しブロック用のマップチップを叩いたときに、1upキノコを出現させるというものです。

原作では、一度出現させると出現しないようになっているため、フラグ管理も行います。

マリオ1のステージ1で実装されていますね。

今回実装する内容

1.隠しブロック用のマップチップに上から当たり判定を起こした場合に隠しブロックを出現させる。

2.出現させた隠しブロックは再び出現しないような処理を書く。

実装内容は短いので、すぐ終わります!

では、実装に移ります。

実装

まずcollisionUtilsに隠しブロックを叩いたかどうか判定する関数を書きます。

今後コインの隠しブロックなどを実装することを考えて、隠しブロックか判定する関数と1upブロックか判定する関数を作りました。

collisionUtils.js

/**
 * 隠しブロック判定
 * @param {*} mapNumber 
 */
function isHideBlock(mapNumber){
	if(mapNumber >= 192 && mapNumber <= 192){
		return true;
	}
	return false;
}

/**
 * 隠しブロック1up判定
 * @param {*} mapNumber 
 */
function isHideOneUpBlock(mapNumber){
	if(mapNumber == 192){
		return true;
	}
	return false;
}

mario.js

隠しブロックの出現させたか保存できるように、マリオのクラスメンバーに
隠しブロックの出現位置を保存する変数を用意します。

この変数の初期値に-1をいれておいて、値が-1以外なら隠しブロックが出現したということにします。

// chapter49
// 隠しブロックの出現セーブ用
this.hideBlockX = -1;
this.hideBlockY = -1;

つづいて、collisionY関数の修正をします。

当たり判定を行うobjectマップとは別に、隠しブロックか判定する処理を追加します。

隠しブロックの出現条件は、

1.マリオが上昇中である。

2.隠しブロックの下半分よりもマリオの頭上が下にある

とします。

// マリオの上側に当たった場合
			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();
				}

				// キノコブロックだった場合(chapter34&38)
				if(isKinokoBlock(map[this.upMapY][mapsX[i]])){
					// chapter40 キノコを有効化する処理を関数にした
					var kinokoPosX = mapsX[i] * MAP_SIZE;
					var kinokoPosY = this.upMapY * MAP_SIZE;
					this.activateKinoko(kinokoPosX,kinokoPosY,LEFT_DIR);
					// ボックスを空にする
					replaceEmptyBoxMap(map,mapsX[i],this.upMapY);
				}

				// starブロックだった場合(chapter41)
				if(isStarBlock(map[this.upMapY][mapsX[i]])){
					// chapter40 キノコを有効化する処理を関数にした
					let starPosX = mapsX[i] * MAP_SIZE;
					let starPosY = this.upMapY * MAP_SIZE;
					this.star.activate(starPosX,starPosY,LEFT_DIR);
					// ボックスを空にする
					replaceEmptyBoxMap(map,mapsX[i],this.upMapY);
				}      
				
				// ブロックのアニメーション
				if(isBlockMap(map[this.upMapY][mapsX[i]])){
					var posX = mapsX[i] * MAP_SIZE;
					var posY = this.upMapY * MAP_SIZE;
					this.blockAction(mapsX[i],this.upMapY,false,map);
				}

				// one up blockだった場合
				if(isOneUpBlock(map[this.upMapY][mapsX[i]])){
					let posX = mapsX[i] * MAP_SIZE;
					let posY = this.upMapY * MAP_SIZE;
					this.oneUpKinoko.activate(posX,posY,LEFT_DIR);
					// ボックスを空にする
					replaceEmptyBoxMap(map,mapsX[i],this.upMapY);
				}
				// (加算される前の)中心点からの距離をみる
				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;
				return true;
			}
			// 隠しブロックだった場合
			else if(isHideBlock(map[this.upMapY][mapsX[i]])){
				// ブロックの下半分かつマリオが上昇中のみ隠しブロックを出現させる
				if(this.addPosY > 0){
					// 半分以下なら隠しブロックを出現させる
					let blockPosY = (this.upMapY * MAP_SIZE) - HALF_MAP_SIZE;
					// マリオの頭上が隠しブロックブロックの半分の位置以下
					if(posY - 32 > blockPosY){
						// 隠し1up block
						if((map[this.upMapY][mapsX[i]])){
							// 1up kinokoを出現させる
							let posX = mapsX[i] * MAP_SIZE;
							let posY = this.upMapY * MAP_SIZE;
							this.oneUpKinoko.activate(posX,posY,LEFT_DIR);
							// ボックスを空にする
							replaceEmptyBoxMap(map,mapsX[i],this.upMapY);
							// 隠しブロックが出現しないように状態を保存する。
							this.hideBlockX = mapsX[i];
							this.hideBlockY = this.upMapY;
						}
						// (加算される前の)中心点からの距離をみる
						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;
						return true;
					}
				}
			}		

1up隠しブロックとの判定時に、隠しブロックの出現状態を保存しています。

コンティニュー時、マップチップを更新する際に、セーブ状態をマップチップに反映させます。

/**
 * stage1用の初期化
 */
function initStage1(){
  // 敵の初期化
  initStage1Enemy();
  // 隠しブロックの出現を保存する
  if(gMario.hideBlockX != -1){
    replaceEmptyBoxMap(gMapChipCopy,gMario.hideBlockX,gMario.hideBlockY);
  }
  // マップ初期化
  gMapChip = JSON.parse(JSON.stringify(gMapChipCopy));
  gBonusMapChip = JSON.parse(JSON.stringify(gBonusMapChipCopy));
  gMario.init(0,384);
}

凡庸的に、関数を作ってstage初期化共通関数で、呼んだほうがいいかもしれません。

あとは、好きな位置に隠しブロックのマップチップを置けばokです。

まとめ

今回は項目が短いかつ、大元が実装ずみだったため、すぐに終わりました。

コイン隠しブロックなどの実装も同様に行えますね。

全体のコードはgithubを参照してください。

感想

思ったよりも早く終わった。

次は、めんどくささmaxのゴール処理をやろうかと思います。

というかほとんど終わったんじゃないだろうか?