222 lines
7.8 KiB
JavaScript
222 lines
7.8 KiB
JavaScript
//
|
|
// whackAMole/mole.js
|
|
//
|
|
// Created by Thijs Wenker on 5/8/17.
|
|
// Copyright 2017 High Fidelity, Inc.
|
|
//
|
|
// Distributed under the Apache License, Version 2.0.
|
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
|
//
|
|
|
|
/* global module */
|
|
// @module mole
|
|
var constants = Script.require('./constants.js');
|
|
var helpers = Script.require('./helpers.js');
|
|
|
|
var MOLE_STATE = constants.MOLE_STATE;
|
|
|
|
// Frame numbers for popping animation
|
|
var POPUP_FRAME_START = 1;
|
|
var POPUP_FRAME_END = 28;
|
|
var DROPDOWN_FRAME_START = 29;
|
|
var DROPDOWN_FRAME_END = 55;
|
|
// Frame numbers for attract animation
|
|
var ATTRACT_FRAME_START = 56;
|
|
var ATTRACT_FRAME_END = 340;
|
|
|
|
var DEFAULT_FPS = 30;
|
|
// Make the mole go down faster on hit:
|
|
var HIT_FPS = 60;
|
|
|
|
var SFX_HIT = SoundCache.getSound(helpers.getSoundURL('whackaMole_hit.wav'));
|
|
var SFX_LIFT = SoundCache.getSound(helpers.getSoundURL('moleLiftMechanism.wav'));
|
|
var SFX_LONG_LAUGH = SoundCache.getSound(helpers.getSoundURL('whackaMole_longLaugh.wav'));
|
|
var SFX_RANDOM_SQUEAKS = [
|
|
SoundCache.getSound(helpers.getSoundURL('whackaMole_randomSqueak_1.wav')),
|
|
SoundCache.getSound(helpers.getSoundURL('whackaMole_randomSqueak_2.wav')),
|
|
SoundCache.getSound(helpers.getSoundURL('whackaMole_randomSqueak_3.wav')),
|
|
SoundCache.getSound(helpers.getSoundURL('whackaMole_randomSqueak_4.wav'))
|
|
];
|
|
var DEFAULT_SFX_VOLUME = 0.2;
|
|
|
|
|
|
var Mole = function(entityID, column, row, defaultIdleTime, masterVolume) {
|
|
this.defaultIdleTime = defaultIdleTime;
|
|
this.moleEntityID = entityID;
|
|
this.column = column;
|
|
this.row = row;
|
|
this.state = MOLE_STATE.DOWN;
|
|
this.lastFPS = 0;
|
|
this.speed = 1.0;
|
|
this.idleTime = 2000;
|
|
this.nextMoveAt = -1;
|
|
this.masterVolume = masterVolume;
|
|
|
|
try {
|
|
var userData = JSON.parse(Entities.getEntityProperties(entityID, ['userData']).userData);
|
|
this.colliderID = userData.whackAMole.colliderID;
|
|
} catch (e) {
|
|
// e
|
|
|
|
}
|
|
};
|
|
|
|
// TODO: make a sub-mole (more physical, so it can really pop out of the hole with the spring action)
|
|
Mole.prototype = {
|
|
moleEntityID: null,
|
|
colliderID: null,
|
|
column: null,
|
|
row: null,
|
|
speed: null,
|
|
idleTime: null,
|
|
nextMoveAt: null,
|
|
_animate: function(firstFrame, lastFrame, fps) {
|
|
if (fps === undefined) {
|
|
fps = DEFAULT_FPS;
|
|
}
|
|
var entityProperties = {
|
|
animation: {
|
|
currentFrame: firstFrame,
|
|
firstFrame: firstFrame,
|
|
lastFrame: lastFrame,
|
|
running: true,
|
|
url: helpers.getModelURL('moleRig_Opt.fbx'),
|
|
loop: false,
|
|
fps: fps,
|
|
hold: true
|
|
}
|
|
};
|
|
helpers.debugPrint('playing animation -> ' + JSON.stringify(entityProperties));
|
|
Entities.editEntity(this.moleEntityID, entityProperties);
|
|
return (Math.abs(firstFrame - lastFrame) / fps) * constants.MILLISECONDS_PER_SECOND;
|
|
},
|
|
_playSound: function(sound, properties) {
|
|
if (properties === undefined) {
|
|
properties = {};
|
|
}
|
|
if (properties.position === undefined) {
|
|
properties.position = Entities.getEntityProperties(this.moleEntityID, 'position').position;
|
|
}
|
|
if (properties.volume === undefined) {
|
|
properties.volume = DEFAULT_SFX_VOLUME;
|
|
}
|
|
return Audio.playSound(sound, properties);
|
|
},
|
|
// makes the mole spin
|
|
spin: function() {
|
|
Entities.editEntity(this.moleEntityID, {
|
|
angularVelocity: Quat.fromVec3Degrees({
|
|
x: 0,
|
|
y: 20,
|
|
z: 0
|
|
}),
|
|
angularDamping: 0.0
|
|
});
|
|
},
|
|
reset: function() {
|
|
this._animate(0, 0);
|
|
},
|
|
reactAngry: function() {
|
|
var position = Entities.getEntityProperties(this.moleEntityID, 'position').position;
|
|
position.y += 0.3;
|
|
Entities.addEntity({
|
|
azimuthStart: 2.5,
|
|
dimensions: {
|
|
x: 0.26400002837181091,
|
|
y: 0.26400002837181091,
|
|
z: 0.26400002837181091
|
|
},
|
|
emitAcceleration: {
|
|
x: 0,
|
|
y: 0,
|
|
z: 0
|
|
},
|
|
emitOrientation: {
|
|
w: 0.7070610523223877,
|
|
x: -0.70715254545211792,
|
|
y: -1.5258869098033756e-05,
|
|
z: -1.5258869098033756e-05
|
|
},
|
|
emitRate: 3,
|
|
emitSpeed: 0.20000000298023224,
|
|
lifespan: 0.40000000596046448,
|
|
maxParticles: 5,
|
|
particleRadius: 0.045000001788139343,
|
|
radiusFinish: 0.045000001788139343,
|
|
radiusStart: 0.045000001788139343,
|
|
speedSpread: 0.10000000149011612,
|
|
textures: Script.resolvePath('particles/cartoonSwear_wide.png'),
|
|
type: "ParticleEffect",
|
|
lifetime: 0.6,
|
|
position: position
|
|
});
|
|
},
|
|
hit: function() {
|
|
var currentMilliseconds = Date.now();
|
|
helpers.debugPrint('HIT!!');
|
|
this.reactAngry();
|
|
this._playSound(SFX_HIT);
|
|
if (this.state === MOLE_STATE.POPUP) {
|
|
var startFrame = DROPDOWN_FRAME_START;
|
|
try {
|
|
var animation = Entities.getEntityProperties(this.moleEntityID, 'animation').animation;
|
|
var maxDropDownFrames = DROPDOWN_FRAME_END - DROPDOWN_FRAME_START;
|
|
startFrame = DROPDOWN_FRAME_END - Math.min(animation.currentFrame - POPUP_FRAME_START, maxDropDownFrames);
|
|
} catch (e) {
|
|
// e
|
|
}
|
|
this.nextMoveAt = currentMilliseconds + this.dropDown(HIT_FPS, startFrame);
|
|
} else if (this.state === MOLE_STATE.UP) {
|
|
this.nextMoveAt = currentMilliseconds + this.dropDown(HIT_FPS);
|
|
}
|
|
},
|
|
beginMove: function(currentMilliseconds, speed) {
|
|
this.speed = speed;
|
|
this.nextMoveAt = currentMilliseconds + this.popUp();
|
|
},
|
|
nextMove: function(currentMilliseconds) {
|
|
if (this.state === MOLE_STATE.POPUP) {
|
|
this.idle();
|
|
this.nextMoveAt = currentMilliseconds + (this.idleTime / this.speed);
|
|
} else if (this.state === MOLE_STATE.UP) {
|
|
this.nextMoveAt = currentMilliseconds + this.dropDown();
|
|
} else if (this.state === MOLE_STATE.DROPDOWN) {
|
|
this.state = MOLE_STATE.DOWN;
|
|
}
|
|
},
|
|
popUp: function(fps) {
|
|
this._playSound(SFX_LIFT);
|
|
this.state = MOLE_STATE.POPUP;
|
|
var runtimeMilliseconds = this._animate(POPUP_FRAME_START, POPUP_FRAME_END, fps);
|
|
helpers.debugPrint('popUp Mole -> ' + this.moleEntityID);
|
|
return runtimeMilliseconds;
|
|
},
|
|
idle: function() {
|
|
this.state = MOLE_STATE.UP;
|
|
var runtimeMilliseconds = this._animate(POPUP_FRAME_END, POPUP_FRAME_END);
|
|
helpers.debugPrint('idle Mole -> ' + this.moleEntityID);
|
|
return runtimeMilliseconds;
|
|
},
|
|
dropDown: function(fps, startFrame) {
|
|
if (startFrame === undefined) {
|
|
startFrame = DROPDOWN_FRAME_START;
|
|
}
|
|
this.state = MOLE_STATE.DROPDOWN;
|
|
|
|
var randomSqueak = SFX_RANDOM_SQUEAKS[Math.floor(Math.random() * SFX_RANDOM_SQUEAKS.length)];
|
|
this._playSound(randomSqueak);
|
|
|
|
var runtimeMilliseconds = this._animate(startFrame, DROPDOWN_FRAME_END, fps);
|
|
helpers.debugPrint('dropDown Mole -> ' + this.moleEntityID);
|
|
return runtimeMilliseconds;
|
|
},
|
|
attract: function() {
|
|
if (Math.random() < 0.20) {
|
|
this._playSound(SFX_LONG_LAUGH);
|
|
}
|
|
this.state = MOLE_STATE.LURE;
|
|
return this._animate(ATTRACT_FRAME_START, ATTRACT_FRAME_END);
|
|
}
|
|
};
|
|
|
|
module.exports = Mole;
|