今回は簡単だろうことから、即実装した1upキノコの実装を行いたいと思います。
実行結果は以下のようになります。
1upキノコ用の絵とオブジェクトを作成し、マリオを1upさせます。
キノコオブジェクトはすでに作っているので、キノコを取った後の効果さえ別に書けばすぐに終わります。
あとは、キノコを取得した際の演出作ります。
これには、背景が白くて見えませんが、右端に1up演出用の画像を描いたので、
それを使います。
では、今回実装する内容を確認します。
今回実装する内容
1.1upキノコを描く
2.1upキノコオブジェクトを作成する
3.1upキノコを取ったことがわかる演出をする
では、実装していきます。
const.js
// chapter45
let MAX_PLAYER_NUM = 99;
let ONE_UP_CNT = 80;
最大残機と1up演出の最大カウントを定義します。
mario.js
メンバー変数に1up用の変数を追加します。
// chapter45
this.oneUpKinoko = new OneUpKinoko(0,0,LEFT_DIR);
// one upを表示するタイマー
this.oneUpCnt = 0;
this.isDrawOneUp = false;
次に、1up取得後の関数ですが、実装内容にあるように、
1upの画像を演出期間に上に上昇させます。
特に難しいところはないので、関数だけ載せます。
/**
* chapter45
*
* OneUpKinokoを取得した時
*/
Mario.prototype.getOneUpKinoko = function(){
if(this.playerNum < MAX_PLAYER_NUM){
this.playerNum++;
this.isDrawOneUp = true;
}
}
/**
* one upの表示関数
*/
Mario.prototype.oneUpAction = function(){
if(this.isDrawOneUp){
if(this.oneUpCnt++ >= ONE_UP_CNT){
this.oneUpCnt = 0;
this.isDrawOneUp = false;
}
}
}
/**
* oneupの描画
*/
Mario.prototype.drawOneUp = function(ctx,texture){
if(this.isDrawOneUp){
ctx.drawImage(texture,416,480,64,32,this.posX - 16,this.posY - (this.oneUpCnt / 4) - 32,64,32);
}
}
続いて、頭上判定したマップチップが1up用のマップチップだった場合に
1upキノコを出現させる処理を書きます。
ここも、キノコの時と変わりません。
// 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);
}
続いて、1upキノコ用のクラスを書きます。
挙動はキノコクラスと全くかわらないので、そのままキノコクラスをコピーします。
oneUpKinoko.js
function OneUpKinoko(posX,posY,dir){
this.posX = posX;
this.posY = posY;
this.addPosX = 0;
this.addPosY = 0;
this.direction = dir;
// マップチップ座標
this.rightMapX = 0;
this.leftMapX = 0;
this.upMapY = 0;
this.downMapY = 0;
this.height = 32;
this.state = INACTIVE;
// chapter37
// ブロックからの出現アニメーションフラグ
this.isFirstAnimation = true;
this.offsetY = 0;
}
/*
描画関数
ctx:context
texture:img class
scrollX:X軸のスクロール量
*/
OneUpKinoko.prototype.draw = function(ctx,texture,scrollX){
if(this.state != INACTIVE){
ctx.drawImage(texture,64,480,32,this.offsetY,this.posX - scrollX,this.posY,32,this.offsetY);
}
}
/*
動かす役割
moveNum:移動量
*/
OneUpKinoko.prototype.move = function(mapChip,moveNum){
this.updateMapPosition();
// 向きにより加算量を調整する
moveNum = this.direction == LEFT_DIR ? -moveNum : moveNum;
// 加算量を代入する
this.addPosX = moveNum;
// マップチップとの当たり判定
this.collisionX(mapChip,this.posX + this.addPosX);
this.posX += this.addPosX;
// 移動したのでマップ座標更新
this.updateMapPositionX(this.posX);
}
/**
重力動作
mapChip:対象のマップチップ配列
*/
OneUpKinoko.prototype.gravityAction = function(mapChip){
// 重力を加算
this.addPosY += GRAVITY_POWER;
// 落下量調整
if(this.addPosY >= MAX_GRAVITY){
this.addPosY = MAX_GRAVITY;
}
// Y軸方向の当たり判定(地面に接触している場合は、addPosYは0になる)
this.collisionY(mapChip,this.posY + this.addPosY);
this.posY += this.addPosY;
}
/**
x軸方向のマップチップ座標の更新
posX : マップチップ更新対象となるx座標
*/
OneUpKinoko.prototype.updateMapPositionX = function(posX){
// x座標
this.leftMapX = Math.floor(posX / MAP_SIZE);
this.rightMapX = Math.floor((posX + MAP_SIZE - 1) / MAP_SIZE);
// 配列外チェック
if(this.leftMapX >= MAX_MAP_CHIP_X){
this.leftMapX = MAX_MAP_CHIP_X - 1;
}
if(this.leftMapX < 0){
this.leftMapX = 0;
}
if(this.rightMapX >= MAX_MAP_CHIP_X){
this.rightMapX = MAX_MAP_CHIP_X - 1;
}
if(this.rightMapX < 0){
this.rightMapX = 0;
}
}
/**
Y軸方向のマップチップの更新
*/
OneUpKinoko.prototype.updateMapPositionY = function(posY){
// y
this.upMapY = Math.floor(posY / MAP_SIZE);
this.downMapY = Math.floor((posY + MAP_SIZE - 1) / MAP_SIZE);
// 配列外チェック
if(this.upMapY >= MAX_MAP_Y - 1){
this.upMapY = MAX_MAP_Y - 1;
}
if(this.upMapY < 0){
this.upMapY = 0;
}
if(this.downMapY >= MAX_MAP_Y - 1){
this.downMapY = MAX_MAP_Y - 1;
}
if(this.downMapY < 0){
this.downMapY = 0;
}
}
/**
マップチップ座標を更新する
*/
OneUpKinoko.prototype.updateMapPosition = function(){
this.updateMapPositionX(this.posX);
this.updateMapPositionY(this.posY);
}
/**
オブジェクトとの当たり判定X
*/
OneUpKinoko.prototype.collisionX = function(map,posX){
this.updateMapPositionX(posX);
// キノコの右側
if(isObjectMap(map[this.downMapY][this.rightMapX]) || isObjectMap(map[this.upMapY][this.rightMapX])){
// (加算される前の)中心点からの距離を取る
var vecX = Math.abs((this.posX + HALF_MAP_SIZE) - ((this.rightMapX * MAP_SIZE) + HALF_MAP_SIZE));
this.addPosX = Math.abs(MAP_SIZE - vecX);
this.direction = LEFT_DIR;
}
// キノコの左側
else if(isObjectMap(map[this.downMapY][this.leftMapX]) || isObjectMap(map[this.upMapY][this.leftMapX])){
// (加算される前の)中心点からの距離を取る
var vecX = Math.abs((this.posX + HALF_MAP_SIZE) - ((this.leftMapX * MAP_SIZE) + HALF_MAP_SIZE));
this.addPosX = -Math.abs(MAP_SIZE - vecX);
this.direction = RIGHT_DIR;
}
}
/**
オブジェクトとの当たり判定Y
*/
OneUpKinoko.prototype.collisionY = function(map,posY){
this.updateMapPositionY(posY);
// キャラの下側と接触した場合
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;
}
}
/*
マリオとの当たり判定
map:マップチップ配列
mario:Marioクラス
*/
OneUpKinoko.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;
// マリオone up
mario.getOneUpKinoko();
}
}
}
}
}
/*
chapter27
キノコの更新処理
*/
OneUpKinoko.prototype.update = function(map,mario){
if(this.state != INACTIVE){
// chapter37初回出現アニメーション
if(this.isFirstAnimation){
this.appearingAnimation();
}
else{
this.move(map,2);
this.gravityAction(map);
}
this.collisionWithMario(map,mario);
}
}
/**
キノコを出現させる処理
posX:出現X座標
posY:出現Y座標
*/
OneUpKinoko.prototype.activate = function(posX,posY,dir){
this.posX = posX;
this.posY = posY;
this.state = NORMAL_STATE;
this.dir = dir;
this.isFirstAnimation = true;
this.offsetY = 0;
}
/**
* きのこの出現時のアニメーションを行う
*
*/
OneUpKinoko.prototype.appearingAnimation = function(){
this.posY -= 1;
this.offsetY += 1;
if(this.offsetY == 32){
this.isFirstAnimation = false;
}
}
/**
* chapter37
* ブロックの上にのっていた時にきのこを上昇させる処理
*
* blockPosX : ブロックのX座標
* blockPosY : ブロックのY座標
*/
OneUpKinoko.prototype.blockUpAction = function(blockPosX,blockPosY){
// キノコが上にあった場合キノコを上昇させる
if(this.state == NORMAL_STATE){
// Y座標チェック
if(blockPosY == this.posY + MAP_SIZE){
// x座標チェック
if(blockPosX < this.posX + MAP_SIZE && blockPosX + MAP_SIZE > this.posX){
this.addPosY = BLOCK_UP_ADD_Y;
}
}
}
}
oneUpKinoko.jsを読み込むことを忘れないでください。
あとは、main.jsにて、1upキノコの描画と更新関数を呼べば完成です。
まとめ
基本的にいままでやってきたことと変わらないので、
大丈夫でしょうか。
全てのコードはgithubを参照してください。
感想
1upキノコを取得する時の演出がめんどくさいなぁと思ったけど、
適当なものでごまかしました。
次は、隠しブロックの実装か、キノコ状態から敵に当たった時に小さくする
処理を実装してなかったので、その実装を行いたいと思います。