wgge 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (107) hide show
  1. package/core/ActivatedTreeNode.js +187 -0
  2. package/core/Collection.js +156 -0
  3. package/core/Dictionary.js +83 -0
  4. package/core/animation/3d/AnimatedVector3.js +35 -0
  5. package/core/animation/3d/AnimationHelper.js +103 -0
  6. package/core/animation/3d/ProgressVector3.js +26 -0
  7. package/core/animation/AnimatedRotation.js +44 -0
  8. package/core/animation/AnimatedValue.js +33 -0
  9. package/core/animation/AnimatedVector2.js +35 -0
  10. package/core/animation/ProgressRotation.js +40 -0
  11. package/core/animation/ProgressValue.js +27 -0
  12. package/core/animation/ProgressVector2.js +23 -0
  13. package/core/audio/AudioModel.js +36 -0
  14. package/core/audio/AudioRenderer.js +120 -0
  15. package/core/audio/global/GlobalAudioModel.js +88 -0
  16. package/core/audio/global/GlobalAudioRenderer.js +108 -0
  17. package/core/controller/AnimationController.js +37 -0
  18. package/core/controller/AnimationFloatController.js +39 -0
  19. package/core/controller/AnimationVector2Controller.js +39 -0
  20. package/core/controller/CollectionController.js +47 -0
  21. package/core/controller/ConditionalNodeController.js +51 -0
  22. package/core/controller/ControllerBase.js +64 -0
  23. package/core/controller/ControllerWithSaveGame.js +27 -0
  24. package/core/controller/ControllerWithTimeout.js +10 -0
  25. package/core/controller/NullableNodeController.js +35 -0
  26. package/core/controller/TimeoutController.js +26 -0
  27. package/core/helper/ArrayHelper.js +19 -0
  28. package/core/helper/DOMHelper.js +167 -0
  29. package/core/helper/GUIHelper.js +53 -0
  30. package/core/helper/HttpHelper.js +33 -0
  31. package/core/helper/ImageHelper.js +36 -0
  32. package/core/helper/NumberHelper.js +28 -0
  33. package/core/helper/ObjectHelper.js +10 -0
  34. package/core/helper/StringHelper.js +59 -0
  35. package/core/model/ModelBase.js +91 -0
  36. package/core/model/ObjectModel.js +97 -0
  37. package/core/model/collection/ModelNodeCollection.js +232 -0
  38. package/core/model/collection/table/IdentifiedModelNode.js +24 -0
  39. package/core/model/collection/table/ModelNodeTable.js +53 -0
  40. package/core/model/event/ChangeEvent.js +24 -0
  41. package/core/model/event/EventManager.js +44 -0
  42. package/core/model/event/NodeWithEvents.js +32 -0
  43. package/core/model/template/TemplateNode.js +45 -0
  44. package/core/model/value/BoolValue.js +17 -0
  45. package/core/model/value/CapacityValue.js +49 -0
  46. package/core/model/value/DirtyValue.js +66 -0
  47. package/core/model/value/FloatValue.js +8 -0
  48. package/core/model/value/IntValue.js +20 -0
  49. package/core/model/value/NullableNode.js +66 -0
  50. package/core/model/value/StringValue.js +21 -0
  51. package/core/model/vector/Quaternion.js +82 -0
  52. package/core/model/vector/Rotation.js +61 -0
  53. package/core/model/vector/Vector2.js +177 -0
  54. package/core/model/vector/Vector3.js +98 -0
  55. package/core/renderer/RendererBase.js +46 -0
  56. package/core/renderer/canvas/CanvasRenderer.js +60 -0
  57. package/core/renderer/canvas/ImageToCanvasRenderer.js +94 -0
  58. package/core/renderer/dom/DirtyValueRenderer.js +36 -0
  59. package/core/renderer/dom/DomRenderer.js +32 -0
  60. package/core/renderer/dom/ImageRenderer.js +41 -0
  61. package/core/renderer/dom/Vector2Renderer.js +37 -0
  62. package/core/renderer/generic/CollectionRenderer.js +50 -0
  63. package/core/renderer/generic/ConditionalNodeRenderer.js +57 -0
  64. package/core/renderer/generic/NullableNodeRenderer.js +43 -0
  65. package/core/renderer/svg/SvgRenderer.js +130 -0
  66. package/editor/EditorController.js +135 -0
  67. package/editor/EditorModel.js +38 -0
  68. package/editor/EditorRenderer.js +116 -0
  69. package/editor/form/NodeFormRenderer.js +180 -0
  70. package/editor/material/MaterialPreviewRenderer.js +136 -0
  71. package/editor/table/TableRenderer.js +123 -0
  72. package/editor/table/lookup/TableLookupRenderer.js +120 -0
  73. package/editor/table/row/TableRowRenderer.js +97 -0
  74. package/game/GameController.js +144 -0
  75. package/game/GameModel.js +73 -0
  76. package/game/GameRenderer.js +108 -0
  77. package/game/controls/ControlsController.js +104 -0
  78. package/game/controls/ControlsModel.js +60 -0
  79. package/game/menu/MenuModel.js +25 -0
  80. package/game/menu/MenuRenderer.js +37 -0
  81. package/game/menu/item/MenuItemModel.js +31 -0
  82. package/game/menu/item/MenuItemRenderer.js +40 -0
  83. package/game/resources/3d/3DModel.js +30 -0
  84. package/game/resources/ResourcesModel.js +26 -0
  85. package/game/resources/assets/AssetCache.js +193 -0
  86. package/game/resources/assets/loader/AssetLoader.js +56 -0
  87. package/game/resources/assets/loader/AudioLoader.js +15 -0
  88. package/game/resources/assets/loader/GlbLoader.js +16 -0
  89. package/game/resources/assets/loader/ImageLoader.js +15 -0
  90. package/game/resources/assets/loader/MaterialLoader.js +49 -0
  91. package/game/resources/assets/loader/Model3dLoader.js +21 -0
  92. package/game/resources/assets/loader/SpriteLoader.js +40 -0
  93. package/game/resources/image/DualImageModel.js +34 -0
  94. package/game/resources/image/ImageModel.js +43 -0
  95. package/game/resources/material/MaterialModel.js +69 -0
  96. package/game/save/SaveGameController.js +21 -0
  97. package/game/save/SaveGameModel.js +5 -0
  98. package/game/save/SaveGameRenderer.js +17 -0
  99. package/game/save/editor/SaveGameEditorRenderer.js +17 -0
  100. package/index.html +42 -0
  101. package/index.js +73 -0
  102. package/package.json +35 -0
  103. package/style/basic/editor.less +290 -0
  104. package/style/basic/game.less +149 -0
  105. package/style/basic/utilities.less +215 -0
  106. package/style/style.less +3 -0
  107. package/webpack.config.js +29 -0
@@ -0,0 +1,40 @@
1
+ import Rotation from "../model/vector/Rotation";
2
+ import {EASING_FLAT} from "./ProgressValue";
3
+
4
+ export default class ProgressRotation {
5
+
6
+ /**
7
+ * @type Number
8
+ */
9
+ start;
10
+
11
+ /**
12
+ * @type Number
13
+ */
14
+ distance;
15
+
16
+ /**
17
+ * @type Number
18
+ */
19
+ progress;
20
+
21
+ /**
22
+ *
23
+ * @param {Number} start
24
+ * @param {Number} end
25
+ * @param {(float) => float} easing
26
+ * @param {Number} progress
27
+ */
28
+ constructor(start, end, easing = EASING_FLAT, progress = 0) {
29
+ this.start = Rotation.normalizeValue(start);
30
+ this.distance = Rotation.diff(end, start);
31
+ this.easing = easing;
32
+ this.progress = progress;
33
+ }
34
+
35
+ get(progress = null) {
36
+ if (progress !== null) this.progress = progress;
37
+ return Rotation.normalizeValue(this.start + (this.easing(this.progress) * this.distance));
38
+ }
39
+
40
+ }
@@ -0,0 +1,27 @@
1
+ export const EASING_FLAT = (x) => x;
2
+ export const EASING_EXPONENTIAL_IN = (x, e = 2) => Math.pow(x,e);
3
+ export const EASING_EXPONENTIAL_IN_OUT = (x, e = 2) => (x <= 0.5) ? Math.pow(x * 2, e) / 2 : 1 - Math.pow(2 - x * 2, e) / 2;
4
+ export const EASING_QUAD_IN = EASING_EXPONENTIAL_IN;
5
+ export const EASING_QUAD_IN_OUT = EASING_EXPONENTIAL_IN_OUT;
6
+ export const EASING_CUBIC_IN = (x) => EASING_EXPONENTIAL_IN(x, 3);
7
+ export const EASING_CUBIC_IN_OUT = (x) => EASING_EXPONENTIAL_IN_OUT(x, 3);
8
+
9
+ export default class ProgressValue {
10
+ start;
11
+ end;
12
+ progress;
13
+ easing;
14
+
15
+ constructor(start, end, easing = EASING_FLAT, progress = 0) {
16
+ this.start = Number(start);
17
+ this.diff = Number(end) - this.start;
18
+ this.easing = easing;
19
+ this.progress = Number(progress);
20
+ }
21
+
22
+ get(progress = null) {
23
+ if (progress !== null) this.progress = Number(progress);
24
+ return this.start + (this.easing(this.progress) * this.diff);
25
+ }
26
+
27
+ }
@@ -0,0 +1,23 @@
1
+ import ProgressValue, {EASING_FLAT} from "./ProgressValue";
2
+ import Vector2 from "../model/vector/Vector2";
3
+
4
+ export default class ProgressVector2 {
5
+ progressX;
6
+ progressY;
7
+
8
+ constructor(start, end, easing = EASING_FLAT, progress = 0) {
9
+ this.progressX = new ProgressValue(start.x, end.x, easing, progress);
10
+ this.progressY = new ProgressValue(start.y, end.y, easing, progress);
11
+ }
12
+
13
+ setProgress(progress) {
14
+ this.progressX.progress = progress;
15
+ this.progressY.progress = progress;
16
+ }
17
+
18
+ get(progress = null) {
19
+ if (progress !== null) this.setProgress(progress);
20
+ return new Vector2(this.progressX.get(), this.progressY.get());
21
+ }
22
+
23
+ }
@@ -0,0 +1,36 @@
1
+ import ObjectModel from "../model/ObjectModel";
2
+ import StringValue from "../model/value/StringValue";
3
+ import FloatValue from "../model/value/FloatValue";
4
+ import BoolValue from "../model/value/BoolValue";
5
+
6
+ export default class AudioModel extends ObjectModel {
7
+
8
+ /**
9
+ * @type StringValue
10
+ */
11
+ url;
12
+
13
+ /**
14
+ * @type FloatValue
15
+ */
16
+ volume;
17
+
18
+ /**
19
+ * @type BoolValue
20
+ */
21
+ playing;
22
+
23
+ /**
24
+ * @type BoolValue
25
+ */
26
+ loop;
27
+
28
+ constructor(persistent = true) {
29
+ super(persistent);
30
+
31
+ this.url = this.addProperty('uri', new StringValue());
32
+ this.volume = this.addProperty('volume', new FloatValue(1));
33
+ this.playing = this.addProperty('audioOn', new BoolValue(true));
34
+ this.loop = this.addProperty('loop', new BoolValue(false));
35
+ }
36
+ }
@@ -0,0 +1,120 @@
1
+ import RendererBase from "../renderer/RendererBase";
2
+
3
+ const HAVE_ENOUGH_DATA = 4;
4
+
5
+ export default class AudioRenderer extends RendererBase {
6
+
7
+ /**
8
+ * @type AudioModel
9
+ */
10
+ model;
11
+
12
+ audio;
13
+ audioContext;
14
+ destination;
15
+ source;
16
+
17
+ constructor(game, model, audioContext, destination) {
18
+ super(game, model);
19
+
20
+ this.model = model;
21
+ this.audioContext = audioContext;
22
+ this.destination = destination;
23
+
24
+ this.addAutoEvent(
25
+ this.game.audio.paused,
26
+ 'change',
27
+ () => this.updatePlaying()
28
+ );
29
+ }
30
+
31
+ activateInternal() {
32
+ this.audio = new Audio();
33
+ this.source = this.audioContext.createMediaElementSource(this.audio);
34
+ this.source.connect(this.destination);
35
+ this.updateAudio();
36
+
37
+ this.audio.addEventListener('ended', () => {
38
+ if (!this.model.loop.get()) {
39
+ this.model.triggerEvent('remove-me', this.model);
40
+ }
41
+ });
42
+
43
+ this.game.assets.getAsset(this.model.url.get(), (audio) => {
44
+ if (!this.audio) {
45
+ console.log('audio loaded after renderer was deactivated');
46
+ return;
47
+ }
48
+
49
+ this.audio.addEventListener('canplaythrough', () => {
50
+ this.updatePlaying();
51
+ });
52
+
53
+ this.audio.src = audio.src;
54
+ });
55
+ }
56
+
57
+ deactivateInternal() {
58
+ this.pause();
59
+ this.source.disconnect();
60
+ this.source = null;
61
+ this.audio = null;
62
+ }
63
+
64
+ renderInternal() {
65
+ if (this.model.loop.isDirty) {
66
+ this.updateLoop();
67
+ }
68
+ if (this.model.volume.isDirty) {
69
+ this.updateVolume();
70
+ }
71
+ if (this.model.playing.isDirty) {
72
+ this.updatePlaying();
73
+ }
74
+ }
75
+
76
+ updateAudio() {
77
+ this.audio.autoplay = false;
78
+ this.audio.muted = false;
79
+ this.audio.controls = false;
80
+ this.updateLoop();
81
+ this.updateVolume();
82
+ this.updatePlaying();
83
+ }
84
+
85
+ updatePlaying() {
86
+ if (this.model.playing.get() && !this.game.audio.paused.get()) {
87
+ this.play();
88
+ } else {
89
+ this.pause();
90
+ }
91
+ }
92
+
93
+ updateLoop() {
94
+ this.audio.loop = this.model.loop.get();
95
+ }
96
+
97
+ updateVolume() {
98
+ this.audio.volume = this.model.volume.get();
99
+ }
100
+
101
+ rewind(time = 0) {
102
+ this.audio.currentTime = time;
103
+ }
104
+
105
+ replay() {
106
+ this.rewind();
107
+ this.play();
108
+ }
109
+
110
+ play() {
111
+ if (this.audio.readyState === HAVE_ENOUGH_DATA) {
112
+ this.audio.play();
113
+ }
114
+ }
115
+
116
+ pause() {
117
+ this.audio.pause();
118
+ }
119
+
120
+ }
@@ -0,0 +1,88 @@
1
+ import ObjectModel from "../../model/ObjectModel";
2
+ import FloatValue from "../../model/value/FloatValue";
3
+ import BoolValue from "../../model/value/BoolValue";
4
+ import ModelNodeCollection from "../../model/collection/ModelNodeCollection";
5
+ import AudioModel from "../AudioModel";
6
+
7
+ export default class GlobalAudioModel extends ObjectModel {
8
+
9
+ /**
10
+ * @type BoolValue
11
+ */
12
+ audioOn;
13
+
14
+ /**
15
+ * @type FloatValue
16
+ */
17
+ masterVolume;
18
+
19
+ /**
20
+ * @type BoolValue
21
+ */
22
+ musicOn;
23
+
24
+ /**
25
+ * @type BoolValue
26
+ */
27
+ paused;
28
+
29
+ /**
30
+ * @type FloatValue
31
+ */
32
+ musicVolume;
33
+
34
+ /**
35
+ * @type BoolValue
36
+ */
37
+ soundsOn;
38
+
39
+ /**
40
+ * @type FloatValue
41
+ */
42
+ soundsVolume;
43
+
44
+ /**
45
+ * @type ModelNodeCollection<AudioModel>
46
+ */
47
+ music;
48
+
49
+ /**
50
+ * @type ModelNodeCollection<AudioModel>
51
+ */
52
+ sounds;
53
+
54
+ constructor(persistent = true) {
55
+ super(persistent);
56
+
57
+ this.audioOn = this.addProperty('audioOn', new BoolValue(true));
58
+ this.masterVolume = this.addProperty('masterVolume', new FloatValue(1));
59
+ this.paused = this.addProperty('paused', new BoolValue(false));
60
+
61
+ this.musicOn = this.addProperty('musicOn', new BoolValue(true));
62
+ this.musicVolume = this.addProperty('musicVolume', new FloatValue(1));
63
+
64
+ this.soundsOn = this.addProperty('soundsOn', new BoolValue(true));
65
+ this.soundsVolume = this.addProperty('soundsVolume', new FloatValue(1));
66
+
67
+ this.music = this.addProperty('music', new ModelNodeCollection(null, false));
68
+ this.sounds = this.addProperty('sounds', new ModelNodeCollection(null, false));
69
+ }
70
+
71
+ playSound(url, loop = false) {
72
+ const sound = new AudioModel();
73
+ sound.url.set(url);
74
+ sound.loop.set(loop);
75
+ sound.playing.set(true);
76
+ this.sounds.add(sound);
77
+ return sound;
78
+ }
79
+
80
+ removeSound(audio) {
81
+ this.sounds.remove(audio);
82
+ }
83
+
84
+ changeMusic(audio) {
85
+ this.music.reset();
86
+ this.music.add(audio);
87
+ }
88
+ }
@@ -0,0 +1,108 @@
1
+ import CollectionRenderer from "../../renderer/generic/CollectionRenderer";
2
+ import AudioRenderer from "../AudioRenderer";
3
+ import RendererBase from "../../renderer/RendererBase";
4
+ import ConditionalNodeRenderer from "../../renderer/generic/ConditionalNodeRenderer";
5
+
6
+ export default class GlobalAudioRenderer extends RendererBase {
7
+
8
+ /**
9
+ * @type GlobalAudioModel
10
+ */
11
+ model;
12
+
13
+ /**
14
+ * @type AudioContext
15
+ */
16
+ audioContext;
17
+
18
+ constructor(game, model) {
19
+ super(game, model);
20
+
21
+ this.model = model;
22
+
23
+ this.addChild(
24
+ new ConditionalNodeRenderer(
25
+ this.game,
26
+ this.model.musicOn,
27
+ () => this.model.musicOn.get(),
28
+ () => {
29
+ return new CollectionRenderer(
30
+ this.game,
31
+ this.model.music,
32
+ (m) => new AudioRenderer(this.game, m, this.audioContext, this.musicGainNode)
33
+ )
34
+ }
35
+ )
36
+ );
37
+
38
+ this.addChild(
39
+ new ConditionalNodeRenderer(
40
+ this.game,
41
+ this.model.soundsOn,
42
+ () => this.model.soundsOn.get(),
43
+ () => {
44
+ return new CollectionRenderer(
45
+ this.game,
46
+ this.model.sounds,
47
+ (m) => new AudioRenderer(this.game, m, this.audioContext, this.soundsGainNode)
48
+ )
49
+ }
50
+ )
51
+ );
52
+ }
53
+
54
+ activateInternal() {
55
+ this.audioContext = new AudioContext();
56
+
57
+ this.masterGainNode = this.audioContext.createGain();
58
+ this.musicGainNode = this.audioContext.createGain();
59
+ this.soundsGainNode = this.audioContext.createGain();
60
+
61
+ this.musicGainNode.connect(this.masterGainNode);
62
+ this.soundsGainNode.connect(this.masterGainNode);
63
+ this.masterGainNode.connect(this.audioContext.destination);
64
+
65
+ this.updateMasterVolume();
66
+ this.updateSoundsVolume();
67
+ this.updateMusicVolume();
68
+ }
69
+
70
+ deactivateInternal() {
71
+
72
+ this.masterGainNode.disconnect();
73
+ this.soundsGainNode.disconnect();
74
+ this.musicGainNode.disconnect();
75
+
76
+ this.masterGainNode = null;
77
+ this.soundsGainNode = null;
78
+ this.musicGainNode = null;
79
+ this.audioContext = null;
80
+ }
81
+
82
+ renderInternal() {
83
+ if (this.audioContext.state === "suspended") {
84
+ this.audioContext.resume();
85
+ }
86
+ if (this.model.masterVolume.isDirty) {
87
+ this.updateMasterVolume();
88
+ }
89
+ if (this.model.musicVolume.isDirty) {
90
+ this.updateMusicVolume();
91
+ }
92
+ if (this.model.soundsVolume.isDirty) {
93
+ this.updateSoundsVolume();
94
+ }
95
+ }
96
+
97
+ updateMasterVolume() {
98
+ this.masterGainNode.gain.value = this.model.masterVolume.get();
99
+ }
100
+
101
+ updateMusicVolume() {
102
+ this.musicGainNode.gain.value = this.model.musicVolume.get();
103
+ }
104
+
105
+ updateSoundsVolume() {
106
+ this.soundsGainNode.gain.value = this.model.soundsVolume.get();
107
+ }
108
+ }
@@ -0,0 +1,37 @@
1
+ import ControllerBase from "./ControllerBase";
2
+
3
+ export default class AnimationController extends ControllerBase {
4
+
5
+ /**
6
+ * @type () => any|null
7
+ */
8
+ onFinishedHandler;
9
+
10
+ /**
11
+ *
12
+ * @param game GameModel
13
+ * @param model DirtyValue
14
+ * @param onFinished () => any|null
15
+ */
16
+ constructor(game, model, onFinished = null) {
17
+ super(game, model);
18
+
19
+ this.onFinishedHandler = onFinished;
20
+ }
21
+
22
+ /**
23
+ *
24
+ * @param func () => any
25
+ * @returns {AnimationController}
26
+ */
27
+ onFinished(func) {
28
+ this.onFinishedHandler = func;
29
+ return this;
30
+ }
31
+
32
+ finished() {
33
+ this.removeMyself();
34
+ if (this.onFinishedHandler) this.onFinishedHandler();
35
+ }
36
+
37
+ }
@@ -0,0 +1,39 @@
1
+ import AnimationController from "./AnimationController";
2
+ import {EASING_FLAT} from "../animation/ProgressValue";
3
+ import AnimatedValue from "../animation/AnimatedValue";
4
+
5
+ export default class AnimationFloatController extends AnimationController {
6
+
7
+ /**
8
+ * @type FloatValue
9
+ */
10
+ model;
11
+
12
+ /**
13
+ * @type AnimatedValue
14
+ */
15
+ animated;
16
+
17
+ /**
18
+ *
19
+ * @param game GameModel
20
+ * @param model DirtyValue
21
+ * @param target Number
22
+ * @param duration Number
23
+ * @param easing (float) => float
24
+ * @param elapsed Number
25
+ */
26
+ constructor(game, model, target, duration, easing = EASING_FLAT, elapsed = 0) {
27
+ super(game, model);
28
+ this.model = model;
29
+ this.animated = new AnimatedValue(model.get(), target, duration, easing, elapsed);
30
+ }
31
+
32
+ updateInternal(delta) {
33
+ this.model.set(this.animated.get(delta));
34
+ if (this.animated.isFinished()) {
35
+ this.finished();
36
+ }
37
+ }
38
+
39
+ }
@@ -0,0 +1,39 @@
1
+ import AnimationController from "./AnimationController";
2
+ import AnimatedVector2 from "../animation/AnimatedVector2";
3
+ import {EASING_FLAT} from "../animation/ProgressValue";
4
+
5
+ export default class AnimationVector2Controller extends AnimationController {
6
+
7
+ /**
8
+ * @type AnimatedVector2
9
+ */
10
+ animatedVector;
11
+
12
+ /**
13
+ * @type Vector2
14
+ */
15
+ model;
16
+
17
+ /**
18
+ *
19
+ * @param game GameModel
20
+ * @param model Vector2
21
+ * @param target Vector2
22
+ * @param duration Number
23
+ * @param easing (float) => float
24
+ * @param elapsed Number
25
+ */
26
+ constructor(game, model, target, duration, easing = EASING_FLAT, elapsed = 0) {
27
+ super(game, model);
28
+ this.model = model;
29
+ this.animatedVector = new AnimatedVector2(model, target, duration, easing, elapsed);
30
+ }
31
+
32
+ updateInternal(delta) {
33
+ this.model.set(this.animatedVector.get(delta));
34
+ if (this.animatedVector.isFinished()) {
35
+ this.finished();
36
+ }
37
+ }
38
+
39
+ }
@@ -0,0 +1,47 @@
1
+ import ControllerBase from "./ControllerBase";
2
+
3
+ export default class CollectionController extends ControllerBase {
4
+
5
+ /**
6
+ * @type ModelNodeCollection
7
+ */
8
+ model;
9
+
10
+ constructor(game, model, controllerFactory) {
11
+ super(game, model);
12
+ this.model = model;
13
+
14
+ this.controllerFactory = controllerFactory;
15
+
16
+ this.addAutoEvent(
17
+ this.model.children,
18
+ 'add',
19
+ (model) => this.createController(model)
20
+ );
21
+
22
+ this.addAutoEvent(
23
+ this.model.children,
24
+ 'remove',
25
+ (model) => this.removeController(model)
26
+ );
27
+ }
28
+
29
+ activateInternal() {
30
+ this.resetChildren();
31
+ this.model.children.forEach((model) => this.createController(model));
32
+ }
33
+
34
+ deactivateInternal() {
35
+ this.resetChildren();
36
+ }
37
+
38
+ createController(model) {
39
+ return this.addChild(this.controllerFactory(model));
40
+ }
41
+
42
+ removeController(model) {
43
+ const controller = this.children.find((ch) => ch.model === model);
44
+ this.removeChild(controller);
45
+ }
46
+
47
+ }
@@ -0,0 +1,51 @@
1
+ import ControllerBase from "./ControllerBase";
2
+
3
+ export default class ConditionalNodeController extends ControllerBase {
4
+
5
+ /**
6
+ * @type DirtyValue
7
+ */
8
+ model;
9
+
10
+ constructor(game, model, condition, controllerFactory, defaultControllerFactory = null) {
11
+ super(game, model);
12
+ this.model = model;
13
+
14
+ this.condition = condition;
15
+
16
+ this.controllerFactory = controllerFactory;
17
+ this.defaultControllerFactory = defaultControllerFactory;
18
+
19
+ this.controller = null;
20
+ this.isUsingDefaultController = false;
21
+
22
+ this.addAutoEvent(
23
+ this.model,
24
+ 'change',
25
+ () => this.updateController(),
26
+ true
27
+ );
28
+ }
29
+
30
+ updateController() {
31
+ if (this.condition()) {
32
+ if (this.isUsingDefaultController || this.controller === null) {
33
+ this.resetChildren();
34
+ this.controller = this.addChild(this.controllerFactory());
35
+ this.isUsingDefaultController = false;
36
+ }
37
+ } else {
38
+ if (this.defaultControllerFactory) {
39
+ if (this.controller === null || this.isUsingDefaultController === false) {
40
+ this.resetChildren();
41
+ this.controller = this.addChild(this.defaultControllerFactory());
42
+ this.isUsingDefaultController = true;
43
+ }
44
+ } else {
45
+ this.resetChildren();
46
+ this.controller = null;
47
+ }
48
+ }
49
+ }
50
+
51
+ }