ブロックを積み上げる

ブロックとの当たり判定

プレイヤーとブロックに当たり判定を入れます。

四角を表示しているので、当たり判定も見た目と同じで大丈夫です。
ですからプレイヤーのみにCollisionを入れます。

    // プレイヤー
    Crafty.e('Player, 2D, Canvas, Color, Collision')
        .attr({x:0, y:30, w:150, h:24, xx:5, yy:0})
        .color(0,191,255)
        .bind('KeyDown', function(e) {
            if( e.key == Crafty.keys.Z ) {
                if( this.y == 30 ) {    // 初期配置y座標にいるときのみ受け付け
                    this.xx = 0;
                    this.yy = 5;
                }
            }
        })
        .onHit('Block', function (hitDatas) {  // ブロックに当たった
            let vv = hitDatas[0].obj;       // 当たったブロックを取得
            // 土台に残すブロックを作成する
            Crafty.e('Block, 2D, Canvas, Color')
                .attr({x:this.x, y:vv.y-25, w:this.w, h:24})
                .color(this._red,this._green,this._blue);
            // プレイヤーを画面上部へ戻して横移動
            this.x = 0;
            this.y = 30;
            this.xx = 5;
            this.yy = 0;
        })
        .bind('EnterFrame', function () {
            this.x += this.xx
            this.y += this.yy
            if( this.x < 0 ){
                this.x = 0;
                this.xx = -this.xx
            }
            if( this.x > 500 - this.w ){
                this.x = 500 - this.w;
                this.xx = -this.xx            
            }
            if( this.y >= 375 ){    // 画面下まで来た
                this.y = 375;
            }
        });

Crafty.e(‘Player, 2D, Canvas, Color, Collision’)

Collision を追加します。当たり判定には必須です。

.onHit(‘Block’, function (hitDatas) {
let vv = hitDatas[0].obj;

Block との当たり判定を拾ったら、変数vvに取得します。
後々、いろいろと使います。

.attr({x:this.x, y:vv.y-25, w:this.w, h:24})
.color(this._red,this._green,this._blue);

土台のブロックにのせるプレイヤーの分身を作ります。
プレイヤー情報は this で取得できます。
y座標だけは土台の情報から算出(vv.y-25)します。
プレイヤーと土台が当たっているということは、重なっているということです。
実際には少し開けてのせるため下のブロックから逆算します。

 

実行してみましょう。
プレイヤーを落下させ土台に当たると、新しくブロックが作られます。
そして、プレイヤーは画面上部に戻ります。

落下したプレイヤーと同じ四角が土台に残る

今のままだと下図のように、どのブロックにものってしまいます。
ルールとしては、最上部に積まれたブロックにのみ積みたいですね。

どのように落下させても土台の上にのる

 

 

最上部のブロックのみに積む

最上部のブロックのみに当たり判定を残します。

方法は簡単で、当たったブロックから Block 属性を消すだけです。

先ほど追加した onHit の中に2行追加します。

        .onHit('Block', function (hitDatas) {  // ブロックに当たった
            let vv = hitDatas[0].obj;       // 当たったブロックを取得
            // 土台に残すブロックを作成する
            Crafty.e('Block, 2D, Canvas, Color')
                .attr({x:this.x, y:vv.y-25, w:this.w, h:24})
                .color(this._red,this._green,this._blue);
            // 当たったブロックは当たり判定対象から外す
            vv.removeComponent("Block");
            // プレイヤーを画面上部へ戻して横移動
            this.x = 0;
            this.y = 30;
            this.xx = 5;
            this.yy = 0;
        })

 

プレイヤーと当たったブロックから Block 属性を消したので、この属性を持っているのは直近で作ったブロックのみです。つまり、最上部のブロックのみ Block 属性があります。

テストしてみましょう。
他のブロックに当てようとしても、すり抜けてプレイヤーは最下部まで落ちるようになりました。

block要素を消して

 

 

プレイヤーの色を変更する

青いブロックも見飽きたのでプレイヤーの色を変えます。

まず、カラーテーブルcoltblを作ります。
プログラムのはじめの方(3行目)に追加します。

一度、乱数で色を変更してみたら、なんか汚い画面になってしまいました。
ここはテーブルを作ってランダムに参照するようにします。

Crafty.init(500,400, document.getElementById('game'));
Crafty.background('#101010');

const coltbl = ['#ff7f7f','#ff7fbf','#ff7fff','#bf7fff','#7f7fff','#7fbfff',
'#7fffff','#7fffbf','#7fff7f','#bfff7f','#ffff7f','#ffbf7f'];

Crafty.scene("title", function() {
    Crafty.e('2D, DOM, Text').attr({x:100, y:40, w:300})

シーン main の中でなく外に宣言した理由は、今後、シーン title でも使えるようにするためです。
(実際には使いませんでした。)

 

次は色の変更です。
変更のタイミングは、ブロックと当たって画面上部に戻す時です。
onHit の中に追加します。

        .onHit('Block', function (hitDatas) {  // ブロックに当たった
            let vv = hitDatas[0].obj;       // 当たったブロックを取得
            // 土台に残すブロックを作成する
            Crafty.e('Block, 2D, Canvas, Color')
                .attr({x:this.x, y:vv.y-25, w:this.w, h:24})
                .color(this._red,this._green,this._blue);
            // 当たったブロックは当たり判定対象から外す
            vv.removeComponent("Block");
            // プレイヤーを画面上部へ戻して横移動
            this.x = 0;
            this.y = 30;
            this.xx = 5;
            this.yy = 0;
            const ii = Crafty.math.randomInt(0, 11);
            this.color(coltbl[ii])  // 色を変更する
        })

 

プレイする度にブロックの色がランダムに変わります。

ブロックの色がランダムに変わる

 

土台の右側に乗ったとき

ここからゲームシステムの要です。

まずは土台の右側に、プレイヤーを乗せたときの処理を作ります。

        .onHit('Block', function (hitDatas) {  // ブロックに当たった
            let vv = hitDatas[0].obj;       // 当たったブロックを取得
            let ww = vv.w;   // ブロックの幅
            if( vv.x < this.x ){  // 土台の右側に乗ったとき
                ww -= (this.x - vv.x);
            }
            // 土台に残すブロックを作成する
            Crafty.e('Block, 2D, Canvas, Color')
                .attr({x:this.x, y:vv.y-25, w:ww, h:24})
                .color(this._red,this._green,this._blue);
            // 当たったブロックは当たり判定対象から外す
            vv.removeComponent("Block");
            // プレイヤーを画面上部へ戻して横移動
            this.x = 0;
            this.y = 30;
            this.xx = 5;
            this.yy = 0;
            this.w = ww;    // プレイヤーの幅を変更
            const ii = Crafty.math.randomInt(0, 11);
            this.color(coltbl[ii])  // 色を変更する
        })

 

土台の右側に乗せてみましょう。
はみ出た部分は削られます。

土台の右端よりはみ出た部分は削られる

let ww = vv.w;

幅を計算するための変数wwを作り、まず土台の幅を入れます。

ww -= (this.x - vv.x);

土台のxよりプレイヤーのxが大きいとき、つまり土台の右側に乗ったときに幅を計算します。
土台からはみ出た長さは、プレイヤーxから土台xを引いた値と同じです。
この値を引けばいいのです。

土台からはみ出た長さはプレイヤーxから土台xを引いた値

.attr({x:this.x, y:vv.y-25, w:ww, h:24})

土台に残すブロックの幅に、計算した幅をセットします。w:ww

this.w = ww;

プレイヤーの幅にも計算した幅をセットします。

 

 

土台の左側に乗ったとき

土台の左側に乗ったときの処理を作ります。

        .onHit('Block', function (hitDatas) {  // ブロックに当たった
            let vv = hitDatas[0].obj;       // 当たったブロックを取得
            let ww = vv.w   // ブロックの幅
            if( vv.x < this.x ){  // 土台の右側に乗ったとき
                ww -= (this.x - vv.x);
            }
            if( vv.x > this.x ){  // 土台の左側に乗ったとき
                ww -= (vv.x - this.x);
                this.x = vv.x;    // 土台の左端を基点にする
            }
            // 土台に残すブロックを作成する
            Crafty.e('Block, 2D, Canvas, Color')
                .attr({x:this.x, y:vv.y-25, w:ww, h:24})
                .color(this._red,this._green,this._blue);
            // 当たったブロックは当たり判定対象から外す
            vv.removeComponent("Block");
            // プレイヤーを画面上部へ戻して横移動
            this.x = 0;
            this.y = 30;
            this.xx = 5;
            this.yy = 0;
            this.w = ww;    // プレイヤーの幅を変更
            const ii = Crafty.math.randomInt(0, 11);
            this.color(coltbl[ii])  // 色を変更する
        })

 

左側に乗せていくと次のようになります。

土台からはみ出た長さを土台の幅より引く

ww -= (vv.x - this.x);

土台よりはみ出た長さを引くだけです。

this.x = vv.x;

土台に残すブロックはプレイヤー情報を元に作っています。
そのためプレイヤーxに土台のxを入れて、ここを基点とします。

それなりに遊べるようになりました。
ゲームシステムの8割くらい出来ましたね。

 

 

表示優先を高くする

今、遊んでみて違和感がある、と思った人は鋭いです。

プレイヤーが最上部の土台に乗らず落下していくとき、
ブロックの後ろを通過するため見えなくなります。

ゲーム作りの鉄則として、プレイヤーキャラの表示優先は一番高くするものです。
(演出で隠れるようにすることはあります)

ブロックの後ろを通過するためプレイヤーが隠れてしまう

積み重ねているブロックは新規に作っています。
それに対しプレイヤーは使い回しです。
描画をするとき新規に作ったオブジェクトの方が、表示優先が高くなるのです。

 

プレイヤーの表示優先を高くします。
方法はz属性を大きくするだけです。

    // プレイヤー
    Crafty.e('Player, 2D, Canvas, Color, Collision')
        .attr({x:0, y:30, w:150, h:24, xx:5, yy:0, z:1000})
        .color(0,191,255)
        .bind('KeyDown', function(e) {

z:1000

適当に大きい数値をzに入れてみました。
x y 属性(座標)と同じように使えます。
大きい数値は手前に、小さい数値は後ろになります。
マイナス値も使えますよ。

 

 

『ブロックつみつみ』

ゲームを作ってみよう

  1. ブロックつみつみに挑戦
  2. タイトルと操作
  3. ブロックを積み上げる
  4. 演出とゲームオーバー