116 lines
3.1 KiB
JavaScript
116 lines
3.1 KiB
JavaScript
import {BEAT_WARMUP_OFFSET, BEAT_WARMUP_SPEED, BEAT_WARMUP_TIME} from '../constants/beat';
|
|
|
|
// So wall does not clip the stage ground.
|
|
const RAISE_Y_OFFSET = 0.1;
|
|
|
|
const WALL_THICKNESS = 0.50;
|
|
const CEILING_THICKNESS = 1.5;
|
|
const CEILING_HEIGHT = 1.4 + CEILING_THICKNESS / 2;
|
|
|
|
/**
|
|
* Wall to dodge.
|
|
*/
|
|
AFRAME.registerComponent('wall', {
|
|
schema: {
|
|
anticipationPosition: {default: 0},
|
|
durationSeconds: {default: 0},
|
|
height: {default: 1.3},
|
|
horizontalPosition: {default: 'middleleft',
|
|
oneOf: ['left', 'middleleft', 'middleright', 'right']},
|
|
isCeiling: {default: false},
|
|
speed: {default: 1.0},
|
|
warmupPosition: {default: 0},
|
|
width: {default: 1}
|
|
},
|
|
|
|
horizontalPositions: {
|
|
left: -0.75,
|
|
middleleft: -0.25,
|
|
middleright: 0.25,
|
|
right: 0.75
|
|
},
|
|
|
|
init: function () {
|
|
this.maxZ = 10;
|
|
},
|
|
|
|
update: function () {
|
|
const el = this.el;
|
|
const data = this.data;
|
|
const width = data.width * WALL_THICKNESS;
|
|
|
|
const halfDepth = data.durationSeconds * data.speed / 2;
|
|
|
|
if (data.isCeiling) {
|
|
el.object3D.position.set(
|
|
0,
|
|
CEILING_HEIGHT,
|
|
data.anticipationPosition + data.warmupPosition - halfDepth
|
|
);
|
|
el.object3D.scale.set(
|
|
width,
|
|
CEILING_THICKNESS,
|
|
data.durationSeconds * data.speed
|
|
);
|
|
return;
|
|
}
|
|
|
|
// Box geometry is constructed from the local 0,0,0 growing in the positive and negative
|
|
// x and z axis. We have to shift by half width and depth to be positioned correctly.
|
|
el.object3D.position.set(
|
|
this.horizontalPositions[data.horizontalPosition] + width / 2 - 0.25,
|
|
data.height + RAISE_Y_OFFSET,
|
|
data.anticipationPosition + data.warmupPosition - halfDepth
|
|
);
|
|
el.object3D.scale.set(
|
|
width,
|
|
2.5,
|
|
data.durationSeconds * data.speed
|
|
);
|
|
},
|
|
|
|
pause: function () {
|
|
this.el.object3D.visible = false;
|
|
this.el.removeAttribute('data-collidable-head');
|
|
},
|
|
|
|
play: function () {
|
|
this.el.object3D.visible = true;
|
|
this.el.setAttribute('data-collidable-head', '');
|
|
this.el.setAttribute('raycastable-game');
|
|
},
|
|
|
|
tock: function (time, timeDelta) {
|
|
const data = this.data;
|
|
const halfDepth = data.durationSeconds * data.speed / 2;
|
|
const position = this.el.object3D.position;
|
|
|
|
// Move.
|
|
if (position.z < (data.anticipationPosition - halfDepth)) {
|
|
let newPositionZ = position.z + BEAT_WARMUP_SPEED * (timeDelta / 1000);
|
|
// Warm up / warp in.
|
|
if (newPositionZ < (data.anticipationPosition - halfDepth)) {
|
|
position.z = newPositionZ;
|
|
} else {
|
|
position.z = data.anticipationPosition - halfDepth;
|
|
}
|
|
} else {
|
|
// Standard moving.
|
|
position.z += this.data.speed * (timeDelta / 1000);
|
|
}
|
|
|
|
if (this.el.object3D.position.z > (this.maxZ + halfDepth)) {
|
|
this.returnToPool();
|
|
return;
|
|
}
|
|
},
|
|
|
|
returnToPool: function () {
|
|
this.el.sceneEl.components.pool__wall.returnEntity(this.el);
|
|
this.el.object3D.position.z = 9999;
|
|
this.el.pause();
|
|
this.el.removeAttribute('data-collidable-head');
|
|
this.el.removeAttribute('raycastable-game');
|
|
}
|
|
});
|