マリオがファイアーマリオになる処理

ファイアーマリオの実装1(プログラミングでマリオを作る第38回)

ファイアーマリオになるための実装を行います。
実行結果は以下になります。

マリオがファイアーマリオになる処理

実装する内容

実装する内容は以下になります。

1.マリオがでかい状態の時に、キノコが出現するブロックを叩くと、
フラワーが出現して、接触するとファイアーマリオになる。

2.ファイアーマリオ状態でボタンを押すと、ファイアーが出現して、
敵を倒すことができる。

以上を実装しますが、量の関係上今回は、1を実装します。

画像を入れ替える

ファイアーマリオ用の画像とフラワー用のファイアーキノコを作成したので、
画像を以下のものに入れ替えてください

ファイアーキノコを追加したマップチップ画像

ファイアーマリオを追加したマリオ画像

ファイアーキノコクラス

キノコにそのままファイアーキノコ用の処理を追加してもいいんですが、
別個にファイアーキノコ用のクラスを作成します。

キノコクラスとの違いは、画像と、ブロックから出現した時に動かないことくらいです。
キノコクラスをコピーして、使用しない変数や関数を削除します。

fireKinoko.js

まず、fireKinoko.jsファイルを作成します。

続いて、クラスのコンストラクタを書きます。

function FireKinoko(posX,posY){
	this.posX = posX;
	this.posY = posY;
	//  mapchip pos
	this.rightMapX = 0;
	this.leftMapX = 0;
	this.upMapY = 0;
	this.downMapY = 0;
	this.height = 32;
	this.state = INACTIVE;
	// animation flag when appear
	this.isFirstAnimation = true;
	this.offsetY = 0;
}

kinoko.jsから不必要な変数を削除しています。

続いて、描画関数です。

/*
	draw
	
	ctx:context
	texture:img class
	scrollX:X align scroll num
*/
FireKinoko.prototype.draw = function(ctx,texture,scrollX){
	if(this.state != INACTIVE){
		ctx.drawImage(texture, 32,480,32,this.offsetY,this.posX - scrollX,this.posY,32,this.offsetY);
	}
}

ファイアーキノコ画像は、キノコの右隣においてので、
キノコ + 32に切り出し座標をセットしています。

続いて、マリオとファイアーキノコが接触した時のイベントを書きます。

キノコと違ってファイアーマリオにする必要があるので、
marioクラスにgetFireKinoko関数を作ってそれを読んでいます。

/*
  collision with mario

  map:MapChip array
  mario:Mario class
*/
FireKinoko.prototype.collisionWithMario = function(map,mario){
  if(!mario.isDead()){
    // x軸
    if(mario.moveNumX < this.posX + 32 && mario.moveNumX + 32 > this.posX)
    {
      // マリオの上とキノコの下(キノコは32*32で切り取られているので、最下部は32+される)
      if(mario.posY < this.posY + 32){
        // マリオの下とキノコの上
        if(mario.posY + mario.height > this.posY + (32 - this.height)){
          // マリオを大きくする処理を書く
          this.state = INACTIVE;
          // マリオを大きくする処理
          mario.getFireKinoko();
        }
      }
    }
  }
}

これ以降は、特に理解に困る箇所がないので、全体をgithubで確認してください。

続いて、marioクラスに処理を追加します。

ファイアーマリオにする処理

ファイアーマリオにするために、マリオクラスにファイアーキノコクラスと、
絵を変更するためのY軸のoffsetを保持する変数を追加します。

function Mario(posX,posY){
  ...
  // chapter38
  this.fireKinoko = new FireKinoko(0,0);
  this.textureOffsetY = 0;
}

続いて、描画処理を書きます。

ファイアーマリオを切り取るために、textureOffsetYを描画を開始する位置に置いています。

/*
	描画関数
	ctx:context
	texture:img class
*/
Mario.prototype.draw = function(ctx,texture){
	if(!this.isDead()) {
		ctx.drawImage(texture, (this.animX * 32) + this.animOffsetX,(this.direction * this.height) + this.textureOffsetY,32,this.height,this.posX,this.posY,32,this.height);
	}
	else {
		ctx.drawImage(texture, (this.animX * 32) + this.animOffsetX,this.direction * this.height + this.textureOffsetY,32,this.height,this.posX,this.posY,32,this.height);
	}
}

続いて、ファイアーキノコをとった時の処理を書きます。

const.jsに新しい定数FIRE_STATEを定義して、stateに代入します。

また、textureOffsetYに192を代入して、
ファイアーマリオを描画するようにしています。

/**
 * get fire kinoko action
 */
Mario.prototype.getFireKinoko = function(){
	this.state = FIRE_STATE;
	this.textureOffsetY = 192;
}

キノコを出現させる処理

マリオが大きい時にファイアーキノコを出現させるので、
便宜上、マリオがキノコをとってでかい状態なのか判定する関数を作ります。

/**
 * judge big size mario
 * 
 * return:if big true
 */
Mario.prototype.isBig = function(){
	if(this.state == KINOKO_STATE || this.state == FIRE_STATE){
		return true;
	}
	return false;
}

続いて、ブロックを叩いた時に、ファイアーキノコを出す処理を書きます。
先ほど定義したisBig関数を使います。

// キノコブロックだった場合(chapter34&38)
if(isKinokoBlock(map[this.upMapY][mapsX[i]])){
	// when mario is big appear fire kinoko
	if(this.isBig()){
		// chapter38 appear fire kinoko
        var fireKinokoX = mapsX[i] * MAP_SIZE;
        // appeared from box
        var fireKinokoY = this.upMapY * MAP_SIZE;
        this.fireKinoko.activate(fireKinokoX,fireKinokoY);    		
	}
	else{
        // appear kinoko
        var kinokoX = mapsX[i] * MAP_SIZE;
        // boxから出現させるようにする
        var kinokoY = this.upMapY * MAP_SIZE;
        this.kinoko.activate(kinokoX,kinokoY,LEFT_DIR);		
	}
	// ボックスを空にする
	replaceEmptyBoxMap(map,mapsX[i],this.upMapY);
}

また、ブロックを破壊する条件にもisBig()を適応します。

Mario.prototype.blockAction = function(mapIndexX,mapIndexY,isUp,map){
	...
	// 大きい場合は破壊可能
	else if(this.isBig()){
          ...		
	}
}

マップチップを更新する際も、ファイアーマリオの場合を考慮する必要があります。

Mario.prototype.updateMapPositionY = function(posY){
	// キノコ状態の時と分ける
	if(this.isBig()){
		// キノコ状態の時のマップチップ座標
		this.upMapY = Math.floor(posY / MAP_SIZE);
		// 通常よりもマップチップ一つ分多い
		this.downMapY = Math.floor((posY + this.height - 1) / MAP_SIZE);
		// 中央座標
		this.centerMapY = Math.floor((posY + MAP_SIZE - 1) / MAP_SIZE);
	}
	..
}

ファイアーマリオ用の定数を追加する

const.jsにファイアーマリオ用の定数を追加します。

// chapter27
var NORMAL_STATE = 1;
var KINOKO_STATE = 2;
// chapter38
var FIRE_STATE = 3;

fireKinoko.jsが読み込まれるようにする

新しく作成したfireKinoko.jsが読み込まれるようにしましょう。
mario.jsでfireKinokoを参照しているので、mario.jsが読み込まれるまえに、
fireKinoko.jsが読み込まれないといけないことに注意です。

<script lang="JavaScript" src=fireKinoko.js></script>
<script lang="JavaScript" src=mario.js></script>

main.jsに、fireKinokoの動作関数を追加する

fireKinokoの動作と描画関数を追加します。

function Draw(){
  ..  gMario.kinoko.draw(g_Ctx,gMapTex,gMario.mapScrollX);
  // chapter38
  gMario.fireKinoko.draw(g_Ctx,gMapTex,gMario.mapScrollX);
}
function move(){
  gMario.update(gMapChip,gKuribos);
  enemyMove();
  gMario.kinoko.update(gMapChip,gMario);
  gMario.fireKinoko.update(gMapChip,gMario);
}

だいたいの必要な処理はこんな感じです。

全体のコードはgithubに上げているので確認してみてください。

感想

絵を描くのが大変だった。
解説を描くのも大変だった。