Add some sound functionality
parent
dd066f0aa3
commit
c5a4167846
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -40,6 +40,11 @@ export default class ItemBuilder {
|
|||
return this;
|
||||
}
|
||||
|
||||
withDropCallback(callback) {
|
||||
this.item.addDropCallback(callback);
|
||||
return this;
|
||||
}
|
||||
|
||||
withTickCallback(callback) {
|
||||
this.item.addTickCallback(callback);
|
||||
return this;
|
||||
|
|
|
@ -3,6 +3,6 @@ export default function EchoCommand(args, context) {
|
|||
context.print(`Usage: echo <on/off>`);
|
||||
} else {
|
||||
context.setInputEcho(args[1] == "on" ? true : false);
|
||||
context.print(`Command echo is now ${args[1]}`);
|
||||
context.print(`Command echo is now ${args[1]}.`);
|
||||
}
|
||||
}
|
|
@ -12,7 +12,7 @@ export default function LookCommand(args, context) {
|
|||
}
|
||||
}
|
||||
if (!item) {
|
||||
context.output.say(`I could not find a ${args[1]}`);
|
||||
context.output.say(`I could not find a ${args[1]}.`);
|
||||
} else {
|
||||
context.output.say(item.name);
|
||||
context.output.say(item.description);
|
||||
|
|
|
@ -9,14 +9,14 @@ export default function TakeCommand(args, context) {
|
|||
}
|
||||
}
|
||||
if (!item) {
|
||||
context.print(`You can't find any ${args[1]}`);
|
||||
context.print(`You can't find any ${args[1]}.`);
|
||||
} else {
|
||||
if (!item.takeable) {
|
||||
context.print(`You can't take ${item.name}`);
|
||||
context.print(`You can't take ${item.name}.`);
|
||||
} else {
|
||||
room.removeItem(item.id);
|
||||
context.player.addItem(item.id);
|
||||
context.print(`You take ${item.name}`);
|
||||
context.print(`You take ${item.name}.`);
|
||||
item.onTake();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,7 +9,16 @@ export default async function UseCommand(args, context) {
|
|||
}
|
||||
}
|
||||
if (!item) {
|
||||
context.output.say(`I could not find a ${args[1]}`);
|
||||
const items = context.player.getInventory();
|
||||
for (let i of items) {
|
||||
if (i.name.includes(args[1])) {
|
||||
item = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!item) {
|
||||
context.output.say(`I could not find a ${args[1]}.`);
|
||||
} else {
|
||||
await item.onUse();
|
||||
}
|
||||
|
|
|
@ -24,7 +24,6 @@ export default class Game {
|
|||
}
|
||||
|
||||
init(data) {
|
||||
console.log(data);
|
||||
this.rooms = data.rooms.map((room) => {
|
||||
room.context = this;
|
||||
return room;
|
||||
|
@ -33,7 +32,7 @@ export default class Game {
|
|||
item.context = this;
|
||||
return item;
|
||||
});
|
||||
this.state = data.state;
|
||||
this.state = data.state || State;
|
||||
this.commandHandler.addCommands(data.commands);
|
||||
this.player = new Player();
|
||||
this.player.context = this;
|
||||
|
@ -70,16 +69,38 @@ export default class Game {
|
|||
examineItems() {
|
||||
const room = this.getRoom(this.player.currentRoom);
|
||||
const items = room.getItems();
|
||||
items.forEach((item) => this.output.say(item.name));
|
||||
if (items.length < 1) return;
|
||||
let itemDescription = `You see `;
|
||||
items.forEach((item, index) => {
|
||||
if (index < items.length - 2) {
|
||||
itemDescription += `${item.name}, `;
|
||||
} else if (index < items.length - 1) {
|
||||
itemDescription += `${item.name} and `;
|
||||
} else {
|
||||
itemDescription += item.name
|
||||
}
|
||||
});
|
||||
this.output.say(itemDescription + ".");
|
||||
}
|
||||
|
||||
examineExits() {
|
||||
const room = this.getRoom(this.player.currentRoom);
|
||||
let exits = [];
|
||||
let exitDescription = "You can go ";
|
||||
for (let exit of room.exits.keys()) {
|
||||
exitDescription += " " + exit;
|
||||
const exitKeys = room.exits.keys();
|
||||
for (let exit of exitKeys) {
|
||||
exits.push(exit);
|
||||
}
|
||||
this.output.say(exitDescription);
|
||||
exits.forEach((item, index) => {
|
||||
if (index < exits.length - 2) {
|
||||
exitDescription += `${item}, `;
|
||||
} else if (index < exits.length - 1) {
|
||||
exitDescription += `${item} and `;
|
||||
} else {
|
||||
exitDescription += item
|
||||
}
|
||||
});
|
||||
this.output.say(exitDescription + ".");
|
||||
}
|
||||
|
||||
getRoom(id) {
|
||||
|
|
|
@ -17,9 +17,12 @@ export default class Item {
|
|||
}
|
||||
|
||||
async onTake() {
|
||||
if (this.takeCallback) return this.takeCallback();
|
||||
if (this.takeCallback) return this.takeCallback(this.context);
|
||||
}
|
||||
|
||||
async onDrop() {
|
||||
if (this.dropCallback) return this.dropCallback(this.context);
|
||||
}
|
||||
async onTick() {
|
||||
if (this.tickCallback) return this.tickCallback(this.context);
|
||||
}
|
||||
|
|
|
@ -1,13 +1,16 @@
|
|||
import { TTS } from '../framework/tts';
|
||||
import { AriaOutput } from '../framework/tts/outputs/aria';
|
||||
import Sound from './sound';
|
||||
|
||||
export default class Output {
|
||||
constructor() {
|
||||
this.tts = new TTS(new AriaOutput());
|
||||
this.history = document.getElementById("output-area");
|
||||
this.sound = new Sound();
|
||||
}
|
||||
|
||||
say(string) {
|
||||
this.sound.play(`assets/scroll.wav`);
|
||||
const node = document.createElement("p");
|
||||
string.split("\n").forEach((line) => {
|
||||
node.appendChild(document.createTextNode(line));
|
||||
|
@ -16,4 +19,8 @@ export default class Output {
|
|||
this.history.appendChild(node);
|
||||
// this.tts.speak(string);
|
||||
}
|
||||
|
||||
play(file) {
|
||||
this.sound.play(file);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
import Resonator from '../framework/resonator';
|
||||
|
||||
|
||||
export default class Sound {
|
||||
constructor() {
|
||||
this.res = new Resonator();
|
||||
this.res.setEnvironmentImpulse(`assets/Greek7EchoHall.wav`);
|
||||
this.ambience = null;
|
||||
this.music = null;
|
||||
this.previousAmbience = null;
|
||||
this.previousMusic = null;
|
||||
}
|
||||
|
||||
play(file) {
|
||||
const sound = this.res.loadImmediate(file);
|
||||
sound.play();
|
||||
}
|
||||
}
|
|
@ -4,6 +4,9 @@ class State {
|
|||
}
|
||||
|
||||
get(key) {
|
||||
if (!this.states.has(key)) {
|
||||
return null;
|
||||
}
|
||||
return this.states.get(key);
|
||||
}
|
||||
|
||||
|
|
|
@ -32,4 +32,6 @@ export default class AudioSource implements BaseSource {
|
|||
stop(): void;
|
||||
destroy(): void;
|
||||
loop(value: boolean): void;
|
||||
fadeOut(time: number): void;
|
||||
fadeIn(time: number): void;
|
||||
}
|
||||
|
|
|
@ -129,4 +129,18 @@ export default class AudioSource {
|
|||
this.node.loop = value;
|
||||
}
|
||||
}
|
||||
fadeOut(time) {
|
||||
if (!this.node) {
|
||||
return;
|
||||
}
|
||||
this.gain.gain.exponentialRampToValueAtTime(0.0001, this.context.getContext().currentTime + time);
|
||||
setTimeout(() => this.stop(), time * 1000);
|
||||
}
|
||||
fadeIn(time) {
|
||||
if (!this.node) {
|
||||
this.play();
|
||||
}
|
||||
this.gain.gain.setValueAtTime(0, this.context.getContext().currentTime);
|
||||
this.gain.gain.exponentialRampToValueAtTime(this.volume, this.context.getContext().currentTime + time);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,5 +6,7 @@ export interface BaseSource {
|
|||
setVolume(value: number): void;
|
||||
getVolume(): number;
|
||||
loop(value: boolean): void;
|
||||
fadeOut(time: number): void;
|
||||
fadeIn(time: number): void;
|
||||
destroy(): void;
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ export declare class StreamingSource implements BaseSource {
|
|||
private node;
|
||||
private canPlay;
|
||||
private sceneNode;
|
||||
private gain;
|
||||
private position;
|
||||
constructor(graph: AudioGraph, scene: ResonatorScene, context: ResonatorAudioContext, element: HTMLAudioElement, type?: SourceType);
|
||||
private init;
|
||||
|
@ -27,4 +28,6 @@ export declare class StreamingSource implements BaseSource {
|
|||
setPosition(x: number, y: number, z: number): void;
|
||||
destroy(): void;
|
||||
loop(value: boolean): void;
|
||||
fadeIn(time: number): void;
|
||||
fadeOut(time: number): void;
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@ export class StreamingSource {
|
|||
}
|
||||
init() {
|
||||
this.node = this.context.createMediaElementSource(this.element);
|
||||
this.gain = this.context.createGain();
|
||||
this.createConnections();
|
||||
this.element.addEventListener('canplay', (event) => {
|
||||
this.canPlay = true;
|
||||
|
@ -50,7 +51,8 @@ export class StreamingSource {
|
|||
if (!this.sceneNode) {
|
||||
this.sceneNode = this.scene.createSource();
|
||||
}
|
||||
this.node.connect(this.sceneNode);
|
||||
this.node.connect(this.gain);
|
||||
this.gain.connect(this.sceneNode);
|
||||
break;
|
||||
default:
|
||||
this.graph.connectToMaster(this.node);
|
||||
|
@ -78,4 +80,18 @@ export class StreamingSource {
|
|||
loop(value) {
|
||||
this.element.loop = true;
|
||||
}
|
||||
fadeIn(time) {
|
||||
if (!this.node) {
|
||||
this.play();
|
||||
}
|
||||
this.gain.gain.setValueAtTime(0, this.context.getContext().currentTime);
|
||||
this.gain.gain.exponentialRampToValueAtTime(this.getVolume(), this.context.getContext().currentTime + time);
|
||||
}
|
||||
fadeOut(time) {
|
||||
if (!this.node) {
|
||||
return;
|
||||
}
|
||||
this.gain.gain.exponentialRampToValueAtTime(0.0001, this.context.getContext().currentTime + time);
|
||||
setTimeout(() => this.stop(), time * 1000);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
import ItemBuilder from "../../engine/builders/item";
|
||||
import Item from "../../engine/item";
|
||||
|
||||
export default new ItemBuilder()
|
||||
.withID("cup")
|
||||
.withName("a cup")
|
||||
.withDescription("A standard coffee cup")
|
||||
.isTakeable(true)
|
||||
.isUsable(false)
|
||||
.create();
|
|
@ -1,5 +1,9 @@
|
|||
import Stone from './stone';
|
||||
import Torch from './torch';
|
||||
import Cup from './cup';
|
||||
|
||||
export default [
|
||||
Stone
|
||||
Stone,
|
||||
Torch,
|
||||
Cup
|
||||
]
|
|
@ -2,13 +2,16 @@ import ItemBuilder from "../../engine/builders/item";
|
|||
|
||||
export default new ItemBuilder()
|
||||
.withID("stone")
|
||||
.withName("A dull stone")
|
||||
.withName("a dull stone")
|
||||
.withDescription("There is nothing remarkable about this rough, bland stone.")
|
||||
.isTakeable(true)
|
||||
.isUsable(true)
|
||||
.withTakeCallback(async function(context) {
|
||||
context.print(`The ${this.id} feels heavy in your hands.`);
|
||||
})
|
||||
.withDropCallback(async function(context) {
|
||||
context.print(`It bounces back and forth a little.`)
|
||||
})
|
||||
.withUseCallback(async function(context) {
|
||||
context.print(`You can't really figure out what to do with ${this.name} yet`);
|
||||
})
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
import ItemBuilder from "../../engine/builders/item";
|
||||
|
||||
export default new ItemBuilder()
|
||||
.withID("torch")
|
||||
.withName("a torch")
|
||||
.withDescription("A standard torch that provides light.")
|
||||
.isUsable(true)
|
||||
.isTakeable(true)
|
||||
.withUseCallback(async function(context) {
|
||||
context.print(`You try to light the torch but fail.`)
|
||||
})
|
||||
.create();
|
|
@ -1,7 +1,9 @@
|
|||
import Start from './start';
|
||||
import Tunnel1 from './tunnel1';
|
||||
import tunnel2 from './tunnel2';
|
||||
|
||||
export default [
|
||||
Start,
|
||||
Tunnel1
|
||||
Tunnel1,
|
||||
tunnel2
|
||||
];
|
|
@ -3,15 +3,17 @@ import RoomBuilder from '../../engine/builders/room';
|
|||
export default new RoomBuilder()
|
||||
.withID("start")
|
||||
.withTitle("The starting room")
|
||||
.withFirstDescription(`
|
||||
You set foot in your very first ever room.
|
||||
.withFirstDescription(
|
||||
`You set foot in your very first ever room.
|
||||
You're not quite sure what you were supposed to expect, but it definitely wasn't this.
|
||||
I mean who would expect a boring old room like this one? Ugh.
|
||||
Just... make it stop. Please.
|
||||
`)
|
||||
Just... make it stop. Please.`
|
||||
)
|
||||
.withDescription("The first room. Nothing special about it.")
|
||||
.withExit("north", "tunnel_1")
|
||||
.withExit("northwest", "tunnel_2")
|
||||
.withEnterCallback(async function(context) {
|
||||
if (context.state.get("start.awoken")) return;
|
||||
const { output, wait } = context;
|
||||
context.enableCommandInput(false);
|
||||
output.say("You slowly wake up");
|
||||
|
@ -20,6 +22,9 @@ Just... make it stop. Please.
|
|||
await wait(5000);
|
||||
output.say("Yet here we are.");
|
||||
context.enableCommandInput(true);
|
||||
context.state.set("start.awoken", true);
|
||||
})
|
||||
.withItem("stone")
|
||||
.withItem("cup")
|
||||
.withItem("torch")
|
||||
.create();
|
|
@ -0,0 +1,13 @@
|
|||
import RoomBuilder from "../../engine/builders/room";
|
||||
|
||||
export default new RoomBuilder()
|
||||
.withID("tunnel_2")
|
||||
.withTitle("A long, winding tunnel")
|
||||
.withFirstDescription(
|
||||
`You step out from your hidy hole into a thin, winding tunnel. The walls and ceiling appear to get thinner and thinner, space slowly dwindling away to nothing.`
|
||||
)
|
||||
.withDescription(
|
||||
`A tunnel that ends in a bowl shape.`
|
||||
)
|
||||
.withExit("southeast", "start")
|
||||
.create();
|
|
@ -18,6 +18,11 @@ module.exports = {
|
|||
title: Package.name,
|
||||
template: path.join(__dirname, "src/game/index.html")
|
||||
}),
|
||||
new CopyWebpackPlugin({
|
||||
patterns: [
|
||||
{ from: 'assets', to: 'assets' },
|
||||
]
|
||||
})
|
||||
],
|
||||
module: {
|
||||
rules: [
|
||||
|
@ -28,7 +33,7 @@ module.exports = {
|
|||
]
|
||||
},
|
||||
resolve: {
|
||||
extensions: [ '.ts', '.js' ]
|
||||
extensions: ['.ts', '.js']
|
||||
},
|
||||
output: {
|
||||
filename: 'game.js',
|
||||
|
|
Loading…
Reference in New Issue