diff --git a/src/components/beat.js b/src/components/beat.js index 129e1d7..db3f133 100644 --- a/src/components/beat.js +++ b/src/components/beat.js @@ -127,7 +127,6 @@ AFRAME.registerComponent('beat', { this.onEndStroke = this.onEndStroke.bind(this); this.initBlock(); - this.initColliders(); if (this.data.type === 'mine') { this.initMineFragments(); } else { @@ -282,37 +281,6 @@ 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; @@ -657,43 +625,6 @@ 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); @@ -709,19 +640,36 @@ AFRAME.registerComponent('beat', { this.destroyBeat(saberEls[i]); - if (this.data.type === 'dot' && saberEls[i].components['saber-controls'].swinging && + if (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 7c0b69c..efb6519 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: 10000}, - strokeMinAngle: {default: 5} + strokeMinSpeed: {default: 0.002}, + strokeMinDuration: {default: 40} }, init: function () { @@ -28,7 +28,17 @@ 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)); @@ -57,8 +67,6 @@ 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); @@ -76,26 +84,32 @@ 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() * 1000000; + distance = this.bladeTipPreviousPosition.sub(this.bladeTipPosition).length(); // 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.data.strokeMinSpeed) { - // Saber has to move more than strokeMinAngle to consider a swing. + if (this.accumulatedDistance / this.accumulatedDelta > this.data.strokeMinSpeed) { // This filters out unintentional swings. if (!this.swinging) { - startSpeed = this.accumulatedDistance; + this.startStrokePosition.copy(this.bladeTipPosition); 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; @@ -104,8 +118,6 @@ 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(); } @@ -113,13 +125,27 @@ AFRAME.registerComponent('saber-controls', { }, endStroke: function () { + if (!this.swinging || this.strokeDuration < this.data.strokeMinDuration) { return; } + this.el.emit('strokeend'); - if (this.swinging) { return; } + this.swinging = false; + // Stroke finishes. Reset swinging state. 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) {