@woosh/meep-engine 2.33.65 → 2.33.70

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 (31) hide show
  1. package/core/geom/2d/quad-tree/QuadTreeNode.js +3 -2
  2. package/core/geom/3d/triangle/computeTriangleRayIntersection.js +3 -9
  3. package/engine/asset/loaders/GLTFAssetLoader.js +0 -4
  4. package/engine/ecs/fow/FogOfWarRevealerSystem.js +8 -0
  5. package/engine/ecs/fow/shader/screenSpaceFogOfWarShader.js +2 -10
  6. package/engine/ecs/grid/NormalMap2AOMap.js +10 -13
  7. package/engine/ecs/terrain/ecs/BuildLightTexture.js +106 -0
  8. package/engine/ecs/terrain/ecs/PromiseSamplerHeight.js +59 -0
  9. package/engine/ecs/terrain/ecs/Terrain.js +14 -153
  10. package/engine/graphics/FULL_SCREEN_QUAD_VERTEX_SHADER.js +10 -0
  11. package/engine/graphics/filter/ImageFilter.js +6 -2
  12. package/engine/graphics/geometry/buffered/deinterleaveBufferAttribute.js +3 -2
  13. package/engine/graphics/geometry/buffered/query/ClippingPlaneContainmentComputingVisitor.js +28 -27
  14. package/engine/graphics/geometry/buffered/query/GeometryVisitor.js +29 -2
  15. package/engine/graphics/geometry/buffered/query/RaycastNearestHitComputingVisitor.js +28 -27
  16. package/engine/graphics/micron/convert_three_object_to_micron.js +14 -3
  17. package/engine/graphics/micron/plugin/MicronRenderPlugin.js +3 -0
  18. package/engine/graphics/shaders/AmbientOcclusionShader.js +57 -77
  19. package/engine/graphics/shaders/DenoiseShader.js +119 -0
  20. package/engine/graphics/texture/noise_octaves.js +33 -0
  21. package/engine/graphics/texture/sampler/Sampler2D2Texture.js +7 -18
  22. package/engine/graphics/texture/sampler/debug/paintSamplerOnHTML.js +8 -5
  23. package/engine/graphics/texture/sampler/sampler2DToFloat32Texture.js +10 -3
  24. package/generation/example/SampleGenerator0.js +7 -11
  25. package/generation/example/filters/SampleGroundMoistureFilter.js +2 -1
  26. package/generation/example/main.js +215 -0
  27. package/generation/example/themes/SampleTheme0.js +22 -9
  28. package/generation/filtering/numeric/complex/CellFilterGaussianBlur.js +29 -13
  29. package/generation/grid/GridData.js +17 -2
  30. package/generation/placement/GridCellPlacementRule.js +3 -5
  31. package/package.json +1 -1
@@ -21,7 +21,6 @@ import { matcher_tag_traversable } from "./rules/matcher_tag_traversable.js";
21
21
  import { GridTaskGenerateRoads } from "../grid/generation/road/GridTaskGenerateRoads.js";
22
22
  import { mir_generator_place_road_decorators } from "./generators/mir_generator_place_road_decorators.js";
23
23
  import { MarkerNodeMatcherByType } from "../markers/matcher/MarkerNodeMatcherByType.js";
24
- import { mir_generator_place_buff_objects } from "./generators/interactive/mir_generator_place_buff_objects.js";
25
24
  import { GridTaskDensityMarkerDistribution } from "../grid/generation/GridTaskDensityMarkerDistribution.js";
26
25
  import { CellFilterSimplexNoise } from "../filtering/numeric/complex/CellFilterSimplexNoise.js";
27
26
  import { NumericInterval } from "../../core/math/interval/NumericInterval.js";
@@ -211,12 +210,11 @@ const prEnemyCorridorGuard = GridCellPlacementRule.from(
211
210
  ), actions: [
212
211
  ACTION_PLACE_ENEMY_MARKER,
213
212
  ACTION_PLACE_ENEMY_TAG
214
- ]
213
+ ],
214
+ probability: CellFilterLiteralFloat.from(0.5)
215
215
  }
216
216
  );
217
217
 
218
- prEnemyCorridorGuard.probability = 0.5;
219
-
220
218
  const gRuleSet2 = GridTaskActionRuleSet.from({ rules: GridActionRuleSet.from({ rules: [prEnemyTreasureGuard, prEnemyCorridorGuard] }) });
221
219
 
222
220
  gRuleSet2.addDependency(gRuleSetTreasureGuards);
@@ -226,7 +224,11 @@ const gPlaceStartingPoint = mir_generator_place_starting_point();
226
224
 
227
225
  gPlaceStartingPoint.addDependency(gConnectRooms);
228
226
 
229
- const gBuildDistanceMap = GridTaskBuildSourceDistanceMap.from({ source: MATCH_STARTING_POINT, pass: MATCH_EMPTY });
227
+ const gBuildDistanceMap = GridTaskBuildSourceDistanceMap.from({
228
+ source: MATCH_STARTING_POINT,
229
+ pass: MATCH_EMPTY,
230
+ layer: MirGridLayers.DistanceFromStart
231
+ });
230
232
 
231
233
  gBuildDistanceMap.addDependency(gPlaceStartingPoint);
232
234
 
@@ -235,11 +237,8 @@ gRuleSet1.addDependency(gBuildDistanceMap);
235
237
  const gBases = mir_generator_place_bases();
236
238
  gBases.addDependency(gMakeEmpty);
237
239
 
238
- const gBuffObjects = mir_generator_place_buff_objects();
239
- gBuffObjects.addDependency(gBases);
240
240
 
241
241
  gConnectRooms.addDependency(gBases);
242
- gConnectRooms.addDependency(gBuffObjects);
243
242
 
244
243
  gPlaceStartingPoint.addDependency(gBases);
245
244
 
@@ -250,7 +249,6 @@ const gRoads = new GridTaskGenerateRoads();
250
249
 
251
250
  gRoads.addDependency(gConnectRooms);
252
251
  gRoads.addDependency(gBases);
253
- gRoads.addDependency(gBuffObjects);
254
252
 
255
253
  const gRoadDecorators = mir_generator_place_road_decorators();
256
254
 
@@ -540,7 +538,6 @@ gFoliageLarge.addDependencies([
540
538
  gRuleSet1,
541
539
  gRuleSet2,
542
540
  gRuleSetTreasureGuards,
543
- gBuffObjects,
544
541
  gBases
545
542
  ]);
546
543
 
@@ -555,7 +552,6 @@ SampleGenerator0.addGenerator(gConnectRooms);
555
552
  SampleGenerator0.addGenerator(gRoads);
556
553
  SampleGenerator0.addGenerator(gRoadDecorators);
557
554
  SampleGenerator0.addGenerator(gBases);
558
- SampleGenerator0.addGenerator(gBuffObjects);
559
555
  SampleGenerator0.addGenerator(gPlaceStartingPoint);
560
556
  SampleGenerator0.addGenerator(gBuildDistanceMap);
561
557
  SampleGenerator0.addGenerator(gRuleSet1);
@@ -24,7 +24,8 @@ export const SampleGroundMoistureFilter = CellFilterAdd.from(
24
24
  CellFilterStep.from(CellFilterLiteralFloat.from(0), fReadHeight)
25
25
  ),
26
26
  7,
27
- 7
27
+ 7,
28
+ 1
28
29
  ),
29
30
  CellFilterLiteralFloat.from(0.6)
30
31
  )
@@ -0,0 +1,215 @@
1
+ import { EngineHarness } from "../../engine/EngineHarness.js";
2
+ import RenderSystem from "../../engine/ecs/systems/RenderSystem.js";
3
+ import { Camera } from "../../engine/graphics/ecs/camera/Camera.js";
4
+ import TopDownCameraController from "../../engine/graphics/ecs/camera/topdown/TopDownCameraController.js";
5
+ import Vector3 from "../../core/geom/Vector3.js";
6
+ import { TopDownCameraLander } from "../../engine/graphics/ecs/camera/topdown/TopDownCameraLander.js";
7
+ import Terrain from "../../engine/ecs/terrain/ecs/Terrain.js";
8
+ import { TerrainFlags } from "../../engine/ecs/terrain/ecs/TerrainFlags.js";
9
+ import Water from "../../engine/graphics/ecs/water/Water.js";
10
+ import GridObstacle from "../../engine/grid/components/GridObstacle.js";
11
+ import EntityBuilder from "../../engine/ecs/EntityBuilder.js";
12
+ import GridPosition from "../../engine/grid/components/GridPosition.js";
13
+ import { Transform } from "../../engine/ecs/transform/Transform.js";
14
+ import { GridData } from "../grid/GridData.js";
15
+ import { computeStringHash } from "../../core/primitives/strings/computeStringHash.js";
16
+ import { ThemeEngine } from "../theme/ThemeEngine.js";
17
+ import { AreaTheme } from "../theme/AreaTheme.js";
18
+ import TaskGroup from "../../core/process/task/TaskGroup.js";
19
+ import { actionTask } from "../../core/process/task/TaskUtils.js";
20
+ import { generateTerrainPreview } from "../../../../generator/generator/generateTerrainPreview.js";
21
+ import { SampleTheme0 } from "./themes/SampleTheme0.js";
22
+ import { SampleGenerator0 } from "./SampleGenerator0.js";
23
+ import { configureMirGrid } from "./grid/configureMirGrid.js";
24
+ import { EngineConfiguration } from "../../engine/EngineConfiguration.js";
25
+ import TerrainSystem from "../../engine/ecs/terrain/ecs/TerrainSystem.js";
26
+ import WaterSystem from "../../engine/graphics/ecs/water/WaterSystem.js";
27
+ import { MeshSystem } from "../../engine/graphics/ecs/mesh/MeshSystem.js";
28
+ import TopDownCameraControllerSystem from "../../engine/graphics/ecs/camera/topdown/TopDownCameraControllerSystem.js";
29
+ import { TopDownCameraLanderSystem } from "../../engine/graphics/ecs/camera/topdown/TopDownCameraLanderSystem.js";
30
+ import LightSystem from "../../engine/graphics/ecs/light/LightSystem.js";
31
+
32
+ function makeEngineConfig(engine) {
33
+ const config = new EngineConfiguration();
34
+
35
+ const graphics = engine.graphics;
36
+
37
+ config.addSystem(new RenderSystem(graphics));
38
+ config.addSystem(new TerrainSystem(graphics, engine.assetManager));
39
+ config.addSystem(new WaterSystem(graphics));
40
+ config.addSystem(new MeshSystem(engine));
41
+ config.addSystem(new TopDownCameraControllerSystem());
42
+ config.addSystem(new TopDownCameraLanderSystem());
43
+ config.addSystem(new LightSystem(engine))
44
+
45
+ return config;
46
+ }
47
+
48
+
49
+ /**
50
+ *
51
+ * @param {EngineHarness} harness
52
+ * @return {Promise<void>}
53
+ */
54
+ async function init(harness) {
55
+ const engine = harness.engine;
56
+
57
+ await makeEngineConfig(engine).apply(engine);
58
+
59
+ await harness.initialize();
60
+
61
+ main(engine);
62
+ }
63
+
64
+ function prepare_gen_task({
65
+ SIZE_X = 64,
66
+ SIZE_Y = 64,
67
+ ecd
68
+ }) {
69
+
70
+ const camera = EngineHarness.buildCamera({
71
+ engine,
72
+ target: new Vector3(15, 0, 16),
73
+ // pitch: -PI_HALF,
74
+ pitch: 1.1,
75
+ yaw: 3.14,
76
+ distance: 13,
77
+ ecd,
78
+ distanceMin: 5,
79
+ distanceMax: 30
80
+ });
81
+
82
+ camera.add(new TopDownCameraLander());
83
+
84
+ // build lights
85
+ EngineHarness.buildLights({ engine })
86
+
87
+
88
+ // build terrain
89
+ const terrain = new Terrain();
90
+
91
+ terrain.resolution = 4;
92
+
93
+ terrain.size.set(SIZE_X, SIZE_Y);
94
+ terrain.samplerHeight.resize(SIZE_X, SIZE_Y);
95
+ terrain.splat.resize(SIZE_X * 4, SIZE_Y * 4, 0);
96
+
97
+ terrain.layers.resolution.set(512, 512);
98
+
99
+ terrain.clearFlag(TerrainFlags.Built);
100
+ terrain.build(engine.assetManager);
101
+
102
+ const water = new Water();
103
+
104
+ water.color.setRGB(0.2, 0.0, 0.5);
105
+ water.shoreColor.setRGB(0.3, 0.3, 1);
106
+ water.shoreDepthTransition.set(0.16, 0.5);
107
+ water.waveFrequency.set(1.3);
108
+ water.waveAmplitude.set(0.15);
109
+ water.waveSpeed.set(1.2);
110
+ water.scattering.set(1.2);
111
+ water.level.set(-0.3);
112
+
113
+ const obstacle = new GridObstacle();
114
+ obstacle.resize(terrain.size.x, terrain.size.y);
115
+
116
+ const terrainBuilder = new EntityBuilder();
117
+
118
+ terrainBuilder
119
+ .add(terrain)
120
+ .add(water)
121
+ .add(obstacle)
122
+ .add(new GridPosition())
123
+ .add(new Transform())
124
+ .build(ecd);
125
+
126
+
127
+ const gridData = new GridData();
128
+
129
+ configureMirGrid(gridData);
130
+
131
+ gridData.resize(terrain.size.x, terrain.size.y);
132
+ gridData.computeScale(1);
133
+
134
+ const generator = SampleGenerator0;
135
+
136
+ const tGenerationTask = generator.generate(ecd, gridData, computeStringHash('alexx855'));
137
+
138
+
139
+ const themeEngine = new ThemeEngine();
140
+ themeEngine.assetManager = engine.assetManager;
141
+
142
+ const theme0 = new AreaTheme();
143
+
144
+ const width = gridData.width;
145
+ const height = gridData.height;
146
+
147
+ theme0.mask.resize(width, height);
148
+ theme0.mask.mask.fill(0, 0, width, height, [1]);
149
+ theme0.theme = SampleTheme0;
150
+
151
+ themeEngine.add(theme0);
152
+
153
+
154
+ themeEngine.random.setCurrentSeed(1);
155
+ const tTheme = themeEngine.apply(gridData, ecd);
156
+
157
+ tTheme.addDependency(tGenerationTask);
158
+
159
+
160
+ const tBuildLevel = new TaskGroup([tGenerationTask, tTheme]);
161
+
162
+
163
+ const tAddGameplayElements = actionTask(() => {
164
+ // prepare gameplay-specific things on top of the generated level
165
+
166
+ //build minimap
167
+ const terrainPreview = generateTerrainPreview(terrainBuilder.entity, ecd);
168
+ terrain.preview.copy(terrainPreview);
169
+ });
170
+
171
+ tAddGameplayElements.addDependency(tBuildLevel);
172
+
173
+ return new TaskGroup([tBuildLevel, tAddGameplayElements]);
174
+ }
175
+
176
+ /**
177
+ *
178
+ * @param {Engine} engine
179
+ */
180
+ function main(engine) {
181
+ const ecd = engine.entityManager.dataset;
182
+
183
+ const tBuildLevel = prepare_gen_task({ ecd });
184
+
185
+ engine.loadSlowTask(tBuildLevel);
186
+
187
+ engine.executor.runGroup(tBuildLevel);
188
+
189
+ tBuildLevel.promise().then(() => {
190
+ console.log('Generation took ', tBuildLevel.getExecutedCpuTime(), 'ms');
191
+
192
+ const camera = ecd.getAnyComponent(Camera);
193
+
194
+ EngineHarness.buildOrbitalCameraController({
195
+ cameraEntity: camera.entity,
196
+ engine
197
+ });
198
+
199
+ // tweak camera for prototyping
200
+ const ctrl = ecd.getComponent(camera.entity, TopDownCameraController);
201
+ if (ctrl !== undefined) {
202
+ ctrl.distanceMax = 200;
203
+ }
204
+
205
+ });
206
+
207
+ // Resume audio context
208
+ engine.devices.pointer.on.down.addOne(engine.sound.resumeContext, engine.sound);
209
+ engine.devices.pointer.on.wheel.addOne(engine.sound.resumeContext, engine.sound);
210
+
211
+ }
212
+
213
+ const engineHarness = new EngineHarness();
214
+
215
+ init(engineHarness);
@@ -46,6 +46,8 @@ import { SoundEmitter } from "../../../engine/sound/ecs/emitter/SoundEmitter.js"
46
46
  import { SampleGroundMoistureFilter } from "../filters/SampleGroundMoistureFilter.js";
47
47
  import GeneratedArmy from "../../../../model/game/ecs/component/generator/army/GeneratedArmy.js";
48
48
  import { MirMarkerTypes } from "../../../../generator/MirMarkerTypes.js";
49
+ import { TerrainLayerDescription } from "../../theme/TerrainLayerDescription.js";
50
+ import Vector2 from "../../../core/geom/Vector2.js";
49
51
 
50
52
  export const SampleTheme0 = new Theme();
51
53
 
@@ -123,10 +125,6 @@ const filterSand = CellFilterMultiply.from(
123
125
  filterNotRockAndNotRoad
124
126
  );
125
127
 
126
- const TERRAIN_LAYER_GRASS = 0;
127
- const TERRAIN_LAYER_ROCK = 1;
128
- const TERRAIN_LAYER_SAND = 3;
129
-
130
128
  terrainTheme.rules.push(TerrainLayerRule.from(
131
129
  CellFilterMultiply.from(
132
130
  CellFilterMultiply.from(
@@ -135,22 +133,34 @@ terrainTheme.rules.push(TerrainLayerRule.from(
135
133
  ),
136
134
  filterNotRockAndNotRoad
137
135
  ),
138
- TERRAIN_LAYER_GRASS
136
+ TerrainLayerDescription.from({
137
+ diffuse:'data/textures/materials/Sci-Fi Planet/Grass_02.png',
138
+ size:new Vector2(7,7)
139
+ })
139
140
  ));
140
141
 
141
142
  terrainTheme.rules.push(TerrainLayerRule.from(
142
143
  filterRock,
143
- TERRAIN_LAYER_ROCK
144
+ TerrainLayerDescription.from({
145
+ diffuse:'data/textures/Materials_Stylized/4k JPEG/Stylized_04_Rocks/Stylized_04_Rocks_basecolor.jpg',
146
+ size:new Vector2(7,7)
147
+ })
144
148
  ));
145
149
 
146
150
  terrainTheme.rules.push(TerrainLayerRule.from(
147
151
  filterSand,
148
- TERRAIN_LAYER_SAND
152
+ TerrainLayerDescription.from({
153
+ diffuse:'data/textures/Materials_Stylized/4k JPEG/Stylized_06_Sand/Stylized_06_Sand_basecolor.jpg',
154
+ size:new Vector2(7,7)
155
+ })
149
156
  ));
150
157
 
151
158
  terrainTheme.rules.push(TerrainLayerRule.from(
152
159
  filterRoad,
153
- 2,
160
+ TerrainLayerDescription.from({
161
+ diffuse:'data/textures/Materials_Stylized/4k JPEG/Stylized_02_Stone_Ground/Stylized_02_Stone_Ground_basecolor.jpg',
162
+ size:new Vector2(7,7)
163
+ })
154
164
  ));
155
165
 
156
166
  terrainTheme.rules.push(TerrainLayerRule.from(
@@ -158,7 +168,10 @@ terrainTheme.rules.push(TerrainLayerRule.from(
158
168
  ROAD_FILTER,
159
169
  CellFilterLerp.from(CellFilterLiteralFloat.from(1), CellFilterLiteralFloat.from(0.3), NOISE_10_a)
160
170
  ),
161
- TERRAIN_LAYER_GRASS,
171
+ TerrainLayerDescription.from({
172
+ diffuse:'data/textures/materials/Sci-Fi Planet/Grass_02.png',
173
+ size:new Vector2(7,7)
174
+ }),
162
175
  ));
163
176
 
164
177
  SampleTheme0.terrain = terrainTheme;
@@ -1,9 +1,23 @@
1
1
  import { CellFilter } from "../../CellFilter.js";
2
2
  import { gaussian } from "../../../../core/math/gaussian.js";
3
-
3
+ import { max2 } from "../../../../core/math/max2.js";
4
+ import { assert } from "../../../../core/assert.js";
5
+
6
+ /**
7
+ *
8
+ * @param {number[]} result
9
+ * @param {number} samplesX
10
+ * @param {number} samplesY
11
+ * @param {number} sigma_x
12
+ * @param {number} sigma_y
13
+ * @return {number}
14
+ */
4
15
  function buildKernel(result, samplesX, samplesY, sigma_x, sigma_y) {
5
- const half_samples_x = (samplesX / 2);
6
- const half_samples_y = (samplesY / 2);
16
+ assert.isNonNegativeInteger(samplesX, 'samplesX');
17
+ assert.isNonNegativeInteger(samplesY, 'samplesY');
18
+
19
+ const half_samples_x = samplesX * 0.5;
20
+ const half_samples_y = samplesY * 0.5;
7
21
 
8
22
  let powerTotal = 0;
9
23
  let ix, iy;
@@ -70,6 +84,8 @@ export class CellFilterGaussianBlur extends CellFilter {
70
84
  if (!this.source.initialized) {
71
85
  this.source.initialize(grid, seed);
72
86
 
87
+ this.__kernel = new Float32Array(this.samples_x * this.samples_y);
88
+
73
89
  // initialize kernel
74
90
  this.__kernel_total_power = buildKernel(this.__kernel, this.samples_x, this.samples_y, this.sigma_x, this.sigma_y);
75
91
  }
@@ -84,13 +100,13 @@ export class CellFilterGaussianBlur extends CellFilter {
84
100
  * @param {number} quality
85
101
  * @returns {CellFilterGaussianBlur}
86
102
  */
87
- static from(source, x, y, quality = 5) {
103
+ static from(source, x, y, quality = 3) {
88
104
  const r = new CellFilterGaussianBlur();
89
105
 
90
106
  r.source = source;
91
107
 
92
- r.samples_x = quality * x;
93
- r.samples_y = quality * y;
108
+ r.samples_x = max2(2, Math.round(quality * x));
109
+ r.samples_y = max2(2, Math.round(quality * y));
94
110
 
95
111
  r.size_x = x;
96
112
  r.size_y = y;
@@ -102,24 +118,24 @@ export class CellFilterGaussianBlur extends CellFilter {
102
118
  const samplesX = this.samples_x;
103
119
  const samplesY = this.samples_y;
104
120
 
105
- const half_samples_x = (samplesX / 2);
106
- const half_samples_y = (samplesY / 2);
121
+ const half_samples_x = (samplesX - 1) * 0.5;
122
+ const half_samples_y = (samplesY - 1) * 0.5;
107
123
 
108
124
  const sizeX = this.size_x;
109
125
  const sizeY = this.size_y;
110
126
 
111
- const local_u_scale = 1 / samplesX;
112
- const local_v_scale = 1 / samplesY;
127
+ const local_u_scale = 1 / (samplesX - 1);
128
+ const local_v_scale = 1 / (samplesY - 1);
113
129
 
114
130
  let sum = 0;
115
- let ix, iy;
131
+ let ix, iy = 0;
116
132
 
117
133
  const source = this.source;
118
134
  const kernel = this.__kernel;
119
135
 
120
- const i_samples_x = samplesX|0;
136
+ const i_samples_x = samplesX | 0;
121
137
 
122
- for (iy = 0; iy < samplesY; iy++) {
138
+ for (; iy < samplesY; iy++) {
123
139
  const local_y = iy - half_samples_y;
124
140
 
125
141
  const ny = local_y * local_v_scale;
@@ -2,6 +2,7 @@ import { assert } from "../../core/assert.js";
2
2
  import { QuadTreeNode } from "../../core/geom/2d/quad-tree/QuadTreeNode.js";
3
3
  import { OffsetScaleTransform2D } from "../../engine/ecs/terrain/ecs/OffsetScaleTransform2D.js";
4
4
  import { MarkerMatchCounter } from "./MarkerMatchCounter.js";
5
+ import { max2 } from "../../core/math/max2.js";
5
6
 
6
7
  const scratch_match_counter = new MarkerMatchCounter();
7
8
 
@@ -167,8 +168,14 @@ export class GridData {
167
168
  * @param {number} height
168
169
  */
169
170
  resize(width, height) {
170
- assert.typeOf(width, 'number', 'width');
171
- assert.typeOf(height, 'number', 'height');
171
+ assert.isNumber(width, 'width');
172
+ assert.isNumber(height, 'height');
173
+
174
+ assert.isNonNegativeInteger(width,'width');
175
+ assert.isNonNegativeInteger(height,'height');
176
+
177
+ assert.isFiniteNumber(width, 'width');
178
+ assert.isFiniteNumber(height, 'width');
172
179
 
173
180
  if (width === this.width && height === this.height) {
174
181
  //no need, already the right size
@@ -187,6 +194,14 @@ export class GridData {
187
194
 
188
195
  layer.resize(width, height);
189
196
  }
197
+
198
+ // resize the quad tree pre-emptively, to avoid expensive re-balancing operations later on
199
+ this.markers.resize(
200
+ -max2(1, width * 0.5),
201
+ -max2(1, height * 0.5),
202
+ max2(width + 1, width * 1.5),
203
+ max2(height + 1, height * 1.5)
204
+ );
190
205
  }
191
206
 
192
207
  /**
@@ -44,7 +44,7 @@ export class GridCellPlacementRule {
44
44
  * @param {Vector2} [offset]
45
45
  * @returns {GridCellPlacementRule}
46
46
  */
47
- static from({ matcher, actions, probability, offset = Vector2.zero }) {
47
+ static from({ matcher, actions, probability = CellFilterLiteralFloat.from(1), offset = Vector2.zero }) {
48
48
 
49
49
  assert.defined(matcher);
50
50
  assert.defined(actions);
@@ -56,10 +56,8 @@ export class GridCellPlacementRule {
56
56
  r.pattern = matcher;
57
57
  r.actions = actions;
58
58
 
59
- if (probability !== undefined) {
60
- assert.equal(probability.isCellFilter, true, 'probability.isCellFilter !== true');
61
- r.probability = probability;
62
- }
59
+ assert.equal(probability.isCellFilter, true, 'probability.isCellFilter !== true');
60
+ r.probability = probability;
63
61
 
64
62
  r.positionOffset.copy(offset);
65
63
 
package/package.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "productName": "Meep",
6
6
  "description": "production-ready JavaScript game engine based on Entity Component System Architecture",
7
7
  "author": "Alexander Goldring",
8
- "version": "2.33.65",
8
+ "version": "2.33.70",
9
9
  "dependencies": {
10
10
  "gl-matrix": "3.4.3",
11
11
  "fast-levenshtein": "2.0.6",