みかづきブログ その3

3ヶ月つづけてみました。

JavaScriptであたり判定をつくろう その4

ちょっと期間が空いてしまいましたが、前々々回前々回前回 のつづきです。

今回はいよいよあたり判定の部分を実装していきます。


インスタンスを複数つくれるようにする

まずはhitAreaを複数描画できるように、DOMにクラス名を渡せるように変更してみます。

JavaScript

function HitArea(obj) {
    var that = this;
    
    _init();
    
    function _init() {
        var elm = doc.createElement("div");
        
        elm.className = "hitarea " + obj.name || ""; // 追加
        elm.style.position = "absolute";
        that.elm = elm;
    }
    
    that.name   = obj.name   || ""; // 追加
    that.top    = obj.top    || 0;
    that.left   = obj.left   || 0;
    that.width  = obj.width  || 100;
    that.height = obj.height || 100;
    that.stride = obj.stride || 10;
}

これでhitAreaを複数つくってもCSSで見た目を変更できるようになりました。

JavaScript

var me = new HitArea({
        name   : "me",
        top    : 10,
        left   : 10,
        width  : 100,
        height : 100,
        stride : 10
    }),
    target = new HitArea({
        name   : "target",
        top    : 200,
        left   : 200,
        width  : 100,
        height : 100,
        stride : 10,
    });

CSS

.hitarea.me {
    background: rgba(255, 0, 0, .1);
}

.hitarea.target {
    background: rgba(0, 255, 0, .1);
}

あたりを判定する

自分と引数で渡された相手が重なっているかを判定する isHitメソッド を実装します。

JavaScript

HitArea.prototype.isHit = function(targetArea) {
    if (this.top + this.height > targetArea.top && this.top < targetArea.top + targetArea.height) {
        if (this.left + this.width > targetArea.left && this.left < targetArea.left + targetArea.width) {
    console.log("HIT!");
        }
    }
};

で、重なった際に自分と相手の hitメソッド を実行するようにしておきましょう。

JavaScript

HitArea.prototype.isHit = function(targetArea) {
    if (this.top + this.height > targetArea.top && this.top < targetArea.top + targetArea.height) {
        if (this.left + this.width > targetArea.left && this.left < targetArea.left + targetArea.width) {
            this.hit();
            targetArea.hit();
        }
    }
};

コールバックを登録できるようにする

あとは hitメソッド にコールバックを登録できるように改修すれば完成です。

JavaScript

function HitArea(obj) {
    var that = this;
    
    _init();
    
    function _init() {
        var elm = doc.createElement("div");
        
        elm.className = "hitarea " + obj.name || "";
        elm.style.position = "absolute";
        that.elm = elm;
    }
    
    that.name   = obj.name     || "";
    that.top    = obj.top      || 0;
    that.left   = obj.left     || 0;
    that.width  = obj.width    || 100;
    that.height = obj.height   || 100;
    that.stride = obj.stride   || 10;
    this.hit    = obj.callback || function() {}; // 追加
}

インスタンスをつくるときにコールバックを渡す設計にしてみました。

JavaScript

var target = new HitArea({
    name     : "target",
    top      : 200,
    left     : 200,
    width    : 100,
    height   : 100,
    stride   : 10,
    callback : function() {
        console.log("HIT: " + this.name + "!");
    }
});

domo

JavaScript

(function(win, doc) {

    "use strict";

    // あたり判定
    function HitArea(obj) {
        var that = this;
        
        _init();
        
        function _init() {
            var elm = doc.createElement("div");
            
            elm.className = "hitarea " + obj.name || "";
            elm.style.position = "absolute";
            that.elm = elm;
        }
        
        that.name   = obj.name     || "";
        that.top    = obj.top      || 0;
        that.left   = obj.left     || 0;
        that.width  = obj.width    || 100;
        that.height = obj.height   || 100;
        that.stride = obj.stride   || 10;
        this.hit    = obj.callback || function() {};
    }

    HitArea.prototype._setPosition = function(obj) {
        this.top  = (typeof obj.top  === "number") ? obj.top  : this.top;
        this.left = (typeof obj.left === "number") ? obj.left : this.left;
    };
    
    HitArea.prototype.stepForTop = function() {
        this._setPosition({top: this.top - this.stride});
    };

    HitArea.prototype.stepForBottom = function() {
        this._setPosition({top: this.top + this.stride});
    };
    
    HitArea.prototype.stepForLeft = function() {
        this._setPosition({left: this.left - this.stride});
    };
    
    HitArea.prototype.stepForRight = function() {
        this._setPosition({left: this.left + this.stride});
    };

    HitArea.prototype.isHit = function(targetArea) {
        if (this.top + this.height > targetArea.top && this.top < targetArea.top + targetArea.height) {
            if (this.left + this.width > targetArea.left && this.left < targetArea.left + targetArea.width) {
                this.hit();
                targetArea.hit();
            }
        }
    };
    
    HitArea.prototype.appendTo = function(elm) {
        elm.appendChild(this.elm);
    };
    
    HitArea.prototype.render = function() {
        this.elm.style.top    = this.top    + "px";
        this.elm.style.left   = this.left   + "px";
        this.elm.style.width  = this.width  + "px";
        this.elm.style.height = this.height + "px";
    };
    
    var me = new HitArea({
            name   : "me",
            top    : 10,
            left   : 10,
            width  : 100,
            height : 100,
            stride : 10
        }),
        target = new HitArea({
            name     : "target",
            top      : 200,
            left     : 200,
            width    : 100,
            height   : 100,
            stride   : 10,
            callback : function() {
                console.log("HIT: " + this.name + "!");
            }
        });

    me.appendTo(doc.body);
    target.appendTo(doc.body);

    
    // キーボードイベント
    (function() {
        var TOP_KEY_INDEX    = 38,
            BOTTOM_KEY_INDEX = 40,
            LEFT_KEY_INDEX   = 37,
            RIGHT_KEY_INDEX  = 39;
    
        doc.addEventListener("keyup", function(evt) {
            switch(evt.keyCode) {
                case TOP_KEY_INDEX:
                    me.stepForTop();
                    break;
                case BOTTOM_KEY_INDEX:
                    me.stepForBottom();
                    break;
                case LEFT_KEY_INDEX:
                    me.stepForLeft();
                    break;
                case RIGHT_KEY_INDEX:
                    me.stepForRight();
                    break;
            }
        }, false);
    })();
    
    
    // 定期的にオブジェクトを表示
    setInterval(function() {
        me.render();
        me.isHit(target);
        target.render();
    }, 100);

})(this, document);



後半駆け足になってしまいましたが、こんな感じで完成です。




続きは こちら

kimizuka.hatenablog.com