Costume - theRAPTLab/gsgo GitHub Wiki
See !97 !108 !177
There are three color systems: RGB, HSV, and a ColorScale.
- Color is stored in the Costume Feature as HSV.
- RGB is converted to HSV during the update loop.
- ColorScale color is also set during the update loop (the color is applied directly rather than converting through RGB).
During the update loop the Feature color HSV properties are converted to a HEX/RGB color value and the agent.prop.color
property is set to the color.
(This is why in general you should not set agent.prop.color
directly: the agent.prop.color
property is overridden with every Costume feature update loop.)
Any agent can be assigned a costume. Costumes can be static PNGs, spritesheets (via TexturePacker), or an animation sequence.
Colorizes a character by overlaying the color on top of the base sprite color. When using the Wizard, the color can be selected via a popup color picker.
featProp character.Costume.setToColor <decimal>
where <decimal>
is a decimal number corresponding to the hex RGB color. e.g. #FF0000
is 16711680
There are many ways to set character colors (see all the featCall
methods and featProps
for Costume
), each of which may override others. In general, we recommend using the featProp character.Costume.color setToColor
approach.
Priority Order During each Costume update loop, colors are applied in this order:
- ColorScaleIndex -- if a ColorScaleIndex value is set, it will override any
color
featProp (used for Moths to set a graduated scale of white to black moths). -
color
featProp -- If thecolor
featProp is set, it will override other colorfeatCall
methods andfeatProps
- HSV values from featProp or featCalls -- Otherwise, the character will use the HSV values previously set by any
featCall
orfeatProp
s.
Note that you should NOT use agent.prop.color
to set color as agent.prop.color
is overwritten by the Costume Feature with each update loop.
featCall agent.Costume.setCostume '<costumeName>' <pose>
where <costumeName>
is either:
- a PNG file reference (e.g.
bee.png
=>featCall agent.Costume.setCostume 'bee.png'
) - a TexturePacker spritesheet (e.g.
bee.json
=> featCall agent.Costume.setCostume 'bee.json'`)
and <pose>
is the frame number in the spritesheet. is optional.
Flip the sprite texture either along the x-axis or y-axis during Physics updates.
featProp Costume flipX setTo <boolean>
where <boolean>
is true
or false
.
Flipping is implemented by PIXIjs via a negative scale setting. Setting this property to true will tell the Physics feature to use a negative scale when sizing the sprite.
Currently most Costume updates are handled by other Features, so setting this property will have no immediate effect. We need to rewrite Costume do its own phase loop processing in order to do that.
- Make sure Physics feature is enabled.
- Set the property
Costumes now use HSV as the core color model. You can now set these properties directly. The agent color will be set automatically during the SIM/VIS_UPDATE
phase based on the three values.
IMPORTANT! You MUST either:
- Call
setColorize
orsetColorizeHSV
to initialize the colors first or - Set all three parameters before changing just one.
These values default to
undefined
so if you set, saycolorValue
without having setcolorHue
andcolorSaturation
, then the resulting color would be unpredictable because hue and saturation have not been set.
All RGB and randomize colorization routines have been updated to set the HSV properties.
The color feature properties make it easier to programmatically change color values without resorting to stack operations.
featProp Costume colorHue setTo <value>
featProp Costume colorSaturation setTo <value>
featProp Costume colorValue setTo <value>
where <value>
is a number between 0 and 1.
Since the properties are GVarNumbers, you can use any GVarNumber method.
e.g. to darken, you might call featProp Costume colorValue sub 0.1
e.g. to set a random darken you might call (this will darken the color by anywhere between 0 and 0.2) featProp Costume colorValue subRnd 0.2
featCall Costume setColorize <red> <green> <blue>
where <red>
, <green>
, and <blue>
are values between 0 and 1.
This will apply both a ColorOverlay at 50% alpha, and an AdjustmentFilter to the sprite.
featCall Costume resetColorize
This will remove the color overlay and adjustment filters and restore the sprite to its original colors.
featCall Costume randomizeColor <red> <green> <blue>
This will change the existing colorized color of the sprite by a random +/- amount. The color values allow you to control how much the color should deviate from the original color.
For example, if you have a green sprite, and you want to randomize ONLY the green levels, you could call:
featCall Costume randomizeColor 0 1 0
With this call green might be changed by as much as 1.0. But red and blue would never be changed.
On the other hand, if you have a green sprite, and want only small changes in red and blue, you could call:
featCall Costume randomizeColor 0.2 0 0.2
With this call green will never be changed, but red and blue might vary by as much as 0.2 in either direction. e.g. if the sprite's red color was originally 0.5, the 0.2 randomization value might set it to as low as 0.3 and as high as 0.7.
You'll have to play with the values to determine what works best for a given sprite image.
Colorizes the agent using Hue/Saturation/Value parameters.
featCall Costume setColorizeHSV <hue> <saturation> <value>
where <hue>
, <saturation>
, and <value>
are numbers between 0 and 1.
Changes the existing colorization of the agent with a random value using Hue/Saturation/Value parameters.
featCall Costume randomizeColorHSV <hue> <saturation> <value>
where <hue>
, <saturation>
, and <value>
are numbers between 0 and 1 representing the +/- range for random variation. e.g. if <hue>
was 0.2
, then the randomized color could have a hue of the current hue +/- 0.2.
Notes:
- Generally you'll want to set the color first, then use
randomizeColorHSV
to shift it. - To allow the full range of values, use a h/s/v of
1
. To not allow any variation, use0
.
Tests whether the two passed colors are within range of each other. For example, this is used to see if a moth color matches the tree color it is resting on.
featCall Costume colorHSVWithinRange <color1> <color2> <hue> <saturation> <value>
where
-
<color1>
and<color2>
are hex colors to be compared -
<hue>
,<saturation>
, and<value>
are numbers between 0 and 1 representing the +/- range for comparison. e.g. if<hue>
was0.2
, and<color1>
had a hue of0.5
and<color2>
had a hue of0.7
then,colorHSVWithinRange
would return true. The test used is<=
for each dimension, e.g.Math.abs(<color1h> - <color2h>) <= <hue>
.
This is most likely used in an ifExpr
expression, e.g.:
ifExpr {{ Moth.callFeatMethod('Costume', 'colorHSVWithinRange', Moth.prop.color.value, TreeTrunk.prop.color.value, 0.2, 1, 0.2)}} [[
// make the moth invisilbe if the Moth color and TreeTrunk color are similar
featProp Vision visionable setTo false
]]
Notes:
- To ignore a dimension, use
1
. For example, callingcolorHSVWithinRange
with1 1 1
would match all colors, while calling t with1 1 0.2
would match any two colors that were within a<value>
of 0.2. - Using
0
for any h/s/v value would result in no colors ever matching.
Agent colors can be assigned to a predefined series of colors in a graded scale. To use this feature, you need to:
- Define the colorscale:
intHSVColorScale
- Set a Costume property:
colorScaleIndex
See !113 Mini-Rounds for a full example.
This defines the color scale, setting the basic starting color values (HSV), the color dimension to vary across the scale, and the number of steps in the scale.
Currently you can vary only one scale type. e.g. you can vary value
but you can't also vary saturation
at the same time.
featCall Costume initHSVColorScale <baseHue> <baseSaturation> <baseValue> <type> <count>
where
-
<baseHue> <baseSaturation> <baseValue>
defines the starting color of the scale. -
<type>
defines the color dimension to vary:hue
,saturation
, orvalue
-
<count>
is the number of steps in the scale.
In order to make it possible for students to create their own color schemes, we split the sinlge featCall Costume initHSVColorScale 0 0 1 'value' 11
into individual featProp settings.
Each dimension can now be set separately.
If a value is omitted, the default values are used.
Calls with default values
featProp Costume colorScaleHue setTo 0
featProp Costume colorScaleSaturation setTo 0
featProp Costume colorScaleValue setTo 1
featProp Costume colorScaleType setTo 'value'
featProp Costume colorScaleSteps setTo 5
featCall Costume initHSVColorScale
is the equivalent of
featCall Costume initHSVColorScale 0 0 1 'value' 11
featCall Costume initHSVColorScale 0 0 1 'value' 11
This will create a scale of 11 gray values. 0 0 1
is white, since there is no saturation and value is maxed.
To set the agent to a color in the scale, just set the colorScaleIndex
property. The corresponding color will be automatically applied during the VIS_UPDATE
cycle.
colorScaleIndex
is a GVarNumber, so you can use GVar math.
We implemented this as a featProperty so that you can easily do math with it.
For example, this will set the agent to the 9th color in the scale.
featProp Costume colorScaleIndex setTo 9
For example, this will change the colorScaleIndex
value by a random value up to +/-2.
featProp Costume colorScaleIndex addRnd -2 2 true
The colorize methods are all part of the Costume Feature.
Example:
# PROGRAM DEFINE
useFeature Costume
featCall Costume setCostume 'bee.json' 0
// Turn the bee green
featCall Costume setColorize 0 1 0
# PROGRAM UPDATE
when Moth touches Tree [[
// when moth touches tree show the true colors
featCall Costume resetColorize
]]
when Moth touches Mushroom [[
// when moth touches Mushroom show psychedelic color changes
featCall Costume randomizeColor 1 1 1
]]
The recent changes to asset management should make it really easy to add, update, and remove art assets for any installation:
- Any art can simply be added to the
/gs_assets/local/sprites
folder. - There is no need to use TexturePacker to create a spritesheet (.json file) if you do not need it.
- There is no need to create an asset manifest file.
- Use the filename to set the costume name, e.g.
featCall Costume setCostume 'bird.jpg'
For example, you can draw a bird using any art program of your choice, save it as "bird.jpg" and move it into /gs_assets/local/sprites/bird.jpg
. e.g. featCall Costume setCostume 'hawk.png'
Per Corey's request, we have made it easy to create animations with a new setAnimatedCostume
command.
- Name your graphic files with a number at the end representing the animation frame, e.g.
fly1.png
,fly2.png
,fly3.png
. - Save them in
/gs_assets/local/sprites
. - Instead of using
setCostume
, callsetAnimatedCostume
. e.g.
featCall Costume setAnimatedCostume 'fly1.png'
The Costume feature will find the last number before the extension and use that as the starting frame. The system will then look for fly2.png
as the next frame, and so on, until it can't find any more frames. At which point it'll return to the first frame.
- You can set the frame rate as the last parameter.
featCall Costume setAnimatedCostume 'fly1.png' 1
This will update the animation every 1 second.
By default the frame rate is 0.3.
I used Corey's method of frame rate calculation, which is more akin to "every n seconds" or "go to the next frame every n seconds". So the default frame rate of 0.3 is "change frames every 0.3 seconds", a leisurely rate.
We might consider changing it to a true "frames per second" value, e.g. 30 would be running 30 updates per second.
A few general notes:
- Animations only run when the simulation is running. So you need to push "START ROUND" to see the animation.
- You can start the animation on a specific frame. When the animation loops, it will start again with the first frame. e.g. if you call
featCall Costume setAnimatedCostume 'fly3.png'
, the system will start with fly3, go to fly 4, fly5, etc. until it hits the last frame, then it'll start back at fly3. - Don't use leading 0's. The system will ignore the leading zero for the next frame, e.g. if you use
toot01.jpg
, the next frame will betoot2.jpg
. - If you skip a number, the animation will loop. e.g. if you have fly1, fly2, fly4 (no fly3), then the animation will just loop between fly1 and fly2. When the system can't find an animation frame, it assumes it's time to loop.