Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
FlatRedBall.Forms is a library which provides a full set of UI functionality similar to other UI libraries like Windows Forms, Xamarin.Forms, and WPF.
FlatRedBall.Forms is intended to mimic the syntax of WPF while allowing you to customize the visuals and layout of your UI using the Gum UI tool. Properly using FlatRedBall.Forms requires at least a basic understanding of working with Gum. Developers who are not familiar with Gum should first visit the Gum tutorials, which can be found here: https://docs.flatredball.com/flatredball/gum/tutorials
FlatRedBall.Forms is an easy-to-use UI library for games. This tutorial will walk you through setup of a game project including FlatRedBall.Forms.
First we'll create a Glue project. If you already have a Glue project you can skip this section. To create a new project:
Open Glue
Select File -> New Project
Enter your project name and click Create Project!
On the wizard, pick Standard Platformer, Standard Top Down, or Ui - any of those three will add FlatRedBall.Forms to your project.
Now we have a project that is ready to go. Note that if you already have an existing FlatRedBall project, you can continue on the next step.
If your project does not have Gum (such as if you skipped the wizard), you can it at any point. To do so:
Click the Gum icon in Glue to add a new Gum project
Note that if you already have a Gum project, this icon will open the file in Gum
Click the option to include forms
If you either created your project through the wizard, then all FlatRedBall Screens have an associated Gum screen. In other words, you can start adding FlatRedBall.Forms to any existing screen. You can verify that your FlatRedBall Screens have an associated Gum screen by checking the Files folder and finding a file with the .gusx extension. For example, the GameScreen has an associated Gum screen in the following image.
If you open Gum, it will have a GameScreenGum screen.
To add a Button to your GameScreen:
Expand the Components -> Controls folder
Drag+drop the ButtonStandard component onto the GameScreenGum or MainMenuGum (depending on which project type you created)
The Button should now appear in the Gum.
Running the game will also show a fully-functional button.
If you have used Gum before (or if you have read the Gum tutorials), you may be wondering about the difference between Gum and Forms. A deep dive into this topic would be too long for this tutorial, but we will briefly look compare Gum and Forms using the project we just created earlier in this tutorial. As mentioned earlier, FlatRedBall.Forms is a UI library which provides common UI logic. For example, notice that our button instance automatically reacts to a moue hover and click. We didn't have to write any code to tell it to change its appearance. Technically FlatRedBall.Forms is a collection of classes which can modify Gum objects in response to a variety of interactions such as mouse hover, keyboard actions, an clicks. Gum components may or may not be represented as Forms objects at runtime depending on their behaviors as defined in Gum. All Forms objects have a backing Gum object, which is stored in their Visual property. By contrast, not all Gum objects are wrapped by Forms objects.
To help understand the difference, let's take a look at the Gum button components. The default Gum project contains multiple Controls which begin with the word "Button".
If any of these components are added as instances to a screen, they will be represented by the Button forms type. We can see this by adding an instance of each to our Screen and running the game. For example, consider the following screen:
Each instance in this screen is a different component type: ButtonClose, ButtonConfirm, and so on. However, if we access these buttons at runtime through the Forms property, they are all of type Button.
We can even go to the definition of our Forms object and see that all Buttons are of the same type.
Not all Gum components are represented as Forms controls. For example, the default Gum project contains a component named Icon which can be used to display one of a collection of standard icons in games.
If we add an instance of our Icon to GameScreen, we can see that the Forms object does not contain a property for IconInstance.
Note that Visual Studio's auto complete does not provide a suggestion for IconInstance (but it does provide a suggestion for ButtonIconInstance, which is an instance of a Button).
We can still access the icon through the GumScreen property, which provides typed access to all Gum instances whether they are forms or not.
Ultimately, FlatRedBall decides whether a component should be in Forms or not depending on the Behaviors that the component implements. For example, all of our Button components implement the Button behavior.
The presence of this behavior is all that is needed to mark a component as a Forms object. You can browse other components such as TextBox and ListBox to see the behaviors they implement as well. If you would like to create custom components which should be treated as Forms objects, you can add these behaviors to your controls as well.
This tutorial shows you how to access FlatRedBall.Forms controls in code to perform common logic like assigning event handlers and accessing properties.
The previous tutorial showed how to create a new project with a Button control. Most controls require no additional code to work - just drag+drop the control into a screen and it will have full functionality. For this tutorial we'll create an instance of the following controls:
Button (multiple versions exist, but ButtonStandard is the most common)
CheckBox
ListBox
TextBox
All controls are present in the Components/Controls folder.
To create these controls, drag drop them into your current screen, such as GameScreenGum or MainMenuGum. If you have a GameScreen, but would like to create a screen with only UI, you can add a new MainMenu screen to your FlatRedBall project.
You can drag+drop controls into your screen. The following screenshot shows a Gum screen with four controls:
Now we can access all of our controls from the Gum screen in code. Every Gum object can be accessed in its respective screen using the Forms
object. For example, to add a click event to the button:
Open the project in Visual Studio
Go to your screen's code file (GameScreen.cs or MainMenu.cs, for example)
Add the following code to the GameScreen:
This results in the button updating its text to indicate when it was last clicked:
Let's take a look at a few parts of the code. First, we should note that the code above is all compile-time protected. This means:
Any changes in the Gum project may result in a compile error, notifying you that something has to change in the code. For example, we are accessing the ButtonStandardInstance. If this object is removed or renamed, your code will not compile.
Visual Studio provides intellisense (code completion) to help you fill in the code
In the code above we accessed the button through the Forms.ButtonStandardInstance property. Note that ButtonStandardInstance is the same name as the object in Gum.
Notice that we are accessing the object through Forms allows us to interact with the Gum object casted as a FlatRedBall.Forms Button. Once we have access to the button we can interact with it in a standard way, such as by assigning a click event or by setting its Text property.
The CheckBox control can be used to allow the user to set true/false values. Just like with Button , before we'll get a reference to the CheckBox through the screen.
Clicking the CheckBox results in the value being printed to the screen.
The ListBox control is used to display options or a collection of current items to the user (such as active quests). The following code adds items to the list box whenever the user presses a key on the keyboard. Note that this code requires code in CustomActivity to read input from the keyboard.
Typing the A, B, or C characters on the keyboard results in items added to the list box:
The TextBox control provides free-form input support for users to enter string values like a character's name. Note that at the time of this writing the TextBox relies on the MonoGame key bindings which do not consider different keyboard configurations (such as languages other than English). The following code can be used to react to any changes in the TextBox Text property and print it out to the screen.
Note that the TextChanged event will be raised for each new character (including spaces) or whenever a character is deleted.
FlatRedBall Forms is a set of classes which are used to give UI controls automatic behavior. When using FlatRedBall Forms, your code has access to the FlatRedBall Forms object (such as Button) as well as the Visual for the Forms object (such as the component DefaultForms/Button). Since your code has access to both the Forms and Gum object, some confusion may arise about which object to interact with in code.
This guide discusses the relationship between the Forms and Gum objects, and provides some guidelines to determine whether to interact with one of the other.
The most important concept here is - some components in your project are Forms types, and some are not. Only Forms-implementing component instances appear in the Forms property, but all instances appear in the GumScreen property.
To understand how Forms and Gum objects interact, we will consider a simple example - a Screen with a single Button. The following image shows a default Button instance in a Gum screen:
In this example, the MenuScreenGum is loaded by the FlatRedBall screen MenuScreen.
We can access both the Gum and Forms objects in Visual Studio as shown in the following code. Keep in mind that every Screen with Gum and Forms objects will have GumScreen and Forms properties. These make it easy to access objects the same way no matter which Screen you are working on:
Notice that setting width and height modifies the same object at runtime - it appears as a square. Also, filling in the two click handlers would result in both handlers being called when the button is clicked.
You may be wondering - which object should I access in code? The answer is - usually it's best to use the Forms object. If you end up needing to make changes to the Gum object (such as to change its position or size), it's worth considering whether this change should actually be done in code. Most of the time these changes should be performed in the Gum tool.
FlatRedBall.Forms objects are wrappers around Gum objects. For example, in the example above we have a Forms.ButtonInstance. This object has a reference to the Gum object. The Forms object automates behavior so that the Gum object behaves like a UI element. For example, the Forms Button object automatically modifies the state of the button in response to cursor hovers and clicks. No custom code is necessary to achieve this behavior.
This behavior is convenient, but it is not particularly complex - at least not conceptually. The Forms object is responsible for detecting if the cursor is hovering over the button, or if the left mouse button is pressed. If so, the Forms object modifies the state of the button. These states are part of the default Button control, and can be inspected (and modified) in Gum.
The Forms Button logic is responsible for setting the button's state, and it will do so in response to any UI behavior. Therefore, manually setting the Gum object's state is not recommended - it will be over written by the Forms object as shown in the following code and animation:
Notice that the state is not immediately changed, but rather only when the mouse moves over the button. Once the mouse hovers over the button, its state changes immediatelz. After the mouse leaves the button, the state is reverted to Enabled. Setting the state through the Gum object can produce confusion. For example, a button may appear pushed or disabled if the state is manually assigned; however, the actual behavior of the button will not match a disabled state. Therefore, the button's state (specifically the CurrentButtonCategoryState) is controlled by the Forms Button object. The Forms Button object will modify the state according to standard button behavior, so custom code should not modify the Gum button's state.
The Forms property in FlatRedBall Screens contains properties for all Forms objects in the Gum screen, and only the Forms objects. Therefore, any object that is part of the Gum screen which is not a Forms type (such as Button or TextBox) does not appear in the Forms property.
For example, consider the following screen in Gum:
The left column consists of Forms controls: a Button, ListBox, and TextBox. The right column consists of instances of Gum objects which do not implement any Forms controls: a Text, ColoredRectangle, and Container.
In code, the Forms property only contains references to the Gum-implementing instances. Therefore, the following code is valid:
However, the following is not valid code because these instances are not Forms-implementing types:
To access the non-forms objects, you must use the GameScreen object. For example, the following code is valid:
Keep in mind that an instance in a Gum screen will always be a Gum object but only sometimes be a Forms object. This means that any instance that is a Forms object can also be accessed through GumScreen as shown in the following code:
As mentioned above, accessing Forms objects through GumScreen is generally not good practice.
FlatRedBall Forms contains many types of controls each with their own type of automatic behavior. The following list is an example (not a complete list) of properties which are controlled by Forms behaviors, and which should not be modified on the Gum object:
Button ButtonCategoryState controlled by cursor and Button.IsEnabled
RadioButton RadioButtonCategoryState controlled by RadioButton.IsChecked
ComboBox ListBoxInstance Visible controlled by ComboBox.IsDropDownOpen
ListBox and ScrollViewer VerticalScrollBarInstance Visible controlled by ScrollViewer.VerticalScrollBarVisibility and the number of items in the list
Slider ThumbInstance X controlled by Slider.Value, Slider.Minimum, and Slider.Maximum
TextBox.CaretInstance X and Y controlled by TextBox.CareIndex and TextBox.TextWrapping
As mentioned above, this is not a complete list. In general, if you plan on modifying a Forms object in code, you should first look to the Forms object to see if it provides a way to modify the object as desired. If your custom code modifies the Gum properties mentioned above, these changes will likely be overwritten by automatic Forms behavior.
FlatRedBall Forms also provides a way to standardize UI programming. When working against Gum objects, the types of the Gum objects depend on the project. For example, one project may use the default Button object for its Button, whereas another project may create a customized button called StyledButton which contains a different set of values. In both cases (assuming the behaviors have been set up correctly in Gum), both objects will produce a Forms Button, and programming against both will be identical. This makes it easier to learn the Forms syntax once and code the same everywhere.
The Forms objects standardize syntax, but they do not provide the full control that can be provided by access to the Gum objects. For example, consider a game which lets the player choose which save slot to load. Each save slot may be represented by a Button, and the Text on the button may display the name of the character. However, the game may also include additional information on each save slot, such as the level of the character, or the percentage completed in the game. These properties are not part of the Button class because they are custom to a particular game. In this case, the code may need to access the Gum object to modify the CharacterLevelText or PercentageCompletedText objects. Forms objects also provide a subset of the standard Gum layout variables. The following lists the current set of layout variables available to every Forms control:
X
Y
Width
Height
Games which need to modify the layout in code may benefit from access to the full set of Gum layout variables:
X
XUnits
XOrigin
Y
YUnits
YOrigin
Width
WidthUnits
Height
HeightUnits
To access the full set (units and origin values), the Gum object must be accessed.