@m2c2kit/core 0.3.15 → 0.3.16

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/dist/index.d.ts CHANGED
@@ -726,12 +726,21 @@ interface CallbackOptions {
726
726
  }
727
727
 
728
728
  /**
729
- * Notifies when events in the Frame cycle occur on a Game.
729
+ * A Plugin is code that can be registered to run at certain points in the game loop.
730
730
  */
731
- interface FrameCycleEvent extends EventBase {
732
- target: Game;
733
- /** difference in milliseconds since the last Frame lifecycle began */
734
- deltaTime: number;
731
+ interface Plugin {
732
+ /** Short identifier of the plugin. */
733
+ id: string;
734
+ /** What kind of m2c2kit object does the plugin work with? */
735
+ type: "Game" | "Session" | "Survey";
736
+ /** Initialization code run when the plugin is registered with the game. */
737
+ initialize?: (game: Game) => Promise<void>;
738
+ /** Is the plugin disabled and not to be run? Default is false. @remarks Disabled plugins will still be initialized. */
739
+ disabled?: boolean;
740
+ /** Plugin code run before the frame update, but before the frame draw. */
741
+ beforeUpdate?: (game: Game, deltaTime: number) => void;
742
+ /** Plugin code run after the frame update, but before the frame draw. */
743
+ afterUpdate?: (game: Game, deltaTime: number) => void;
735
744
  }
736
745
 
737
746
  interface TrialData {
@@ -757,6 +766,7 @@ declare class Game implements Activity {
757
766
  private warmupFunctionQueue;
758
767
  private loaderElementsRemoved;
759
768
  private _dataStores?;
769
+ private plugins;
760
770
  additionalParameters?: unknown;
761
771
  staticTrialSchema: {
762
772
  [key: string]: JsonSchemaDataTypeScriptTypes;
@@ -983,7 +993,7 @@ declare class Game implements Activity {
983
993
  * is not found, then return fallback value
984
994
  *
985
995
  * @param parameterName - the name of the game parameter whose value is requested
986
- * @param fallback - the value to return if parameterName is not found
996
+ * @param fallbackValue - the value to return if parameterName is not found
987
997
  * @returns
988
998
  */
989
999
  getParameterOrFallback<T, U>(parameterName: string, fallbackValue: U): T | U;
@@ -1171,12 +1181,14 @@ declare class Game implements Activity {
1171
1181
  */
1172
1182
  private createOutgoingScene;
1173
1183
  /**
1174
- * Executes a callback when the frame has finished simulating physics.
1184
+ * Registers a plugin with the game.
1175
1185
  *
1176
- * @param callback - function to execute.
1177
- * @param options - options for the callback.
1186
+ * @remarks Upon registration, the plugin's optional asynchronous
1187
+ * `initialize()` method will be called.
1188
+ *
1189
+ * @param plugin - Plugin to register
1178
1190
  */
1179
- onFrameDidSimulatePhysics(callback: (frameCycleEvent: FrameCycleEvent) => void, options?: CallbackOptions): void;
1191
+ registerPlugin(plugin: Plugin): Promise<void>;
1180
1192
  private update;
1181
1193
  private draw;
1182
1194
  private calculateFps;
@@ -1224,17 +1236,6 @@ declare class Game implements Activity {
1224
1236
  private htmlCanvasPointerDownHandler;
1225
1237
  private htmlCanvasPointerUpHandler;
1226
1238
  private htmlCanvasPointerMoveHandler;
1227
- /**
1228
- * Adjusts dragging behavior when the pointer leaves the canvas
1229
- *
1230
- * @remarks This is necessary because the pointerup event is not fired when
1231
- * the pointer leaves the canvas. On desktop, this means that the user might
1232
- * lift the pointer outside the canvas, but the entity will still be dragged
1233
- * when the pointer is moved back into the canvas.
1234
- *
1235
- * @param domPointerEvent
1236
- * @returns
1237
- */
1238
1239
  private htmlCanvasPointerLeaveHandler;
1239
1240
  /**
1240
1241
  * Determines if/how m2c2kit entities respond to the DOM PointerDown event
@@ -1246,6 +1247,7 @@ declare class Game implements Activity {
1246
1247
  private processDomPointerDown;
1247
1248
  private processDomPointerUp;
1248
1249
  private processDomPointerMove;
1250
+ private processDomPointerLeave;
1249
1251
  private raiseM2PointerDownEvent;
1250
1252
  private raiseTapDownEvent;
1251
1253
  private raiseTapLeaveEvent;
@@ -1688,7 +1690,7 @@ interface EventBase {
1688
1690
  /** Type of event. */
1689
1691
  type: EventType | string;
1690
1692
  /** The object on which the event occurred. */
1691
- target: Entity | Session | Activity;
1693
+ target: Entity | Session | Activity | Plugin;
1692
1694
  /** Has the event been taken care of by the listener and not be dispatched to other targets? */
1693
1695
  handled?: boolean;
1694
1696
  }
@@ -1794,10 +1796,10 @@ declare abstract class Entity implements EntityOptions {
1794
1796
  isShape: boolean;
1795
1797
  isText: boolean;
1796
1798
  name: string;
1797
- position: Point;
1798
- scale: number;
1799
+ _position: Point;
1800
+ _scale: number;
1799
1801
  alpha: number;
1800
- zRotation: number;
1802
+ _zRotation: number;
1801
1803
  isUserInteractionEnabled: boolean;
1802
1804
  draggable: boolean;
1803
1805
  hidden: boolean;
@@ -2095,6 +2097,12 @@ declare abstract class Entity implements EntityOptions {
2095
2097
  */
2096
2098
  get canvasKit(): CanvasKit;
2097
2099
  get parentSceneAsEntity(): Entity;
2100
+ get position(): Point;
2101
+ set position(position: Point);
2102
+ get zRotation(): number;
2103
+ set zRotation(zRotation: number);
2104
+ get scale(): number;
2105
+ set scale(scale: number);
2098
2106
  /**
2099
2107
  * For a given directed acyclic graph, topological ordering of the vertices will be identified using BFS
2100
2108
  * @param adjList Adjacency List that represent a graph with vertices and edges
@@ -3263,4 +3271,4 @@ declare class WebGlInfo {
3263
3271
  static dispose(): void;
3264
3272
  }
3265
3273
 
3266
- export { Action, type Activity, type ActivityKeyValueData, type ActivityLifecycleEvent, type ActivityResultsEvent, ActivityType, type BrowserImage, type CallbackOptions, CanvasKitHelpers, ColorfulMutablePath, Composite, type CompositeOptions, Constants, ConstraintType, type Constraints, CustomAction, type CustomActionOptions, type DefaultParameter, Dimensions, type DrawableOptions, type EasingFunction, Easings, Entity, type EntityEvent, type EntityEventListener, type EntityOptions, EntityType, Equals, type EventBase, type EventListenerBase, EventType, FadeAlphaAction, type FadeAlphaActionOptions, type FontData, FontManager, Game, type GameData, type GameOptions, type GameParameters, GlobalVariables, type GoToActivityOptions, GroupAction, I18n, type IDataStore, type IDrawable, type IText, ImageManager, Label, LabelHorizontalAlignmentMode, type LabelOptions, type Layout, LayoutConstraint, LoadedImage, type M2ColorfulPath, type M2DragEvent, type M2Path, type M2PointerEvent, MoveAction, type MoveActionOptions, MutablePath, NoneTransition, type Point, RandomDraws, type RectOptions, type RgbaColor, RotateAction, ScaleAction, type ScaleActionOptions, Scene, type SceneOptions, SceneTransition, SequenceAction, Session, type SessionDictionaryValues, type SessionLifecycleEvent, type SessionOptions, Shape, type ShapeOptions, ShapeType, type Size, SlideTransition, type SlideTransitionOptions, Sprite, type SpriteOptions, Story, type StoryOptions, type TapEvent, TextLine, type TextLineOptions, type TextOptions, Timer, Transition, TransitionDirection, TransitionType, type Translations, type TrialData, type TrialSchema, Uuid, WaitAction, type WaitActionOptions, WebColors, WebGlInfo, handleInterfaceOptions };
3274
+ export { Action, type Activity, type ActivityKeyValueData, type ActivityLifecycleEvent, type ActivityResultsEvent, ActivityType, type BrowserImage, type CallbackOptions, CanvasKitHelpers, ColorfulMutablePath, Composite, type CompositeOptions, Constants, ConstraintType, type Constraints, CustomAction, type CustomActionOptions, type DefaultParameter, Dimensions, type DrawableOptions, type EasingFunction, Easings, Entity, type EntityEvent, type EntityEventListener, type EntityOptions, EntityType, Equals, type EventBase, type EventListenerBase, EventType, FadeAlphaAction, type FadeAlphaActionOptions, type FontData, FontManager, Game, type GameData, type GameOptions, type GameParameters, GlobalVariables, type GoToActivityOptions, GroupAction, I18n, type IDataStore, type IDrawable, type IText, ImageManager, Label, LabelHorizontalAlignmentMode, type LabelOptions, type Layout, LayoutConstraint, LoadedImage, type M2ColorfulPath, type M2DragEvent, type M2Path, type M2PointerEvent, MoveAction, type MoveActionOptions, MutablePath, NoneTransition, type Plugin, type Point, RandomDraws, type RectOptions, type RgbaColor, RotateAction, ScaleAction, type ScaleActionOptions, Scene, type SceneOptions, SceneTransition, SequenceAction, Session, type SessionDictionaryValues, type SessionLifecycleEvent, type SessionOptions, Shape, type ShapeOptions, ShapeType, type Size, SlideTransition, type SlideTransitionOptions, Sprite, type SpriteOptions, Story, type StoryOptions, type TapEvent, TextLine, type TextLineOptions, type TextOptions, Timer, Transition, TransitionDirection, TransitionType, type Translations, type TrialData, type TrialSchema, Uuid, WaitAction, type WaitActionOptions, WebColors, WebGlInfo, handleInterfaceOptions };
package/dist/index.js CHANGED
@@ -1515,11 +1515,11 @@ class Entity {
1515
1515
  this.isDrawable = false;
1516
1516
  this.isShape = false;
1517
1517
  this.isText = false;
1518
- this.position = { x: 0, y: 0 };
1518
+ this._position = { x: 0, y: 0 };
1519
1519
  // position of the entity in the parent coordinate system
1520
- this.scale = 1;
1520
+ this._scale = 1;
1521
1521
  this.alpha = 1;
1522
- this.zRotation = 0;
1522
+ this._zRotation = 0;
1523
1523
  this.isUserInteractionEnabled = false;
1524
1524
  this.draggable = false;
1525
1525
  this.hidden = false;
@@ -2352,6 +2352,38 @@ class Entity {
2352
2352
  }
2353
2353
  throw new Error(`Entity ${this} has not been added to a scene`);
2354
2354
  }
2355
+ get position() {
2356
+ const entity = this;
2357
+ return {
2358
+ get x() {
2359
+ return entity._position.x;
2360
+ },
2361
+ set x(x) {
2362
+ entity._position.x = x;
2363
+ },
2364
+ get y() {
2365
+ return entity._position.y;
2366
+ },
2367
+ set y(y) {
2368
+ entity._position.y = y;
2369
+ }
2370
+ };
2371
+ }
2372
+ set position(position) {
2373
+ this._position = position;
2374
+ }
2375
+ get zRotation() {
2376
+ return this._zRotation;
2377
+ }
2378
+ set zRotation(zRotation) {
2379
+ this._zRotation = zRotation;
2380
+ }
2381
+ get scale() {
2382
+ return this._scale;
2383
+ }
2384
+ set scale(scale) {
2385
+ this._scale = scale;
2386
+ }
2355
2387
  // from https://medium.com/@konduruharish/topological-sort-in-typescript-and-c-6d5ecc4bad95
2356
2388
  /**
2357
2389
  * For a given directed acyclic graph, topological ordering of the vertices will be identified using BFS
@@ -3670,6 +3702,7 @@ class Game {
3670
3702
  this.steppingNow = 0;
3671
3703
  this.warmupFunctionQueue = new Array();
3672
3704
  this.loaderElementsRemoved = false;
3705
+ this.plugins = [];
3673
3706
  this.staticTrialSchema = {};
3674
3707
  this.data = {
3675
3708
  trials: new Array()
@@ -4117,7 +4150,7 @@ class Game {
4117
4150
  * is not found, then return fallback value
4118
4151
  *
4119
4152
  * @param parameterName - the name of the game parameter whose value is requested
4120
- * @param fallback - the value to return if parameterName is not found
4153
+ * @param fallbackValue - the value to return if parameterName is not found
4121
4154
  * @returns
4122
4155
  */
4123
4156
  getParameterOrFallback(parameterName, fallbackValue) {
@@ -5112,27 +5145,34 @@ class Game {
5112
5145
  return outgoingScene;
5113
5146
  }
5114
5147
  /**
5115
- * Executes a callback when the frame has finished simulating physics.
5148
+ * Registers a plugin with the game.
5116
5149
  *
5117
- * @param callback - function to execute.
5118
- * @param options - options for the callback.
5150
+ * @remarks Upon registration, the plugin's optional asynchronous
5151
+ * `initialize()` method will be called.
5152
+ *
5153
+ * @param plugin - Plugin to register
5119
5154
  */
5120
- onFrameDidSimulatePhysics(callback, options) {
5121
- this.addEventListener(
5122
- EventType.FrameDidSimulatePhysics,
5123
- callback,
5124
- options
5125
- );
5155
+ async registerPlugin(plugin) {
5156
+ if (plugin.type !== ActivityType.Game) {
5157
+ throw new Error(
5158
+ `registerPlugin(): plugin ${plugin.id} is not a game plugin. It is a ${plugin.type} plugin.`
5159
+ );
5160
+ }
5161
+ if (this.plugins.includes(plugin) || this.plugins.map((p) => p.id).includes(plugin.id)) {
5162
+ throw new Error(
5163
+ `registerPlugin(): plugin ${plugin.id} already registered.`
5164
+ );
5165
+ }
5166
+ this.plugins.push(plugin);
5167
+ if (plugin.initialize) {
5168
+ await plugin.initialize(this);
5169
+ }
5126
5170
  }
5127
5171
  update() {
5172
+ this.plugins.filter((p) => p.beforeUpdate !== void 0 && p.disabled !== true).forEach((p) => p.beforeUpdate(this, Globals.deltaTime));
5128
5173
  this.scenes.filter((scene) => scene._active).forEach((scene) => scene.update());
5129
5174
  this.freeEntitiesScene.update();
5130
- const frameDidSimulatePhysicsEvent = {
5131
- target: this,
5132
- type: EventType.FrameDidSimulatePhysics,
5133
- deltaTime: Globals.deltaTime
5134
- };
5135
- this.raiseActivityEventOnListeners(frameDidSimulatePhysicsEvent);
5175
+ this.plugins.filter((p) => p.afterUpdate !== void 0 && p.disabled !== true).forEach((p) => p.afterUpdate(this, Globals.deltaTime));
5136
5176
  }
5137
5177
  draw(canvas) {
5138
5178
  this.scenes.filter((scene) => scene._active).forEach((scene) => scene.draw(canvas));
@@ -5546,35 +5586,26 @@ class Game {
5546
5586
  domPointerEvent
5547
5587
  );
5548
5588
  }
5549
- /**
5550
- * Adjusts dragging behavior when the pointer leaves the canvas
5551
- *
5552
- * @remarks This is necessary because the pointerup event is not fired when
5553
- * the pointer leaves the canvas. On desktop, this means that the user might
5554
- * lift the pointer outside the canvas, but the entity will still be dragged
5555
- * when the pointer is moved back into the canvas.
5556
- *
5557
- * @param domPointerEvent
5558
- * @returns
5559
- */
5560
5589
  htmlCanvasPointerLeaveHandler(domPointerEvent) {
5561
5590
  if (!this.currentScene) {
5562
5591
  return;
5563
5592
  }
5564
- this.currentScene.children.forEach((entity) => {
5565
- if (entity.dragging) {
5566
- const m2Event = {
5567
- target: entity,
5568
- type: EventType.DragEnd,
5569
- handled: false
5570
- };
5571
- entity.dragging = false;
5572
- entity.pressed = false;
5573
- entity.pressedAndWithinHitArea = false;
5574
- this.raiseM2DragEndEvent(entity, m2Event, domPointerEvent);
5575
- return;
5576
- }
5577
- });
5593
+ domPointerEvent.preventDefault();
5594
+ const scene = this.currentScene;
5595
+ if (!scene || !this.sceneCanReceiveUserInteraction(scene)) {
5596
+ return;
5597
+ }
5598
+ const m2Event = {
5599
+ target: scene,
5600
+ type: EventType.PointerLeave,
5601
+ handled: false
5602
+ };
5603
+ this.processDomPointerLeave(scene, m2Event, domPointerEvent);
5604
+ this.processDomPointerLeave(
5605
+ this.freeEntitiesScene,
5606
+ m2Event,
5607
+ domPointerEvent
5608
+ );
5578
5609
  }
5579
5610
  /**
5580
5611
  * Determines if/how m2c2kit entities respond to the DOM PointerDown event
@@ -5687,7 +5718,7 @@ class Game {
5687
5718
  entity.pressedAndWithinHitArea = false;
5688
5719
  this.raiseTapLeaveEvent(entity, m2Event, domPointerEvent);
5689
5720
  }
5690
- if (this.IsCanvasPointWithinEntityBounds(
5721
+ if (entity.isUserInteractionEnabled && this.IsCanvasPointWithinEntityBounds(
5691
5722
  entity,
5692
5723
  domPointerEvent.offsetX,
5693
5724
  domPointerEvent.offsetY
@@ -5695,15 +5726,13 @@ class Game {
5695
5726
  this.raiseM2PointerMoveEvent(entity, m2Event, domPointerEvent);
5696
5727
  entity.withinHitArea = true;
5697
5728
  }
5698
- if (!this.IsCanvasPointWithinEntityBounds(
5729
+ if (entity.isUserInteractionEnabled && entity.withinHitArea && !this.IsCanvasPointWithinEntityBounds(
5699
5730
  entity,
5700
5731
  domPointerEvent.offsetX,
5701
5732
  domPointerEvent.offsetY
5702
5733
  )) {
5703
- if (entity.withinHitArea) {
5704
- this.raiseM2PointerLeaveEvent(entity, m2Event, domPointerEvent);
5705
- entity.withinHitArea = false;
5706
- }
5734
+ entity.withinHitArea = false;
5735
+ this.raiseM2PointerLeaveEvent(entity, m2Event, domPointerEvent);
5707
5736
  }
5708
5737
  if (entity.children) {
5709
5738
  entity.children.filter((entity2) => !entity2.hidden).filter((entity2) => entity2.isDrawable).sort(
@@ -5713,6 +5742,46 @@ class Game {
5713
5742
  );
5714
5743
  }
5715
5744
  }
5745
+ processDomPointerLeave(entity, m2Event, domPointerEvent) {
5746
+ if (m2Event.handled) {
5747
+ return;
5748
+ }
5749
+ if (entity.dragging) {
5750
+ const m2Event2 = {
5751
+ target: entity,
5752
+ type: EventType.DragEnd,
5753
+ handled: false
5754
+ };
5755
+ entity.dragging = false;
5756
+ entity.pressed = false;
5757
+ entity.pressedAndWithinHitArea = false;
5758
+ this.raiseM2DragEndEvent(entity, m2Event2, domPointerEvent);
5759
+ return;
5760
+ }
5761
+ if (entity.isUserInteractionEnabled && entity.pressed && entity.pressedAndWithinHitArea && !this.IsCanvasPointWithinEntityBounds(
5762
+ entity,
5763
+ domPointerEvent.offsetX,
5764
+ domPointerEvent.offsetY
5765
+ )) {
5766
+ entity.pressedAndWithinHitArea = false;
5767
+ this.raiseTapLeaveEvent(entity, m2Event, domPointerEvent);
5768
+ }
5769
+ if (entity.isUserInteractionEnabled && entity.withinHitArea && !this.IsCanvasPointWithinEntityBounds(
5770
+ entity,
5771
+ domPointerEvent.offsetX,
5772
+ domPointerEvent.offsetY
5773
+ )) {
5774
+ entity.withinHitArea = false;
5775
+ this.raiseM2PointerLeaveEvent(entity, m2Event, domPointerEvent);
5776
+ }
5777
+ if (entity.children) {
5778
+ entity.children.filter((entity2) => !entity2.hidden).filter((entity2) => entity2.isDrawable).sort(
5779
+ (a, b) => b.zPosition - a.zPosition
5780
+ ).forEach(
5781
+ (entity2) => this.processDomPointerLeave(entity2, m2Event, domPointerEvent)
5782
+ );
5783
+ }
5784
+ }
5716
5785
  raiseM2PointerDownEvent(entity, m2Event, domPointerEvent) {
5717
5786
  m2Event.target = entity;
5718
5787
  m2Event.type = EventType.PointerDown;
@@ -7422,7 +7491,7 @@ class Session {
7422
7491
  this.eventListeners = new Array();
7423
7492
  this.sessionDictionary = /* @__PURE__ */ new Map();
7424
7493
  this.initialized = false;
7425
- this.version = "0.3.15 (38470c49)";
7494
+ this.version = "0.3.16 (d8a00e86)";
7426
7495
  this.options = options;
7427
7496
  for (const activity of this.options.activities) {
7428
7497
  if (this.options.activities.filter((a) => a === activity).length > 1) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@m2c2kit/core",
3
- "version": "0.3.15",
3
+ "version": "0.3.16",
4
4
  "description": "The m2c2kit core functionality",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.js",
@@ -48,7 +48,7 @@
48
48
  "jest-environment-jsdom": "29.7.0",
49
49
  "jsdom": "23.0.1",
50
50
  "rimraf": "5.0.5",
51
- "rollup": "4.8.0",
51
+ "rollup": "4.9.2",
52
52
  "rollup-plugin-copy": "3.5.0",
53
53
  "rollup-plugin-dts": "6.1.0",
54
54
  "rollup-plugin-esbuild": "6.1.0",