@m2c2kit/assessment-color-shapes 0.8.10 → 0.8.11

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 (2) hide show
  1. package/dist/index.js +434 -468
  2. package/package.json +10 -10
package/dist/index.js CHANGED
@@ -1,29 +1,6 @@
1
- import { Game, Shape, Sprite, Scene, WebColors, Transition, RandomDraws, Label, Action, Timer, TransitionDirection, Easings } from '@m2c2kit/core';
1
+ import { Game, Sprite, Scene, WebColors, Transition, RandomDraws, Shape, Label, Action, Timer, TransitionDirection, Easings } from '@m2c2kit/core';
2
2
  import { Instructions, Grid, Button } from '@m2c2kit/addons';
3
3
 
4
- var __getProtoOf = Object.getPrototypeOf;
5
- var __reflectGet = Reflect.get;
6
- var __superGet = (cls, obj, key) => __reflectGet(__getProtoOf(cls), key, obj);
7
- var __async = (__this, __arguments, generator) => {
8
- return new Promise((resolve, reject) => {
9
- var fulfilled = (value) => {
10
- try {
11
- step(generator.next(value));
12
- } catch (e) {
13
- reject(e);
14
- }
15
- };
16
- var rejected = (value) => {
17
- try {
18
- step(generator.throw(value));
19
- } catch (e) {
20
- reject(e);
21
- }
22
- };
23
- var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
24
- step((generator = generator.apply(__this, __arguments)).next());
25
- });
26
- };
27
4
  class ColorShapes extends Game {
28
5
  constructor() {
29
6
  const defaultParameters = {
@@ -243,7 +220,7 @@ class ColorShapes extends Game {
243
220
  const options = {
244
221
  name: "Color Shapes",
245
222
  id: "color-shapes",
246
- version: "0.8.10 (25099410)",
223
+ version: "0.8.11 (60325bea)",
247
224
  shortDescription: "Color Shapes is a visual array change detection task, measuring intra-item feature binding, where participants determine if shapes change color across two sequential presentations of shape stimuli.",
248
225
  longDescription: `Color Shapes is a change detection paradigm used to measure visual short-term memory binding (Parra et al., 2009). Participants are asked to memorize the shapes and colors of three different polygons for 3 seconds. The three polygons are then removed from the screen and re-displayed at different locations, either having the same or different colors. Participants are then asked to decide whether the combination of colors and shapes are the "Same" or "Different" between the study and test phases.`,
249
226
  showFps: defaultParameters.show_fps.default,
@@ -288,519 +265,508 @@ class ColorShapes extends Game {
288
265
  };
289
266
  super(options);
290
267
  }
291
- initialize() {
292
- return __async(this, null, function* () {
293
- yield __superGet(ColorShapes.prototype, this, "initialize").call(this);
294
- const game = this;
295
- const SHAPE_SVG_HEIGHT = 96;
296
- const SQUARE_SIDE_LENGTH = 350;
297
- const SHAPE_SIZE = { width: 116, height: 116 };
298
- const numberOfShapesShown = game.getParameter(
299
- "number_of_shapes_shown"
300
- );
301
- const shapeLibrary = this.makeShapes(SHAPE_SVG_HEIGHT, SHAPE_SIZE);
302
- if (game.getParameter("show_quit_button")) {
303
- const quitSprite = new Sprite({
304
- imageName: "circle-x",
305
- position: { x: 380, y: 20 },
306
- isUserInteractionEnabled: true
268
+ async initialize() {
269
+ await super.initialize();
270
+ const game = this;
271
+ const SHAPE_SVG_HEIGHT = 96;
272
+ const SQUARE_SIDE_LENGTH = 350;
273
+ const numberOfShapesShown = game.getParameter(
274
+ "number_of_shapes_shown"
275
+ );
276
+ const shapeLibrary = this.makeShapes(SHAPE_SVG_HEIGHT);
277
+ if (game.getParameter("show_quit_button")) {
278
+ const quitSprite = new Sprite({
279
+ imageName: "circle-x",
280
+ position: { x: 380, y: 20 },
281
+ isUserInteractionEnabled: true
282
+ });
283
+ game.addFreeEntity(quitSprite);
284
+ quitSprite.onTapDown((e) => {
285
+ game.removeAllFreeEntities();
286
+ e.handled = true;
287
+ const blankScene = new Scene();
288
+ game.addScene(blankScene);
289
+ game.presentScene(blankScene);
290
+ game.addTrialData("quit_button_pressed", true);
291
+ game.trialComplete();
292
+ game.cancel();
293
+ });
294
+ }
295
+ let instructionsScenes;
296
+ switch (game.getParameter("instruction_type")) {
297
+ case "short": {
298
+ instructionsScenes = Instructions.Create({
299
+ instructionScenes: [
300
+ {
301
+ title: "Color Shapes",
302
+ text: `Try to remember the location and color of ${numberOfShapesShown} shapes, because they will soon disappear. When the shapes reappear, answer whether they have the SAME or DIFFERENT colors as they had before.`,
303
+ imageName: "instructions-1",
304
+ imageAboveText: false,
305
+ imageMarginTop: 32,
306
+ textFontSize: 24,
307
+ titleFontSize: 30,
308
+ textVerticalBias: 0.2,
309
+ nextButtonText: "START",
310
+ nextButtonBackgroundColor: WebColors.Green,
311
+ nextSceneTransition: Transition.none()
312
+ }
313
+ ]
307
314
  });
308
- game.addFreeEntity(quitSprite);
309
- quitSprite.onTapDown((e) => {
310
- game.removeAllFreeEntities();
311
- e.handled = true;
312
- const blankScene = new Scene();
313
- game.addScene(blankScene);
314
- game.presentScene(blankScene);
315
- game.addTrialData("quit_button_pressed", true);
316
- game.trialComplete();
317
- game.cancel();
315
+ break;
316
+ }
317
+ case "long": {
318
+ instructionsScenes = Instructions.Create({
319
+ instructionScenes: [
320
+ {
321
+ title: "Color Shapes",
322
+ text: `Try to remember the location and color of ${numberOfShapesShown} shapes, because they will soon disappear.`,
323
+ imageName: "instructions-1",
324
+ imageAboveText: false,
325
+ imageMarginTop: 32,
326
+ textFontSize: 24,
327
+ titleFontSize: 30,
328
+ textVerticalBias: 0.2
329
+ },
330
+ {
331
+ title: "Color Shapes",
332
+ text: "Next you will see the same shapes reappear.",
333
+ imageName: "instructions-2",
334
+ imageAboveText: false,
335
+ imageMarginTop: 32,
336
+ textFontSize: 24,
337
+ titleFontSize: 30,
338
+ textVerticalBias: 0.2
339
+ },
340
+ {
341
+ title: "Color Shapes",
342
+ text: "Answer whether the shapes have the SAME or DIFFERENT colors as they had before.",
343
+ imageName: "instructions-3",
344
+ imageAboveText: false,
345
+ imageMarginTop: 32,
346
+ textFontSize: 24,
347
+ titleFontSize: 30,
348
+ textVerticalBias: 0.2,
349
+ nextButtonText: "START",
350
+ nextButtonBackgroundColor: WebColors.Green,
351
+ nextSceneTransition: Transition.none()
352
+ }
353
+ ]
318
354
  });
355
+ break;
319
356
  }
320
- let instructionsScenes;
321
- switch (game.getParameter("instruction_type")) {
322
- case "short": {
323
- instructionsScenes = Instructions.Create({
324
- instructionScenes: [
325
- {
326
- title: "Color Shapes",
327
- text: `Try to remember the location and color of ${numberOfShapesShown} shapes, because they will soon disappear. When the shapes reappear, answer whether they have the SAME or DIFFERENT colors as they had before.`,
328
- imageName: "instructions-1",
329
- imageAboveText: false,
330
- imageMarginTop: 32,
331
- textFontSize: 24,
332
- titleFontSize: 30,
333
- textVerticalBias: 0.2,
334
- nextButtonText: "START",
335
- nextButtonBackgroundColor: WebColors.Green,
336
- nextSceneTransition: Transition.none()
337
- }
338
- ]
339
- });
340
- break;
341
- }
342
- case "long": {
343
- instructionsScenes = Instructions.Create({
344
- instructionScenes: [
345
- {
346
- title: "Color Shapes",
347
- text: `Try to remember the location and color of ${numberOfShapesShown} shapes, because they will soon disappear.`,
348
- imageName: "instructions-1",
349
- imageAboveText: false,
350
- imageMarginTop: 32,
351
- textFontSize: 24,
352
- titleFontSize: 30,
353
- textVerticalBias: 0.2
354
- },
355
- {
356
- title: "Color Shapes",
357
- text: "Next you will see the same shapes reappear.",
358
- imageName: "instructions-2",
359
- imageAboveText: false,
360
- imageMarginTop: 32,
361
- textFontSize: 24,
362
- titleFontSize: 30,
363
- textVerticalBias: 0.2
364
- },
365
- {
366
- title: "Color Shapes",
367
- text: "Answer whether the shapes have the SAME or DIFFERENT colors as they had before.",
368
- imageName: "instructions-3",
369
- imageAboveText: false,
370
- imageMarginTop: 32,
371
- textFontSize: 24,
372
- titleFontSize: 30,
373
- textVerticalBias: 0.2,
374
- nextButtonText: "START",
375
- nextButtonBackgroundColor: WebColors.Green,
376
- nextSceneTransition: Transition.none()
377
- }
378
- ]
379
- });
380
- break;
381
- }
382
- default: {
383
- throw new Error("invalid value for instruction_type");
384
- }
357
+ default: {
358
+ throw new Error("invalid value for instruction_type");
385
359
  }
386
- instructionsScenes[0].onAppear(() => {
387
- game.addTrialData(
388
- "activity_begin_iso8601_timestamp",
389
- this.beginIso8601Timestamp
390
- );
391
- });
392
- game.addScenes(instructionsScenes);
393
- const gridRows = game.getParameter("cells_per_side");
394
- const gridColumns = game.getParameter("cells_per_side");
395
- const numberOfTrials = game.getParameter("number_of_trials");
396
- const shapeColors = game.getParameter(
397
- "shape_colors"
360
+ }
361
+ instructionsScenes[0].onAppear(() => {
362
+ game.addTrialData(
363
+ "activity_begin_iso8601_timestamp",
364
+ this.beginIso8601Timestamp
398
365
  );
399
- const trialConfigurations = [];
400
- const rows = game.getParameter("cells_per_side");
401
- const columns = rows;
402
- const numberOfDifferentColorsTrials = game.getParameter(
403
- "number_of_different_colors_trials"
366
+ });
367
+ game.addScenes(instructionsScenes);
368
+ const gridRows = game.getParameter("cells_per_side");
369
+ const gridColumns = game.getParameter("cells_per_side");
370
+ const numberOfTrials = game.getParameter("number_of_trials");
371
+ const shapeColors = game.getParameter(
372
+ "shape_colors"
373
+ );
374
+ const trialConfigurations = [];
375
+ const rows = game.getParameter("cells_per_side");
376
+ const columns = rows;
377
+ const numberOfDifferentColorsTrials = game.getParameter(
378
+ "number_of_different_colors_trials"
379
+ );
380
+ const differentColorsTrialIndexes = RandomDraws.FromRangeWithoutReplacement(
381
+ numberOfDifferentColorsTrials,
382
+ 0,
383
+ numberOfTrials - 1
384
+ );
385
+ for (let i = 0; i < numberOfTrials; i++) {
386
+ const presentShapes = new Array();
387
+ const responseShapes = new Array();
388
+ const shapesToShowIndexes = RandomDraws.FromRangeWithoutReplacement(
389
+ numberOfShapesShown,
390
+ 0,
391
+ shapeLibrary.length - 1
404
392
  );
405
- const differentColorsTrialIndexes = RandomDraws.FromRangeWithoutReplacement(
406
- numberOfDifferentColorsTrials,
393
+ const shapeColorsIndexes = RandomDraws.FromRangeWithoutReplacement(
394
+ numberOfShapesShown,
407
395
  0,
408
- numberOfTrials - 1
396
+ shapeColors.length - 1
409
397
  );
410
- for (let i = 0; i < numberOfTrials; i++) {
411
- const presentShapes = new Array();
412
- const responseShapes = new Array();
413
- const shapesToShowIndexes = RandomDraws.FromRangeWithoutReplacement(
414
- numberOfShapesShown,
415
- 0,
416
- shapeLibrary.length - 1
417
- );
418
- const shapeColorsIndexes = RandomDraws.FromRangeWithoutReplacement(
419
- numberOfShapesShown,
420
- 0,
421
- shapeColors.length - 1
422
- );
423
- const onDiagonal = (locations) => {
424
- if (locations.map((c) => c.row === 0 && c.column === 0).some((e) => e === true) && locations.map((c) => c.row === 1 && c.column === 1).some((e) => e === true) && locations.map((c) => c.row === 2 && c.column === 2).some((e) => e === true)) {
425
- return true;
426
- }
427
- if (locations.map((c) => c.row === 2 && c.column === 0).some((e) => e === true) && locations.map((c) => c.row === 1 && c.column === 1).some((e) => e === true) && locations.map((c) => c.row === 0 && c.column === 2).some((e) => e === true)) {
428
- return true;
429
- }
430
- return false;
431
- };
432
- const inLine = (locations) => {
433
- const uniqueRows = new Set(locations.map((l) => l.row)).size;
434
- const uniqueColumns = new Set(locations.map((l) => l.column)).size;
435
- if (uniqueRows !== 1 && uniqueColumns !== 1) {
436
- return false;
437
- }
398
+ const onDiagonal = (locations) => {
399
+ if (locations.map((c) => c.row === 0 && c.column === 0).some((e) => e === true) && locations.map((c) => c.row === 1 && c.column === 1).some((e) => e === true) && locations.map((c) => c.row === 2 && c.column === 2).some((e) => e === true)) {
438
400
  return true;
439
- };
440
- let presentLocationsOk = false;
441
- let presentLocations;
442
- do {
443
- presentLocations = RandomDraws.FromGridWithoutReplacement(
444
- numberOfShapesShown,
445
- rows,
446
- columns
447
- );
448
- if (!inLine(presentLocations) && !onDiagonal(presentLocations)) {
449
- presentLocationsOk = true;
450
- } else {
451
- presentLocationsOk = false;
452
- }
453
- } while (!presentLocationsOk);
454
- for (let j = 0; j < numberOfShapesShown; j++) {
455
- const presentShape = {
456
- shape: shapeLibrary[shapesToShowIndexes[j]],
457
- shapeIndex: shapesToShowIndexes[j],
458
- color: shapeColors[shapeColorsIndexes[j]].rgbaColor,
459
- colorName: shapeColors[shapeColorsIndexes[j]].colorName,
460
- location: presentLocations[j]
461
- };
462
- presentShapes.push(presentShape);
463
401
  }
464
- let responseLocationsOk = false;
465
- let responseLocations;
466
- do {
467
- responseLocations = RandomDraws.FromGridWithoutReplacement(
468
- numberOfShapesShown,
469
- rows,
470
- columns
471
- );
472
- if (!inLine(responseLocations) && !onDiagonal(responseLocations)) {
473
- responseLocationsOk = true;
474
- } else {
475
- responseLocationsOk = false;
476
- }
477
- } while (!responseLocationsOk);
478
- for (let j = 0; j < numberOfShapesShown; j++) {
479
- const responseShape = {
480
- shape: presentShapes[j].shape,
481
- shapeIndex: shapesToShowIndexes[j],
482
- color: presentShapes[j].color,
483
- colorName: shapeColors[shapeColorsIndexes[j]].colorName,
484
- location: responseLocations[j]
485
- };
486
- responseShapes.push(responseShape);
402
+ if (locations.map((c) => c.row === 2 && c.column === 0).some((e) => e === true) && locations.map((c) => c.row === 1 && c.column === 1).some((e) => e === true) && locations.map((c) => c.row === 0 && c.column === 2).some((e) => e === true)) {
403
+ return true;
487
404
  }
488
- let numberOfShapesWithDifferentColors = 0;
489
- const differentColorTrial = differentColorsTrialIndexes.includes(i);
490
- if (differentColorTrial) {
491
- const numberOfShapesToChange = RandomDraws.SingleFromRange(
492
- 2,
493
- numberOfShapesShown
494
- );
495
- const shapesToChangeIndexes = RandomDraws.FromRangeWithoutReplacement(
496
- numberOfShapesToChange,
497
- 0,
498
- numberOfShapesShown - 1
499
- );
500
- const shapesToChange = shapesToChangeIndexes.map(
501
- (index) => responseShapes[index]
502
- );
503
- numberOfShapesWithDifferentColors = shapesToChange.length;
504
- const firstShapeColor = shapesToChange[0].color;
505
- for (let j = 0; j < numberOfShapesToChange; j++) {
506
- const shape = shapesToChange[j];
507
- if (j + 1 < numberOfShapesToChange) {
508
- shape.color = shapesToChange[j + 1].color;
509
- } else {
510
- shape.color = firstShapeColor;
511
- }
512
- }
405
+ return false;
406
+ };
407
+ const inLine = (locations) => {
408
+ const uniqueRows = new Set(locations.map((l) => l.row)).size;
409
+ const uniqueColumns = new Set(locations.map((l) => l.column)).size;
410
+ if (uniqueRows !== 1 && uniqueColumns !== 1) {
411
+ return false;
513
412
  }
514
- trialConfigurations.push({
515
- presentShapes,
516
- responseShapes,
517
- numberOfShapesWithDifferentColors
518
- });
519
- }
520
- const fixationScene = new Scene();
521
- game.addScene(fixationScene);
522
- const fixationSceneSquare = new Shape({
523
- rect: { size: { width: SQUARE_SIDE_LENGTH, height: SQUARE_SIDE_LENGTH } },
524
- fillColor: WebColors.Transparent,
525
- strokeColor: WebColors.Gray,
526
- lineWidth: 4,
527
- position: { x: 200, y: 300 }
528
- });
529
- fixationScene.addChild(fixationSceneSquare);
530
- const plusLabel = new Label({
531
- text: "+",
532
- fontSize: 32,
533
- fontColor: WebColors.Black
534
- });
535
- fixationSceneSquare.addChild(plusLabel);
536
- fixationScene.onAppear(() => {
537
- game.addTrialData(
538
- "activity_begin_iso8601_timestamp",
539
- this.beginIso8601Timestamp
540
- );
541
- game.addTrialData(
542
- "trial_begin_iso8601_timestamp",
543
- (/* @__PURE__ */ new Date()).toISOString()
544
- );
545
- fixationScene.run(
546
- Action.sequence([
547
- Action.wait({ duration: game.getParameter("fixation_duration_ms") }),
548
- Action.custom({
549
- callback: () => {
550
- game.presentScene(shapePresentationScene);
551
- }
552
- })
553
- ])
413
+ return true;
414
+ };
415
+ let presentLocationsOk = false;
416
+ let presentLocations;
417
+ do {
418
+ presentLocations = RandomDraws.FromGridWithoutReplacement(
419
+ numberOfShapesShown,
420
+ rows,
421
+ columns
554
422
  );
555
- });
556
- const shapePresentationScene = new Scene();
557
- game.addScene(shapePresentationScene);
558
- const presentationSceneSquare = new Shape({
559
- rect: { size: { width: SQUARE_SIDE_LENGTH, height: SQUARE_SIDE_LENGTH } },
560
- fillColor: WebColors.Transparent,
561
- strokeColor: WebColors.Gray,
562
- lineWidth: 4,
563
- position: { x: 200, y: 300 }
564
- });
565
- shapePresentationScene.addChild(presentationSceneSquare);
566
- const presentationGrid = new Grid({
567
- rows: gridRows,
568
- columns: gridColumns,
569
- size: { width: SQUARE_SIDE_LENGTH, height: SQUARE_SIDE_LENGTH },
570
- position: { x: 200, y: 300 },
571
- backgroundColor: WebColors.Transparent,
572
- gridLineColor: WebColors.Transparent
573
- });
574
- shapePresentationScene.addChild(presentationGrid);
575
- shapePresentationScene.onAppear(() => {
576
- const trialConfiguration = trialConfigurations[game.trialIndex];
577
- for (let i = 0; i < trialConfiguration.presentShapes.length; i++) {
578
- const presentShape = trialConfiguration.presentShapes[i].shape;
579
- presentShape.fillColor = trialConfiguration.presentShapes[i].color;
580
- presentShape.position = { x: 0, y: 0 };
581
- presentationGrid.addAtCell(
582
- presentShape,
583
- trialConfiguration.presentShapes[i].location.row,
584
- trialConfiguration.presentShapes[i].location.column
585
- );
423
+ if (!inLine(presentLocations) && !onDiagonal(presentLocations)) {
424
+ presentLocationsOk = true;
425
+ } else {
426
+ presentLocationsOk = false;
586
427
  }
587
- shapePresentationScene.run(
588
- Action.sequence([
589
- Action.wait({
590
- duration: game.getParameter("shapes_presented_duration_ms")
591
- }),
592
- Action.custom({
593
- callback: () => {
594
- presentationGrid.removeAllChildren();
595
- }
596
- }),
597
- Action.wait({
598
- duration: game.getParameter("shapes_removed_duration_ms")
599
- }),
600
- Action.custom({
601
- callback: () => {
602
- presentationGrid.removeAllChildren();
603
- game.presentScene(shapeResponseScene);
604
- }
605
- })
606
- ])
428
+ } while (!presentLocationsOk);
429
+ for (let j = 0; j < numberOfShapesShown; j++) {
430
+ const presentShape = {
431
+ shape: shapeLibrary[shapesToShowIndexes[j]],
432
+ shapeIndex: shapesToShowIndexes[j],
433
+ color: shapeColors[shapeColorsIndexes[j]].rgbaColor,
434
+ colorName: shapeColors[shapeColorsIndexes[j]].colorName,
435
+ location: presentLocations[j]
436
+ };
437
+ presentShapes.push(presentShape);
438
+ }
439
+ let responseLocationsOk = false;
440
+ let responseLocations;
441
+ do {
442
+ responseLocations = RandomDraws.FromGridWithoutReplacement(
443
+ numberOfShapesShown,
444
+ rows,
445
+ columns
607
446
  );
608
- });
609
- const shapeResponseScene = new Scene();
610
- game.addScene(shapeResponseScene);
611
- const responseSceneSquare = new Shape({
612
- rect: { size: { width: SQUARE_SIDE_LENGTH, height: SQUARE_SIDE_LENGTH } },
613
- fillColor: WebColors.Transparent,
614
- strokeColor: WebColors.Gray,
615
- lineWidth: 4,
616
- position: { x: 200, y: 300 }
617
- });
618
- shapeResponseScene.addChild(responseSceneSquare);
619
- const responseGrid = new Grid({
620
- rows: gridRows,
621
- columns: gridColumns,
622
- size: { width: SQUARE_SIDE_LENGTH, height: SQUARE_SIDE_LENGTH },
623
- position: { x: 200, y: 300 },
624
- backgroundColor: WebColors.Transparent,
625
- gridLineColor: WebColors.Transparent
626
- });
627
- shapeResponseScene.addChild(responseGrid);
628
- shapeResponseScene.onAppear(() => {
629
- const trialConfiguration = trialConfigurations[game.trialIndex];
630
- for (let i = 0; i < trialConfiguration.responseShapes.length; i++) {
631
- const responseShape = trialConfiguration.responseShapes[i].shape;
632
- responseShape.fillColor = trialConfiguration.responseShapes[i].color;
633
- responseShape.position = { x: 0, y: 0 };
634
- responseGrid.addAtCell(
635
- responseShape,
636
- trialConfiguration.responseShapes[i].location.row,
637
- trialConfiguration.responseShapes[i].location.column
638
- );
447
+ if (!inLine(responseLocations) && !onDiagonal(responseLocations)) {
448
+ responseLocationsOk = true;
449
+ } else {
450
+ responseLocationsOk = false;
639
451
  }
640
- sameButton.isUserInteractionEnabled = true;
641
- differentButton.isUserInteractionEnabled = true;
642
- Timer.start("rt");
643
- });
644
- const sameButton = new Button({
645
- text: "Same",
646
- position: { x: 100, y: 700 },
647
- size: { width: 125, height: 50 }
648
- });
649
- shapeResponseScene.addChild(sameButton);
650
- sameButton.onTapDown(() => {
651
- sameButton.isUserInteractionEnabled = false;
652
- handleSelection(false);
653
- });
654
- const differentButton = new Button({
655
- text: "Different",
656
- position: { x: 300, y: 700 },
657
- size: { width: 125, height: 50 }
658
- });
659
- shapeResponseScene.addChild(differentButton);
660
- differentButton.onTapDown(() => {
661
- differentButton.isUserInteractionEnabled = false;
662
- handleSelection(true);
663
- });
664
- const handleSelection = (differentPressed) => {
665
- const rt = Timer.elapsed("rt");
666
- Timer.remove("rt");
667
- responseGrid.removeAllChildren();
668
- game.addTrialData(
669
- "trial_end_iso8601_timestamp",
670
- (/* @__PURE__ */ new Date()).toISOString()
452
+ } while (!responseLocationsOk);
453
+ for (let j = 0; j < numberOfShapesShown; j++) {
454
+ const responseShape = {
455
+ shape: presentShapes[j].shape,
456
+ shapeIndex: shapesToShowIndexes[j],
457
+ color: presentShapes[j].color,
458
+ colorName: shapeColors[shapeColorsIndexes[j]].colorName,
459
+ location: responseLocations[j]
460
+ };
461
+ responseShapes.push(responseShape);
462
+ }
463
+ let numberOfShapesWithDifferentColors = 0;
464
+ const differentColorTrial = differentColorsTrialIndexes.includes(i);
465
+ if (differentColorTrial) {
466
+ const numberOfShapesToChange = RandomDraws.SingleFromRange(
467
+ 2,
468
+ numberOfShapesShown
671
469
  );
672
- const trialConfiguration = trialConfigurations[game.trialIndex];
673
- game.addTrialData("response_time_duration_ms", rt);
674
- game.addTrialData(
675
- "number_of_different_shapes",
676
- trialConfiguration.numberOfShapesWithDifferentColors
470
+ const shapesToChangeIndexes = RandomDraws.FromRangeWithoutReplacement(
471
+ numberOfShapesToChange,
472
+ 0,
473
+ numberOfShapesShown - 1
677
474
  );
678
- game.addTrialData(
679
- "user_response",
680
- differentPressed ? "different" : "same"
475
+ const shapesToChange = shapesToChangeIndexes.map(
476
+ (index) => responseShapes[index]
681
477
  );
682
- const correctResponse = trialConfiguration.numberOfShapesWithDifferentColors === 0 && !differentPressed || trialConfiguration.numberOfShapesWithDifferentColors > 0 && differentPressed;
683
- game.addTrialData("user_response_correct", correctResponse);
684
- const presentShapes = trialConfiguration.presentShapes.map((p) => {
685
- return {
686
- shape_index: p.shapeIndex,
687
- color_name: p.colorName,
688
- rgba_color: p.color,
689
- location: p.location
690
- };
691
- });
692
- game.addTrialData("present_shapes", presentShapes);
693
- game.addTrialData("quit_button_pressed", false);
694
- const responseShapes = trialConfiguration.responseShapes.map((p) => {
695
- return {
696
- shape_index: p.shapeIndex,
697
- color_name: p.colorName,
698
- rgba_color: p.color,
699
- location: p.location
700
- };
701
- });
702
- game.addTrialData("response_shapes", responseShapes);
703
- game.addTrialData("trial_index", game.trialIndex);
704
- game.trialComplete();
705
- if (game.trialIndex < numberOfTrials) {
706
- game.presentScene(fixationScene);
707
- } else {
708
- game.presentScene(
709
- doneScene,
710
- Transition.slide({
711
- direction: TransitionDirection.Left,
712
- duration: 500,
713
- easing: Easings.sinusoidalInOut
714
- })
715
- );
478
+ numberOfShapesWithDifferentColors = shapesToChange.length;
479
+ const firstShapeColor = shapesToChange[0].color;
480
+ for (let j = 0; j < numberOfShapesToChange; j++) {
481
+ const shape = shapesToChange[j];
482
+ if (j + 1 < numberOfShapesToChange) {
483
+ shape.color = shapesToChange[j + 1].color;
484
+ } else {
485
+ shape.color = firstShapeColor;
486
+ }
716
487
  }
717
- };
718
- const doneScene = new Scene();
719
- game.addScene(doneScene);
720
- const doneSceneText = new Label({
721
- text: game.getParameter("trials_complete_scene_text"),
722
- position: { x: 200, y: 400 }
723
- });
724
- doneScene.addChild(doneSceneText);
725
- const okButton = new Button({
726
- text: game.getParameter("trials_complete_scene_button_text"),
727
- position: { x: 200, y: 650 }
488
+ }
489
+ trialConfigurations.push({
490
+ presentShapes,
491
+ responseShapes,
492
+ numberOfShapesWithDifferentColors
728
493
  });
729
- okButton.isUserInteractionEnabled = true;
730
- okButton.onTapDown(() => {
731
- okButton.isUserInteractionEnabled = false;
732
- doneScene.removeAllChildren();
733
- game.end();
494
+ }
495
+ const fixationScene = new Scene();
496
+ game.addScene(fixationScene);
497
+ const fixationSceneSquare = new Shape({
498
+ rect: { size: { width: SQUARE_SIDE_LENGTH, height: SQUARE_SIDE_LENGTH } },
499
+ fillColor: WebColors.Transparent,
500
+ strokeColor: WebColors.Gray,
501
+ lineWidth: 4,
502
+ position: { x: 200, y: 300 }
503
+ });
504
+ fixationScene.addChild(fixationSceneSquare);
505
+ const plusLabel = new Label({
506
+ text: "+",
507
+ fontSize: 32,
508
+ fontColor: WebColors.Black
509
+ });
510
+ fixationSceneSquare.addChild(plusLabel);
511
+ fixationScene.onAppear(() => {
512
+ game.addTrialData(
513
+ "activity_begin_iso8601_timestamp",
514
+ this.beginIso8601Timestamp
515
+ );
516
+ game.addTrialData(
517
+ "trial_begin_iso8601_timestamp",
518
+ (/* @__PURE__ */ new Date()).toISOString()
519
+ );
520
+ fixationScene.run(
521
+ Action.sequence([
522
+ Action.wait({ duration: game.getParameter("fixation_duration_ms") }),
523
+ Action.custom({
524
+ callback: () => {
525
+ game.presentScene(shapePresentationScene);
526
+ }
527
+ })
528
+ ])
529
+ );
530
+ });
531
+ const shapePresentationScene = new Scene();
532
+ game.addScene(shapePresentationScene);
533
+ const presentationSceneSquare = new Shape({
534
+ rect: { size: { width: SQUARE_SIDE_LENGTH, height: SQUARE_SIDE_LENGTH } },
535
+ fillColor: WebColors.Transparent,
536
+ strokeColor: WebColors.Gray,
537
+ lineWidth: 4,
538
+ position: { x: 200, y: 300 }
539
+ });
540
+ shapePresentationScene.addChild(presentationSceneSquare);
541
+ const presentationGrid = new Grid({
542
+ rows: gridRows,
543
+ columns: gridColumns,
544
+ size: { width: SQUARE_SIDE_LENGTH, height: SQUARE_SIDE_LENGTH },
545
+ position: { x: 200, y: 300 },
546
+ backgroundColor: WebColors.Transparent,
547
+ gridLineColor: WebColors.Transparent
548
+ });
549
+ shapePresentationScene.addChild(presentationGrid);
550
+ shapePresentationScene.onAppear(() => {
551
+ const trialConfiguration = trialConfigurations[game.trialIndex];
552
+ for (let i = 0; i < trialConfiguration.presentShapes.length; i++) {
553
+ const presentShape = trialConfiguration.presentShapes[i].shape;
554
+ presentShape.fillColor = trialConfiguration.presentShapes[i].color;
555
+ presentShape.position = { x: 0, y: 0 };
556
+ presentationGrid.addAtCell(
557
+ presentShape,
558
+ trialConfiguration.presentShapes[i].location.row,
559
+ trialConfiguration.presentShapes[i].location.column
560
+ );
561
+ }
562
+ shapePresentationScene.run(
563
+ Action.sequence([
564
+ Action.wait({
565
+ duration: game.getParameter("shapes_presented_duration_ms")
566
+ }),
567
+ Action.custom({
568
+ callback: () => {
569
+ presentationGrid.removeAllChildren();
570
+ }
571
+ }),
572
+ Action.wait({
573
+ duration: game.getParameter("shapes_removed_duration_ms")
574
+ }),
575
+ Action.custom({
576
+ callback: () => {
577
+ presentationGrid.removeAllChildren();
578
+ game.presentScene(shapeResponseScene);
579
+ }
580
+ })
581
+ ])
582
+ );
583
+ });
584
+ const shapeResponseScene = new Scene();
585
+ game.addScene(shapeResponseScene);
586
+ const responseSceneSquare = new Shape({
587
+ rect: { size: { width: SQUARE_SIDE_LENGTH, height: SQUARE_SIDE_LENGTH } },
588
+ fillColor: WebColors.Transparent,
589
+ strokeColor: WebColors.Gray,
590
+ lineWidth: 4,
591
+ position: { x: 200, y: 300 }
592
+ });
593
+ shapeResponseScene.addChild(responseSceneSquare);
594
+ const responseGrid = new Grid({
595
+ rows: gridRows,
596
+ columns: gridColumns,
597
+ size: { width: SQUARE_SIDE_LENGTH, height: SQUARE_SIDE_LENGTH },
598
+ position: { x: 200, y: 300 },
599
+ backgroundColor: WebColors.Transparent,
600
+ gridLineColor: WebColors.Transparent
601
+ });
602
+ shapeResponseScene.addChild(responseGrid);
603
+ shapeResponseScene.onAppear(() => {
604
+ const trialConfiguration = trialConfigurations[game.trialIndex];
605
+ for (let i = 0; i < trialConfiguration.responseShapes.length; i++) {
606
+ const responseShape = trialConfiguration.responseShapes[i].shape;
607
+ responseShape.fillColor = trialConfiguration.responseShapes[i].color;
608
+ responseShape.position = { x: 0, y: 0 };
609
+ responseGrid.addAtCell(
610
+ responseShape,
611
+ trialConfiguration.responseShapes[i].location.row,
612
+ trialConfiguration.responseShapes[i].location.column
613
+ );
614
+ }
615
+ sameButton.isUserInteractionEnabled = true;
616
+ differentButton.isUserInteractionEnabled = true;
617
+ Timer.start("rt");
618
+ });
619
+ const sameButton = new Button({
620
+ text: "Same",
621
+ position: { x: 100, y: 700 },
622
+ size: { width: 125, height: 50 }
623
+ });
624
+ shapeResponseScene.addChild(sameButton);
625
+ sameButton.onTapDown(() => {
626
+ sameButton.isUserInteractionEnabled = false;
627
+ handleSelection(false);
628
+ });
629
+ const differentButton = new Button({
630
+ text: "Different",
631
+ position: { x: 300, y: 700 },
632
+ size: { width: 125, height: 50 }
633
+ });
634
+ shapeResponseScene.addChild(differentButton);
635
+ differentButton.onTapDown(() => {
636
+ differentButton.isUserInteractionEnabled = false;
637
+ handleSelection(true);
638
+ });
639
+ const handleSelection = (differentPressed) => {
640
+ const rt = Timer.elapsed("rt");
641
+ Timer.remove("rt");
642
+ responseGrid.removeAllChildren();
643
+ game.addTrialData(
644
+ "trial_end_iso8601_timestamp",
645
+ (/* @__PURE__ */ new Date()).toISOString()
646
+ );
647
+ const trialConfiguration = trialConfigurations[game.trialIndex];
648
+ game.addTrialData("response_time_duration_ms", rt);
649
+ game.addTrialData(
650
+ "number_of_different_shapes",
651
+ trialConfiguration.numberOfShapesWithDifferentColors
652
+ );
653
+ game.addTrialData(
654
+ "user_response",
655
+ differentPressed ? "different" : "same"
656
+ );
657
+ const correctResponse = trialConfiguration.numberOfShapesWithDifferentColors === 0 && !differentPressed || trialConfiguration.numberOfShapesWithDifferentColors > 0 && differentPressed;
658
+ game.addTrialData("user_response_correct", correctResponse);
659
+ const presentShapes = trialConfiguration.presentShapes.map((p) => {
660
+ return {
661
+ shape_index: p.shapeIndex,
662
+ color_name: p.colorName,
663
+ rgba_color: p.color,
664
+ location: p.location
665
+ };
734
666
  });
735
- doneScene.addChild(okButton);
736
- doneScene.onSetup(() => {
737
- game.removeAllFreeEntities();
667
+ game.addTrialData("present_shapes", presentShapes);
668
+ game.addTrialData("quit_button_pressed", false);
669
+ const responseShapes = trialConfiguration.responseShapes.map((p) => {
670
+ return {
671
+ shape_index: p.shapeIndex,
672
+ color_name: p.colorName,
673
+ rgba_color: p.color,
674
+ location: p.location
675
+ };
738
676
  });
677
+ game.addTrialData("response_shapes", responseShapes);
678
+ game.addTrialData("trial_index", game.trialIndex);
679
+ game.trialComplete();
680
+ if (game.trialIndex < numberOfTrials) {
681
+ game.presentScene(fixationScene);
682
+ } else {
683
+ game.presentScene(
684
+ doneScene,
685
+ Transition.slide({
686
+ direction: TransitionDirection.Left,
687
+ duration: 500,
688
+ easing: Easings.sinusoidalInOut
689
+ })
690
+ );
691
+ }
692
+ };
693
+ const doneScene = new Scene();
694
+ game.addScene(doneScene);
695
+ const doneSceneText = new Label({
696
+ text: game.getParameter("trials_complete_scene_text"),
697
+ position: { x: 200, y: 400 }
698
+ });
699
+ doneScene.addChild(doneSceneText);
700
+ const okButton = new Button({
701
+ text: game.getParameter("trials_complete_scene_button_text"),
702
+ position: { x: 200, y: 650 }
703
+ });
704
+ okButton.isUserInteractionEnabled = true;
705
+ okButton.onTapDown(() => {
706
+ okButton.isUserInteractionEnabled = false;
707
+ doneScene.removeAllChildren();
708
+ game.end();
709
+ });
710
+ doneScene.addChild(okButton);
711
+ doneScene.onSetup(() => {
712
+ game.removeAllFreeEntities();
739
713
  });
740
714
  }
741
- makeShapes(svgHeight, size) {
715
+ makeShapes(svgHeight) {
742
716
  const shape01 = new Shape({
743
717
  path: {
744
- svgPathString: shapeSvgPathStrings[0],
718
+ pathString: shapePathStrings[0],
745
719
  height: svgHeight
746
720
  },
747
- size,
748
721
  lineWidth: 0
749
722
  });
750
723
  const shape02 = new Shape({
751
724
  path: {
752
- svgPathString: shapeSvgPathStrings[1],
725
+ pathString: shapePathStrings[1],
753
726
  height: svgHeight
754
727
  },
755
- size,
756
728
  lineWidth: 0
757
729
  });
758
730
  const shape03 = new Shape({
759
731
  path: {
760
- svgPathString: shapeSvgPathStrings[2],
732
+ pathString: shapePathStrings[2],
761
733
  height: svgHeight * 0.8
762
734
  },
763
- size,
764
735
  lineWidth: 0
765
736
  });
766
737
  const shape04 = new Shape({
767
738
  path: {
768
- svgPathString: shapeSvgPathStrings[3],
739
+ pathString: shapePathStrings[3],
769
740
  height: svgHeight
770
741
  },
771
- size,
772
742
  lineWidth: 0
773
743
  });
774
744
  const shape05 = new Shape({
775
745
  path: {
776
- svgPathString: shapeSvgPathStrings[4],
746
+ pathString: shapePathStrings[4],
777
747
  height: svgHeight * 0.8
778
748
  },
779
- size,
780
749
  lineWidth: 0
781
750
  });
782
751
  const shape06 = new Shape({
783
752
  path: {
784
- svgPathString: shapeSvgPathStrings[5],
753
+ pathString: shapePathStrings[5],
785
754
  height: svgHeight
786
755
  },
787
- size,
788
756
  lineWidth: 0
789
757
  });
790
758
  const shape07 = new Shape({
791
759
  path: {
792
- svgPathString: shapeSvgPathStrings[6],
760
+ pathString: shapePathStrings[6],
793
761
  height: svgHeight
794
762
  },
795
- size,
796
763
  lineWidth: 0
797
764
  });
798
765
  const shape08 = new Shape({
799
766
  path: {
800
- svgPathString: shapeSvgPathStrings[7],
767
+ pathString: shapePathStrings[7],
801
768
  height: svgHeight
802
769
  },
803
- size,
804
770
  lineWidth: 0
805
771
  });
806
772
  const shapes = [
@@ -816,7 +782,7 @@ class ColorShapes extends Game {
816
782
  return shapes;
817
783
  }
818
784
  }
819
- const shapeSvgPathStrings = [
785
+ const shapePathStrings = [
820
786
  "M0 89.94v-2L131.95 0h2v88.7c2.34 1.6 4.47 3.11 6.65 4.55 42.77 28.22 85.54 56.42 128.3 84.63v2c-44.65 29.65-89.3 59.29-133.95 88.94h-1v-90.84C89.44 148.72 44.72 119.33 0 89.94Z",
821
787
  "M162 188c-.33 27-.67 54-1 81-26.87-26.18-53.74-52.35-80-77.94V269H0C0 180.83 0 92.67.04 4.5.04 3 .67 1.5 1 0c24.64 29.1 49.15 58.31 73.96 87.26 28.88 33.7 58.01 67.17 87.04 100.74Z",
822
788
  "M3 148.86V61.12C41.76 40.75 80.52 20.37 119.28 0h2.91c21.32 20.7 42.64 41.4 63.96 62.11v89.71c-38.44 20.04-76.88 40.09-115.31 60.13h-2.91L3.01 148.86Z",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@m2c2kit/assessment-color-shapes",
3
- "version": "0.8.10",
3
+ "version": "0.8.11",
4
4
  "description": "A visual array change detection task, measuring intra-item feature binding, where participants determine if shapes change color across two sequential presentations of shape stimuli",
5
5
  "scripts": {
6
6
  "build": "npm run clean && tsc && rollup -c",
@@ -30,17 +30,17 @@
30
30
  },
31
31
  "homepage": "https://m2c2-project.github.io/m2c2kit",
32
32
  "dependencies": {
33
- "@m2c2kit/addons": "^0.3.3",
34
- "@m2c2kit/core": "^0.3.6"
33
+ "@m2c2kit/addons": "^0.3.11",
34
+ "@m2c2kit/core": "^0.3.14"
35
35
  },
36
36
  "devDependencies": {
37
- "@rollup/plugin-node-resolve": "15.1.0",
38
- "@rollup/plugin-replace": "5.0.2",
39
- "rimraf": "5.0.1",
40
- "rollup": "3.25.3",
41
- "rollup-plugin-copy": "3.4.0",
42
- "rollup-plugin-esbuild": "5.0.0",
43
- "typescript": "5.1.6"
37
+ "@rollup/plugin-node-resolve": "15.2.3",
38
+ "@rollup/plugin-replace": "5.0.5",
39
+ "rimraf": "5.0.5",
40
+ "rollup": "4.6.1",
41
+ "rollup-plugin-copy": "3.5.0",
42
+ "rollup-plugin-esbuild": "6.1.0",
43
+ "typescript": "5.3.2"
44
44
  },
45
45
  "engines": {
46
46
  "node": ">=18"