From a3016dcb875557afe58972504b6addcfaa09d55c Mon Sep 17 00:00:00 2001 From: Michael Kauzmann Date: Fri, 19 Jul 2024 17:11:05 -0600 Subject: [PATCH] create density mystery screen random materials only once. AND support initial materialProperty value as custom, https://github.com/phetsims/density-buoyancy-common/issues/275 Signed-off-by: Michael Kauzmann --- js/buoyancy/model/applications/Bottle.ts | 31 +- .../model/shapes/BuoyancyShapesModel.ts | 2 +- js/common/model/Cube.ts | 14 +- js/common/model/Mass.ts | 41 +-- js/common/model/MaterialProperty.ts | 7 +- js/common/model/Pool.ts | 10 +- js/density/model/DensityMysteryModel.ts | 275 +++++++++++------- 7 files changed, 238 insertions(+), 142 deletions(-) diff --git a/js/buoyancy/model/applications/Bottle.ts b/js/buoyancy/model/applications/Bottle.ts index a519fa7a..8be50bf5 100644 --- a/js/buoyancy/model/applications/Bottle.ts +++ b/js/buoyancy/model/applications/Bottle.ts @@ -196,22 +196,23 @@ export default class Bottle extends ApplicationsMass { const vertices = Bottle.getFlatIntersectionVertices(); - // The overall composite material for the bottle + inside material system. - // This is not used for colorizing, since the bottle + liquid composite system is rendered separately, it just - // needs to be a superset of all possible values across the different inside materials - const customMaterial = new CustomSolidMaterial( providedOptions.tandem.createTandem( 'customMaterial' ), { - nameProperty: DensityBuoyancyCommonStrings.systemAStringProperty, - density: ( BOTTLE_MASS + BOTTLE_INITIAL_INTERIOR_MATERIAL.density * BOTTLE_INITIAL_INTERIOR_VOLUME ) / BOTTLE_VOLUME, - densityRange: new Range( 0, 1000000000 ) - } ); const options = optionize()( { body: engine.createFromVertices( vertices, true ), shape: Shape.polygon( vertices ), volume: BOTTLE_VOLUME, - material: customMaterial, + material: 'CUSTOM', materialPropertyOptions: { - validValues: [ customMaterial ] + phetioReadOnly: true + }, + + // The overall composite material for the bottle + inside material system. + // This is not used for colorizing, since the bottle + liquid composite system is rendered separately, it just + // needs to be a superset of all possible values across the different inside materials + customMaterialOptions: { + nameProperty: DensityBuoyancyCommonStrings.systemAStringProperty, + density: ( BOTTLE_MASS + BOTTLE_INITIAL_INTERIOR_MATERIAL.density * BOTTLE_INITIAL_INTERIOR_VOLUME ) / BOTTLE_VOLUME, + densityRange: new Range( 0, 1000000000 ) }, massShape: MassShape.BLOCK, @@ -225,13 +226,17 @@ export default class Bottle extends ApplicationsMass { const materialInsideTandem = options.tandem.createTandem( 'materialInside' ); - this.materialInsideProperty = new MaterialProperty( BOTTLE_INITIAL_INTERIOR_MATERIAL, tandem => new CustomSolidMaterial( tandem, { + const materialInsidePropertyTandem = materialInsideTandem.createTandem( 'materialProperty' ); + + const customInsideMaterial = new CustomSolidMaterial( materialInsidePropertyTandem.createTandem( 'customMaterial' ), { density: BOTTLE_INITIAL_INTERIOR_MATERIAL.density, densityRange: new Range( 50, 20000 ) - } ), { + } ); + + this.materialInsideProperty = new MaterialProperty( BOTTLE_INITIAL_INTERIOR_MATERIAL, customInsideMaterial, { valueType: Material, reentrant: true, - tandem: materialInsideTandem.createTandem( 'materialProperty' ), + tandem: materialInsidePropertyTandem, phetioValueType: ReferenceIO( IOType.ObjectIO ) } ); diff --git a/js/buoyancy/model/shapes/BuoyancyShapesModel.ts b/js/buoyancy/model/shapes/BuoyancyShapesModel.ts index 7f531844..0d500dac 100644 --- a/js/buoyancy/model/shapes/BuoyancyShapesModel.ts +++ b/js/buoyancy/model/shapes/BuoyancyShapesModel.ts @@ -57,7 +57,7 @@ export default class BuoyancyShapesModel extends DensityBuoyancyModel { this.materialProperty = new MaterialProperty( Material.WOOD, // This hack is a way of saying, we do not create or support a custom material in this case. - () => Material.WOOD, { + Material.WOOD, { tandem: objectsTandem.createTandem( 'materialProperty' ), phetioValueType: ReferenceIO( IOType.ObjectIO ) } ); diff --git a/js/common/model/Cube.ts b/js/common/model/Cube.ts index 6c7346de..e89e91bc 100644 --- a/js/common/model/Cube.ts +++ b/js/common/model/Cube.ts @@ -77,7 +77,7 @@ export default class Cube extends Cuboid { /** * Creates a Cube with a defined volume */ - public static createWithVolume( engine: PhysicsEngine, material: Material, position: Vector2, volume: number, options?: StrictOmit ): Cube { + public static createWithVolume( engine: PhysicsEngine, material: Material | 'CUSTOM', position: Vector2, volume: number, options?: StrictOmit ): Cube { return new Cube( engine, volume, combineOptions( { matrix: Matrix3.translation( position.x, position.y ), minVolume: Cuboid.MIN_VOLUME, @@ -89,8 +89,16 @@ export default class Cube extends Cuboid { /** * Creates a Cube with a defined volume */ - public static createWithMass( engine: PhysicsEngine, material: Material, position: Vector2, mass: number, options?: StrictOmit ): Cube { - return Cube.createWithVolume( engine, material, position, mass / material.density, options ); + public static createWithMass( engine: PhysicsEngine, material: Material | 'CUSTOM', position: Vector2, mass: number, options?: StrictOmit ): Cube { + let density: number; + if ( material === 'CUSTOM' ) { + assert && assert( options?.customMaterialOptions?.density, 'density needed to create with mass' ); + density = options!.customMaterialOptions!.density!; + } + else { + density = material.density; + } + return Cube.createWithVolume( engine, material, position, mass / density, options ); } } diff --git a/js/common/model/Mass.ts b/js/common/model/Mass.ts index e4986403..9e800115 100644 --- a/js/common/model/Mass.ts +++ b/js/common/model/Mass.ts @@ -10,7 +10,7 @@ import BooleanProperty, { BooleanPropertyOptions } from '../../../../axon/js/Boo import DerivedProperty from '../../../../axon/js/DerivedProperty.js'; import Emitter from '../../../../axon/js/Emitter.js'; import NumberProperty, { NumberPropertyOptions } from '../../../../axon/js/NumberProperty.js'; -import Property, { PropertyOptions } from '../../../../axon/js/Property.js'; +import Property from '../../../../axon/js/Property.js'; import Matrix3, { Matrix3StateObject } from '../../../../dot/js/Matrix3.js'; import Range from '../../../../dot/js/Range.js'; import Utils from '../../../../dot/js/Utils.js'; @@ -27,7 +27,7 @@ import BooleanIO from '../../../../tandem/js/types/BooleanIO.js'; import IOType from '../../../../tandem/js/types/IOType.js'; import densityBuoyancyCommon from '../../densityBuoyancyCommon.js'; import InterpolatedProperty from './InterpolatedProperty.js'; -import Material, { CustomSolidMaterial } from './Material.js'; +import Material, { CustomSolidMaterial, MaterialOptions } from './Material.js'; import PhysicsEngine, { PhysicsEngineBody } from './PhysicsEngine.js'; import Basin from './Basin.js'; import TReadOnlyProperty from '../../../../axon/js/TReadOnlyProperty.js'; @@ -41,7 +41,7 @@ import Bounds3 from '../../../../dot/js/Bounds3.js'; import BlendedVector2Property from './BlendedVector2Property.js'; import { GuardedNumberProperty, GuardedNumberPropertyOptions } from './GuardedNumberProperty.js'; import DensityBuoyancyCommonConstants from '../DensityBuoyancyCommonConstants.js'; -import MaterialProperty from './MaterialProperty.js'; +import MaterialProperty, { MaterialPropertyOptions } from './MaterialProperty.js'; import ReferenceIO from '../../../../tandem/js/types/ReferenceIO.js'; // For the Buoyancy Shapes screen, but needed here because setRatios is included in each core type @@ -54,7 +54,9 @@ type SelfOptions = { // Required body: PhysicsEngineBody; shape: Shape; - material: Material; + + // Use "CUSTOM" to tell the MaterialProperty to take the initial value from the internal customMaterial it creates. + material: Material | 'CUSTOM'; volume: number; massShape: MassShape; @@ -73,7 +75,8 @@ type SelfOptions = { tag?: MassTag; accessibleName?: PDOMValueType | null; inputEnabledPropertyOptions?: BooleanPropertyOptions; - materialPropertyOptions?: PropertyOptions; + materialPropertyOptions?: Partial; + customMaterialOptions?: MaterialOptions; volumePropertyOptions?: NumberPropertyOptions; massPropertyOptions?: NumberPropertyOptions; @@ -199,7 +202,13 @@ export default abstract class Mass extends PhetioObject { accessibleName: null, phetioType: Mass.MassIO, inputEnabledPropertyOptions: {}, - materialPropertyOptions: {}, + materialPropertyOptions: { + valueType: Material, + reentrant: true, + phetioValueType: ReferenceIO( IOType.ObjectIO ), + phetioFeatured: true + }, + customMaterialOptions: {}, volumePropertyOptions: {}, massPropertyOptions: {}, minVolume: 0, @@ -212,7 +221,7 @@ export default abstract class Mass extends PhetioObject { super( options ); // TODO: Why did the question mark disappear? See https://github.com/phetsims/density-buoyancy-common/issues/243 - const tandem: Tandem = options.tandem; + const tandem = options.tandem; this.engine = engine; this.body = options.body; @@ -245,19 +254,13 @@ export default abstract class Mass extends PhetioObject { this.visibleProperty = new GatedVisibleProperty( this.internalVisibleProperty, tandem ); - this.materialProperty = new MaterialProperty( options.material, tandem => new CustomSolidMaterial( tandem, { - density: options.material.density, - - // TODO: It is incorrect to take the range of the default value, this affects the color, see https://github.com/phetsims/density-buoyancy-common/issues/268 - densityRange: options.material.densityProperty.range - } ), combineOptions & PickRequired>( { - valueType: Material, - reentrant: true, + options.materialPropertyOptions.tandem = options.materialPropertyOptions.tandem || tandem.createTandem( 'materialProperty' ); + const customSolidMaterial = new CustomSolidMaterial( options.materialPropertyOptions.tandem.createTandem( 'customMaterial' ), combineOptions( { + density: options.material === 'CUSTOM' ? undefined : options.material.density + }, options.customMaterialOptions ) ); - tandem: tandem?.createTandem( 'materialProperty' ), - phetioValueType: ReferenceIO( IOType.ObjectIO ), - phetioFeatured: true - }, options.materialPropertyOptions ) ); + const initialMaterial = options.material === 'CUSTOM' ? customSolidMaterial : options.material; + this.materialProperty = new MaterialProperty( initialMaterial, customSolidMaterial, options.materialPropertyOptions as MaterialPropertyOptions ); this.volumeProperty = new NumberProperty( options.volume, combineOptions( { tandem: tandem?.createTandem( 'volumeProperty' ), diff --git a/js/common/model/MaterialProperty.ts b/js/common/model/MaterialProperty.ts index 1250a9ef..efb827a4 100644 --- a/js/common/model/MaterialProperty.ts +++ b/js/common/model/MaterialProperty.ts @@ -13,20 +13,19 @@ import Material from './Material.js'; import TReadOnlyProperty from '../../../../axon/js/TReadOnlyProperty.js'; import MappedWrappedProperty from './MappedWrappedProperty.js'; import { combineOptions, EmptySelfOptions } from '../../../../phet-core/js/optionize.js'; -import Tandem from '../../../../tandem/js/Tandem.js'; import PickRequired from '../../../../phet-core/js/types/PickRequired.js'; import { PhetioObjectOptions } from '../../../../tandem/js/PhetioObject.js'; type SelfOptions = EmptySelfOptions; -type MaterialPropertyOptions = SelfOptions & PropertyOptions & PickRequired; +export type MaterialPropertyOptions = SelfOptions & PropertyOptions & PickRequired; export default class MaterialProperty extends MappedWrappedProperty { public readonly densityProperty: TReadOnlyProperty; public readonly customMaterial: Material; - public constructor( material: Material, createCustomMaterial: ( tandem: Tandem ) => Material, providedOptions: MaterialPropertyOptions ) { - const customMaterial = createCustomMaterial( providedOptions.tandem.createTandem( 'customMaterial' ) ); + // Note the material could be the customMaterial + public constructor( material: Material, customMaterial: Material, providedOptions: MaterialPropertyOptions ) { super( material, customMaterial, combineOptions( { phetioFeatured: true }, providedOptions ) ); diff --git a/js/common/model/Pool.ts b/js/common/model/Pool.ts index 9233795f..178f2852 100644 --- a/js/common/model/Pool.ts +++ b/js/common/model/Pool.ts @@ -57,13 +57,17 @@ export default class Pool extends Basin { this.stepBottom = bounds.minY; this.stepTop = bounds.maxY; - this.fluidMaterialProperty = new MaterialProperty( Material.WATER, tandem => new CustomLiquidMaterial( tandem, { + const fluidMaterialPropertyTandem = this.fluidTandem.createTandem( 'materialProperty' ); + + const customFluidMaterial = new CustomLiquidMaterial( fluidMaterialPropertyTandem.createTandem( 'customMaterial' ), { density: Material.WATER.density, densityRange: DensityBuoyancyCommonConstants.FLUID_DENSITY_RANGE_PER_M3 - } ), { + } ); + + this.fluidMaterialProperty = new MaterialProperty( Material.WATER, customFluidMaterial, { valueType: Material, phetioValueType: ReferenceIO( IOType.ObjectIO ), - tandem: this.fluidTandem.createTandem( 'materialProperty' ), + tandem: fluidMaterialPropertyTandem, phetioDocumentation: 'The material of the fluid in the pool' } ); diff --git a/js/density/model/DensityMysteryModel.ts b/js/density/model/DensityMysteryModel.ts index 0cdaf488..23266faf 100644 --- a/js/density/model/DensityMysteryModel.ts +++ b/js/density/model/DensityMysteryModel.ts @@ -26,10 +26,10 @@ import Cuboid from '../../common/model/Cuboid.js'; import MassTag from '../../common/model/MassTag.js'; import DensityBuoyancyCommonStrings from '../../DensityBuoyancyCommonStrings.js'; import LocalizedStringProperty from '../../../../chipper/js/LocalizedStringProperty.js'; -import Tandem from '../../../../tandem/js/Tandem.js'; +import { ColorProperty } from '../../../../scenery/js/imports.js'; +import Emitter from '../../../../axon/js/Emitter.js'; // constants -const randomMaterials = Material.DENSITY_MYSTERY_MATERIALS; const randomColors = [ DensityBuoyancyCommonColors.compareYellowColorProperty, DensityBuoyancyCommonColors.compareBlueColorProperty, @@ -78,17 +78,16 @@ export default class DensityMysteryModel extends BlockSetModel adjustableMaterial: true }; - // TODO AV: this should just set density/color on 5 references that live forever. https://github.com/phetsims/density-buoyancy-common/issues/256 - const createMysteryMaterials = () => { - const densities = dotRandom.shuffle( randomMaterials ).slice( 0, 5 ).map( material => material.density ); - const colors = dotRandom.shuffle( randomColors ).slice( 0, 5 ); - - // TODO AV: Specify the correct tandems throughout this file? See https://github.com/phetsims/density-buoyancy-common/issues/123 - return _.range( 0, 5 ).map( i => Material.createCustomMaterial( Tandem.OPT_OUT, { - density: densities[ i ], - colorProperty: colors[ i ] - } ) ); + let densities: number[]; + let colors: ColorProperty[]; + const randomizeMaterialsEmitter = new Emitter(); + const randomizeMysteryMaterials = () => { + densities = dotRandom.shuffle( Material.DENSITY_MYSTERY_MATERIALS ).slice( 0, 5 ).map( material => material.density ); + colors = dotRandom.shuffle( randomColors ).slice( 0, 5 ); + randomizeMaterialsEmitter.emit(); }; + randomizeMysteryMaterials(); // initial setup + const createMysteryVolumes = () => { return [ // we will want 3 smaller masses on the right, then 2 larger masses on the left @@ -109,174 +108,236 @@ export default class DensityMysteryModel extends BlockSetModel return [ Cube.createWithVolume( model.engine, - Material.createCustomMaterial( Tandem.OPT_OUT, { - density: Material.WATER.density, - colorProperty: DensityBuoyancyCommonColors.compareRedColorProperty - } ), + 'CUSTOM', Vector2.ZERO, 0.005, - combineOptions( {}, commonCubeOptions, { tag: MassTag.ONE_D, tandem: set1Tandem.createTandem( `block${MassTag.ONE_D.tandemName}` ) } ) + combineOptions( {}, commonCubeOptions, { + customMaterialOptions: { + density: Material.WATER.density, + colorProperty: DensityBuoyancyCommonColors.compareRedColorProperty + }, + tag: MassTag.ONE_D, + tandem: set1Tandem.createTandem( `block${MassTag.ONE_D.tandemName}` ) + } ) ), Cube.createWithVolume( model.engine, - Material.createCustomMaterial( Tandem.OPT_OUT, { - density: Material.WOOD.density, - colorProperty: DensityBuoyancyCommonColors.compareBlueColorProperty - } ), + 'CUSTOM', Vector2.ZERO, 0.001, - combineOptions( {}, commonCubeOptions, { tag: MassTag.ONE_B, tandem: set1Tandem.createTandem( `block${MassTag.ONE_B.tandemName}` ) } ) + combineOptions( {}, commonCubeOptions, { + customMaterialOptions: { + density: Material.WOOD.density, + colorProperty: DensityBuoyancyCommonColors.compareBlueColorProperty + }, + tag: MassTag.ONE_B, + tandem: set1Tandem.createTandem( `block${MassTag.ONE_B.tandemName}` ) + } ) ), Cube.createWithVolume( model.engine, - Material.createCustomMaterial( Tandem.OPT_OUT, { - density: Material.WOOD.density, - colorProperty: DensityBuoyancyCommonColors.compareGreenColorProperty - } ), + 'CUSTOM', Vector2.ZERO, 0.007, - combineOptions( {}, commonCubeOptions, { tag: MassTag.ONE_E, tandem: set1Tandem.createTandem( `block${MassTag.ONE_E.tandemName}` ) } ) + combineOptions( {}, commonCubeOptions, { + customMaterialOptions: { + density: Material.WOOD.density, + colorProperty: DensityBuoyancyCommonColors.compareGreenColorProperty + }, + tag: MassTag.ONE_E, + tandem: set1Tandem.createTandem( `block${MassTag.ONE_E.tandemName}` ) + } ) ), Cube.createWithVolume( model.engine, - Material.createCustomMaterial( Tandem.OPT_OUT, { - density: Material.GOLD.density, - colorProperty: DensityBuoyancyCommonColors.compareYellowColorProperty - } ), + 'CUSTOM', Vector2.ZERO, 0.001, - combineOptions( {}, commonCubeOptions, { tag: MassTag.ONE_C, tandem: set1Tandem.createTandem( `block${MassTag.ONE_C.tandemName}` ) } ) + combineOptions( {}, commonCubeOptions, { + customMaterialOptions: { + density: Material.GOLD.density, + colorProperty: DensityBuoyancyCommonColors.compareYellowColorProperty + }, + tag: MassTag.ONE_C, + tandem: set1Tandem.createTandem( `block${MassTag.ONE_C.tandemName}` ) + } ) ), Cube.createWithVolume( model.engine, - Material.createCustomMaterial( Tandem.OPT_OUT, { - density: Material.DIAMOND.density, - colorProperty: DensityBuoyancyCommonColors.comparePurpleColorProperty - } ), + 'CUSTOM', Vector2.ZERO, 0.0055, - combineOptions( {}, commonCubeOptions, { tag: MassTag.ONE_A, tandem: set1Tandem.createTandem( `block${MassTag.ONE_A.tandemName}` ) } ) + combineOptions( {}, commonCubeOptions, { + customMaterialOptions: { + density: Material.DIAMOND.density, + colorProperty: DensityBuoyancyCommonColors.comparePurpleColorProperty + }, + tag: MassTag.ONE_A, + tandem: set1Tandem.createTandem( `block${MassTag.ONE_A.tandemName}` ) + } ) ) ]; case MysteryBlockSet.SET_2: return [ Cube.createWithMass( model.engine, - Material.createCustomMaterial( Tandem.OPT_OUT, { - density: 4500, - colorProperty: DensityBuoyancyCommonColors.mysteryPinkColorProperty - } ), + 'CUSTOM', Vector2.ZERO, 18, - combineOptions( {}, commonCubeOptions, { tag: MassTag.TWO_D, tandem: set2Tandem.createTandem( `block${MassTag.TWO_D.tandemName}` ) } ) + combineOptions( {}, commonCubeOptions, { + customMaterialOptions: { + density: 4500, + colorProperty: DensityBuoyancyCommonColors.mysteryPinkColorProperty + }, + tag: MassTag.TWO_D, + tandem: set2Tandem.createTandem( `block${MassTag.TWO_D.tandemName}` ) + } ) ), Cube.createWithMass( model.engine, - Material.createCustomMaterial( Tandem.OPT_OUT, { - density: 11340, - colorProperty: DensityBuoyancyCommonColors.mysteryOrangeColorProperty - } ), + 'CUSTOM', Vector2.ZERO, 18, - combineOptions( {}, commonCubeOptions, { tag: MassTag.TWO_A, tandem: set2Tandem.createTandem( `block${MassTag.TWO_A.tandemName}` ) } ) + combineOptions( {}, commonCubeOptions, { + customMaterialOptions: { + density: 11340, + colorProperty: DensityBuoyancyCommonColors.mysteryOrangeColorProperty + }, + tag: MassTag.TWO_A, + tandem: set2Tandem.createTandem( `block${MassTag.TWO_A.tandemName}` ) + } ) ), Cube.createWithVolume( model.engine, - Material.createCustomMaterial( Tandem.OPT_OUT, { - density: Material.COPPER.density, - colorProperty: DensityBuoyancyCommonColors.mysteryLightPurpleColorProperty - } ), + 'CUSTOM', Vector2.ZERO, 0.005, - combineOptions( {}, commonCubeOptions, { tag: MassTag.TWO_E, tandem: set2Tandem.createTandem( `block${MassTag.TWO_E.tandemName}` ) } ) + combineOptions( {}, commonCubeOptions, { + customMaterialOptions: { + density: Material.COPPER.density, + colorProperty: DensityBuoyancyCommonColors.mysteryLightPurpleColorProperty + }, + tag: MassTag.TWO_E, + tandem: set2Tandem.createTandem( `block${MassTag.TWO_E.tandemName}` ) + } ) ), Cube.createWithMass( model.engine, - Material.createCustomMaterial( Tandem.OPT_OUT, { - density: 2700, - colorProperty: DensityBuoyancyCommonColors.mysteryLightGreenColorProperty - } ), + 'CUSTOM', Vector2.ZERO, 2.7, - combineOptions( {}, commonCubeOptions, { tag: MassTag.TWO_C, tandem: set2Tandem.createTandem( `block${MassTag.TWO_C.tandemName}` ) } ) + combineOptions( {}, commonCubeOptions, { + customMaterialOptions: { + density: 2700, + colorProperty: DensityBuoyancyCommonColors.mysteryLightGreenColorProperty + }, + tag: MassTag.TWO_C, + tandem: set2Tandem.createTandem( `block${MassTag.TWO_C.tandemName}` ) + } ) ), Cube.createWithMass( model.engine, - Material.createCustomMaterial( Tandem.OPT_OUT, { - density: 2700, - colorProperty: DensityBuoyancyCommonColors.mysteryBrownColorProperty - } ), + 'CUSTOM', Vector2.ZERO, 10.8, - combineOptions( {}, commonCubeOptions, { tag: MassTag.TWO_B, tandem: set2Tandem.createTandem( `block${MassTag.TWO_B.tandemName}` ) } ) + combineOptions( {}, commonCubeOptions, { + customMaterialOptions: { + density: 2700, + colorProperty: DensityBuoyancyCommonColors.mysteryBrownColorProperty + }, + tag: MassTag.TWO_B, + tandem: set2Tandem.createTandem( `block${MassTag.TWO_B.tandemName}` ) + } ) ) ]; case MysteryBlockSet.SET_3: return [ Cube.createWithMass( model.engine, - Material.createCustomMaterial( Tandem.OPT_OUT, { - density: 950, - colorProperty: DensityBuoyancyCommonColors.mysteryWhiteColorProperty - } ), + 'CUSTOM', Vector2.ZERO, 6, - combineOptions( {}, commonCubeOptions, { tag: MassTag.THREE_E, tandem: set3Tandem.createTandem( `block${MassTag.THREE_E.tandemName}` ) } ) + combineOptions( {}, commonCubeOptions, { + customMaterialOptions: { + density: 950, + colorProperty: DensityBuoyancyCommonColors.mysteryWhiteColorProperty + }, + tag: MassTag.THREE_E, + tandem: set3Tandem.createTandem( `block${MassTag.THREE_E.tandemName}` ) + } ) ), Cube.createWithMass( model.engine, - Material.createCustomMaterial( Tandem.OPT_OUT, { - density: 1000, // same as water, in SI (kg/m^3) - colorProperty: DensityBuoyancyCommonColors.mysteryGrayColorProperty - } ), + 'CUSTOM', Vector2.ZERO, 6, - combineOptions( {}, commonCubeOptions, { tag: MassTag.THREE_B, tandem: set3Tandem.createTandem( `block${MassTag.THREE_B.tandemName}` ) } ) + combineOptions( {}, commonCubeOptions, { + customMaterialOptions: { + density: 1000, // same as water, in SI (kg/m^3) + colorProperty: DensityBuoyancyCommonColors.mysteryGrayColorProperty + }, + tag: MassTag.THREE_B, + tandem: set3Tandem.createTandem( `block${MassTag.THREE_B.tandemName}` ) + } ) ), Cube.createWithMass( model.engine, - Material.createCustomMaterial( Tandem.OPT_OUT, { - density: 400, - colorProperty: DensityBuoyancyCommonColors.mysteryMustardColorProperty - } ), + 'CUSTOM', Vector2.ZERO, 2, - combineOptions( {}, commonCubeOptions, { tag: MassTag.THREE_D, tandem: set3Tandem.createTandem( `block${MassTag.THREE_D.tandemName}` ) } ) + combineOptions( {}, commonCubeOptions, { + customMaterialOptions: { + density: 400, + colorProperty: DensityBuoyancyCommonColors.mysteryMustardColorProperty + }, + tag: MassTag.THREE_D, + tandem: set3Tandem.createTandem( `block${MassTag.THREE_D.tandemName}` ) + } ) ), Cube.createWithMass( model.engine, - Material.createCustomMaterial( Tandem.OPT_OUT, { - density: 7800, - colorProperty: DensityBuoyancyCommonColors.mysteryPeachColorProperty - } ), + 'CUSTOM', Vector2.ZERO, 23.4, - combineOptions( {}, commonCubeOptions, { tag: MassTag.THREE_C, tandem: set3Tandem.createTandem( `block${MassTag.THREE_C.tandemName}` ) } ) + combineOptions( {}, commonCubeOptions, { + customMaterialOptions: { + density: 7800, + colorProperty: DensityBuoyancyCommonColors.mysteryPeachColorProperty + }, + tag: MassTag.THREE_C, + tandem: set3Tandem.createTandem( `block${MassTag.THREE_C.tandemName}` ) + } ) ), Cube.createWithMass( model.engine, - Material.createCustomMaterial( Tandem.OPT_OUT, { - density: 950, - colorProperty: DensityBuoyancyCommonColors.mysteryMaroonColorProperty - } ), + 'CUSTOM', Vector2.ZERO, 2.85, - combineOptions( {}, commonCubeOptions, { tag: MassTag.THREE_A, tandem: set3Tandem.createTandem( `block${MassTag.THREE_A.tandemName}` ) } ) + combineOptions( {}, commonCubeOptions, { + customMaterialOptions: { + density: 950, + colorProperty: DensityBuoyancyCommonColors.mysteryMaroonColorProperty + }, + tag: MassTag.THREE_A, + tandem: set3Tandem.createTandem( `block${MassTag.THREE_A.tandemName}` ) + } ) ) ]; case MysteryBlockSet.RANDOM: { + + // The ordering here is like this to ensure that the blocks are in order when stacked on both sides of the pool. const tags = [ MassTag.C, MassTag.D, @@ -285,16 +346,33 @@ export default class DensityMysteryModel extends BlockSetModel MassTag.B ]; - const mysteryMaterials = createMysteryMaterials(); const mysteryVolumes = createMysteryVolumes(); return _.range( 0, 5 ).map( i => { - return Cube.createWithVolume( model.engine, mysteryMaterials[ i ], Vector2.ZERO, mysteryVolumes[ i ], { + const cubeTandem = randomTandem.createTandem( `block${tags[ i ].tandemName}` ); + + const colorProperty = new ColorProperty( colors[ i ].value, { + // TODO: Is this where we want things? https://github.com/phetsims/density-buoyancy-common/issues/268 + tandem: cubeTandem.createTandem( 'materialProperty' ).createTandem( 'customMaterial' ).createTandem( 'colorProperty' ) + } ); + + const cube = Cube.createWithVolume( model.engine, 'CUSTOM', Vector2.ZERO, mysteryVolumes[ i ], { adjustVolumeOnMassChanged: true, adjustableMaterial: true, tag: tags[ i ], - tandem: randomTandem.createTandem( `block${tags[ i ].tandemName}` ) + tandem: cubeTandem, + customMaterialOptions: { + colorProperty: colorProperty, + density: densities[ i ] + } } ); + + randomizeMaterialsEmitter.addListener( () => { + cube.materialProperty.customMaterial.densityProperty.value = densities[ i ]; + colorProperty.value = colors[ i ].value; + } ); + + return cube; } ); } default: @@ -303,15 +381,14 @@ export default class DensityMysteryModel extends BlockSetModel }; const regenerateMasses = ( blockSet: MysteryBlockSet, masses: Cuboid[] ) => { - if ( blockSet === MysteryBlockSet.RANDOM ) { - const mysteryMaterials = createMysteryMaterials(); - const mysteryVolumes = createMysteryVolumes(); - - masses.forEach( ( mass, i ) => { - mass.materialProperty.value = mysteryMaterials[ i ]; - mass.updateSize( Cube.boundsFromVolume( mysteryVolumes[ i ] ) ); - } ); - } + assert && assert( blockSet === MysteryBlockSet.RANDOM, 'Unexpected blockSet regeneration:', blockSet ); + + randomizeMysteryMaterials(); + const mysteryVolumes = createMysteryVolumes(); + + masses.forEach( ( mass, i ) => { + mass.updateSize( Cube.boundsFromVolume( mysteryVolumes[ i ] ) ); + } ); }; const positionMasses = ( model: DensityBuoyancyModel, blockSet: MysteryBlockSet, masses: Cuboid[] ) => {