diff --git a/src/Events/Emitter.ts b/src/Events/Emitter.ts new file mode 100644 index 0000000..35f6b8a --- /dev/null +++ b/src/Events/Emitter.ts @@ -0,0 +1,20 @@ +import Map from "../DataTypes/Map"; +import EventQueue from "./EventQueue"; +import GameEvent from "./GameEvent"; + +export default class Emitter { + private eventQueue: EventQueue; + + constructor(){ + this.eventQueue = EventQueue.getInstance(); + } + + /** + * Emit and event of type eventType with the data packet data + * @param eventType + * @param data + */ + fireEvent(eventType: string, data: Map | Record = null): void { + this.eventQueue.addEvent(new GameEvent(eventType, data)); + } +} \ No newline at end of file diff --git a/src/Events/EventQueue.ts b/src/Events/EventQueue.ts index 103b991..2d88f8d 100644 --- a/src/Events/EventQueue.ts +++ b/src/Events/EventQueue.ts @@ -2,6 +2,7 @@ import Queue from "../DataTypes/Queue"; import Map from "../DataTypes/Map"; import GameEvent from "./GameEvent"; import Receiver from "./Receiver"; +import { GameEventType } from "./GameEventType"; export default class EventQueue { private static instance: EventQueue = null; @@ -65,8 +66,8 @@ export default class EventQueue { } // If a receiver is subscribed to all events, send it the event - if(this.receivers.has("all")){ - for(let receiver of this.receivers.get("all")){ + if(this.receivers.has(GameEventType.ALL)){ + for(let receiver of this.receivers.get(GameEventType.ALL)){ receiver.receive(event); } } diff --git a/src/Events/GameEventType.ts b/src/Events/GameEventType.ts new file mode 100644 index 0000000..5607f6c --- /dev/null +++ b/src/Events/GameEventType.ts @@ -0,0 +1,59 @@ +export enum GameEventType { + /** + * Mouse Down event. Has data: {position: Vec2 - Mouse Position} + */ + MOUSE_DOWN = "mouse_down", + /** + * Mouse Up event. Has data: {position: Vec2 - Mouse Position} + */ + MOUSE_UP = "mouse_up", + /** + * Mouse Move event. Has data: {position: Vec2 - Mouse Position} + */ + MOUSE_MOVE = "mouse_move", + + /** + * Key Down event. Has data: {key: string - The key that is down} + */ + KEY_DOWN = "key_down", + + /** + * Key Up event. Has data: {key: string - The key that is up} + */ + KEY_UP = "key_up", + + /** + * Canvas Blur event. Has data: {} + */ + CANVAS_BLUR = "canvas_blur", + + /** + * Start Recording event. Has data: {} + */ + START_RECORDING = "start_recording", + + /** + * Stop Recording event. Has data: {} + */ + STOP_RECORDING = "stop_recording", + + /** + * Play Recording event. Has data: {} + */ + PLAY_RECORDING = "play_recording", + + /** + * Play Sound event. Has data: {key: string, loop: boolean, holdReference: boolean } + */ + PLAY_SOUND = "play_sound", + + /** + * Play Sound event. Has data: {key: string} + */ + STOP_SOUND = "stop_sound", + + /** + * Encompasses all event types. Used for receivers only. + */ + ALL = "all", +} \ No newline at end of file diff --git a/src/Input/InputHandler.ts b/src/Input/InputHandler.ts index 8f5fe31..2fa56c9 100644 --- a/src/Input/InputHandler.ts +++ b/src/Input/InputHandler.ts @@ -1,6 +1,7 @@ import EventQueue from "../Events/EventQueue"; import Vec2 from "../DataTypes/Vec2"; import GameEvent from "../Events/GameEvent"; +import { GameEventType } from "../Events/GameEventType"; /** * Handles communication with the web browser to receive asynchronous events and send them to the event queue @@ -23,36 +24,36 @@ export default class InputHandler{ private handleMouseDown = (event: MouseEvent, canvas: HTMLCanvasElement): void => { let pos = this.getMousePosition(event, canvas); - let gameEvent = new GameEvent("mouse_down", {position: pos}); + let gameEvent = new GameEvent(GameEventType.MOUSE_DOWN, {position: pos}); this.eventQueue.addEvent(gameEvent); } private handleMouseUp = (event: MouseEvent, canvas: HTMLCanvasElement): void => { let pos = this.getMousePosition(event, canvas); - let gameEvent = new GameEvent("mouse_up", {position: pos}); + let gameEvent = new GameEvent(GameEventType.MOUSE_UP, {position: pos}); this.eventQueue.addEvent(gameEvent); } private handleMouseMove = (event: MouseEvent, canvas: HTMLCanvasElement): void => { let pos = this.getMousePosition(event, canvas); - let gameEvent = new GameEvent("mouse_move", {position: pos}); + let gameEvent = new GameEvent(GameEventType.MOUSE_MOVE, {position: pos}); this.eventQueue.addEvent(gameEvent); } private handleKeyDown = (event: KeyboardEvent): void => { let key = this.getKey(event); - let gameEvent = new GameEvent("key_down", {key: key}); + let gameEvent = new GameEvent(GameEventType.KEY_DOWN, {key: key}); this.eventQueue.addEvent(gameEvent); } private handleKeyUp = (event: KeyboardEvent): void => { let key = this.getKey(event); - let gameEvent = new GameEvent("key_up", {key: key}); + let gameEvent = new GameEvent(GameEventType.KEY_UP, {key: key}); this.eventQueue.addEvent(gameEvent); } private handleBlur = (event: Event): void => { - let gameEvent = new GameEvent("canvas_blur", {}); + let gameEvent = new GameEvent(GameEventType.CANVAS_BLUR, {}); this.eventQueue.addEvent(gameEvent); } diff --git a/src/Input/InputReceiver.ts b/src/Input/InputReceiver.ts index 4ffac5c..4a8b0b3 100644 --- a/src/Input/InputReceiver.ts +++ b/src/Input/InputReceiver.ts @@ -3,6 +3,8 @@ import Map from "../DataTypes/Map"; import Vec2 from "../DataTypes/Vec2"; import EventQueue from "../Events/EventQueue"; import Viewport from "../SceneGraph/Viewport"; +import GameEvent from "../Events/GameEvent"; +import { GameEventType } from "../Events/GameEventType"; /** * Receives input events from the event queue and allows for easy access of information about input @@ -31,7 +33,8 @@ export default class InputReceiver{ this.eventQueue = EventQueue.getInstance(); // Subscribe to all input events - this.eventQueue.subscribe(this.receiver, ["mouse_down", "mouse_up", "mouse_move", "key_down", "key_up", "canvas_blur"]); + this.eventQueue.subscribe(this.receiver, [GameEventType.MOUSE_DOWN, GameEventType.MOUSE_UP, GameEventType.MOUSE_MOVE, + GameEventType.KEY_DOWN, GameEventType.KEY_UP, GameEventType.CANVAS_BLUR]); } static getInstance(): InputReceiver{ @@ -50,21 +53,21 @@ export default class InputReceiver{ let event = this.receiver.getNextEvent(); // Handle each event type - if(event.type === "mouse_down"){ + if(event.type === GameEventType.MOUSE_DOWN){ this.mouseJustPressed = true; this.mousePressed = true; this.mousePressPosition = event.data.get("position"); } - if(event.type === "mouse_up"){ + if(event.type === GameEventType.MOUSE_UP){ this.mousePressed = false; } - if(event.type === "mouse_move"){ + if(event.type === GameEventType.MOUSE_MOVE){ this.mousePosition = event.data.get("position"); } - if(event.type === "key_down"){ + if(event.type === GameEventType.KEY_DOWN){ let key = event.data.get("key") if(!this.keyPressed.get(key)){ this.keyJustPressed.set(key, true); @@ -72,12 +75,12 @@ export default class InputReceiver{ } } - if(event.type === "key_up"){ + if(event.type === GameEventType.KEY_UP){ let key = event.data.get("key") this.keyPressed.set(key, false); } - if(event.type === "canvas_blur"){ + if(event.type === GameEventType.CANVAS_BLUR){ this.clearKeyPresses() } } diff --git a/src/MainScene.ts b/src/MainScene.ts index db2f9c2..dd19cde 100644 --- a/src/MainScene.ts +++ b/src/MainScene.ts @@ -8,7 +8,7 @@ import UIElement from "./Nodes/UIElement"; import Button from "./Nodes/UIElements/Button"; import Layer from "./Scene/Layer"; import SecondScene from "./SecondScene"; -import GameEvent from "./Events/GameEvent"; +import { GameEventType } from "./Events/GameEventType"; export default class MainScene extends Scene { @@ -42,7 +42,7 @@ export default class MainScene extends Scene { backgroundTilemap.getLayer().setAlpha(0.5); // Add the music and start playing it on a loop - this.emit("play_sound", {key: "level_music", loop: true, holdReference: true}); + this.emitter.fireEvent(GameEventType.PLAY_SOUND, {key: "level_music", loop: true, holdReference: true}); // Add the tilemap this.add.tilemap("platformer", OrthogonalTilemap); @@ -65,19 +65,19 @@ export default class MainScene extends Scene { recordButton.setSize(100, 50); recordButton.setText("Record"); recordButton.setPosition(400, 30); - recordButton.onClickEventId = "record_button_press"; + recordButton.onClickEventId = GameEventType.START_RECORDING; let stopButton = this.add.uiElement(Button, uiLayer); stopButton.setSize(100, 50); stopButton.setText("Stop"); stopButton.setPosition(550, 30); - stopButton.onClickEventId = "stop_button_press"; + stopButton.onClickEventId = GameEventType.STOP_RECORDING; let playButton = this.add.uiElement(Button, uiLayer); playButton.setSize(100, 50); playButton.setText("Play"); playButton.setPosition(700, 30); - playButton.onClickEventId = "play_button_press"; + playButton.onClickEventId = GameEventType.PLAY_RECORDING; let cycleFramerateButton = this.add.uiElement(Button, uiLayer); cycleFramerateButton.setSize(150, 50); @@ -123,7 +123,7 @@ export default class MainScene extends Scene { switchButton.setText("Change Scene"); switchButton.setPosition(340, 190); switchButton.onClick = () => { - this.emit("stop_sound", {key: "level_music"}); + this.emitter.fireEvent(GameEventType.STOP_SOUND, {key: "level_music"}); this.sceneManager.changeScene(SecondScene); } } diff --git a/src/Nodes/GameNode.ts b/src/Nodes/GameNode.ts index c062406..4864a1d 100644 --- a/src/Nodes/GameNode.ts +++ b/src/Nodes/GameNode.ts @@ -1,27 +1,27 @@ import EventQueue from "../Events/EventQueue"; import InputReceiver from "../Input/InputReceiver"; import Vec2 from "../DataTypes/Vec2"; -import Map from "../DataTypes/Map"; import Receiver from "../Events/Receiver"; -import GameEvent from "../Events/GameEvent"; +import Emitter from "../Events/Emitter"; import Scene from "../Scene/Scene"; import Layer from "../Scene/Layer"; /** * The representation of an object in the game world */ -export default abstract class GameNode{ - private eventQueue: EventQueue; +export default abstract class GameNode { protected input: InputReceiver; protected position: Vec2; - private receiver: Receiver; + protected receiver: Receiver; + protected emitter: Emitter; protected scene: Scene; protected layer: Layer; constructor(){ - this.eventQueue = EventQueue.getInstance(); this.input = InputReceiver.getInstance(); this.position = new Vec2(0, 0); + this.receiver = new Receiver(); + this.emitter = new Emitter(); } setScene(scene: Scene): void { @@ -52,24 +52,6 @@ export default abstract class GameNode{ } } - /** - * Subscribe this object's receiver to the specified event type - * @param eventType - */ - subscribe(eventType: string): void { - this.eventQueue.subscribe(this.receiver, eventType); - } - - /** - * Emit and event of type eventType with the data packet data - * @param eventType - * @param data - */ - emit(eventType: string, data: Map | Record = null): void { - let event = new GameEvent(eventType, data); - this.eventQueue.addEvent(event); - } - // TODO - This doesn't seem ideal. Is there a better way to do this? protected getViewportOriginWithParallax(): Vec2 { return this.scene.getViewport().getPosition().clone().mult(this.layer.getParallax()); diff --git a/src/Nodes/UIElement.ts b/src/Nodes/UIElement.ts index d46eefb..72face5 100644 --- a/src/Nodes/UIElement.ts +++ b/src/Nodes/UIElement.ts @@ -82,7 +82,7 @@ export default class UIElement extends CanvasNode{ } if(this.onClickEventId !== null){ let data = {}; - this.emit(this.onClickEventId, data); + this.emitter.fireEvent(this.onClickEventId, data); } } } @@ -104,7 +104,7 @@ export default class UIElement extends CanvasNode{ } if(this.onEnterEventId !== null){ let data = {}; - this.emit(this.onEnterEventId, data); + this.emitter.fireEvent(this.onEnterEventId, data); } } else if(this.isEntered) { @@ -115,7 +115,7 @@ export default class UIElement extends CanvasNode{ } if(this.onLeaveEventId !== null){ let data = {}; - this.emit(this.onLeaveEventId, data); + this.emitter.fireEvent(this.onLeaveEventId, data); } } else if(this.isClicked) { // If mouse is dragged off of element while down, it is not clicked anymore diff --git a/src/Playback/Recorder.ts b/src/Playback/Recorder.ts index 71683b4..c9f2ff6 100644 --- a/src/Playback/Recorder.ts +++ b/src/Playback/Recorder.ts @@ -2,6 +2,7 @@ import Queue from "../DataTypes/Queue"; import Receiver from "../Events/Receiver"; import GameEvent from "../Events/GameEvent"; import EventQueue from "../Events/EventQueue"; +import { GameEventType } from "../Events/GameEventType"; export default class Recorder{ private receiver: Receiver; @@ -53,7 +54,7 @@ export default class Recorder{ while(this.receiver.hasNextEvent()){ let event = this.receiver.getNextEvent(); - if(event.type === "stop_button_press"){ + if(event.type === GameEventType.STOP_RECORDING){ this.recording = false; } @@ -61,13 +62,13 @@ export default class Recorder{ this.log.enqueue(new LogItem(this.frame, deltaT, event)); } - if(event.type === "record_button_press"){ + if(event.type === GameEventType.START_RECORDING){ this.log.clear(); this.recording = true; this.frame = 0 } - if(event.type === "play_button_press"){ + if(event.type === GameEventType.PLAY_RECORDING){ this.frame = 0; this.recording = false; this.playing = true; diff --git a/src/Player.ts b/src/Player.ts index e47a317..7f599f4 100644 --- a/src/Player.ts +++ b/src/Player.ts @@ -3,6 +3,7 @@ import Vec2 from "./DataTypes/Vec2"; import Debug from "./Debug/Debug"; import AABB from "./Physics/Colliders/AABB"; import CanvasNode from "./Nodes/CanvasNode"; +import { GameEventType } from "./Events/GameEventType"; export default class Player extends PhysicsNode { velocity: Vec2; @@ -83,7 +84,7 @@ export default class Player extends PhysicsNode { if(this.grounded){ if(dir.y === -1){ // Jumping - this.emit("play_sound", {key: "player_jump"}); + this.emitter.fireEvent(GameEventType.PLAY_SOUND, {key: "player_jump"}); } vel.y = dir.y*1800; } diff --git a/src/Scene/Scene.ts b/src/Scene/Scene.ts index ec2f0f9..9db1acb 100644 --- a/src/Scene/Scene.ts +++ b/src/Scene/Scene.ts @@ -10,9 +10,8 @@ import Tilemap from "../Nodes/Tilemap"; import ResourceManager from "../ResourceManager/ResourceManager"; import GameLoop from "../Loop/GameLoop"; import SceneManager from "./SceneManager"; -import EventQueue from "../Events/EventQueue"; -import GameEvent from "../Events/GameEvent"; -import Map from "../DataTypes/Map"; +import Receiver from "../Events/Receiver"; +import Emitter from "../Events/Emitter"; export default class Scene{ protected layers: Stack; @@ -21,6 +20,8 @@ export default class Scene{ protected running: boolean; protected game: GameLoop; protected sceneManager: SceneManager; + protected receiver: Receiver; + protected emitter: Emitter; protected tilemaps: Array; @@ -48,6 +49,8 @@ export default class Scene{ this.running = false; this.game = game; this.sceneManager = sceneManager; + this.receiver = new Receiver(); + this.emitter = new Emitter(); this.tilemaps = new Array(); this.sceneGraph = new SceneGraphArray(this.viewport, this); @@ -146,14 +149,4 @@ export default class Scene{ getViewport(): Viewport { return this.viewport; } - - /** - * Emit and event of type eventType with the data packet data - * @param eventType - * @param data - */ - emit(eventType: string, data: Map | Record = null): void { - let event = new GameEvent(eventType, data); - EventQueue.getInstance().addEvent(event); - } } \ No newline at end of file diff --git a/src/SecondScene.ts b/src/SecondScene.ts index bb9f623..234177b 100644 --- a/src/SecondScene.ts +++ b/src/SecondScene.ts @@ -7,6 +7,7 @@ import Vec2 from "./DataTypes/Vec2"; import UIElement from "./Nodes/UIElement"; import Button from "./Nodes/UIElements/Button"; import Layer from "./Scene/Layer"; +import { GameEventType } from "./Events/GameEventType"; export default class SecondScene extends Scene { @@ -40,7 +41,7 @@ export default class SecondScene extends Scene { backgroundTilemap.getLayer().setAlpha(0.2); // Add the music and start playing it on a loop - this.emit("play_sound", {key: "level_music", loop: true, holdReference: true}); + this.emitter.fireEvent(GameEventType.PLAY_SOUND, {key: "level_music", loop: true, holdReference: true}); // Add the tilemap this.add.tilemap("level2", OrthogonalTilemap); @@ -63,19 +64,19 @@ export default class SecondScene extends Scene { recordButton.setSize(100, 50); recordButton.setText("Record"); recordButton.setPosition(400, 30); - recordButton.onClickEventId = "record_button_press"; + recordButton.onClickEventId = GameEventType.START_RECORDING; let stopButton = this.add.uiElement(Button, uiLayer); stopButton.setSize(100, 50); stopButton.setText("Stop"); stopButton.setPosition(550, 30); - stopButton.onClickEventId = "stop_button_press"; + stopButton.onClickEventId = GameEventType.STOP_RECORDING; let playButton = this.add.uiElement(Button, uiLayer); playButton.setSize(100, 50); playButton.setText("Play"); playButton.setPosition(700, 30); - playButton.onClickEventId = "play_button_press"; + playButton.onClickEventId = GameEventType.PLAY_RECORDING; let cycleFramerateButton = this.add.uiElement(Button, uiLayer); cycleFramerateButton.setSize(150, 50); diff --git a/src/Sound/AudioManager.ts b/src/Sound/AudioManager.ts index 4006f3a..f440bf8 100644 --- a/src/Sound/AudioManager.ts +++ b/src/Sound/AudioManager.ts @@ -1,6 +1,7 @@ import Map from "../DataTypes/Map"; import Receiver from "../Events/Receiver"; import ResourceManager from "../ResourceManager/ResourceManager"; +import { GameEventType } from "../Events/GameEventType"; export default class AudioManager { private static instance: AudioManager; @@ -12,7 +13,7 @@ export default class AudioManager { private constructor(){ this.initAudio(); this.receiver = new Receiver(); - this.receiver.subscribe(["play_sound", "stop_sound"]); + this.receiver.subscribe([GameEventType.PLAY_SOUND, GameEventType.STOP_SOUND]); this.currentSounds = new Map(); } @@ -117,14 +118,14 @@ export default class AudioManager { // TODO - Add logic to merge sounds if there are multiple of the same key while(this.receiver.hasNextEvent()){ let event = this.receiver.getNextEvent(); - if(event.type === "play_sound"){ + if(event.type === GameEventType.PLAY_SOUND){ let soundKey = event.data.get("key"); let loop = event.data.get("loop"); let holdReference = event.data.get("holdReference"); this.playSound(soundKey, loop, holdReference); } - if(event.type === "stop_sound"){ + if(event.type === GameEventType.STOP_SOUND){ let soundKey = event.data.get("key"); this.stopSound(soundKey); }