Browse Source
- VoiceChannel and GameVoiceChannels for managing character dialog (vox) - the start of enemy behaviors to drive enemy sprites - Removed character-specific GameEnemy variantsdevelop
Rob Colbert
2 years ago
16 changed files with 219 additions and 282 deletions
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -1,51 +0,0 @@ |
|||
// lib/game-enemy-beardson.js
|
|||
// Copyright (C) 2022 Rob Colbert @[email protected]
|
|||
// License: Apache-2.0
|
|||
|
|||
'use strict'; |
|||
|
|||
import GameEnemy from './game-enemy.js'; |
|||
|
|||
/** |
|||
* Implements a Beardson. The Beardson moves toward the bottom of the game play |
|||
* area. When he reaches the bottom, he pulls out a rainbow-colored dildo and |
|||
* chases Tex. When he catches Tex, Tex loses a life. |
|||
*/ |
|||
export default class GameEnemyBeardson extends GameEnemy { |
|||
|
|||
constructor (game, image, position, moveSpeed) { |
|||
super(game, image, position); |
|||
|
|||
this.targetX = position.x; |
|||
this.moveSpeed = { |
|||
x: moveSpeed.x, |
|||
y: moveSpeed.y, |
|||
}; |
|||
|
|||
this.isDescending = true; |
|||
} |
|||
|
|||
update ( ) { |
|||
if (this.isDescending) { |
|||
if (this.position.y < 480) { |
|||
this.position.y += this.moveSpeed.y; |
|||
} else { |
|||
this.position.y = 480; |
|||
this.isDescending = false; |
|||
this.game.audio.playSound('beardson-touchdown'); |
|||
} |
|||
} |
|||
|
|||
if (Math.random() > 0.998) { |
|||
this.targetX = this.game.getRandomPlayfieldX(); |
|||
} |
|||
|
|||
if (this.position.x > this.targetX) { |
|||
this.position.x -= this.moveSpeed.x; |
|||
} |
|||
|
|||
if (this.position.x < this.targetX) { |
|||
this.position.x += this.moveSpeed.x; |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,50 @@ |
|||
// lib/game-enemy-behaviors.js
|
|||
// Copyright (C) 2022 Rob Colbert @[email protected]
|
|||
// License: Apache-2.0
|
|||
|
|||
'use strict'; |
|||
|
|||
export class DescendToSurface { |
|||
|
|||
constructor (game, enemy, moveSpeed) { |
|||
this.game = game; |
|||
this.enemy = enemy; |
|||
this.moveSpeed = moveSpeed; |
|||
|
|||
this.isDescending = true; |
|||
this.targetX = this.enemy.position.x; |
|||
} |
|||
|
|||
update (/* elapsed, now */) { |
|||
if (this.isDescending) { |
|||
if (this.enemy.position.y < 480) { |
|||
this.enemy.position.y += this.moveSpeed; |
|||
} else { |
|||
this.enemy.position.y = 480; |
|||
this.isDescending = false; |
|||
this.game.audio.playSound('beardson-touchdown'); |
|||
return false; // end of behavior
|
|||
} |
|||
} |
|||
|
|||
if (Math.random() > 0.998) { |
|||
this.targetX = this.game.getRandomPlayfieldX(this.enemy.image.width / 2); |
|||
} |
|||
|
|||
if (this.enemy.position.x > this.targetX) { |
|||
this.enemy.position.x -= this.moveSpeed; |
|||
if (this.enemy.position.x < this.targetX) { |
|||
this.enemy.position.x = this.targetX; |
|||
} |
|||
} |
|||
|
|||
if (this.enemy.position.x < this.targetX) { |
|||
this.enemy.position.x += this.moveSpeed; |
|||
if (this.enemy.position.x > this.targetX) { |
|||
this.enemy.position.x = this.targetX; |
|||
} |
|||
} |
|||
|
|||
return true; // keep running
|
|||
} |
|||
} |
@ -1,46 +0,0 @@ |
|||
// lib/game-enemy-groyper.js
|
|||
// Copyright (C) 2022 Rob Colbert @[email protected]
|
|||
// License: Apache-2.0
|
|||
|
|||
'use strict'; |
|||
|
|||
import GameEnemy from './game-enemy.js'; |
|||
|
|||
export default class GameEnemyGroyper extends GameEnemy { |
|||
|
|||
constructor (game, image, position, moveSpeed) { |
|||
super(game, image, position); |
|||
|
|||
this.targetX = position.x; |
|||
this.moveSpeed = { |
|||
x: moveSpeed.x, |
|||
y: moveSpeed.y, |
|||
}; |
|||
|
|||
this.isDescending = true; |
|||
} |
|||
|
|||
update ( ) { |
|||
if (this.isDescending) { |
|||
if (this.position.y < 480) { |
|||
this.position.y += this.moveSpeed.y; |
|||
} else { |
|||
this.position.y = 480; |
|||
this.isDescending = false; |
|||
this.game.audio.playSound('beardson-touchdown'); |
|||
} |
|||
} |
|||
|
|||
if (Math.random() > 0.998) { |
|||
this.targetX = this.game.getRandomPlayfieldX(); |
|||
} |
|||
|
|||
if (this.position.x > this.targetX) { |
|||
this.position.x -= this.moveSpeed.x; |
|||
} |
|||
|
|||
if (this.position.x < this.targetX) { |
|||
this.position.x += this.moveSpeed.x; |
|||
} |
|||
} |
|||
} |
@ -1,46 +0,0 @@ |
|||
// lib/game-enemy-torba.js
|
|||
// Copyright (C) 2022 Rob Colbert @[email protected]
|
|||
// License: Apache-2.0
|
|||
|
|||
'use strict'; |
|||
|
|||
import GameEnemy from './game-enemy.js'; |
|||
|
|||
export default class GameEnemyTorba extends GameEnemy { |
|||
|
|||
constructor (game, image, position, moveSpeed) { |
|||
super(game, image, position); |
|||
|
|||
this.targetX = position.x; |
|||
this.moveSpeed = { |
|||
x: moveSpeed.x, |
|||
y: moveSpeed.y, |
|||
}; |
|||
|
|||
this.isDescending = true; |
|||
} |
|||
|
|||
update ( ) { |
|||
if (this.isDescending) { |
|||
if (this.position.y < 480) { |
|||
this.position.y += this.moveSpeed.y; |
|||
} else { |
|||
this.position.y = 480; |
|||
this.isDescending = false; |
|||
this.game.audio.playSound('beardson-touchdown'); |
|||
} |
|||
} |
|||
|
|||
if (Math.random() > 0.998) { |
|||
this.targetX = this.game.getRandomPlayfieldX(); |
|||
} |
|||
|
|||
if (this.position.x > this.targetX) { |
|||
this.position.x -= this.moveSpeed.x; |
|||
} |
|||
|
|||
if (this.position.x < this.targetX) { |
|||
this.position.x += this.moveSpeed.x; |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,89 @@ |
|||
// lib/game-voice-channels.js
|
|||
// Copyright (C) 2022 Rob Colbert @[email protected]
|
|||
// License: Apache-2.0
|
|||
|
|||
'use strict'; |
|||
|
|||
import { NiceLog } from "dtp-nice-game"; |
|||
|
|||
export class VoiceChannel { |
|||
|
|||
constructor (game, name) { |
|||
this.game = game; |
|||
this.name = name; |
|||
|
|||
this.log = new NiceLog(`VoiceChannel:${name}`); |
|||
this.log.enable(); |
|||
|
|||
this.playing = false; |
|||
|
|||
this.quips = [ ]; |
|||
} |
|||
|
|||
async loadQuip (soundId) { |
|||
if (this.quips.includes(soundId)) { |
|||
throw new Error(`Quip ${soundId} has already been loaded`); |
|||
} |
|||
this.quips.push(soundId); |
|||
return this.game.audio.loadSound(soundId, `/dist/assets/audio/vox/${soundId}.wav`); |
|||
} |
|||
|
|||
playRandomQuip ( ) { |
|||
this.log.debug('playRandomQuip', 'request to play random quipt', { playing: this.playing }); |
|||
if (this.playing) { |
|||
return; |
|||
} |
|||
|
|||
const soundId = this.getRandomQuipSoundId(); |
|||
this.log.debug('playRandomQuip', 'playing random voiceover sound', { soundId }); |
|||
const { source } = this.game.audio.playSound(soundId); |
|||
source.addEventListener('ended', ( ) => { |
|||
this.log.debug('playRandomQuip', 'quip ending', { soundId }); |
|||
this.playing = false; |
|||
}); |
|||
|
|||
this.playing = true; |
|||
} |
|||
|
|||
getRandomQuipSoundId ( ) { |
|||
if (!Array.isArray(this.quips) || (this.quips.length === 0)) { |
|||
throw new Error(`No valid quips loaded on channel "${this.name}"`); |
|||
} |
|||
const quipIdx = Math.floor(Math.random() * (this.quips.length - 1)); |
|||
const quipSoundId = this.quips[quipIdx]; |
|||
this.log.debug('getRandomQuipSoundId', 'selected a random quip', { quipIdx, quipSoundId }); |
|||
return quipSoundId; |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* GameVoiceChannels tracks audio playing in named channels and will prevent the |
|||
* game from playing a sound on a channel if a sound is currently playing on |
|||
* that channel. |
|||
*/ |
|||
export class GameVoiceChannels { |
|||
|
|||
constructor (game) { |
|||
this.game = game; |
|||
this.channels = { }; |
|||
} |
|||
|
|||
addChannel (channelName) { |
|||
const channel = new VoiceChannel(this.game, channelName); |
|||
this.channels[channelName] = channel; |
|||
return channel; |
|||
} |
|||
|
|||
getChannel (channelName) { |
|||
const channel = this.channels[channelName]; |
|||
if (!channel) { |
|||
throw new Error(`Invalid voice channel "${channelName}"`); |
|||
} |
|||
return channel; |
|||
} |
|||
|
|||
playSound (channelName, soundId) { |
|||
const channel = this.getChannel(channelName); |
|||
channel.playSound(soundId); |
|||
} |
|||
} |
Loading…
Reference in new issue