diff --git a/src/components/beat.js b/src/components/beat.js index db3f133..129e1d7 100644 --- a/src/components/beat.js +++ b/src/components/beat.js @@ -127,6 +127,7 @@ AFRAME.registerComponent('beat', { this.onEndStroke = this.onEndStroke.bind(this); this.initBlock(); + this.initColliders(); if (this.data.type === 'mine') { this.initMineFragments(); } else { @@ -281,6 +282,37 @@ AFRAME.registerComponent('beat', { } }, + initColliders: function () { + var data = this.data; + var hitColliderConfiguration; + var hitColliderEl; + + if (this.data.type === 'dot' || this.data.type === 'mine') { return; } + + // Hit colliders are 40% larger than the block. + hitColliderConfiguration = { + position: {x: 0, y: data.size / 2, z: 0}, + size: {width: data.size * 1.4, height: data.size / 3.0, depth: data.size* 1.4} + }; + + hitColliderEl = this.hitColliderEl = document.createElement('a-entity'); + hitColliderEl.setAttribute('geometry', { + primitive: 'box', + height: hitColliderConfiguration.size.height, + width: hitColliderConfiguration.size.width, + depth: hitColliderConfiguration.size.depth + }); + + hitColliderEl.object3D.position.copy(hitColliderConfiguration.position); + hitColliderEl.object3D.visible = false; + this.el.appendChild(hitColliderEl); + + if (data.debug) { + hitColliderEl.object3D.visible = true; + hitColliderEl.setAttribute('material', 'color', 'purple'); + } + }, + initFragments: function () { var cutEl; var partEl; @@ -625,6 +657,43 @@ AFRAME.registerComponent('beat', { const hand = saberEls[i].getAttribute('saber-controls').hand; + if (hitBoundingBox && saberBoundingBox.intersectsBox(hitBoundingBox)) { + if (saberEls[i].components['saber-controls'].swinging && + this.data.color === saberColors[hand]) { + saberControls = saberEls[i].components['saber-controls']; + this.hitHand = hand; + this.hitSaberEl = saberEls[i]; + this.hitSaberEl.addEventListener('strokeend', this.onEndStroke, ONCE); + if (cutDirection === 'up' || cutDirection === 'down') { + maxAngle = saberControls.maxAnglePlaneX; + } else if (cutDirection === 'left' || cutDirection === 'right') { + maxAngle = saberControls.maxAnglePlaneY; + } else { + maxAngle = saberControls.maxAnglePlaneXY; + } + this.angleBeforeHit = maxAngle; + saberControls.maxAnglePlaneX = 0; + saberControls.maxAnglePlaneY = 0; + saberControls.maxAnglePlaneXY = 0; + } else { + this.wrongHit(hand); + } + + // Notify for haptics. + this.el.emit(`beatcollide${hand}`, null, true); + + // Sound. + this.el.parentNode.components['beat-hit-sound'].playSound( + this.el, this.data.cutDirection); + + if (this.data.type === 'mine') { + this.destroyMine(); + } else { + this.destroyBeat(saberEls[i]); + } + break; + } + if (saberBoundingBox.intersectsBox(beatBoundingBox)) { // Notify for haptics. this.el.emit(`beatcollide${hand}`, null, true); @@ -640,36 +709,19 @@ AFRAME.registerComponent('beat', { this.destroyBeat(saberEls[i]); - if (saberEls[i].components['saber-controls'].swinging && + if (this.data.type === 'dot' && saberEls[i].components['saber-controls'].swinging && this.data.color === saberColors[hand]) { this.hitSaberEl = saberEls[i]; this.hitSaberEl.addEventListener('strokeend', this.onEndStroke, ONCE); saberControls = saberEls[i].components['saber-controls']; + maxAngle = Math.max(saberControls.maxAnglePlaneX, saberControls.maxAnglePlaneY, + saberControls.maxAnglePlaneXY); this.hitHand = hand; + this.angleBeforeHit = maxAngle; saberControls.maxAnglePlaneX = 0; saberControls.maxAnglePlaneY = 0; saberControls.maxAnglePlaneXY = 0; - if (this.data.type === 'arrow') { - saberControls.updateStrokeDirection(); - if (!saberControls.strokeDirection[this.data.cutDirection]) { - this.wrongHit(hand); - break; - } - - if (cutDirection === 'up' || cutDirection === 'down') { - maxAngle = saberControls.maxAnglePlaneX; - } else if (cutDirection === 'left' || cutDirection === 'right') { - maxAngle = saberControls.maxAnglePlaneY; - } else { - maxAngle = saberControls.maxAnglePlaneXY; - } - } else { - maxAngle = Math.max(saberControls.maxAnglePlaneX, saberControls.maxAnglePlaneY, - saberControls.maxAnglePlaneXY); - } - this.angleBeforeHit = maxAngle; - } else { this.wrongHit(hand); } diff --git a/src/components/saber-controls.js b/src/components/saber-controls.js index efb6519..7c0b69c 100644 --- a/src/components/saber-controls.js +++ b/src/components/saber-controls.js @@ -6,8 +6,8 @@ AFRAME.registerComponent('saber-controls', { bladeEnabled: {default: false}, hand: {default: 'right', oneOf: ['left', 'right']}, isPaused: {default: false}, - strokeMinSpeed: {default: 0.002}, - strokeMinDuration: {default: 40} + strokeMinSpeed: {default: 10000}, + strokeMinAngle: {default: 5} }, init: function () { @@ -28,17 +28,7 @@ AFRAME.registerComponent('saber-controls', { this.swinging = false; this.strokeCount = 0; this.distanceSamples = []; - this.deltaSamples = []; - this.startStrokePosition = new THREE.Vector3(); - this.strokeDirectionVector = new THREE.Vector3(); - this.strokeDirection = { - down: false, - left: false, - right: false, - up: false - }; this.accumulatedDistance = 0; - this.accumulatedDelta = 0; el.addEventListener('controllerconnected', this.initSaber.bind(this)); @@ -67,6 +57,8 @@ AFRAME.registerComponent('saber-controls', { var distanceSamples = this.distanceSamples; var data = this.data; var directionChange; + var startSpeed; + var strokeMinSpeed = this.swinging ? startSpeed : this.data.strokeMinSpeed; // Tip of the blade position in world coordinates. this.bladeTipPosition.set(0, 0, -0.8); @@ -84,32 +76,26 @@ AFRAME.registerComponent('saber-controls', { var anglePlaneXY = this.projectedBladeVector.copy(this.bladeTipPosition).projectOnPlane(this.xyPlaneNormal).angleTo(this.bladeVector); // Distance covered but the saber tip in one frame. - distance = this.bladeTipPreviousPosition.sub(this.bladeTipPosition).length(); + distance = this.bladeTipPreviousPosition.sub(this.bladeTipPosition).length() * 1000000; // Sample distance of the last 5 frames. if (this.distanceSamples.length === 5) { this.accumulatedDistance -= this.distanceSamples.shift(); - this.accumulatedDelta -= this.deltaSamples.shift(); } this.distanceSamples.push(distance); this.accumulatedDistance += distance; - this.deltaSamples.push(delta); - this.accumulatedDelta += delta; - // Filter out saber movements that are too slow. Too slow is considered wrong hit. - if (this.accumulatedDistance / this.accumulatedDelta > this.data.strokeMinSpeed) { + if (this.accumulatedDistance > this.data.strokeMinSpeed) { + // Saber has to move more than strokeMinAngle to consider a swing. // This filters out unintentional swings. if (!this.swinging) { - this.startStrokePosition.copy(this.bladeTipPosition); + startSpeed = this.accumulatedDistance; this.swinging = true; - this.strokeDuration = 0; this.maxAnglePlaneX = 0; this.maxAnglePlaneY = 0; this.maxAnglePlaneXY = 0; } - this.updateStrokeDirection(); - this.strokeDuration += delta; const anglePlaneXIncreased = anglePlaneX > this.maxAnglePlaneX; const anglePlaneYIncreased = anglePlaneY > this.maxAnglePlaneY; const anglePlaneXYIncreased = anglePlaneXY > this.maxAnglePlaneXY; @@ -118,6 +104,8 @@ AFRAME.registerComponent('saber-controls', { this.maxAnglePlaneXY = anglePlaneXYIncreased ? anglePlaneXY : this.maxAnglePlaneXY; if (!anglePlaneXIncreased && !anglePlaneYIncreased) { this.endStroke(); } } else { + // Stroke finishes. Reset swinging state. + this.swinging = false; this.endStroke(); } @@ -125,27 +113,13 @@ AFRAME.registerComponent('saber-controls', { }, endStroke: function () { - if (!this.swinging || this.strokeDuration < this.data.strokeMinDuration) { return; } - this.el.emit('strokeend'); - this.swinging = false; - // Stroke finishes. Reset swinging state. + if (this.swinging) { return; } this.accumulatedDistance = 0; - this.accumulatedDelta = 0; this.maxAnglePlaneX = 0; this.maxAnglePlaneY = 0; this.maxAnglePlaneXY = 0; for (let i = 0; i < this.distanceSamples.length; i++) { this.distanceSamples[i] = 0; } - for (let i = 0; i < this.deltaSamples.length; i++) { this.deltaSamples[i] = 0; } - }, - - updateStrokeDirection: function () { - this.strokeDirectionVector.copy(this.bladeTipPosition).sub(this.startStrokePosition); - if (this.strokeDirectionVector.x === 0 && this.strokeDirectionVector.y === 0) { return; } - this.strokeDirection.right = this.strokeDirectionVector.x > 0; - this.strokeDirection.left = this.strokeDirectionVector.x < 0; - this.strokeDirection.up = this.strokeDirectionVector.y > 0; - this.strokeDirection.down = this.strokeDirectionVector.y < 0; }, initSaber: function (evt) {