Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
State Categories can be thought of as folders for states. State Categories are used for a number of reasons:
To organize similar states into categories
To allow multiple states to be set at the same time (if not sharing variables between states)
To create multiple state types for more expressive code (if not sharing variables between states)
To enable including and excluding particular variables from assignment
State categories will appear as folders in the tree view, and can contain any number of States.
Note that categorized cannot be added inside of other categories.
To add a state category:
Expand a Screen or Entity that you want to add a category to
Right-click on the States item
Select Add State Category
Enter the name for the new category. By convention, categories should have the suffix "Category"
Click OK
By default a category categories do not set any variables. Any variable that should be set by the category must be explicitly added.
To exclude or exclude variables, click the ... button in the State Data tab and use the << and >> buttons to include and exclude variables.
Excluding variables has two benefits:
Simplifies the grid so only relevant variables are displayed
Removes unnecessary assignment of variables when a state is set
StateData is the concept of treating states similar to CSV data. FlatRedBall supports treating States as CSV data by providing a CSV-like interface when selecting a category, as shown in the following image:
For an in-depth discussion of State Data, including how to exclude variables from inclusion, see the State Data blog post.
Glue creates a custom class for every state category, and a separate class for all uncategorized states. Note that previous versions of Glue used to create enumerations for states, but this behavior was changed in 2018. For details about the change, see the post about state data.
The default class for uncategorized states in an entity is VariableState . To prevent naming conflicts, the class is defined inside the generated class for the screen/entity. For example, if a Screen named GameScreen includes uncategorized states, then the following qualified class is generated:
The class is an embedded class, so it must be accessed through the screen class. For example, the fully qualified name of the VariableState class would be:
States will appear in the VariableState class if they are either uncategorized.
Glue automatically provides two methods for any Screen or Entity which includes multiple states: InterpolateToState and InterpolateBetween. Although both of these methods use similar concepts (interpolation using states) they have slightly different functionality. InterpolateToState is a function which requires only a single state argument and a time value. InterpolateToState is a function which continues to apply itself over time as specified by the time argument. InterpolateBetween is a one-time call which combines two states using a given interpolation value (which is between 0 and 1). It requires two states so that it can create an "in between" state.
InterpolateToState uses a "linear interpolation" which means that the values are changed at a constant rate. For example, if one state sets an object's X to 0 and another state sets it to 10, and you interpolate over the course of 1 second, then the object's X will change at 10 units per second for the entire second. InterpolateToState is useful if you want to perform some type of automatic state change over time. For example, you may tint a player Entity's Sprite to red when it gets hit, then interpolate back to the regular (non-tinted) color after being hit.
InterpolateBetween is generally used in two situations. The first is if your states represent a range of values which your Entity or Screen can occupy, and which should persist until explicitly changed. The InterpolateBetween article gives an example of creating a health bar. The user's health bar should remain at a set value until the player either collects health items, or until the player is hit by an enemy. InterpolateBetween can also be used to perform advanced interpolation over time. This requires continually calling InterpolateBetween every frame, but passing a constantly changing value. This allows for the implementation of custom (non-linear) interpolation. InterpolateBetween also allows for the setting of values outside of the 0-1 range, which may or may not be desirable depending on the type of interpolation you are performing.
State categories automatically create variables in Screens and Entities through generated code. These generated variables can also be accessed in the FRB editor so they can be set on instances, or to assign change events.
For this example, consider an Entity named StateEntity which has a SizeCategory with three states: Small, Medium, and Large.
This entity generates a variable called CurrentSizeCategoryState which can be accessed in code, as shown in the following code block:
The CurrentSizeCategoryState can be tunneled on the entity which can be useful in a number of situations:
To set a default state for the entity
To set the state per-instance in the FRB Editor
To create events which is raised whenever a state is set to perform custom logic
To tunnel into a variable, drag+drop the category on the Variables folder.
The tunneled variable now behaves like any other variable. For example, an event can be added to the variable which is raised whenever the SizeCategory changes.
States are very powerful, but their behavior can be a little confusing when combined with inheritance. This article discusses how states and inheritance work together and things you should be aware of in your project when using States with Screens/Entities that inherit from other Screens/Entities.
For starters we should lay the programming foundation that States are enums. In other words, when you create a new State, you add a new entry to an enum in your code. For example, if you have created an Entity with the following four States:
Disabled
Enabled
Highlighted
Invisible
The generated code will create this enum:
The fact that States use enums is very important to the discussion of inheritance. Enums do not have a sense of inheritance - you can not inherit one enum from another (this is a C# language rule). Therefore, if you define a set of variables in the base class - that's it! You can't add or remove from them in a derived object.
Of course, the CurrentState property is public:
This means that the derived object can set its CurrentState just the same way the base class:
The InterpolateToState method allows Entities and Screens to smoothly interpolate (also known as "tweening") from one state to another over time. For example, you could set up two States for a Button Entity like "OffScreen" and "OnScreen", where each State set the X variable of the Entity. Interpolating between States allows for easily making the button slide on and off screen.
If you are working with an Entity or Screen that has multiple States, then Glue has already gneerated an InterpolateToState for you.
See this page to discuss the difference between InterpolateToState and InterpolateBetween.
For this example we'll create a simple Entity that contains a Circle. We'll create some Variables and States to modify the Entity and show how they work in code.
First, let's create the Entity:
Right-click on your Entities item and select "Add Entity"
Name the Entity "InterpolatingEntity" and click OK
Right click on your newly-created Entity's Objects and select "Add Object"
Enter the name "Circle" and click OK
Select your newly-created object and change its SourceType to "FlatRedBallType"
Change SourceClassType to "Circle"
Next we'll create some Variables that we'll use in our States:
Right-click on the Variables item and select "Add Variable"
Under the "Expose Existing" tab, select "X" and click OK
Right-click (again) on the Variables item and select "Add Variable"
Under the "Tunneling" tab, select "Circle" as the Object, and select "Radius" as the Variable and click OK
Set the default value of the newly-created CircleRadius variable to 1
Now that we have our Variables, let's create States for them:
Right-click on the States item and select "Add State"
Enter the name "Left"
Create a second state called "Right"
Create a third state called "Big"
Create a fourth state called "Small"
Note: In this example we created four states which are all uncategorized. In an actual project you would probably want to categorize these under state categories.
These states need to have variables assigned to them:
Select "Left" and set the X value to -3
Select "Right" and set the X value to 3
Select "Big" and set the CircleRadius value to 6
Select "Small" and set the CircleRadius to 2
Finally we'll want to make sure that there is an instance of our InterpolatingEntity that we can see in the game
Right-click on the "Screens" item and select "Add Screen"
Name the Screen "TestScreen" and click OK
Click+drag the InterpolatingEntity onto TestScreen
A notification will appear asking you if you want to create a new Object in TestScreen. Click Yes.
At this point we have four states. They've been intentionally created so that they can be interpolated between each other. This is done by having each pair of states (Left/Right and Big/Small) modify the same values. That is, both Left and Right modify the X value. Since they set the same value then they can be interpolated between.
If you created another state called "Up" which modified the Y value, you would not be able to interpolate between the "Up" and "Left" states. Technically, you could still call InterpolateToState, but you wouldn't see anything happen. Usually when you intend to use InterpolateToState, you will create two (or more) states which modify the same variables.
Glue will generate an InterpolateToState method for each category which has its SharesVariablesWithOtherCategories value set to false as well as an InterpolateToState method for uncategorized states.
Now that we have our Entity and states set up, let's create the code. Open up the InterpolatingEntity.cs file and add the following code to your CustomActivity method:
States allow you to modify your object in an organized, type-safe, way. States can also be previewed when the game is running in edit mode, speeding up iteration. States are a lightweight alternative to using inheritance, and can even be used to apply changes to a Screen or Entity multiple times. States can exist on any Screen or Entity, and appear under the States folder in the FRB Editor tree view.
Previous versions of FlatRedBall supported uncategorized states. These states can cause confusion about when properties are assigned so they have been removed from FlatRedBall. Now, all states must be categorized.
The following image shows a PowerUp entity with a PowerUpCategory containing three states.
The FRB Editor provides two different ways to add states. The preferred method is using the State Data tab. The second way is using the right-click menu. The two can both be used, so you don't have to pick which to use; that said, using the State Data method can be easier, so it is recommended.
Before you can add states, you must first add a state category. For information on how to add a state category, see the State Categories page.
Once a category has been created, states can be added in the State Data tab.
New states can be added by entering names in the left-most column. Adding a new name creates a new state.
By default, variables do not appear in the State Data tab (and are not accessible by states in the category). You must explicitly add variables which you would like to edit in your state. Conceptually, this makes sense considering categories are usually built to only modify a subset of variables.
For example, consider a variable which tunnels into a Sprite's CurrentChainName - which we'll call "Animation" to keep the name short:
To make this variable accessible to the PowerUpCategory, drag+drop the variable onto the category. Doing so results in the variable appearing in the State Data grid.
Alternatively, a category's variables can be added and removed in the State Data tab.
States can also be added through the right-click menu on a category.
This method is the old way of adding states. It is still supported, but it is a little more cumbersome compared to using state data. States added this way still appear in the State Data tab.
Every state category generates a class which is embedded in the screen or entity containing the state. By default states can only be assigned inside the entity or screen defining the state. For example, if the PowerUp entity defines a state category named PowerUpCategory, then states can be assigned in code.
Assigning the state in code applies all state's variables which were assigned in the FRB Editor.
The state can be compared against the values which are assigned to perform logic. For example, the following code could be written to perform logic based on the state of the power up.