約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; } }