prefetch beat data + get access to beat info early
This commit is contained in:
@@ -8,9 +8,10 @@ AFRAME.registerComponent('beat-loader', {
|
||||
schema: {
|
||||
beatAnticipationTime: {default: 2.0},
|
||||
beatSpeed: {default: 4.0},
|
||||
challengeId: {type: 'string'},
|
||||
challengeId: {type: 'string'}, // If clicked play.
|
||||
difficulty: {type: 'string'},
|
||||
isPlaying: {default: false}
|
||||
isPlaying: {default: false},
|
||||
menuSelectedChallengeId: {type: 'string'} // If menu selected.
|
||||
},
|
||||
|
||||
orientations: [180, 0, 270, 90, 225, 135, 315, 45, 0],
|
||||
@@ -21,12 +22,14 @@ AFRAME.registerComponent('beat-loader', {
|
||||
this.audioAnalyserEl = document.getElementById('audioanalyser');
|
||||
this.beams = document.getElementById('beams').components.beams;
|
||||
this.beatData = null;
|
||||
this.beatDataProcessed = false;
|
||||
this.beatContainer = document.getElementById('beatContainer');
|
||||
this.beatsTime = undefined;
|
||||
this.beatsTimeOffset = undefined;
|
||||
this.bpm = undefined;
|
||||
this.songCurrentTime = undefined;
|
||||
this.onKeyDown = this.onKeyDown.bind(this);
|
||||
this.xhr = null;
|
||||
|
||||
this.stageColors = this.el.components['stage-colors'];
|
||||
this.twister = document.getElementById('twister');
|
||||
@@ -35,52 +38,24 @@ AFRAME.registerComponent('beat-loader', {
|
||||
|
||||
this.el.addEventListener('cleargame', this.clearBeats.bind(this));
|
||||
|
||||
//this.addDebugControls();
|
||||
// this.addDebugControls();
|
||||
},
|
||||
|
||||
update: function (oldData) {
|
||||
const data = this.data;
|
||||
|
||||
if (!data.challengeId || !data.difficulty) { return; }
|
||||
|
||||
if (data.challengeId !== oldData.challengeId ||
|
||||
data.difficulty !== oldData.difficulty) {
|
||||
this.loadBeats();
|
||||
// Start playing.
|
||||
if (!oldData.challengeId && data.challengeId) {
|
||||
this.processBeats();
|
||||
return;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* XHR.
|
||||
*/
|
||||
loadBeats: function () {
|
||||
var el = this.el;
|
||||
var xhr;
|
||||
if (!data.menuSelectedChallengeId || !data.difficulty) { return; }
|
||||
|
||||
// Load beats.
|
||||
let url = utils.getS3FileUrl(this.data.challengeId, `${this.data.difficulty}.json`);
|
||||
xhr = new XMLHttpRequest();
|
||||
el.emit('beatloaderstart');
|
||||
console.log(`Fetching ${url}...`);
|
||||
xhr.open('GET', url);
|
||||
xhr.addEventListener('load', () => {
|
||||
this.handleBeats(JSON.parse(xhr.responseText));
|
||||
});
|
||||
xhr.send();
|
||||
},
|
||||
|
||||
onKeyDown: function (event) {
|
||||
var keyCode = event.keyCode;
|
||||
switch (keyCode) {
|
||||
case 32: // Space
|
||||
this.generateBeat({
|
||||
_lineIndex: 2,
|
||||
_lineLayer: 1,
|
||||
_cutDirection: 1,
|
||||
_type: 1
|
||||
});
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
// Prefetch beats.
|
||||
if (data.menuSelectedChallengeId !== oldData.menuSelectedChallengeId ||
|
||||
data.difficulty !== oldData.difficulty) {
|
||||
this.fetchBeats();
|
||||
}
|
||||
},
|
||||
|
||||
@@ -92,30 +67,54 @@ AFRAME.registerComponent('beat-loader', {
|
||||
window.removeEventListener('keydown', this.onKeyDown);
|
||||
},
|
||||
|
||||
/**
|
||||
* XHR. Beat data is prefetched when user selects a menu challenge, and stored away
|
||||
* to be processed later.
|
||||
*/
|
||||
fetchBeats: function () {
|
||||
var el = this.el;
|
||||
|
||||
if (this.xhr) { this.xhr.abort(); }
|
||||
|
||||
// Load beats.
|
||||
let url = utils.getS3FileUrl(this.data.menuSelectedChallengeId,
|
||||
`${this.data.difficulty}.json`);
|
||||
const xhr = this.xhr = new XMLHttpRequest();
|
||||
el.emit('beatloaderstart');
|
||||
console.log(`[beat-loader] Fetching ${url}...`);
|
||||
xhr.open('GET', url);
|
||||
xhr.addEventListener('load', () => {
|
||||
this.beatData = JSON.parse(xhr.responseText);
|
||||
this.beatDataProcessed = false;
|
||||
this.xhr = null;
|
||||
this.el.sceneEl.emit('beatloaderfinish', null, false);
|
||||
});
|
||||
xhr.send();
|
||||
},
|
||||
|
||||
/**
|
||||
* Load the beat data into the game.
|
||||
*/
|
||||
handleBeats: function (beatData) {
|
||||
this.el.sceneEl.emit('beatloaderfinish', beatData, false);
|
||||
|
||||
processBeats: function () {
|
||||
// Reset variables used during playback.
|
||||
// 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;
|
||||
this.beatData = beatData;
|
||||
this.beatData._events.sort(lessThan);
|
||||
this.beatData._obstacles.sort(lessThan);
|
||||
this.beatData._notes.sort(lessThan);
|
||||
this.bpm = this.beatData._beatsPerMinute;
|
||||
|
||||
// some events have negative time stamp to inicialize the stage
|
||||
var events = this.beatData._events;
|
||||
// Some events have negative time stamp to initialize the stage.
|
||||
const events = this.beatData._events;
|
||||
if (events.length && events[0]._time < 0) {
|
||||
for (let i = 0; events[i]._time < 0; i++) {
|
||||
this.generateEvent(events[i]);
|
||||
}
|
||||
}
|
||||
console.log('Finished loading challenge data.');
|
||||
|
||||
this.beatDataProcessed = true;
|
||||
console.log('[beat-loader] Finished processing beat data.');
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -134,7 +133,8 @@ AFRAME.registerComponent('beat-loader', {
|
||||
if (!this.data.isPlaying || !this.data.challengeId || !this.beatData) { return; }
|
||||
|
||||
// Re-sync song with beats playback.
|
||||
if (this.beatsTimeOffset !== undefined && this.songCurrentTime !== this.el.components.song.context.currentTime) {
|
||||
if (this.beatsTimeOffset !== undefined &&
|
||||
this.songCurrentTime !== this.el.components.song.context.currentTime) {
|
||||
this.songCurrentTime = this.el.components.song.context.currentTime;
|
||||
this.beatsTime = (this.songCurrentTime + this.data.beatAnticipationTime) * 1000;
|
||||
}
|
||||
@@ -303,7 +303,8 @@ AFRAME.registerComponent('beat-loader', {
|
||||
addDebugControls: function () {
|
||||
var self = this;
|
||||
var currControl = 0;
|
||||
function addControl(i, name, type){
|
||||
|
||||
function addControl (i, name, type) {
|
||||
var div = document.createElement('div');
|
||||
div.style.position = 'absolute';
|
||||
div.id = 'stagecontrol' + i;
|
||||
@@ -324,18 +325,22 @@ AFRAME.registerComponent('beat-loader', {
|
||||
document.getElementById('stagecontrol' + currControl).style.background = '#000';
|
||||
div.style.background = '#66f';
|
||||
currControl = i;
|
||||
} )
|
||||
});
|
||||
} else {
|
||||
div.addEventListener('click', () => { self.generateEvent({_type: currControl, _value: i}) })
|
||||
div.addEventListener('click', () => {
|
||||
self.generateEvent({_type: currControl, _value: i})
|
||||
})
|
||||
}
|
||||
document.body.appendChild(div);
|
||||
}
|
||||
|
||||
[ 'sky',
|
||||
[
|
||||
'sky',
|
||||
'tunnelNeon',
|
||||
'leftStageLasers',
|
||||
'rightStageLasers',
|
||||
'floor'].forEach((id, i) => {addControl(i, id, 'element'); });
|
||||
'floor'
|
||||
].forEach((id, i) => { addControl(i, id, 'element'); });
|
||||
|
||||
[
|
||||
'off',
|
||||
@@ -346,11 +351,27 @@ AFRAME.registerComponent('beat-loader', {
|
||||
'red',
|
||||
'red',
|
||||
'redfade'
|
||||
].forEach((id, i) => {addControl(i, id, 'value'); });
|
||||
;
|
||||
].forEach((id, i) => { addControl(i, id, 'value'); });
|
||||
},
|
||||
|
||||
/**
|
||||
* Debug generate beats.
|
||||
*/
|
||||
onKeyDown: function (event) {
|
||||
const keyCode = event.keyCode;
|
||||
switch (keyCode) {
|
||||
case 32: // Space.
|
||||
this.generateBeat({
|
||||
_lineIndex: 2,
|
||||
_lineLayer: 1,
|
||||
_cutDirection: 1,
|
||||
_type: 1
|
||||
});
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
function lessThan (a, b) {
|
||||
return a._time - b._time;
|
||||
}
|
||||
function lessThan (a, b) { return a._time - b._time; }
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
|
||||
<a-scene
|
||||
mixin="gameoverAnimation fogAnimation"
|
||||
bind__beat-loader="challengeId: challenge.id; difficulty: challenge.difficulty; isPlaying: isPlaying"
|
||||
bind__beat-loader="challengeId: challenge.id; difficulty: menuSelectedChallenge.difficulty; isPlaying: isPlaying; menuSelectedChallengeId: menuSelectedChallenge.id"
|
||||
bind__gameover="isGameOver: isGameOver"
|
||||
bind__intro-song="isPlaying: menuActive && !menuSelectedChallenge.id; isSearching: isSearching"
|
||||
bind__overlay="enabled: !isPlaying"
|
||||
|
||||
@@ -29,6 +29,7 @@ AFRAME.registerState({
|
||||
image: '',
|
||||
isLoading: false,
|
||||
isBeatsPreloaded: false,
|
||||
numBeats: 0,
|
||||
songName: '',
|
||||
songSubName: '',
|
||||
songLength: 0
|
||||
@@ -46,7 +47,6 @@ AFRAME.registerState({
|
||||
menuDifficulties: [],
|
||||
menuSelectedChallenge: {
|
||||
author: '',
|
||||
bpm: 0,
|
||||
difficulty: '',
|
||||
downloads: '',
|
||||
downloadsText: '',
|
||||
@@ -218,7 +218,6 @@ AFRAME.registerState({
|
||||
state.menuSelectedChallenge.id = '';
|
||||
|
||||
state.isSearching = false;
|
||||
state.challenge.isLoading = true;
|
||||
state.isSongLoading = true;
|
||||
},
|
||||
|
||||
|
||||
@@ -171,11 +171,12 @@
|
||||
id="menuSelectedChallengePanel"
|
||||
bind__visible="!!menuSelectedChallenge.id"
|
||||
position="0.82 0 0.001">
|
||||
<a-entity id="menuSelectedChallengeImage"
|
||||
bind__menu-selected-challenge-image="selectedChallengeId: menuSelectedChallenge.id"
|
||||
geometry="primitive: plane; height: 0.3; width: 0.3"
|
||||
material="shader: flat"
|
||||
position="0 0.382 0"></a-entity>
|
||||
<a-entity
|
||||
id="menuSelectedChallengeImage"
|
||||
bind__menu-selected-challenge-image="selectedChallengeId: menuSelectedChallenge.id"
|
||||
geometry="primitive: plane; height: 0.3; width: 0.3"
|
||||
material="shader: flat"
|
||||
position="0 0.382 0"></a-entity>
|
||||
<a-entity id="menuSelectedChallengeInfo">
|
||||
<a-entity class="menuSelectedChallengeSongAuthor" position="0 0.058 0"
|
||||
mixin="textFont" text="wrapCount: 40; align: center; color: #FF185B" bind__text="value: menuSelectedChallenge.songSubName"></a-entity>
|
||||
@@ -188,19 +189,20 @@
|
||||
mixin="textFont" text="align: center; color: #FFF; wrapCount: 35" bind__text="value: menuSelectedChallenge.downloadsText"></a-entity>
|
||||
</a-entity>
|
||||
|
||||
<a-plane id="playButton"
|
||||
play-sound="event: mouseenter; sound: #hoverSound; volume: 0.03"
|
||||
position="0 -0.482 0"
|
||||
proxy-event="event: click; to: a-scene; as: playbuttonclick"
|
||||
material="shader: flat; src: #playImg; transparent: true; color: #CCC"
|
||||
width="0.4"
|
||||
height="0.2"
|
||||
animation__mouseenter1="property: components.material.material.color; type: color; from: #CCC; to: #FFF; startEvents: mouseenter; pauseEvents: mouseleave; dur: 150"
|
||||
animation__mouseleave1="property: components.material.material.color; type: color; from: #FFF; to: #CCC; startEvents: mouseleave; pauseEvents: mouseenter; dur: 150"
|
||||
animation__mouseenter2="property: scale; from: 1 1 1; to: 1.1 1.1 1.1; startEvents: mouseenter; pauseEvents: mouseleave; dur: 150"
|
||||
animation__mouseleave2="property: scale; to: 1 1 1; from: 1.1 1.1 1.1; startEvents: mouseleave; pauseEvents: mouseenter; dur: 150"
|
||||
bind-toggle__raycastable="menuActive && !!menuSelectedChallenge.id"
|
||||
bind__visible="menuActive && !!menuSelectedChallenge.id"></a-plane>
|
||||
<a-plane
|
||||
id="playButton"
|
||||
play-sound="event: mouseenter; sound: #hoverSound; volume: 0.03"
|
||||
position="0 -0.482 0"
|
||||
proxy-event="event: click; to: a-scene; as: playbuttonclick"
|
||||
material="shader: flat; src: #playImg; transparent: true; color: #CCC"
|
||||
width="0.4"
|
||||
height="0.2"
|
||||
animation__mouseenter1="property: components.material.material.color; type: color; from: #CCC; to: #FFF; startEvents: mouseenter; pauseEvents: mouseleave; dur: 150"
|
||||
animation__mouseleave1="property: components.material.material.color; type: color; from: #FFF; to: #CCC; startEvents: mouseleave; pauseEvents: mouseenter; dur: 150"
|
||||
animation__mouseenter2="property: scale; from: 1 1 1; to: 1.1 1.1 1.1; startEvents: mouseenter; pauseEvents: mouseleave; dur: 150"
|
||||
animation__mouseleave2="property: scale; to: 1 1 1; from: 1.1 1.1 1.1; startEvents: mouseleave; pauseEvents: mouseenter; dur: 150"
|
||||
bind-toggle__raycastable="menuActive && !!menuSelectedChallenge.id"
|
||||
bind__visible="menuActive && !!menuSelectedChallenge.id"></a-plane>
|
||||
</a-entity>
|
||||
</a-entity>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user