Skip to content

Commit 948f293

Browse files
authored
Merge pull request #38 from SaltieRL/pa-bug-fixes
General bug fixes and adjustments
2 parents 6f1de55 + ed88a9e commit 948f293

File tree

17 files changed

+215
-78
lines changed

17 files changed

+215
-78
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "replay-viewer",
3-
"version": "0.3.3",
3+
"version": "0.4.0",
44
"description": "Rocket League replay viewer React component and tooling",
55
"main": "./lib/index.js",
66
"types": "./lib/index.d.ts",

src/constants/eventNames.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
11
export const CAMERA_CHANGE = "CAMERA_CHANGE"
22
export const CAMERA_FRAME_UPDATE = "CAMERA_FRAME_UPDATE"
33
export const PLAY_PAUSE = "PLAY_PAUSE"
4+
export const FRAME = "FRAME"
5+
export const CANVAS_RESIZE = "CANVAS_RESIZE"

src/eventbus/EventBus.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@ class EventBus {
3131
if (!this.listeners[type]) {
3232
this.listeners[type] = []
3333
}
34+
// Remove duplicate event listeners
35+
this.removeEventListener(type, callback, scope)
36+
// Add this listener to the list
3437
this.listeners[type].push({ type, callback, scope })
3538
}
3639

src/eventbus/events/cameraChange.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@ import { Camera } from "three"
33
import { CAMERA_CHANGE } from "../../constants/eventNames"
44
import EventBus from "../EventBus"
55

6+
/**
7+
* Event fired when the active camera is updated with a new object.
8+
*/
69
export interface CameraChangeEvent {
710
camera: Camera
811
}

src/eventbus/events/cameraFrameUpdate.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@ import { Vector3 } from "three"
33
import { CAMERA_FRAME_UPDATE } from "../../constants/eventNames"
44
import EventBus from "../EventBus"
55

6+
/**
7+
* Event that fires telling all cameras to adjust their settings.
8+
*/
69
export interface CameraFrameUpdateEvent {
710
ballPosition: Vector3
811
ballCam: boolean
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import { CANVAS_RESIZE } from "../../constants/eventNames"
2+
import EventBus from "../EventBus"
3+
4+
/**
5+
* Fires when the main canvas is resized and its dimensions are adjusted.
6+
*/
7+
export interface CanvasResizeEvent {
8+
width: number
9+
height: number
10+
}
11+
12+
export const {
13+
addEventListener: addCanvasResizeListener,
14+
removeEventListener: removeCanvasResizeListener,
15+
dispatch: dispatchCanvasResizeEvent,
16+
} = EventBus.buildEvent<CanvasResizeEvent>(CANVAS_RESIZE)

src/eventbus/events/frame.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import { FRAME } from "../../constants/eventNames"
2+
import EventBus from "../EventBus"
3+
4+
/**
5+
* Fires each time the global game clock advances a frame or updates its current frame.
6+
*/
7+
export interface FrameEvent {
8+
frame: number
9+
}
10+
11+
export const {
12+
addEventListener: addFrameListener,
13+
removeEventListener: removeFrameListener,
14+
dispatch: dispatchFrameEvent,
15+
} = EventBus.buildEvent<FrameEvent>(FRAME)

src/eventbus/events/playPause.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import { PLAY_PAUSE } from "../../constants/eventNames"
2+
import EventBus from "../EventBus"
3+
4+
/**
5+
* Fires when the global game clock has paused.
6+
*/
7+
export interface PlayPauseEvent {
8+
paused: boolean
9+
}
10+
11+
export const {
12+
addEventListener: addPlayPauseListener,
13+
removeEventListener: removePlayPauseListener,
14+
dispatch: dispatchPlayPauseEvent,
15+
} = EventBus.buildEvent<PlayPauseEvent>(PLAY_PAUSE)

src/managers/CameraManager.ts

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,12 @@ import {
88
} from "../constants/gameObjectNames"
99
import { dispatchCameraChange } from "../eventbus/events/cameraChange"
1010
import { dispatchCameraFrameUpdate } from "../eventbus/events/cameraFrameUpdate"
11+
import {
12+
addCanvasResizeListener,
13+
CanvasResizeEvent,
14+
removeCanvasResizeListener,
15+
} from "../eventbus/events/canvasResize"
16+
import { addFrameListener, removeFrameListener } from "../eventbus/events/frame"
1117
import SceneManager from "./SceneManager"
1218

1319
const ORTHOGRAPHIC_CAMERA_NAMES: string[] = Object.keys(ORTHOGRAPHIC).map(
@@ -33,15 +39,18 @@ class CameraManager {
3339

3440
this.activeCamera.position.z = 5000
3541
this.activeCamera.position.y = 750
42+
43+
addFrameListener(this.update)
44+
addCanvasResizeListener(this.updateSize)
3645
}
3746

38-
updateSize(width: number, height: number) {
47+
private readonly updateSize = ({ width, height }: CanvasResizeEvent) => {
3948
this.width = width
4049
this.height = height
4150
this.updateCameraSize()
4251
}
4352

44-
update() {
53+
private readonly update = () => {
4554
const { position } = SceneManager.getInstance().ball.ball
4655
dispatchCameraFrameUpdate({
4756
ballPosition: position,
@@ -105,6 +114,25 @@ class CameraManager {
105114
camera.aspect = width / height
106115
camera.updateProjectionMatrix()
107116
} else if (camera instanceof OrthographicCamera) {
117+
/**
118+
* Here, we are computing the zoom of the camera given the aspect ratio. For cameras with an
119+
* aspect ratio greater than 4:3, we base the zoom on the height. Otherwise, we use width. The
120+
* minimum zoom should always be 0.02.
121+
*
122+
* The zoom when based on the height is a simple linear function y = x / 12500 + 0.01, where x
123+
* is the new height and y is the desired zoom.
124+
*
125+
* The denominator of the width-based computation is simply the slope of the previous
126+
* function, 12500, multiplied by 1.3 since this is aspect ratio breaking point we have set in
127+
* the if statement.
128+
*/
129+
if (width / height > 1.3) {
130+
const newZoom = height / 12500 + 0.01
131+
camera.zoom = Math.max(newZoom, 0.02)
132+
} else {
133+
const newZoom = width / 16250 + 0.01
134+
camera.zoom = Math.max(newZoom, 0.02)
135+
}
108136
camera.left = -width / 2
109137
camera.right = width / 2
110138
camera.top = height / 2
@@ -116,6 +144,7 @@ class CameraManager {
116144
private setActiveCamera(camera: Camera) {
117145
this.activeCamera = camera
118146
this.updateCameraSize()
147+
this.update()
119148
}
120149

121150
/**
@@ -134,6 +163,14 @@ class CameraManager {
134163
CameraManager.instance = new CameraManager()
135164
return CameraManager.instance
136165
}
166+
static destruct() {
167+
const { instance } = CameraManager
168+
if (instance) {
169+
removeFrameListener(instance.update)
170+
removeCanvasResizeListener(instance.updateSize)
171+
CameraManager.instance = undefined
172+
}
173+
}
137174
}
138175

139176
export interface CameraLocationOptions {

src/managers/GameManager.ts

Lines changed: 54 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,26 @@ import { WebGLRenderer } from "three"
22

33
import defaultGameBuilder from "../builders/GameBuilder"
44
import EventBus from "../eventbus/EventBus"
5-
import FPSClock, { FPSClockSubscriberOptions } from "../utils/FPSClock"
5+
import {
6+
addCameraChangeListener,
7+
removeCameraChangeListener,
8+
} from "../eventbus/events/cameraChange"
9+
import {
10+
addCanvasResizeListener,
11+
CanvasResizeEvent,
12+
removeCanvasResizeListener,
13+
} from "../eventbus/events/canvasResize"
14+
import {
15+
addFrameListener,
16+
FrameEvent,
17+
removeFrameListener,
18+
} from "../eventbus/events/frame"
19+
import {
20+
addPlayPauseListener,
21+
PlayPauseEvent,
22+
removePlayPauseListener,
23+
} from "../eventbus/events/playPause"
24+
import FPSClock from "../utils/FPSClock"
625
import AnimationManager from "./AnimationManager"
726
import CameraManager from "./CameraManager"
827
import SceneManager from "./SceneManager"
@@ -21,18 +40,22 @@ export class GameManager {
2140
this.animate = this.animate.bind(this)
2241
this.render = this.render.bind(this)
2342
this.clock = clock
24-
clock.subscribe(this.animate)
2543

2644
AnimationManager.getInstance().playAnimationClips()
45+
addPlayPauseListener(this.onPlayPause)
46+
addFrameListener(this.animate)
47+
addCanvasResizeListener(this.updateSize)
48+
addCameraChangeListener(this.render)
2749
}
2850

29-
animate({ }: FPSClockSubscriberOptions) {
51+
onPlayPause = ({ paused }: PlayPauseEvent) => {
52+
paused ? this.clock.pause() : this.clock.play()
53+
}
54+
55+
animate({ }: FrameEvent) {
3056
const delta = this.clock.getDelta()
31-
CameraManager.getInstance().update()
3257

3358
if (delta) {
34-
SceneManager.getInstance().update()
35-
CameraManager.getInstance().update()
3659
AnimationManager.getInstance().updateAnimationClips(delta)
3760
this.render()
3861
}
@@ -42,31 +65,26 @@ export class GameManager {
4265
return this.renderer.domElement
4366
}
4467

45-
updateSize(width: number = 640, height: number = 480) {
46-
CameraManager.getInstance().updateSize(width, height)
47-
this.renderer.setSize(width, height)
48-
this.render()
49-
}
50-
51-
render() {
68+
private readonly render = () => {
5269
const { scene } = SceneManager.getInstance()
5370
const { activeCamera } = CameraManager.getInstance()
5471
this.renderer.render(scene, activeCamera)
5572
}
5673

57-
static builder = defaultGameBuilder
58-
59-
private destruct() {
60-
this.clock.unsubscribe(this.animate)
61-
this.clock.reset()
62-
EventBus.reset()
74+
private readonly updateSize = ({
75+
width = 640,
76+
height = 480,
77+
}: CanvasResizeEvent) => {
78+
this.renderer.setSize(width, height)
79+
this.render()
6380
}
6481

6582
/**
6683
* ========================================
6784
* Managers are singletons
6885
* ========================================
6986
*/
87+
static builder = defaultGameBuilder
7088
private static instance?: GameManager
7189
static getInstance() {
7290
if (!GameManager.instance) {
@@ -75,10 +93,24 @@ export class GameManager {
7593
return GameManager.instance
7694
}
7795
static init(options: GameManagerOptions) {
78-
if (GameManager.instance) {
79-
GameManager.instance.destruct()
80-
}
8196
GameManager.instance = new GameManager(options)
8297
return GameManager.instance
8398
}
99+
static destruct() {
100+
// Destruct other managers
101+
SceneManager.destruct()
102+
CameraManager.destruct()
103+
104+
// Handle destruction of the existing game
105+
const { instance } = GameManager
106+
if (instance) {
107+
removePlayPauseListener(instance.onPlayPause)
108+
removeFrameListener(instance.animate)
109+
removeCanvasResizeListener(instance.updateSize)
110+
removeCameraChangeListener(instance.render)
111+
instance.clock.reset()
112+
EventBus.reset()
113+
GameManager.instance = undefined
114+
}
115+
}
84116
}

0 commit comments

Comments
 (0)