This repository was archived by the owner on Apr 1, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 299
/
Copy pathTutorialGameplayManager.ts
120 lines (94 loc) · 3.3 KB
/
TutorialGameplayManager.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
/**
* TutorialManager
*/
import * as Oni from "oni-api"
import { Event, IEvent } from "oni-types"
import { ITutorial, ITutorialMetadata, ITutorialStage } from "./ITutorial"
export interface ITutorialState {
metadata: ITutorialMetadata
renderFunc?: (context: Oni.BufferLayerRenderContext) => JSX.Element
activeGoalIndex: number
goals: string[]
}
/**
* Class that manages the state / lifecycle of the tutorial
* - Calls the 'tick' function
* - Calls the 'render' function
*/
export const TICK_RATE = 50 /* 50 ms, or 20 times pers second */
export class TutorialGameplayManager {
private _activeTutorial: ITutorial
private _currentStageIdx: number
private _onStateChanged = new Event<ITutorialState>("TutorialGameplayManager::onStateChanged")
private _onCompleted = new Event<boolean>("TutorialGameplayManager::onCompleted")
private _currentState: ITutorialState = null
private _onTick = new Event<void>("TutorialGameplayManager::onTick")
private _isTickInProgress: boolean = false
private _buf: Oni.Buffer
private _pendingTimer: number | null = null
public get onStateChanged(): IEvent<ITutorialState> {
return this._onStateChanged
}
public get onCompleted(): IEvent<boolean> {
return this._onCompleted
}
public get onTick(): IEvent<void> {
return this._onTick
}
public get currentState(): ITutorialState {
return this._currentState
}
public get currentStage(): ITutorialStage {
return this._activeTutorial.stages[this._currentStageIdx]
}
public get currentTutorial(): ITutorial {
return this._activeTutorial
}
constructor(private _editor: Oni.Editor) {}
public start(tutorial: ITutorial, buffer: Oni.Buffer): void {
this._buf = buffer
this._currentStageIdx = 0
this._activeTutorial = tutorial
this._pendingTimer = window.setInterval(() => this._tick(), TICK_RATE)
this._tick()
}
public stop(): void {
if (this._pendingTimer) {
window.clearInterval(this._pendingTimer)
this._pendingTimer = null
}
}
private async _tick(): Promise<void> {
if (this._isTickInProgress) {
return
}
if (!this.currentStage) {
return
}
this._isTickInProgress = true
const result = await this.currentStage.tickFunction({
editor: this._editor,
buffer: this._buf,
})
this._onTick.dispatch()
this._isTickInProgress = false
if (result) {
this._currentStageIdx++
if (this._currentStageIdx >= this._activeTutorial.stages.length) {
this._onCompleted.dispatch(true)
}
}
const goalsToSend = this._activeTutorial.stages.map(f => f.goalName)
const newState: ITutorialState = {
metadata: this._activeTutorial.metadata,
goals: goalsToSend,
activeGoalIndex: this._currentStageIdx,
renderFunc: (context: Oni.BufferLayerRenderContext) =>
this.currentStage && this.currentStage.render
? this.currentStage.render(context)
: null,
}
this._currentState = newState
this._onStateChanged.dispatch(newState)
}
}