@antha/entity-2d 0.16.0 → 0.18.0

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.
package/README.md CHANGED
@@ -15,13 +15,13 @@ npm i @antha/entity-2d
15
15
  ```TypeScript
16
16
  import {AnthaEngine, defineAnthaMod} from '@antha/engine';
17
17
  import {createAnthaGraphics2dMod} from '@antha/graphics-2d';
18
- import {type AnthaEntity2dModState, createAnthaEntityMod2d} from '@antha/entity-2d';
18
+ import {type AnthaEntity2dModState, createAnthaEntity2dSuite} from '@antha/entity-2d';
19
19
 
20
20
  type GameState = AnthaEntity2dModState<{
21
21
  hasCreatedScoreEntity: boolean;
22
22
  }>;
23
23
 
24
- const {defineLogicEntity, mod: entityMod} = createAnthaEntityMod2d<{
24
+ const {defineLogicEntity, updateEntitiesMod} = createAnthaEntity2dSuite<{
25
25
  hasCreatedScoreEntity: boolean;
26
26
  }>();
27
27
 
@@ -38,7 +38,7 @@ const engine = new AnthaEngine<GameState>({
38
38
  },
39
39
  mods: [
40
40
  createAnthaGraphics2dMod(),
41
- entityMod,
41
+ updateEntitiesMod,
42
42
  defineAnthaMod<GameState>({
43
43
  modName: 'game-logic',
44
44
  async execute({state}) {
@@ -1,8 +1,11 @@
1
- import { type AnyObject, type Constructor, type IsAny } from '@augment-vir/common';
1
+ import { type AnthaAssetModState } from '@antha/asset';
2
+ import { type ModTrigger } from '@antha/engine';
3
+ import { type AnthaGraphics2dModState } from '@antha/graphics-2d';
4
+ import { type AnyObject, type Constructor, type PartialWithUndefined } from '@augment-vir/common';
2
5
  import { type Shape } from 'object-shape-tester';
3
- import { BaseEntity2d, type BaseEntityAssetDefinitions, type Entity2dConstructor, type Entity2dConstructorParams, type EntityCollisionDefinition, EntityStore2d, type EntityStore2dConstructorParams, type MappedEntityAssets, type ParamsMap, type ReverseParamsMap, ViewEntity2d } from './entity.js';
6
+ import { BaseEntity2d, EntityStore2d, ViewEntity2d, type BaseEntityAssetDefinitions, type EntityCollisionDefinition, type EntityStore2dConstructorParams, type ParamsMap, type StaticEntity2dParts } from './entity.js';
4
7
  /**
5
- * Params for both {@link EntitySuite2d.defineEntity} and {@link EntitySuite2d.defineLogicEntity}.
8
+ * Params for both `defineEntity` and `defineLogicEntity`.
6
9
  *
7
10
  * @category Internal
8
11
  */
@@ -92,37 +95,6 @@ export type DefineEntity2dArgs<ParamsShape extends Shape | undefined, EntityAsse
92
95
  paramsMap?: ParamsMap<NoInfer<ParamsShape> extends Shape ? NoInfer<ParamsShape>['runtimeType'] : undefined> | undefined;
93
96
  assets?: EntityAssets;
94
97
  };
95
- /**
96
- * Static members of both view and logic entity constructors.
97
- *
98
- * @category Internal
99
- */
100
- export type StaticEntity2dParts<State extends AnyObject = any, ParamsShape extends Shape | undefined = any, EntityAssets extends BaseEntityAssetDefinitions | undefined = any> = {
101
- /** Entity classes this entity observes collisions with. Omit to observe none. */
102
- collidesWith: EntityCollisionDefinition | undefined;
103
- /** Cached entity classes this entity observes collisions with. */
104
- collidesWithSet: ReadonlySet<Entity2dConstructor>;
105
- /**
106
- * This key is used for deserialization of entities to track which class needs to be
107
- * constructed. You cannot have duplicate keys loaded at the same time.
108
- *
109
- * This is used instead of inferring the entity key from the class name so that you can still
110
- * minify your class names without making debugging nigh impossible (you'll still know which
111
- * entities are being serialized and deserialized even if your class names are minified).
112
- */
113
- entityKey: string;
114
- /** Shape definition of this entity's parameters. */
115
- paramsShape: ParamsShape;
116
- /**
117
- * Defines which properties from {@link BaseEntity2d.params} will be mapped to hitbox and/or view
118
- * properties.
119
- */
120
- paramsMap: IsAny<ParamsShape> extends true ? any : ParamsMap<ParamsShape extends Shape ? ParamsShape['runtimeType'] : undefined>;
121
- /** Parses the serialized params generated by {@link BaseEntity2d.serialize}. */
122
- deserialize(serialized: string | undefined): AnyObject | undefined;
123
- assets: MappedEntityAssets<EntityAssets>;
124
- ConstructorArgsType: Entity2dConstructorParams<State, ParamsShape extends Shape ? ParamsShape['runtimeType'] : undefined>;
125
- };
126
98
  /**
127
99
  * ========================
128
100
  *
@@ -145,7 +117,7 @@ export type DefinedViewEntity2dInstance<State extends AnyObject, ParamsShape ext
145
117
  */
146
118
  export type DefinedViewEntity2dConstructor<State extends AnyObject, ParamsShape extends Shape | undefined, EntityAssets extends BaseEntityAssetDefinitions | undefined> = Constructor<DefinedViewEntity2dInstance<State, ParamsShape, EntityAssets>, ConstructorParameters<typeof ViewEntity2d<State, ParamsShape extends Shape ? ParamsShape['runtimeType'] : undefined>>> & StaticEntity2dParts<State, ParamsShape>;
147
119
  /**
148
- * Type for {@link EntitySuite2d.defineEntity}.
120
+ * Type for `defineEntity`.
149
121
  *
150
122
  * @category Internal
151
123
  */
@@ -173,56 +145,62 @@ export type DefinedLogicEntity2dInstance<State extends AnyObject, ParamsShape ex
173
145
  */
174
146
  export type DefinedLogicEntity2dConstructor<State extends AnyObject, ParamsShape extends Shape | undefined> = Constructor<DefinedLogicEntity2dInstance<State, ParamsShape>, ConstructorParameters<typeof BaseEntity2d<State, ParamsShape extends Shape ? ParamsShape['runtimeType'] : undefined>>> & StaticEntity2dParts<State, ParamsShape>;
175
147
  /**
176
- * Type for `EntitySuite.defineEntity`.
148
+ * Type for `defineLogicEntity`.
177
149
  *
178
150
  * @category Internal
179
151
  */
180
152
  export type DefineLogicEntity2d<State extends AnyObject> = <const ParamsShape extends Shape | undefined, const EntityAssets extends BaseEntityAssetDefinitions | undefined>(params: DefineEntity2dArgs<ParamsShape, EntityAssets>) => DefinedLogicEntity2dConstructor<NoInfer<State>, NoInfer<ParamsShape>>;
181
153
  /**
182
- * ========================
183
- *
184
- * # Entity Suite
154
+ * State for {@link createAnthaEntity2dSuite}.
185
155
  *
186
- * ========================
156
+ * @category Internal
187
157
  */
158
+ export type AnthaEntity2dModState<State extends AnyObject = AnyObject> = {
159
+ entityStore: EntityStore2d<Partial<AnthaEntity2dModState<State>>>;
160
+ /** If true, entity updates and collision checks are skipped. */
161
+ disableEntityUpdate: boolean;
162
+ /** If true, entity renders are skipped. */
163
+ disableEntityRender: boolean;
164
+ /** If `true`, hit boxes are visually rendered for debugging purposes. */
165
+ showHitboxDebug: boolean;
166
+ } & State & AnthaGraphics2dModState & AnthaAssetModState;
188
167
  /**
189
- * Output of {@link defineEntitySuite2d}, used to defining and creating entities.
168
+ * Options for {@link createAnthaEntity2dSuite}.
190
169
  *
191
170
  * @category Internal
192
171
  */
193
- export type EntitySuite2d<State extends AnyObject> = {
172
+ export type AnthaEntity2dModOptions = PartialWithUndefined<EntityStore2dConstructorParams & {
173
+ debug: boolean;
194
174
  /**
195
- * The suite's entity store constructor. Instantiate this and to add your first entities.
196
- *
197
- * All defined entities will also have a reference to this store so they can add additional
198
- * entities by themselves.
175
+ * The entity update mod's trigger. If left undefined, enabled entity updates will run on
176
+ * every engine tick.
199
177
  */
200
- EntityStore: new (params: Readonly<EntityStore2dConstructorParams>) => EntityStore2d<State>;
178
+ updateTrigger: ModTrigger;
201
179
  /**
202
- * Define a standard entity (with a view). This is intended to be extended from your entity
203
- * class.
180
+ * If `true`, the `updateEntitiesMod` does not update entity data and collision state.
181
+ *
182
+ * @default false
204
183
  */
205
- defineEntity: DefineViewEntity2d<State>;
206
- /** Define an entity that doesn't have an attached view. These are likely to be rare. */
207
- defineLogicEntity: DefineLogicEntity2d<State>;
184
+ disableEntityUpdate: boolean;
208
185
  /**
209
- * A set of entity keys used within this entity suite. This will only be populated by all
210
- * classes that are defined with `defineEntity` or `defineLogicEntity` (so this will miss any
211
- * not-yet-resolved dynamic imports). This will be populated even before the classes are ever
212
- * instantiated.
186
+ * If `true`, the `updateEntitiesMod` does not update transient entity render state.
187
+ *
188
+ * @default false
213
189
  */
214
- entityKeys: Set<string>;
215
- };
216
- /**
217
- * This is the starting point of the @game-vir/entity package. Call this to produce the function
218
- * needed to define new entities and the store needed to add entity instances.
219
- *
220
- * @category Main
221
- */
222
- export declare function defineEntitySuite2d<State extends AnyObject>(): EntitySuite2d<State>;
190
+ disableEntityRender: boolean;
191
+ }>;
223
192
  /**
224
- * Converts {@link ParamsMap} to {@link ReverseParamsMap}.
193
+ * Creates an entity update mod and entity factories.
225
194
  *
226
- * @category Internal
195
+ * @category Pre-built Mods
227
196
  */
228
- export declare function reverseParamsMap(paramsMap: ParamsMap | undefined): ReverseParamsMap | undefined;
197
+ export declare function createAnthaEntity2dSuite<ExtraState extends AnyObject>(options?: Readonly<AnthaEntity2dModOptions>): {
198
+ /**
199
+ * Updates entity data an/or transient render state, depending on the options you provided
200
+ * to `createAnthaEntity2dSuite`.
201
+ */
202
+ updateEntitiesMod: import("@antha/engine").AnthaMod<NoInfer<AnthaEntity2dModState<ExtraState>>>;
203
+ defineEntity: DefineViewEntity2d<AnthaEntity2dModState<ExtraState>>;
204
+ defineLogicEntity: DefineLogicEntity2d<AnthaEntity2dModState<ExtraState>>;
205
+ entityKeys: Set<string>;
206
+ };
@@ -0,0 +1,101 @@
1
+ import { defineAnthaMod, SkipExecution } from '@antha/engine';
2
+ import { assertWrap } from '@augment-vir/assert';
3
+ import { getObjectTypedEntries, mergeDefinedProperties, } from '@augment-vir/common';
4
+ import { html } from 'element-vir';
5
+ import { BaseEntity2d, EntityStore2d, reverseParamsMap, ViewEntity2d, } from './entity.js';
6
+ function ensureEntityStore({ state, options, }) {
7
+ if (!state.pixi?.pixiApplication || !state.assetLoader) {
8
+ return false;
9
+ }
10
+ if (!state.entityStore) {
11
+ state.entityStore = new EntityStore2d(mergeDefinedProperties({
12
+ pixi: state.pixi.pixiApplication,
13
+ state,
14
+ assetLoader: state.assetLoader,
15
+ }, options));
16
+ }
17
+ return true;
18
+ }
19
+ /**
20
+ * Creates an entity update mod and entity factories.
21
+ *
22
+ * @category Pre-built Mods
23
+ */
24
+ export function createAnthaEntity2dSuite(options = {}) {
25
+ const entityKeys = new Set();
26
+ function createDefiner(entityParent) {
27
+ return (params) => {
28
+ if (params.assets) {
29
+ getObjectTypedEntries(params.assets).forEach(([key, rawAsset,]) => {
30
+ rawAsset.assetName = [
31
+ params.key,
32
+ key,
33
+ ].join(':');
34
+ });
35
+ }
36
+ return defineEntity(entityParent, params);
37
+ };
38
+ }
39
+ function defineEntity(entityParent, { collidesWith, key, paramsShape, paramsMap, assets }) {
40
+ if (entityKeys.has(key)) {
41
+ throw new Error(`Entity key '${key}' has already been attached to an entity class.`);
42
+ }
43
+ entityKeys.add(key);
44
+ const classWrapper = {
45
+ // @ts-expect-error: abstract methods are intentionally not implemented here
46
+ [key]: class extends entityParent {
47
+ static collidesWith = collidesWith;
48
+ static collidesWithSet = new Set(collidesWith?.collidesWithOtherEntities);
49
+ static entityKey = key;
50
+ static paramsShape = paramsShape;
51
+ static assets = assets || {};
52
+ static paramsMap = paramsMap;
53
+ static reverseParamsMap = reverseParamsMap(paramsMap);
54
+ },
55
+ };
56
+ return assertWrap.isDefined(classWrapper[key]);
57
+ }
58
+ const updateEntitiesMod = defineAnthaMod({
59
+ modName: 'antha-entity-2d-update',
60
+ initState: {
61
+ showHitboxDebug: !!options.debug,
62
+ disableEntityRender: !!options.disableEntityRender,
63
+ disableEntityUpdate: !!options.disableEntityUpdate,
64
+ },
65
+ cleanup({ state }) {
66
+ state.entityStore?.destroy();
67
+ },
68
+ trigger: options.updateTrigger,
69
+ async execute(executeParams) {
70
+ if (!ensureEntityStore({
71
+ options,
72
+ state: executeParams.state,
73
+ })) {
74
+ return SkipExecution;
75
+ }
76
+ else if (executeParams.state.entityStore) {
77
+ if (!executeParams.state.disableEntityUpdate) {
78
+ await executeParams.state.entityStore.updateAllEntities(executeParams);
79
+ }
80
+ if (!executeParams.state.disableEntityRender) {
81
+ await executeParams.state.entityStore.renderAllEntities(executeParams);
82
+ }
83
+ }
84
+ return executeParams.state.showHitboxDebug
85
+ ? html `
86
+ <canvas class="hitbox-debug-canvas"></canvas>
87
+ `
88
+ : undefined;
89
+ },
90
+ });
91
+ return {
92
+ /**
93
+ * Updates entity data an/or transient render state, depending on the options you provided
94
+ * to `createAnthaEntity2dSuite`.
95
+ */
96
+ updateEntitiesMod,
97
+ defineEntity: createDefiner(ViewEntity2d),
98
+ defineLogicEntity: createDefiner(BaseEntity2d),
99
+ entityKeys,
100
+ };
101
+ }
package/dist/entity.d.ts CHANGED
@@ -1,12 +1,11 @@
1
1
  import { type Asset, type AssetLoader, type AssetValue } from '@antha/asset';
2
2
  import { type ModExecuteParams } from '@antha/engine';
3
3
  import { type PixiApplication } from '@antha/graphics-2d';
4
- import { ConstructorInstanceMap, type AbstractConstructor, type AnyObject, type Constructor, type EmptyObject, type ExtractKeysWithMatchingValues, type IsEqual, type IsNever, type MaybePromise, type PartialWithUndefined, type WritableKeysOf } from '@augment-vir/common';
4
+ import { ConstructorInstanceMap, type AbstractConstructor, type AnyObject, type Constructor, type EmptyObject, type ExtractKeysWithMatchingValues, type IsAny, type IsEqual, type IsNever, type MaybePromise, type PartialWithUndefined, type WritableKeysOf } from '@augment-vir/common';
5
5
  import { System as HitboxSystem, type Response as Collision, type Body as Hitbox } from 'detect-collisions';
6
6
  import { type Shape } from 'object-shape-tester';
7
7
  import { type Container, type ViewContainer } from 'pixi.js';
8
8
  import { GenericListenTarget } from 'typed-event-target';
9
- import { type StaticEntity2dParts } from './entity-suite.js';
10
9
  export { System as HitboxSystem, type Response as Collision } from 'detect-collisions';
11
10
  /**
12
11
  * Definition of entity assets used when defining an entity.
@@ -74,6 +73,37 @@ export type EntityStore2dConstructorParams<State extends AnyObject = any> = {
74
73
  * @category Internal
75
74
  */
76
75
  export type Entity2dConstructor = Constructor<BaseEntity2d> & StaticEntity2dParts<any, any, BaseEntityAssetDefinitions>;
76
+ /**
77
+ * Static members of both view and logic entity constructors.
78
+ *
79
+ * @category Internal
80
+ */
81
+ export type StaticEntity2dParts<State extends AnyObject = any, ParamsShape extends Shape | undefined = any, EntityAssets extends BaseEntityAssetDefinitions | undefined = any> = {
82
+ /** Entity classes this entity observes collisions with. Omit to observe none. */
83
+ collidesWith: EntityCollisionDefinition | undefined;
84
+ /** Cached entity classes this entity observes collisions with. */
85
+ collidesWithSet: ReadonlySet<Entity2dConstructor>;
86
+ /**
87
+ * This key is used for deserialization of entities to track which class needs to be
88
+ * constructed. You cannot have duplicate keys loaded at the same time.
89
+ *
90
+ * This is used instead of inferring the entity key from the class name so that you can still
91
+ * minify your class names without making debugging nigh impossible (you'll still know which
92
+ * entities are being serialized and deserialized even if your class names are minified).
93
+ */
94
+ entityKey: string;
95
+ /** Shape definition of this entity's parameters. */
96
+ paramsShape: ParamsShape;
97
+ /**
98
+ * Defines which properties from {@link BaseEntity2d.params} will be mapped to hitbox and/or view
99
+ * properties.
100
+ */
101
+ paramsMap: IsAny<ParamsShape> extends true ? any : ParamsMap<ParamsShape extends Shape ? ParamsShape['runtimeType'] : undefined>;
102
+ /** Parses the serialized params generated by {@link BaseEntity2d.serialize}. */
103
+ deserialize(serialized: string | undefined): AnyObject | undefined;
104
+ assets: MappedEntityAssets<EntityAssets>;
105
+ ConstructorArgsType: Entity2dConstructorParams<State, ParamsShape extends Shape ? ParamsShape['runtimeType'] : undefined>;
106
+ };
77
107
  /**
78
108
  * Defines which entity classes this entity observes collisions with.
79
109
  *
@@ -139,10 +169,10 @@ export declare class EntityStore2d<State extends AnyObject = any> {
139
169
  * Runs `.update()` on all current entities and runs collision detection for all hitboxes. If
140
170
  * any entities get marked as destroyed during their update, then they will be removed from the
141
171
  * set of entities.
142
- *
143
- * @returns All detected hitbox collisions (if any).
144
172
  */
145
173
  updateAllEntities(updateParams: Readonly<ModExecuteParams<NoInfer<State>>>): Promise<void>;
174
+ /** Runs presentation-only updates for every entity without simulating collisions. */
175
+ renderAllEntities(renderParams: Readonly<ModExecuteParams<NoInfer<State>>>): Promise<void>;
146
176
  /** Get all current instances of the given entity class constructor. */
147
177
  getEntities<T>(entityClassConstructor: AbstractConstructor<T> | Constructor<T>): Set<T>;
148
178
  /** Remove an entity from the store. */
@@ -299,6 +329,12 @@ export declare const position2dParamsMap: {
299
329
  * @category Internal
300
330
  */
301
331
  export type ReverseParamsMap = Record<string, Partial<Record<'hitbox' | 'view', string[]>>>;
332
+ /**
333
+ * Converts {@link ParamsMap} to {@link ReverseParamsMap}.
334
+ *
335
+ * @category Internal
336
+ */
337
+ export declare function reverseParamsMap(paramsMap: ParamsMap | undefined): ReverseParamsMap | undefined;
302
338
  /**
303
339
  * Base entity class, types, and functionality.
304
340
  *
@@ -357,6 +393,12 @@ export declare abstract class BaseEntity2d<State extends AnyObject = any, Params
357
393
  * entity definition classes.
358
394
  */
359
395
  abstract update(updateParams: Readonly<ModExecuteParams<NoInfer<State>>>): MaybePromise<void>;
396
+ /**
397
+ * This is meant to be used to update transient render state without changing the authoritative
398
+ * entity state or logic. This is optional. `updateEntitiesMod` calls it (if it exists) after
399
+ * each entity data update unless `disableEntityRender` is `true`.
400
+ */
401
+ render(_renderParams: Readonly<ModExecuteParams<NoInfer<State>>>): MaybePromise<void>;
360
402
  /** Called after construction to perform async initialization (e.g. creating views). */
361
403
  initInstance(): MaybePromise<void>;
362
404
  /** The game's current state. */
package/dist/entity.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { assert, check } from '@augment-vir/assert';
2
- import { ConstructorInstanceMap, getObjectTypedEntries, makeWritable, mapObjectValues, } from '@augment-vir/common';
2
+ import { ConstructorInstanceMap, getObjectTypedEntries, getOrSet, makeWritable, mapObjectValues, } from '@augment-vir/common';
3
3
  import { System as HitboxSystem, Response, } from 'detect-collisions';
4
4
  import { assertValidShape, defineShape } from 'object-shape-tester';
5
5
  import { ParticleContainer } from 'pixi.js';
@@ -174,8 +174,6 @@ export class EntityStore2d {
174
174
  * Runs `.update()` on all current entities and runs collision detection for all hitboxes. If
175
175
  * any entities get marked as destroyed during their update, then they will be removed from the
176
176
  * set of entities.
177
- *
178
- * @returns All detected hitbox collisions (if any).
179
177
  */
180
178
  async updateAllEntities(updateParams) {
181
179
  if (this.isDestroyed) {
@@ -229,6 +227,18 @@ export class EntityStore2d {
229
227
  });
230
228
  await Promise.all(collisionPromises);
231
229
  }
230
+ /** Runs presentation-only updates for every entity without simulating collisions. */
231
+ async renderAllEntities(renderParams) {
232
+ if (this.isDestroyed) {
233
+ throw new Error('Cannot operate on a destroyed entity store.');
234
+ }
235
+ for (const entity of this.currentEntityInstances) {
236
+ if (entity.isDestroyed) {
237
+ return;
238
+ }
239
+ await entity.render(renderParams);
240
+ }
241
+ }
232
242
  /** Get all current instances of the given entity class constructor. */
233
243
  getEntities(entityClassConstructor) {
234
244
  return this.entityInstanceMap.getInstances(entityClassConstructor);
@@ -361,6 +371,34 @@ export const position2dParamsMap = {
361
371
  y: true,
362
372
  },
363
373
  };
374
+ /**
375
+ * Converts {@link ParamsMap} to {@link ReverseParamsMap}.
376
+ *
377
+ * @category Internal
378
+ */
379
+ export function reverseParamsMap(paramsMap) {
380
+ if (!paramsMap) {
381
+ return undefined;
382
+ }
383
+ const reverseParamsMap = {};
384
+ getObjectTypedEntries(paramsMap).forEach(([topKey, mappings,]) => {
385
+ getObjectTypedEntries(mappings).forEach(([mapToKey, mapFromKey,]) => {
386
+ if (!mapFromKey) {
387
+ return;
388
+ }
389
+ const paramMapping = getOrSet(reverseParamsMap, check.isString(mapFromKey) ? mapFromKey : mapToKey, () => {
390
+ return {};
391
+ });
392
+ const mapToArray = getOrSet(paramMapping, topKey, () => {
393
+ return [];
394
+ });
395
+ if (!mapToArray.includes(mapToKey)) {
396
+ mapToArray.push(mapToKey);
397
+ }
398
+ });
399
+ });
400
+ return reverseParamsMap;
401
+ }
364
402
  /**
365
403
  * Base entity class, types, and functionality.
366
404
  *
@@ -438,6 +476,13 @@ export class BaseEntity2d {
438
476
  entityAssets: assets,
439
477
  });
440
478
  }
479
+ /**
480
+ * This is meant to be used to update transient render state without changing the authoritative
481
+ * entity state or logic. This is optional. `updateEntitiesMod` calls it (if it exists) after
482
+ * each entity data update unless `disableEntityRender` is `true`.
483
+ */
484
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
485
+ render(_renderParams) { }
441
486
  /** Called after construction to perform async initialization (e.g. creating views). */
442
487
  initInstance() {
443
488
  return;
package/dist/index.d.ts CHANGED
@@ -1,4 +1,3 @@
1
- export * from './antha-entity.mod.js';
2
- export * from './entity-suite.js';
1
+ export * from './antha-entity-2d.mod.js';
3
2
  export * from './entity.js';
4
3
  export * from './load-antha-assets.js';
package/dist/index.js CHANGED
@@ -1,4 +1,3 @@
1
- export * from './antha-entity.mod.js';
2
- export * from './entity-suite.js';
1
+ export * from './antha-entity-2d.mod.js';
3
2
  export * from './entity.js';
4
3
  export * from './load-antha-assets.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@antha/entity-2d",
3
- "version": "0.16.0",
3
+ "version": "0.18.0",
4
4
  "description": "An Antha mod for handling 2D entities.",
5
5
  "keywords": [
6
6
  "vir",
@@ -39,8 +39,11 @@
39
39
  "@augment-vir/common": "^32.3.0"
40
40
  },
41
41
  "devDependencies": {
42
- "@antha/engine": "^0.16.0",
43
- "@antha/web-test-runner-plugin-pixi": "^0.16.0",
42
+ "@antha/asset": "^0.18.0",
43
+ "@antha/audio": "^0.18.0",
44
+ "@antha/engine": "^0.18.0",
45
+ "@antha/graphics-2d": "^0.18.0",
46
+ "@antha/web-test-runner-plugin-pixi": "^0.18.0",
44
47
  "@augment-vir/test": "^32.3.0",
45
48
  "@web/dev-server-esbuild": "^2.0.0",
46
49
  "@web/test-runner": "^1.0.0",
@@ -52,10 +55,10 @@
52
55
  "typed-event-target": "^4.3.3"
53
56
  },
54
57
  "peerDependencies": {
55
- "@antha/asset": "^0.16.0",
56
- "@antha/audio": "^0.16.0",
57
- "@antha/engine": "^0.16.0",
58
- "@antha/graphics-2d": "^0.16.0",
58
+ "@antha/asset": "^0.18.0",
59
+ "@antha/audio": "^0.18.0",
60
+ "@antha/engine": "^0.18.0",
61
+ "@antha/graphics-2d": "^0.18.0",
59
62
  "detect-collisions": "^10",
60
63
  "element-vir": "^27",
61
64
  "object-shape-tester": "^6",
@@ -1,36 +0,0 @@
1
- import { type AnthaAssetModState } from '@antha/asset';
2
- import { type AnthaMod } from '@antha/engine';
3
- import { type AnthaGraphics2dModState } from '@antha/graphics-2d';
4
- import { type AnyObject, type PartialWithUndefined } from '@augment-vir/common';
5
- import { type EntityStore2d, type EntityStore2dConstructorParams } from './entity.js';
6
- /**
7
- * State for {@link createAnthaEntityMod2d}.
8
- *
9
- * @category Internal
10
- */
11
- export type AnthaEntity2dModState<State extends AnyObject = AnyObject> = {
12
- entityStore: EntityStore2d<Partial<AnthaEntity2dModState<State>>>;
13
- /** If true, entity updates and collision checks are skipped. */
14
- disableEntityUpdates: boolean;
15
- /** If `true`, hit boxes are visually rendered for debugging purposes. */
16
- debugHitboxes: boolean;
17
- } & State & AnthaGraphics2dModState & AnthaAssetModState;
18
- /**
19
- * Options for {@link createAnthaEntityMod2d}.
20
- *
21
- * @category Internal
22
- */
23
- export type AnthaEntity2dModOptions = PartialWithUndefined<EntityStore2dConstructorParams & {
24
- debug: boolean;
25
- }>;
26
- /**
27
- * A mod for rendering entities and handling collisions between them.
28
- *
29
- * @category Pre-built Mods
30
- */
31
- export declare function createAnthaEntityMod2d<ExtraState extends AnyObject>(options?: Readonly<AnthaEntity2dModOptions>): {
32
- defineEntity: import("./entity-suite.js").DefineViewEntity2d<AnthaEntity2dModState<ExtraState>>;
33
- defineLogicEntity: import("./entity-suite.js").DefineLogicEntity2d<AnthaEntity2dModState<ExtraState>>;
34
- entityKeys: Set<string>;
35
- mod: AnthaMod<AnthaEntity2dModState<ExtraState>>;
36
- };
@@ -1,60 +0,0 @@
1
- import { anthaAssetModName, AssetLoader } from '@antha/asset';
2
- import { defineAnthaMod, SkipExecution } from '@antha/engine';
3
- import { mergeDefinedProperties, } from '@augment-vir/common';
4
- import { html } from 'element-vir';
5
- import { defineEntitySuite2d } from './entity-suite.js';
6
- /**
7
- * A mod for rendering entities and handling collisions between them.
8
- *
9
- * @category Pre-built Mods
10
- */
11
- export function createAnthaEntityMod2d(options = {}) {
12
- const { EntityStore, ...entitySuite } = defineEntitySuite2d();
13
- const mod = defineAnthaMod({
14
- modName: 'antha-entity-2d',
15
- initState: {
16
- debugHitboxes: !!options.debug,
17
- },
18
- cleanup({ state }) {
19
- state.entityStore?.destroy();
20
- },
21
- async execute(executeParams) {
22
- /**
23
- * If we don't have a mod that is expected to create the asset loader, then we create
24
- * one ourself.
25
- */
26
- if (!executeParams.state.assetLoader &&
27
- !executeParams.engine.currentMods.some((mod) => mod.modName === anthaAssetModName)) {
28
- executeParams.state.assetLoader = new AssetLoader();
29
- }
30
- const pixiApplication = executeParams.state.pixi?.pixiApplication;
31
- if (!pixiApplication) {
32
- return SkipExecution;
33
- }
34
- if (executeParams.state.entityStore) {
35
- if (!executeParams.state.disableEntityUpdates) {
36
- await executeParams.state.entityStore.updateAllEntities(executeParams);
37
- }
38
- }
39
- else if (executeParams.state.assetLoader) {
40
- executeParams.state.entityStore = new EntityStore(mergeDefinedProperties({
41
- pixi: pixiApplication,
42
- state: executeParams.state,
43
- assetLoader: executeParams.state.assetLoader,
44
- }, options));
45
- }
46
- if (executeParams.state.debugHitboxes) {
47
- return html `
48
- <canvas class="hitbox-debug-canvas"></canvas>
49
- `;
50
- }
51
- else {
52
- return undefined;
53
- }
54
- },
55
- });
56
- return {
57
- mod,
58
- ...entitySuite,
59
- };
60
- }
@@ -1,79 +0,0 @@
1
- import { check } from '@augment-vir/assert';
2
- import { getObjectTypedEntries, getOrSet, } from '@augment-vir/common';
3
- import { BaseEntity2d, EntityStore2d, ViewEntity2d, } from './entity.js';
4
- /**
5
- * This is the starting point of the @game-vir/entity package. Call this to produce the function
6
- * needed to define new entities and the store needed to add entity instances.
7
- *
8
- * @category Main
9
- */
10
- export function defineEntitySuite2d() {
11
- const entityKeys = new Set();
12
- function createDefiner(entityParent) {
13
- return (params) => {
14
- if (params.assets) {
15
- getObjectTypedEntries(params.assets).forEach(([key, rawAsset,]) => {
16
- rawAsset.assetName = [
17
- params.key,
18
- key,
19
- ].join(':');
20
- });
21
- }
22
- return defineEntity(entityParent, params);
23
- };
24
- }
25
- function defineEntity(entityParent, { collidesWith, key, paramsShape, paramsMap, assets }) {
26
- if (entityKeys.has(key)) {
27
- throw new Error(`Entity key '${key}' has already been attached to an entity class.`);
28
- }
29
- entityKeys.add(key);
30
- const classWrapper = {
31
- // @ts-expect-error: abstract methods are intentionally not implemented here
32
- [key]: class extends entityParent {
33
- static collidesWith = collidesWith;
34
- static collidesWithSet = new Set(collidesWith?.collidesWithOtherEntities);
35
- static entityKey = key;
36
- static paramsShape = paramsShape;
37
- static assets = assets || {};
38
- static paramsMap = paramsMap;
39
- static reverseParamsMap = reverseParamsMap(paramsMap);
40
- },
41
- };
42
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
43
- return classWrapper[key];
44
- }
45
- return {
46
- EntityStore: EntityStore2d,
47
- defineEntity: createDefiner(ViewEntity2d),
48
- defineLogicEntity: createDefiner(BaseEntity2d),
49
- entityKeys,
50
- };
51
- }
52
- /**
53
- * Converts {@link ParamsMap} to {@link ReverseParamsMap}.
54
- *
55
- * @category Internal
56
- */
57
- export function reverseParamsMap(paramsMap) {
58
- if (!paramsMap) {
59
- return undefined;
60
- }
61
- const reverseParamsMap = {};
62
- getObjectTypedEntries(paramsMap).forEach(([topKey, mappings,]) => {
63
- getObjectTypedEntries(mappings).forEach(([mapToKey, mapFromKey,]) => {
64
- if (!mapFromKey) {
65
- return;
66
- }
67
- const paramMapping = getOrSet(reverseParamsMap, check.isString(mapFromKey) ? mapFromKey : mapToKey, () => {
68
- return {};
69
- });
70
- const mapToArray = getOrSet(paramMapping, topKey, () => {
71
- return [];
72
- });
73
- if (!mapToArray.includes(mapToKey)) {
74
- mapToArray.push(mapToKey);
75
- }
76
- });
77
- });
78
- return reverseParamsMap;
79
- }