みかづきブログ その3

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

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

kimizuka.hatenablog.com

約1年ぶりに改良しました。

ポイント1

jsdo.it HTML5-Gamesをつかってスマートフォンからの操作を実現しました。


ポイント2

willHitを実装し、次の移動で当たり判定が発生するかどうかを判断するように改修しました。

HitArea.prototype.willHit = function(position, targetAreaList) {
    var top  = this.top,
        left = this.left,
        targetArea;

    switch(position) {
        case "UP":
            top  -= this.stride;
            break;
        case "DOWN":
            top  += this.stride;
            break;
        case "LEFT":
            left -= this.stride;
            break;
        case "RIGHT":
            left += this.stride;
            break;
    }

    for (var i = 0, length = targetAreaList.length; i < length; ++i) {
        targetArea = targetAreaList[i];

        if (top + this.height > targetArea.top && top < targetArea.top + targetArea.height) {
            if (left + this.width > targetArea.left && left < targetArea.left + targetArea.width) {
                return true;
            }
        }
    }

    return false;
}

ポイント3

当たり判定と見た目に差をつけるためにtransformで変形しています。

.player {
    border-radius: 50%;
    background: #fff !important;
    transform: scale(2.5);
}

JavaScript

(function(win, doc) {

    "use strict";

    var WIDTH      = 60,
        HEIGHT     = 40,
        INTERVAL   = 30,
        ZERO_POINT = {
            X : 30,
            Y : 30
        };
    
    // あたり判定
    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.willHit = function(position, targetAreaList) {
        var top  = this.top,
            left = this.left,
            targetArea;

        switch(position) {
            case "UP":
                top  -= this.stride;
                break;
            case "DOWN":
                top  += this.stride;
                break;
            case "LEFT":
                left -= this.stride;
                break;
            case "RIGHT":
                left += this.stride;
                break;
        }

        for (var i = 0, length = targetAreaList.length; i < length; ++i) {
            targetArea = targetAreaList[i];

            if (top + this.height > targetArea.top && top < targetArea.top + targetArea.height) {
                if (left + this.width > targetArea.left && left < targetArea.left + targetArea.width) {
                    return true;
                }
            }
        }

        return false;
    }

    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 player = new HitArea({
            top    : 10,
            left   : 10,
            width  : 4,
            height : 4,
            stride : 1,
            name   : "player",
            callback : function() {
                console.log("HIT!");
            }
        }),
        one = new HitArea({
            top    : ZERO_POINT.Y,
            left   : ZERO_POINT.X,
            width  : WIDTH,
            height : HEIGHT,
            name   : ""
        }),
        two = new HitArea({
            top    : ZERO_POINT.Y,
            left   : ZERO_POINT.X + WIDTH + INTERVAL,
            width  : WIDTH,
            height : HEIGHT,
            name   : ""
        }),
        three = new HitArea({
            top    : ZERO_POINT.Y,
            left   : ZERO_POINT.X + (WIDTH + INTERVAL) * 2,
            width  : WIDTH,
            height : HEIGHT,
            name   : ""       
        }),
        four = new HitArea({
            top    : ZERO_POINT.Y + HEIGHT + INTERVAL,
            left   : ZERO_POINT.X,
            width  : WIDTH,
            height : HEIGHT,
            name   : ""         
        }),
        five = new HitArea({
            top    : ZERO_POINT.Y + HEIGHT + INTERVAL,
            left   : ZERO_POINT.X + WIDTH + INTERVAL,
            width  : WIDTH,
            height : HEIGHT,
            name   : ""        
        }),
        six = new HitArea({
            top    : ZERO_POINT.Y + HEIGHT + INTERVAL,
            left   : ZERO_POINT.X + (WIDTH + INTERVAL) * 2,
            width  : WIDTH,
            height : HEIGHT,
            name   : ""         
        }),
        seven = new HitArea({
            top    : ZERO_POINT.Y + (HEIGHT + INTERVAL) * 2,
            left   : ZERO_POINT.X,
            width  : WIDTH,
            height : HEIGHT,
            name   : "" 
        }),
        eight = new HitArea({
            top    : ZERO_POINT.Y + (HEIGHT + INTERVAL) * 2,
            left   : ZERO_POINT.X + WIDTH + INTERVAL,
            width  : WIDTH,
            height : HEIGHT,
            name   : ""   
        }),
        nine = new HitArea({
            top    : ZERO_POINT.Y + (HEIGHT + INTERVAL) * 2,
            left   : ZERO_POINT.X + (WIDTH + INTERVAL) * 2,
            width  : WIDTH,
            height : HEIGHT,
            name   : ""     
        }),
        ten = new HitArea({
            top    : ZERO_POINT.Y + (HEIGHT + INTERVAL) * 3,
            left   : ZERO_POINT.X,
            width  : WIDTH,
            height : HEIGHT,
            name   : ""
        }),
        eleven = new HitArea({
            top    : ZERO_POINT.Y + (HEIGHT + INTERVAL) * 3,
            left   : ZERO_POINT.X + WIDTH + INTERVAL,
            width  : WIDTH,
            height : HEIGHT,
            name   : ""
        }),
        twelve = new HitArea({
            top    : ZERO_POINT.Y + (HEIGHT + INTERVAL) * 3,
            left   : ZERO_POINT.X + (WIDTH + INTERVAL) * 2,
            width  : WIDTH,
            height : HEIGHT,
            name   : ""
        }),
        targetList = [
            one, two, three, four, five, six, seven, eight, nine, ten, eleven, twelve
        ];

    player.appendTo(doc.body);
    one.appendTo(doc.body);
    two.appendTo(doc.body);
    three.appendTo(doc.body);
    four.appendTo(doc.body);
    five.appendTo(doc.body);
    six.appendTo(doc.body);
    seven.appendTo(doc.body);
    eight.appendTo(doc.body);
    nine.appendTo(doc.body);
    ten.appendTo(doc.body);
    eleven.appendTo(doc.body);
    twelve.appendTo(doc.body);
    
    // キーボードイベント
    (function() {
        return;

        var TOP_KEY_INDEX    = 38,
            BOTTOM_KEY_INDEX = 40,
            LEFT_KEY_INDEX   = 37,
            RIGHT_KEY_INDEX  = 39;
    
        doc.addEventListener("keypress", function(evt) {
            switch(evt.keyCode) {
                case TOP_KEY_INDEX:
                    if (!player.willHit("UP", targetList)) {
                        player.stepForTop();
                    } else {
                        player.elm.classList.remove("hit");
                        setTimeout(function() {
                            player.elm.classList.add("hit");
                            console.log("HIT!");
                        }, 0);
                    }
                    break;
                case BOTTOM_KEY_INDEX:
                    if (!player.willHit("DOWN", targetList)) {
                        player.stepForBottom();
                    } else {
                        player.elm.classList.remove("hit");
                        setTimeout(function() {
                            player.elm.classList.add("hit");
                            console.log("HIT!");
                        }, 0);
                    }
                    break;
                case LEFT_KEY_INDEX:
                    if (!player.willHit("LEFT", targetList)) {
                        player.stepForLeft();
                    } else {
                        player.elm.classList.remove("hit");
                        setTimeout(function() {
                            player.elm.classList.add("hit");
                            console.log("HIT!");
                        }, 0);
                    }
                    break;
                case RIGHT_KEY_INDEX:
                    if (!player.willHit("RIGHT", targetList)) {
                        player.stepForRight();
                    } else {
                        player.elm.classList.remove("hit");
                        setTimeout(function() {
                            player.elm.classList.add("hit");
                            console.log("HIT!");
                        }, 0);
                    }
                    break;
            }
        }, false);
    })();
    
    
    // 定期的にオブジェクトを表示
    setInterval(function() {
        player.render();
        one.render();
        two.render();
        three.render();
        four.render();
        five.render();
        six.render();
        seven.render();
        eight.render();
        nine.render();
        ten.render();
        eleven.render();
        twelve.render();
    }, 100);

    
    var timer;
    
    jsdoitController.initialize();
    
    win.addEventListener("Abuttonup", function(event){
    
    }, false);
    
    win.addEventListener("Bbuttonup", function(event){
    
    }, false);
    
    
    win.addEventListener("startbuttonup", function(event){
    
    }, false);
    
    win.addEventListener("movebuttondown", function(evt) {
        timer = setInterval(_move, 20);
    }, false);
    
    win.addEventListener("movebuttonup", function(evt) {
        clearTimeout(timer);
    }, false);
    
    function _move() {
        var btnState = jsdoitController.buttonState;
    
        if (btnState.topbutton) {
            if (!player.willHit("UP", targetList)) {
                player.stepForTop();
            } else {
                player.elm.classList.remove("hit");
                setTimeout(function() {
                    player.elm.classList.add("hit");
                    console.log("HIT!");
                }, 0);
            }
        } else if (btnState.bottombutton) {
            if (!player.willHit("DOWN", targetList)) {
                player.stepForBottom();
            } else {
                player.elm.classList.remove("hit");
                setTimeout(function() {
                    player.elm.classList.add("hit");
                    console.log("HIT!");
                }, 0);
            }
        }
    
        if (btnState.leftbutton) {
            if (!player.willHit("LEFT", targetList)) {
                player.stepForLeft();
            } else {
                player.elm.classList.remove("hit");
                setTimeout(function() {
                    player.elm.classList.add("hit");
                    console.log("HIT!");
                }, 0);
            }
        } else if (btnState.rightbutton) {
            if (!player.willHit("RIGHT", targetList)) {
                player.stepForRight();
            } else {
                player.elm.classList.remove("hit");
                setTimeout(function() {
                    player.elm.classList.add("hit");
                    console.log("HIT!");
                }, 0);
            }
        }
    }

})(this, document);

CSS

* {
    margin: 0;
    padding: 0;
}

html, body {
    height: 100%;
    background: #000;
}

body {
    margin: 0;
}

.hitarea {
    background: rgba(255, 255, 255, .2);
}

.player {
    border-radius: 50%;
    background: #fff !important;
    transform: scale(2.5);
}

.player.hit {
    animation: hit .2s ease-in 1;
}

@keyframes hit {
  0% {
    margin: 0;
  }

  20% {
    margin: -2px;
  }

  40% {
    margin: 2px;
  }

  60% {
    margin: -2px 2px;
  }

  80% {
    margin: 2px -2px;
  }

  100% {
    margin: 0;
  }
}

DEMO