diff --git a/arithmetic_en.html b/arithmetic_en.html
index 87cee60..c1f8cf2 100644
--- a/arithmetic_en.html
+++ b/arithmetic_en.html
@@ -45,7 +45,10 @@
"phet-io"
],
"simFeatures": {
- "supportsSound": true
+ "supportsSound": true,
+ "supportedRegionsAndCultures": [
+ "usa"
+ ]
},
"simulation": true,
"phet-io": {
diff --git a/js/arithmetic-main.js b/js/arithmetic-main.js
index 7f5cecc..638b910 100644
--- a/js/arithmetic-main.js
+++ b/js/arithmetic-main.js
@@ -6,10 +6,12 @@
* @author John Blanco, Andrey Zelenkov (MLearner)
*/
+import PreferencesModel from '../../joist/js/preferences/PreferencesModel.js';
import Sim from '../../joist/js/Sim.js';
import simLauncher from '../../joist/js/simLauncher.js';
import Tandem from '../../tandem/js/Tandem.js';
import ArithmeticStrings from './ArithmeticStrings.js';
+import BoxPlayerImages from './common/view/BoxPlayerImages.js';
import DivideScreen from './divide/DivideScreen.js';
import FactorScreen from './factor/FactorScreen.js';
import MultiplyScreen from './multiply/MultiplyScreen.js';
@@ -20,7 +22,14 @@ const arithmeticTitleStringProperty = ArithmeticStrings.arithmetic.titleStringPr
// constants
const tandem = Tandem.ROOT;
+const preferencesModel = new PreferencesModel( {
+ localizationOptions: {
+ characterSets: BoxPlayerImages.BOX_PLAYER_CHARACTER_SETS
+ }
+} );
+
const simOptions = {
+ preferencesModel: preferencesModel,
credits: {
leadDesign: 'Michael Dubson, Amanda McGarry',
softwareDevelopment: 'John Blanco, Michael Dubson',
@@ -33,8 +42,8 @@ const simOptions = {
simLauncher.launch( () => {
// Create and start the sim
new Sim( arithmeticTitleStringProperty, [
- new MultiplyScreen( { tandem: tandem.createTandem( 'multiplyScreen' ) } ),
- new FactorScreen( { tandem: tandem.createTandem( 'factorScreen' ) } ),
- new DivideScreen( { tandem: tandem.createTandem( 'divideScreen' ) } )
+ new MultiplyScreen( preferencesModel, { tandem: tandem.createTandem( 'multiplyScreen' ) } ),
+ new FactorScreen( preferencesModel, { tandem: tandem.createTandem( 'factorScreen' ) } ),
+ new DivideScreen( preferencesModel, { tandem: tandem.createTandem( 'divideScreen' ) } )
], simOptions ).start();
} );
\ No newline at end of file
diff --git a/js/common/model/ArithmeticModel.js b/js/common/model/ArithmeticModel.js
index 5a4d0be..447b6c6 100644
--- a/js/common/model/ArithmeticModel.js
+++ b/js/common/model/ArithmeticModel.js
@@ -31,7 +31,7 @@ class ArithmeticModel {
/**
* Constructor for ArithmeticModel
*/
- constructor( tandem, options ) {
+ constructor( preferencesModel, tandem, options ) {
// @private - for PhET-iO
this.checkAnswerEmitter = new Emitter( {
@@ -92,6 +92,12 @@ class ArithmeticModel {
this.activeLevelModel.displayScoreProperty.set( this.activeLevelModel.currentScoreProperty.get() );
}
} );
+
+ /**
+ * @public
+ * @type {Property}
+ */
+ this.regionAndCulturePortrayalProperty = preferencesModel.localizationModel.regionAndCulturePortrayalProperty;
}
// @protected - get the current level model, use this to make the code more readable
diff --git a/js/common/view/BoxPlayerCharacterSet.js b/js/common/view/BoxPlayerCharacterSet.js
new file mode 100644
index 0000000..12446d9
--- /dev/null
+++ b/js/common/view/BoxPlayerCharacterSet.js
@@ -0,0 +1,48 @@
+// Copyright 2023, University of Colorado Boulder
+
+/**
+ * The BoxPlayerCharacterSet defines what is needed for each character set in Arithmetic.
+ *
+ * @author Luisa Vargas
+ *
+ */
+
+import RegionAndCulturePortrayal from '../../../../joist/js/preferences/RegionAndCulturePortrayal.js';
+import arithmetic from '../../arithmetic.js';
+
+export default class BoxPlayerCharacterSet extends RegionAndCulturePortrayal {
+
+ /**
+ * @param label { LocalizedStringProperty }
+ * @param multiplyLevel1 { HTMLImageElement }
+ * @param multiplyLevel2 { HTMLImageElement }
+ * @param multiplyLevel3 { HTMLImageElement }
+ * @param factorLevel1 { HTMLImageElement }
+ * @param factorLevel2 { HTMLImageElement }
+ * @param factorLevel3 { HTMLImageElement }
+ * @param divideLevel1 { HTMLImageElement }
+ * @param divideLevel2 { HTMLImageElement }
+ * @param divideLevel3 { HTMLImageElement }
+ * @param queryParameterValue { string }
+ */
+ constructor( label,
+ multiplyLevel1, multiplyLevel2, multiplyLevel3,
+ factorLevel1, factorLevel2, factorLevel3,
+ divideLevel1, divideLevel2, divideLevel3,
+ queryParameterValue ) {
+
+ super( label, queryParameterValue, {} );
+
+ this.multiplyLevel1 = multiplyLevel1;
+ this.multiplyLevel2 = multiplyLevel2;
+ this.multiplyLevel3 = multiplyLevel3;
+ this.factorLevel1 = factorLevel1;
+ this.factorLevel2 = factorLevel2;
+ this.factorLevel3 = factorLevel3;
+ this.divideLevel1 = divideLevel1;
+ this.divideLevel2 = divideLevel2;
+ this.divideLevel3 = divideLevel3;
+ }
+}
+
+arithmetic.register( 'BoxPlayerCharacterSet', BoxPlayerCharacterSet );
\ No newline at end of file
diff --git a/js/common/view/BoxPlayerCharacterSetUSA.js b/js/common/view/BoxPlayerCharacterSetUSA.js
new file mode 100644
index 0000000..19a3dec
--- /dev/null
+++ b/js/common/view/BoxPlayerCharacterSetUSA.js
@@ -0,0 +1,37 @@
+// Copyright 2023, University of Colorado Boulder
+
+/**
+ * This file instantiates the USA region and culture portrayals.
+ *
+ * @author Luisa Vargas
+ *
+ */
+
+import JoistStrings from '../../../../joist/js/JoistStrings.js';
+import { USA_REGION_AND_CULTURE_ID } from '../../../../joist/js/preferences/RegionAndCulturePortrayal.js';
+import divideLevel1Icon_png from '../../../mipmaps/divideLevel1Icon_png.js';
+import divideLevel2Icon_png from '../../../mipmaps/divideLevel2Icon_png.js';
+import divideLevel3Icon_png from '../../../mipmaps/divideLevel3Icon_png.js';
+import factorLevel1Icon_png from '../../../mipmaps/factorLevel1Icon_png.js';
+import factorLevel2Icon_png from '../../../mipmaps/factorLevel2Icon_png.js';
+import factorLevel3Icon_png from '../../../mipmaps/factorLevel3Icon_png.js';
+import multiplyLevel1Icon_png from '../../../mipmaps/multiplyLevel1Icon_png.js';
+import multiplyLevel2Icon_png from '../../../mipmaps/multiplyLevel2Icon_png.js';
+import multiplyLevel3Icon_png from '../../../mipmaps/multiplyLevel3Icon_png.js';
+import BoxPlayerCharacterSet from './BoxPlayerCharacterSet.js';
+
+const ExplorerCharacterSetUSA = new BoxPlayerCharacterSet(
+ JoistStrings.preferences.tabs.localization.regionAndCulture.portrayalSets.unitedStatesOfAmericaStringProperty,
+ multiplyLevel1Icon_png,
+ multiplyLevel2Icon_png,
+ multiplyLevel3Icon_png,
+ factorLevel1Icon_png,
+ factorLevel2Icon_png,
+ factorLevel3Icon_png,
+ divideLevel1Icon_png,
+ divideLevel2Icon_png,
+ divideLevel3Icon_png,
+ USA_REGION_AND_CULTURE_ID
+);
+
+export default ExplorerCharacterSetUSA;
\ No newline at end of file
diff --git a/js/common/view/BoxPlayerController.js b/js/common/view/BoxPlayerController.js
new file mode 100644
index 0000000..09f0875
--- /dev/null
+++ b/js/common/view/BoxPlayerController.js
@@ -0,0 +1,105 @@
+// Copyright 2023, University of Colorado Boulder
+
+/**
+ * The BoxPlayerController creates the images of each version of the 'level' box player ( multiply level 1,
+ * multiply level 2, multiply level 3, factor level 1, factor level 2, factor level 3, divide level 1, divide level 2,
+ * and divide level 3), as well as defines the visibility of each individual image based on the
+ * regionAndCulturePortrayalProperty.
+ *
+ * @author Luisa Vargas
+ *
+ */
+
+import DerivedProperty from '../../../../axon/js/DerivedProperty.js';
+import { Image, Node } from '../../../../scenery/js/imports.js';
+import arithmetic from '../../arithmetic.js';
+import BoxPlayerImages from './BoxPlayerImages.js';
+
+export default class BoxPlayerController {
+
+ /**
+ * @param { ArithmeticModel } sceneModel
+ */
+ constructor( sceneModel ) {
+
+ const boxPlayerSets = BoxPlayerImages.BOX_PLAYER_CHARACTER_SETS;
+ const regionAndCulturePortrayalProperty = sceneModel.regionAndCulturePortrayalProperty;
+
+ const createVisibleProperty = set => {
+ return new DerivedProperty( [ regionAndCulturePortrayalProperty ], portrayal => {
+ return portrayal === set;
+ } );
+ };
+
+ const multiplyLevel1Images = boxPlayerSets.map( set => new Image( set.multiplyLevel1,
+ {
+ visibleProperty: createVisibleProperty( set )
+ } ) );
+ const multiplyLevel2Images = boxPlayerSets.map( set => new Image( set.multiplyLevel2,
+ {
+ visibleProperty: createVisibleProperty( set )
+ } ) );
+ const multiplyLevel3Images = boxPlayerSets.map( set => new Image( set.multiplyLevel3,
+ {
+ visibleProperty: createVisibleProperty( set )
+ } ) );
+ const factorLevel1Images = boxPlayerSets.map( set => new Image( set.factorLevel1,
+ {
+ visibleProperty: createVisibleProperty( set )
+ } ) );
+ const factorLevel2Images = boxPlayerSets.map( set => new Image( set.factorLevel2,
+ {
+ visibleProperty: createVisibleProperty( set )
+ } ) );
+ const factorLevel3Images = boxPlayerSets.map( set => new Image( set.factorLevel3,
+ {
+ visibleProperty: createVisibleProperty( set )
+ } ) );
+ const divideLevel1Images = boxPlayerSets.map( set => new Image( set.divideLevel1,
+ {
+ visibleProperty: createVisibleProperty( set )
+ } ) );
+ const divideLevel2Images = boxPlayerSets.map( set => new Image( set.divideLevel2,
+ {
+ visibleProperty: createVisibleProperty( set )
+ } ) );
+ const divideLevel3Images = boxPlayerSets.map( set => new Image( set.divideLevel3,
+ {
+ visibleProperty: createVisibleProperty( set )
+ } ) );
+
+ const multiplyLevel1Node = new Node( { children: multiplyLevel1Images } );
+ const multiplyLevel2Node = new Node( { children: multiplyLevel2Images } );
+ const multiplyLevel3Node = new Node( { children: multiplyLevel3Images } );
+ const factorLevel1Node = new Node( { children: factorLevel1Images } );
+ const factorLevel2Node = new Node( { children: factorLevel2Images } );
+ const factorLevel3Node = new Node( { children: factorLevel3Images } );
+ const divideLevel1Node = new Node( { children: divideLevel1Images } );
+ const divideLevel2Node = new Node( { children: divideLevel2Images } );
+ const divideLevel3Node = new Node( { children: divideLevel3Images } );
+
+ /**
+ * @public
+ * @type {{divide: Node[], multiply: Node[], factor: Node[]}}
+ */
+ this.boxPlayerNodes = {
+ multiply: [
+ multiplyLevel1Node,
+ multiplyLevel2Node,
+ multiplyLevel3Node
+ ],
+ factor: [
+ factorLevel1Node,
+ factorLevel2Node,
+ factorLevel3Node
+ ],
+ divide: [
+ divideLevel1Node,
+ divideLevel2Node,
+ divideLevel3Node
+ ]
+ };
+ }
+}
+
+arithmetic.register( 'BoxPlayerController', BoxPlayerController );
\ No newline at end of file
diff --git a/js/common/view/BoxPlayerImages.js b/js/common/view/BoxPlayerImages.js
new file mode 100644
index 0000000..a278a36
--- /dev/null
+++ b/js/common/view/BoxPlayerImages.js
@@ -0,0 +1,20 @@
+// Copyright 2023, University of Colorado Boulder
+/**
+ * BoxPlayer images contains an array of character sets, each representing a different region/culture.
+ *
+ * @author Luisa Vargas
+ *
+ */
+
+import arithmetic from '../../arithmetic.js';
+import BoxPlayerCharacterSetUSA from './BoxPlayerCharacterSetUSA.js';
+
+
+const BoxPlayerImages = {
+ BOX_PLAYER_CHARACTER_SETS: [
+ BoxPlayerCharacterSetUSA
+ ]
+};
+
+arithmetic.register( 'BoxPlayerImages', BoxPlayerImages );
+export default BoxPlayerImages;
\ No newline at end of file
diff --git a/js/common/view/LevelSelectionNode.js b/js/common/view/LevelSelectionNode.js
index e19cd2d..40ead2b 100644
--- a/js/common/view/LevelSelectionNode.js
+++ b/js/common/view/LevelSelectionNode.js
@@ -11,47 +11,20 @@ import merge from '../../../../phet-core/js/merge.js';
import ResetAllButton from '../../../../scenery-phet/js/buttons/ResetAllButton.js';
import TimerToggleButton from '../../../../scenery-phet/js/buttons/TimerToggleButton.js';
import PhetFont from '../../../../scenery-phet/js/PhetFont.js';
-import { HBox, Image, Node, Text, VBox } from '../../../../scenery/js/imports.js';
+import { HBox, Node, Text, VBox } from '../../../../scenery/js/imports.js';
import LevelSelectionButton from '../../../../vegas/js/LevelSelectionButton.js';
import ScoreDisplayStars from '../../../../vegas/js/ScoreDisplayStars.js';
-import divideLevel1Icon_png from '../../../mipmaps/divideLevel1Icon_png.js';
-import divideLevel2Icon_png from '../../../mipmaps/divideLevel2Icon_png.js';
-import divideLevel3Icon_png from '../../../mipmaps/divideLevel3Icon_png.js';
-import factorLevel1Icon_png from '../../../mipmaps/factorLevel1Icon_png.js';
-import factorLevel2Icon_png from '../../../mipmaps/factorLevel2Icon_png.js';
-import factorLevel3Icon_png from '../../../mipmaps/factorLevel3Icon_png.js';
-import multiplyLevel1Icon_png from '../../../mipmaps/multiplyLevel1Icon_png.js';
-import multiplyLevel2Icon_png from '../../../mipmaps/multiplyLevel2Icon_png.js';
-import multiplyLevel3Icon_png from '../../../mipmaps/multiplyLevel3Icon_png.js';
import arithmetic from '../../arithmetic.js';
import ArithmeticStrings from '../../ArithmeticStrings.js';
import ArithmeticConstants from '../ArithmeticConstants.js';
import ArithmeticGlobals from '../ArithmeticGlobals.js';
+import BoxPlayerController from './BoxPlayerController.js';
// constants
const CHOOSE_LEVEL_TITLE_FONT = new PhetFont( { size: 24 } );
const TAB_TITLE_FONT = new PhetFont( { size: 54 } );
const BUTTON_LENGTH = 150;
-// icon sets, used to place on the buttons
-const ICON_SETS = {
- multiply: [
- multiplyLevel1Icon_png,
- multiplyLevel2Icon_png,
- multiplyLevel3Icon_png
- ],
- factor: [
- factorLevel1Icon_png,
- factorLevel2Icon_png,
- factorLevel3Icon_png
- ],
- divide: [
- divideLevel1Icon_png,
- divideLevel2Icon_png,
- divideLevel3Icon_png
- ]
-};
-
const chooseYourLevelString = ArithmeticStrings.chooseYourLevel;
class LevelSelectionNode extends Node {
@@ -88,10 +61,16 @@ class LevelSelectionNode extends Node {
} );
this.addChild( chooseLevelTitle );
+
+ const boxPlayerController = new BoxPlayerController( model );
+
+ // icon sets, used to place on the buttons
+ const iconSets = boxPlayerController.boxPlayerNodes;
+
// add select level buttons
- assert && assert( model.levelModels.length === ICON_SETS[ options.iconSet ].length, 'Number of icons doesn\'t match number of levels' );
+ assert && assert( model.levelModels.length === iconSets[ options.iconSet ].length, 'Number of icons doesn\'t match number of levels' );
const levelSelectButtons = model.levelModels.map( ( level, levelIndex ) => new LevelSelectionButton(
- new Image( ICON_SETS[ options.iconSet ][ levelIndex ] ),
+ iconSets[ options.iconSet ][ levelIndex ],
model.levelModels[ levelIndex ].displayScoreProperty,
{
buttonWidth: BUTTON_LENGTH,
diff --git a/js/divide/DivideScreen.js b/js/divide/DivideScreen.js
index c0dc4dd..cb0c743 100644
--- a/js/divide/DivideScreen.js
+++ b/js/divide/DivideScreen.js
@@ -22,9 +22,10 @@ import DivideView from './view/DivideView.js';
class DivideScreen extends Screen {
/**
+ * @param { PreferencesModel } preferencesModel
* @param {Object} [options]
*/
- constructor( options ) {
+ constructor( preferencesModel, options ) {
options = merge( {
name: ArithmeticStrings.divideStringProperty,
@@ -37,7 +38,7 @@ class DivideScreen extends Screen {
}, options );
super(
- () => new DivideModel( options.tandem.createTandem( 'model' ) ),
+ () => new DivideModel( preferencesModel, options.tandem.createTandem( 'model' ) ),
model => new DivideView( model ),
options
);
diff --git a/js/divide/model/DivideModel.js b/js/divide/model/DivideModel.js
index e911c60..5847c20 100644
--- a/js/divide/model/DivideModel.js
+++ b/js/divide/model/DivideModel.js
@@ -16,10 +16,11 @@ import GameState from '../../common/model/GameState.js';
class DivideModel extends ArithmeticModel {
/**
- * @param {Tandem} tandem
+ * @param { PreferencesModel } preferencesModel
+ * @param { Tandem } tandem
*/
- constructor( tandem ) {
- super( tandem, {
+ constructor( preferencesModel, tandem ) {
+ super( preferencesModel, tandem, {
fillEquation: () => {
// Convert any strings entered by the user into numerical values.
diff --git a/js/factor/FactorScreen.js b/js/factor/FactorScreen.js
index 7676224..8cbc4b0 100644
--- a/js/factor/FactorScreen.js
+++ b/js/factor/FactorScreen.js
@@ -21,9 +21,10 @@ import FactorView from './view/FactorView.js';
class FactorScreen extends Screen {
/**
+ * @param { PreferencesModel } preferencesModel
* @param {Object} [options]
*/
- constructor( options ) {
+ constructor( preferencesModel, options ) {
options = merge( {
name: ArithmeticStrings.factorStringProperty,
@@ -36,7 +37,7 @@ class FactorScreen extends Screen {
}, options );
super(
- () => new FactorModel( options.tandem.createTandem( 'model' ) ),
+ () => new FactorModel( preferencesModel, options.tandem.createTandem( 'model' ) ),
model => new FactorView( model ),
options
);
diff --git a/js/factor/model/FactorModel.js b/js/factor/model/FactorModel.js
index fd1e8c4..9d7a13e 100644
--- a/js/factor/model/FactorModel.js
+++ b/js/factor/model/FactorModel.js
@@ -15,10 +15,11 @@ import GameState from '../../common/model/GameState.js';
class FactorModel extends ArithmeticModel {
/**
+ * @param { PreferencesModel } preferencesModel
* @param {Tandem} tandem
*/
- constructor( tandem ) {
- super( tandem );
+ constructor( preferencesModel, tandem ) {
+ super( preferencesModel, tandem );
}
// @public
diff --git a/js/multiply/MultiplyScreen.js b/js/multiply/MultiplyScreen.js
index 197e10e..a5e3382 100644
--- a/js/multiply/MultiplyScreen.js
+++ b/js/multiply/MultiplyScreen.js
@@ -21,9 +21,10 @@ import MultiplyView from './view/MultiplyView.js';
class MultiplyScreen extends Screen {
/**
+ * @param { PreferencesModel } preferencesModel
* @param {Object} [options]
*/
- constructor( options ) {
+ constructor( preferencesModel, options ) {
options = merge( {
name: ArithmeticStrings.multiplyStringProperty,
@@ -36,7 +37,7 @@ class MultiplyScreen extends Screen {
}, options );
super(
- () => new MultiplyModel( options.tandem.createTandem( 'model' ) ),
+ () => new MultiplyModel( preferencesModel, options.tandem.createTandem( 'model' ) ),
model => new MultiplyView( model ),
options
);
diff --git a/js/multiply/model/MultiplyModel.js b/js/multiply/model/MultiplyModel.js
index ae1562b..f9ca390 100644
--- a/js/multiply/model/MultiplyModel.js
+++ b/js/multiply/model/MultiplyModel.js
@@ -14,9 +14,13 @@ import GameState from '../../common/model/GameState.js';
class MultiplyModel extends ArithmeticModel {
- constructor( tandem ) {
+ /**
+ * @param { PreferencesModel } preferencesModel
+ * @param { Tandem } tandem
+ */
+ constructor( preferencesModel, tandem ) {
- super( tandem, {
+ super( preferencesModel, tandem, {
fillEquation: () => {
this.problemModel.productProperty.set( Number( this.inputProperty.get() ) );
this.submitAnswer();
diff --git a/package.json b/package.json
index c04c367..080a42f 100644
--- a/package.json
+++ b/package.json
@@ -22,7 +22,10 @@
"phet-io"
],
"simFeatures": {
- "supportsSound": true
+ "supportsSound": true,
+ "supportedRegionsAndCultures": [
+ "usa"
+ ]
},
"simulation": true,
"phet-io": {