Files
junisaber/src/components/beat-loader.js

236 lines
6.6 KiB
JavaScript
Raw Normal View History

2018-07-20 09:34:52 +02:00
var utils = require('../utils');
/**
* Load beat data (all the beats and such).
*/
AFRAME.registerComponent('beat-loader', {
schema: {
2018-10-02 05:15:56 -07:00
beatAnticipationTime: {default: 2.0},
2018-10-01 17:37:11 -07:00
beatSpeed: {default: 4.0},
2018-10-02 05:15:56 -07:00
challengeId: {type: 'string'},
2018-10-03 18:58:26 -07:00
difficulty: {type: 'string'},
2018-10-09 17:17:41 -07:00
isPlaying: {default: false}
2018-07-20 09:34:52 +02:00
},
2018-10-01 17:37:11 -07:00
orientations: [180, 0, 270, 90, 225, 135, 315, 45, 0],
horizontalPositions: [-0.60, -0.25, 0.25, 0.60],
verticalPositions: [1.00, 1.35, 1.70],
init: function () {
this.audioAnalyserEl = document.getElementById('audioanalyser');
2018-10-08 17:30:13 -07:00
this.beams = document.getElementById('beams').components.beams;
this.beatData = null;
this.beatContainer = document.getElementById('beatContainer');
2018-10-10 18:04:48 -10:00
this.beatsTime = undefined;
2018-10-12 01:43:06 -07:00
this.beatsTimeOffset = undefined;
this.bpm = undefined;
this.songCurrentTime = undefined;
2018-10-10 23:06:35 -10:00
this.onKeyDown = this.onKeyDown.bind(this);
2018-10-08 17:15:30 -07:00
this.el.addEventListener('cleargame', this.clearBeats.bind(this));
},
update: function (oldData) {
const data = this.data;
2018-10-12 01:43:06 -07:00
if (!data.challengeId || !data.difficulty) { return; }
2018-10-12 01:43:06 -07:00
if (data.challengeId !== oldData.challengeId ||
data.difficulty !== oldData.difficulty) {
this.loadBeats();
}
2018-07-21 10:21:30 +02:00
},
/**
* XHR.
*/
2018-10-01 17:37:11 -07:00
loadBeats: function () {
2018-07-20 09:34:52 +02:00
var el = this.el;
var xhr;
// Load beats.
2018-07-21 10:21:30 +02:00
let url = utils.getS3FileUrl(this.data.challengeId, `${this.data.difficulty}.json`);
2018-07-20 09:34:52 +02:00
xhr = new XMLHttpRequest();
el.emit('beatloaderstart');
2018-07-21 10:21:30 +02:00
console.log(`Fetching ${url}...`);
xhr.open('GET', url);
2018-07-20 09:34:52 +02:00
xhr.addEventListener('load', () => {
this.handleBeats(JSON.parse(xhr.responseText));
});
xhr.send();
},
2018-10-10 23:06:35 -10:00
onKeyDown: function (event) {
var keyCode = event.keyCode;
switch (keyCode) {
case 32: // Space
this.generateBeat({
_lineIndex: 2,
_lineLayer: 1,
_cutDirection: 1,
_type: 3
});
break;
default:
break;
}
},
play: function () {
window.addEventListener('keydown', this.onKeyDown);
},
pause: function () {
window.removeEventListener('keydown', this.onKeyDown);
},
2018-07-20 09:34:52 +02:00
/**
2018-10-01 17:37:11 -07:00
* Load the beat data into the game.
2018-07-20 09:34:52 +02:00
*/
handleBeats: function (beatData) {
2018-07-21 10:21:30 +02:00
this.el.sceneEl.emit('beatloaderfinish', beatData, false);
2018-10-10 00:33:28 -10:00
// Reset variables used during playback.
2018-10-10 18:04:48 -10:00
// Beats spawn ahead of the song and get to the user in sync with the music.
this.beatsTimeOffset = this.data.beatAnticipationTime * 1000;
this.beatsTime = 0;
2018-10-10 00:33:28 -10:00
2018-10-01 17:37:11 -07:00
this.beatData = beatData;
this.beatData._obstacles.sort(lessThan);
this.beatData._notes.sort(lessThan);
this.bpm = this.beatData._beatsPerMinute;
2018-07-20 09:34:52 +02:00
console.log('Finished loading challenge data.');
},
2018-10-01 17:37:11 -07:00
2018-10-03 18:58:26 -07:00
/**
* Generate beats and stuff according to timestamp.
*/
2018-10-01 17:37:11 -07:00
tick: function (time, delta) {
var bpm;
2018-10-02 05:15:56 -07:00
var i;
2018-10-01 17:37:11 -07:00
var notes;
var obstacles;
2018-10-10 18:04:48 -10:00
var beatsTime = this.beatsTime;
2018-10-01 17:37:11 -07:00
var msPerBeat;
var noteTime;
if (!this.data.isPlaying || !this.data.challengeId || !this.beatData) { return; }
2018-10-01 17:37:11 -07:00
2018-10-10 00:33:28 -10:00
// Re-sync song with beats playback.
if (this.beatsTimeOffset !== undefined && this.songCurrentTime !== this.el.components.song.context.currentTime) {
this.songCurrentTime = this.el.components.song.context.currentTime;
2018-10-10 18:04:48 -10:00
this.beatsTime = (this.songCurrentTime + this.data.beatAnticipationTime) * 1000;
2018-10-10 00:33:28 -10:00
}
2018-10-01 17:37:11 -07:00
notes = this.beatData._notes;
obstacles = this.beatData._obstacles;
bpm = this.beatData._beatsPerMinute;
2018-10-01 17:37:11 -07:00
msPerBeat = 1000 * 60 / this.beatData._beatsPerMinute;
2018-10-02 05:15:56 -07:00
for (i = 0; i < notes.length; ++i) {
2018-10-01 17:37:11 -07:00
noteTime = notes[i]._time * msPerBeat;
2018-10-10 18:04:48 -10:00
if (noteTime > beatsTime && noteTime <= beatsTime + delta) {
2018-10-01 17:37:11 -07:00
notes[i].time = noteTime;
this.generateBeat(notes[i]);
2018-10-02 05:15:56 -07:00
}
2018-10-01 17:37:11 -07:00
}
for (i=0; i < obstacles.length; ++i) {
noteTime = obstacles[i]._time * msPerBeat;
2018-10-10 18:04:48 -10:00
if (noteTime > beatsTime && noteTime <= beatsTime + delta) {
2018-10-11 22:15:41 -10:00
this.generateWall(obstacles[i]);
2018-10-02 05:15:56 -07:00
}
2018-10-01 17:37:11 -07:00
}
2018-10-10 18:04:48 -10:00
if (this.beatsTimeOffset !== undefined) {
if (this.beatsTimeOffset <= 0) {
2018-10-10 00:33:28 -10:00
this.el.sceneEl.emit('beatloaderpreloadfinish', null, false);
this.songCurrentTime = this.el.components.song.context.currentTime;
2018-10-10 18:04:48 -10:00
this.beatsTimeOffset = undefined;
2018-10-10 00:33:28 -10:00
} else {
2018-10-10 18:04:48 -10:00
this.beatsTimeOffset -= delta;
2018-10-10 00:33:28 -10:00
}
2018-10-02 05:15:56 -07:00
}
2018-10-10 18:04:48 -10:00
this.beatsTime = beatsTime + delta;
2018-10-01 17:37:11 -07:00
},
2018-10-02 05:15:56 -07:00
generateBeat: (function () {
const beatObj = {};
2018-10-10 18:04:48 -10:00
// Beats arrive at sword stroke distance synced with the music.
const swordOffset = 1.5;
2018-10-02 05:15:56 -07:00
return function (noteInfo) {
2018-10-08 17:30:13 -07:00
var beatEl;
2018-10-02 05:15:56 -07:00
var color;
var orientation;
var type = noteInfo._cutDirection === 8 ? 'dot' : 'arrow';
2018-10-08 17:30:13 -07:00
2018-10-02 05:15:56 -07:00
color = noteInfo._type === 0 ? 'red' : 'blue';
if (noteInfo._type === 3) {
type = 'mine';
color = undefined;
}
2018-10-08 17:30:13 -07:00
beatEl = this.requestBeat(type, color);
if (!beatEl) { return; }
2018-10-02 05:15:56 -07:00
beatObj.color = color;
beatObj.type = type;
beatObj.speed = this.data.beatSpeed;
2018-10-08 17:30:13 -07:00
beatEl.setAttribute('beat', beatObj);
beatEl.object3D.position.set(
2018-10-02 05:15:56 -07:00
this.horizontalPositions[noteInfo._lineIndex],
this.verticalPositions[noteInfo._lineLayer],
2018-10-10 18:04:48 -10:00
-this.data.beatAnticipationTime * this.data.beatSpeed - swordOffset
2018-10-02 05:15:56 -07:00
);
2018-10-08 17:30:13 -07:00
beatEl.object3D.rotation.z = THREE.Math.degToRad(this.orientations[noteInfo._cutDirection]);
beatEl.play();
this.beams.newBeam(color, beatEl.object3D.position);
2018-10-01 17:37:11 -07:00
};
2018-10-02 05:15:56 -07:00
})(),
2018-10-01 17:37:11 -07:00
2018-10-11 22:15:41 -10:00
generateWall: function (wallInfo) {
var el = this.el.sceneEl.components.pool__wall.requestEntity();
var speed = this.data.beatSpeed;
var durationMs;
if (!el) { return; }
durationSeconds = 60 * (wallInfo._duration / this.bpm);
el.setAttribute('wall', {
speed: speed
});
el.object3D.position.set(
this.horizontalPositions[wallInfo._lineIndex],
1.30,
-(this.data.beatAnticipationTime * speed)
);
el.object3D.scale.set(wallInfo._width * 0.30, 2.5, durationSeconds * speed);
el.play();
},
2018-10-02 05:15:56 -07:00
2018-10-01 17:37:11 -07:00
requestBeat: function (type, color) {
var beatPoolName = 'pool__beat-' + type;
var pool;
if (color) { beatPoolName += '-' + color; }
2018-10-01 17:37:11 -07:00
pool = this.el.sceneEl.components[beatPoolName];
if (!pool) {
console.warn('Pool ' + beatPoolName + ' unavailable');
2018-10-01 17:37:11 -07:00
return;
}
return pool.requestEntity();
},
2018-07-20 09:34:52 +02:00
2018-10-08 17:15:30 -07:00
/**
* Restart by returning all beats to pool.
*/
clearBeats: function () {
2018-10-12 01:43:06 -07:00
this.beatsTime = 0;
this.beatsTimeOffset = undefined;
for (let i = 0; i < this.beatContainer.children.length; i++) {
2018-10-08 17:15:30 -07:00
this.beatContainer.children[i].components.beat.returnToPool(true);
}
2018-07-20 09:34:52 +02:00
}
});
2018-10-12 01:43:06 -07:00
function lessThan (a, b) {
return a._time - b._time;
};