Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
The CustomDestroy (if using Glue) and Destroy (if not using Glue) methods are called when the Screen is going to be removed from your game. This method should never be manually called - the ScreenManager will call this after the Screen's IsActivityFinished property is set to true.
The purpose of the CustomDestroy/Destroy methods is to remove objects which have been manually added to your Screen. In general, any object which has been added to a FlatRedBall manager must be removed. Entities (which automatically add themselves) must be destroyed.
The following example shows how a Sprite and Entity can be created and destroyed properly. This uses the Glue custom methods, but the idea is the same.
The following are added at your Screen's class scope:
The following would be contained in CustomInitialize:
The following would be contained in CustomDestroy:
Keep in mind that only objects which are instantiated or added in your custom code need to be destroyed in the CustomDestroy method. In other words, if you make an instance of an Entity in a Screen under the Objects item, you do not need to call Destroy on this object. Glue will both instantiate and destroy it automatically.
The BaseScreen value controls the base screen from which the current screen is derived. The derived screen will have all of the objects, files, events, variables, and code of the base screen, but can add more functionality and content in Glue and code. In code setting the BaseScreen sets the screen to inherit from the base screen.
The recommended pattern for creating multiple levels is to create one Screen (called a level Screen) for each level, each inheriting from GameScreen. As of March 2021, Glue recommends this approach by providing options to create Level screens which inherit from GameScreen.
In this case, all of the common objects (such as enemy lists, bullet lists, and collision TileShapeCollections) should be defined in the GameScreen. Similarly, CollisionRelationships should also be defined in the GameScreen. Since the level Screen uses the GameScreen as its base, then all level Screens will also have the same objects at runtime.
The DefaultLayer property is used by generated code when instantiating entities. It is useful if your game requires all entities to be layered as opposed to the default of being created unlayered. This can be useful if your game requires layers for functionality, such as if your main game must render to a render target.
DefaultLayer can be set in the FlatRedBall Editor by selecting a Screen and changing the DefaultLayer variable.
DefaultLayer affects the creation of new entities in the FRB Editor and at runtime. The sections below outline the specific behaviors of setting DefaultLayer
Once a DefaultLayer has been set, any new instance added to the screen or its derived screens automatically has its LayerOn property set.
For example, consider a GameScreen with a DefaultLayer set to HudLayer (as shown in the picture above). If an Enemy instance is added either to the GameScreen or any Level screen, then its LayerOn is also set to HudLayer.
All Factories which are part of a screen automatically have their DefaultLayer assigned to the Screen's DefaultLayer. Using the example above, we can look at GameScreen.Generated.cs and find the EnemyFactory instantiaton. The following shows the generated code for EnemyFactory:
DefaultLayer is used when calling the CreateNew
method without explicitly specifying a Layer. Note that the DefaultLayer can be overridden if a factory parameter is passed to CreateNew
.
DefaultLayer is returned back to null
when the Screen is destroyed. This means that if your code explicitly sets the DefaultLayer, this value may get lost when the Screen is destroyed. If your game relies on a DefaultLayer, be sure to explicitly set it in CustomInitialize rather than in Game1 or some other global context.
If a DefaultLayer is changed, then FRB checks all objects in the current and derived screens. If any use the old DefaultLayer, a window appears asking if they should be changed to use the new layer. For example, the following shows the DefaultLayer changing from HudLayer to the "Under Everything" layer.
Notice that after the change has been made, the Player1's LayerOn property has changed to the Under Everything layer.
At runtime the Screen's DefaultLayer matches the DefaultLayer variable assigned in the FRB Editor. Note that changing this property at runtime does not change the layer used for entity creation in generated code, nor does it change the default layer for Factories.
Entity instantiation is hardcoded to use the Screen's DefaultLayer as set in the FRB Editor at the time when the code is generated. Therefore, changing the property at runtome has no impact on the generated code. Note, this behavior may change in the future, but as of April 2024 the Screen's DefaultLayer property should be treated as if it is read-only.
The Screen constructor is intentionally generated by Glue to have no arguments. However, the constructor should never be explicitly called in your game's custom code. In other words, you will never "new" a Screen in your custom code. Screens are instantiated by the ScreenManager and base Screen class using a variety of methods, but usually through StartAsyncLoad and MoveToScreen.
Just like , the limitations on Screen constructors essentially means that you cannot pass custom information to the Screen's CustomInitialize method through the constructor. Fortunately, there are a number of ways around this.
The most common approach to providing information to Screens which may be used in the Screen's CustomInitialize method is through GlobalData. For a discussion on GlobalData, see .
The AsyncLoadingState property tells you the state that a Screen can be in regarding async loading. The available values are:
NotStarted - Async loading has not started at all. This is the default value, and this value will never change if you never call StartAsyncLoad
LoadingScreen - This value is set as soon as StartAsyncLoad is called. This value will remain as the current AsyncLoadingState until the Screen finishes loading the next Screen asynchronously.
Done - This value is set if the async loading is complete.
AsyncLoadingState is most often used to prevent navigation until async loading is finished. Once a Screen begins loading the next Screen asynchronously, it should not have its IsActivityFinished set to true until AsyncLoadingState is set to Done.
One common application of asynchronous loading is in response to a user clicking on a button. For example, a main menu may have two buttons: Play and Options. For this example we'll say that both Play and Options have their own Screen. Therefore, you may have the following events:
Notice that each event only performs its StartAsyncLoadonly if async loading hasn't already started. This prevents the user from clicking one button, then quickly clicking another one - or from double-clicking the same button.
Async loading will be performed in the background. You can check the status of the async load by looking at the AsyncLoadingState. If it is set to AsyncLoadingState.Done then the async loading is complete and you can progress to the next screen:
For more information on working with Layers in the FRB Editor, see the .
Every Glue project must have at least one screen. To create a new screen:
Right-click on the "Screens" item in Glue
Select "Add Screen"
Enter the name for the new screen
Click OK
For information on how to create a new screen, see this page in the Beefball tutorial.
LoadStaticContent is a generated method which is automatically called when a Screen/Entity is created. By default this method does not ever need to be called manually; however it can be called manually to preload content. If an Entity is part of a Screen in Glue, then its LoadStaticContent is automatically called. If the Entity is either not part of the Screen, or if it is going to be created by custom code then the LoadStaticContent can be called in custom code to pre-load the content. LoadStaticContent internally calls CustomLoadStaticContent.
As mentioned above, LoadStaticContent may be needed to load content that is owned by a Screen or Entity without instantiating the Screen/Entity. For example, you may need to display a sprite that shows what a character looks like in a menu screen, but instantiating and adding the character may be difficult because of dependencies. In this case you may be able to call LoadStaticContent, then access the files in the Entity. Keep in mind that LoadStaticContent loads content necessary to instantiate a Screen or Entity. Therefore whenever a Screen or Entity is instantiated, LoadStaticContent is called. Since this automatic calling is performed when an Entity is instantiated, your code typically does not need to call this method.
LoadStaticContent can be called multiple times, and as long as the same contentManagerName is used, subsequent calls will not reload the content. For example:
The contentManagerName argument specifies which content manager to use to load the content. The content manager is used to cache content so that subsequent calls to LoadStaticContent do not re-load any assets (unless the content manager is unloaded). Typically the argument should be the caller's content manager (if it is a Screen or Entity). For example, the following code would be used in a Screen to load content for an Entity called Character.
Calling LoadStaticContent with a global content manager will load the Screen/Entity into the global content manager. This content will never be unloaded. If a Screen/Entity is loaded into a global content manager, then later into a non-global content manager, then generated code will throw an exception. The two reasons for this exception are:
Loading in global content manager, then non-global results in two times as much memory being used for content. Since the global content is already in memory, there is no reason to use non-global content for a Screen/Entity that has used global content.
Entities and Screens which do not use global content will set their file references to null after their respective content managers are unloaded. However, if entities use global content, then file references are not set to null. This conflict of behavior may result in global content being nulled-out, causing difficult-to-debug crashes in your game.
The MoveToScreen method can be used to move from the current Screen to another Screen. The MoveToScreen method will destroy the current Screen and all of its contained Entities, then begin loading the Screen passed to the MoveToScreen method.
MoveToScreen accepts a string which is the fully-qualified name of the Screen you are moving to. The easiest (and safest) way to get the fully qualified name is to use the Type class. For example, if you want to move to a Screen called GameScreen, you would do:
Why do we use "typeof"? As mentioned above, you can move to a Screen by passing its fully-qualified name. To understand why we use typeof, we need to understand what "fully-qualified" means. First, let's start with a call to MoveToScreen that is not fully qualified:
Fully-qualified means that the namespace is included in the name:
However, what happens if you remove GameScreen, or rename it, or move it to another namespace? The code above would no longer work because the qualified name may have changed to something like "YourProject.Screens.Subfolder.GameScreen"; Using typeof allows us to get the fully qualified name even if it changes...and if the Screen no longer exists you will get a compile error, so you'll know right away instead of having to run the game to find out your code is broken. Very convenient!
The MoveToScreen function does the following (in order):
Destroys the current Screen
Creates the next screen as specified by the argument to MoveToScreen.
MoveToScreen can be used to move to the same screen rather than a different screen. This results in the current screen being destroyed then recreated, resulting in the screen being reset to its original state. For example, consider a situation where the player's character is hit by a bullet. In this case the GameScreen will reset itself:
When the MoveToScreen method is called, the current Screen will be destroyed and the Screen that you are moving to will be created. The things that are destroyed are:
Any files loaded through Glue for the current Screen or any Entities added to the Screen through Glue
Any instances of Entities that have been added to Glue
If you have added objects that should be destroyed (such as additional Entities) in your custom code, then you need to make sure to destroy these objects in your CustomInitialize. For more information on whether you need to destroy an Entity or not, and how to destroy Entities which must be destroyed manually, see the Destroying Entities article.
For more information on this error and how to clean it up, see Glue:Reference:Screens:Cleaning Up Screens.
The MoveToScreen method has only one parameter - the Screen to move to. It does not accept additional parameters. For information on how to pass additional information to new Screens, see the the Proper Information Access tutorial.
The UnloadsContentManagerWhenDestroyed controls whether a Screen will unload all of the content that it has loaded when it is Destroyed. The UnloadsContentManagerWhenDestroyed is set to true by default, meaning a Screen will unload its content at the end of its life. This property can be set to false and the Screen will not unload its ContentManager. There are two common situations when you may not want to unload content:
A series of Screens which use the same content may not want to unload after each is destroyed. This will allow content to be "passed" from Screen to Screen, which can greatly improve load times. Of course, you need to make sure that the last Screen in the series has its UnloadsContentManagerWhenDestroyed set to true.
A popup Screen may use the same content manager as its parent Screen. In this case, it should not unload the content because it will unload its parent's content as well.
The UnloadsContentManagerWhenDestroyed property is simply a property which can be set at any time. The Screen uses this property only when unloading, meaning that this property can be set at any time - even in CustomDestroy. Therefore, you can set UnloadsContentManagerWhenDestroyed depending on which Screen is next if the current Screen may has multiple Screens that it can go to, and one uses the same content while the other does not.
The GameScreen is where the main gameplay for a game takes place. FlatRedBall games are not required to have a screen named GameScreen, but most FlatRedBall games use this convention. If you have created your game using the New Project Wizard, then your game will have a GameScreen.
If a game has multiple levels, then the GameScreen serves as the base screen for each level. Each level would be its own Screen in the FlatRedBall Editor.
Games which do not have multiple levels (such as a chess game) would have the main gameplay take place in the GameScreen without any derived level Screens.
The GameScreen/Level pattern makes it easy to add multiple levels to your game. If you have created a project using the platformer or top down template, then your game is already set up to have two levels: Level1 and Level2. Levels screens may map to actual levels in your game, or they may map to sections in the game which have their own Tiled map but which are not necessarily recognized as new levels by the player.
The word level is used for convenience, but each level screen does not necessarily need to correspond to an actual level in your game. Typically each level screen references a single TMX file. Therefore, your game may have multiple level screens for a single game level. Some games may not even have explicit levels. For example, games like Super Metroid do not define their areas as levels, but each area may be represented as a level screen in FlatRedBall.
Therefore, here are some examples of Level screens as they might exist in some popular Super Nintendo games:
Super Mario World - Levels could be broken up to be one Screen per actual level, or mulitple screens could be used per level for secret areas and underground sections
YoshisHouse
YoshisIsland1 (the level name, not to be confused with the game)
DonutPlains1
DonutGhostHouse
YellowSwitchPalace
Super Metroid - Each level might be a section as broken up by doors. When transitioning through doors, one level is unloaded, and the next is loaded
CrateriaOutdoor
CrateriaBossStatueRoom
BrinstarVerticalRoom
NorfairCrocomireRoom
F-Zero - Each race would be one level Screen
MuteCity1
BigBlue
SandOcean
DeathWind1
Games which include multiple levels typically define one TMX per level. The GameScreen defines a Map object which indicates that a Tiled map will be loaded by each screen, but the individual level Screens specify which level to load.
Therefore, the Map object in a typical GameScreen has its SetByDerived property set to true, which means that the GameScreen expects the derived levels to assign this property using their respective TMX files.
Each Level should have a TMX file, and that TMX file should then be used to create the Map object. This can be observed by selecting the Map object in a Level screen and looking at its properties:
The IsLoadingScreen property can be used to mark a Screen as a loading screen. Loading screens can be used when transitioning into a Screen which must load a lot of content or when returning back into the app after it goes to sleep (tombstones) on a phone.
To mark a Screen as a loading screen, simply set the IsLoadingScreen property to "True":
For this example we'll assume you have a Screen called LoadingScreen which has its IsLoadingScreen property set to true. To use the LoadingScreen:
Identify which screen transitions you want to use a LoadingScren between. For example, you may want to use the LoadingScreen between a main menu screen and the game screen if the game screen has a lot of content to load.
Locate where you want the transition to occur (like when the user presses the Start button or clicks on a button) and add the following code:
You can manually set the next screen even if you do not have an instance of a LoadingScreen (which is required for the TransitionToScreen method. You can do this by setting the static NextScreen property. This is useful if:
You are using the loading screen as the first screen in your game
You are using the loading screen to display something while your app returns from tombstoning
You want to set the next screen before you have created the loading screen (such as in response to a button push)
The following code shows how to use the LoadingScreen as your first screen. This code belongs in Game1.cs's Initialize method. Note that ScreenManager.Start will automatically get generated by Glue, so you would only add the code to set the LoadingScreen's NextScreen.
The TransitionToScreen method is an easy way to move between two Screens. It will
Unload/destroy the current Screen
Load the LoadingScreen and make it the primary Screen
Begin loading the argument Screen (GameScreen in the example above) in a secondary thread
Performs every-frame activity on the LoadingScreen which can be used to play animations or other activity to give the user an indication that the game is not frozen.
The IsLoadingScreen property can help you create loading screens quickly; however there are some things to consider which can make the user experience better:
Keep the logic in the loading screens simple to reduce the amount of resources spent on running your loading screen.
Keep the amount of content loaded on your Screen low. If this is not possible or desirable, consider making the content that is part of your loading screen also a part of Global Content Files. Your game will pre-load this content if you are using async global content loading.
Consider making your loading screens use a global content manager. This means the loading screen's content (such as used textures and Scenes) will always remain in memory making transitioning to a loading screen very fast.
Be careful using minigames in your loading screen. There is currently a patent held by Namco on the use of minigames in loading screens.
A screen's CustomInitialize is the first method in custom code called after a screen is created. It is called before the screen performs any rendering, but after all of the screen's content has been loaded and after the objects defined in the FRB Editor have been initialized.
CustomInitialize can be used to perform any logic-based initialization. Examples of common types of initialization include:
Loading custom data from disk such as loading a user profile from a JSON file
Positioning the player based on spawn locations
Adding events to factories to perform custom code when an entity is instantiated
Assigning input devices based on plugged-in hardware or settings from previous screens
Playing animations or intro sequences such as having a Gum overlay fade out or starting a countdown before the game begins
The IsActivityFinished property is a property which can be set to true to tell the given Screen that it should no longer be active. Setting IsActivityFinished to true can do a number of things depending on the state of the Screen:
If the Screen is the ScreenManager's CurrentScreen, then this method will result in the ScreenManager moving to the Screen's NextScreen.
If the Screen is a Popup Screen, then the Screen will simply destroy itself and remove itself from its parent's mPopups list.
If the Screen is loading another Screen asynchronously, then setting IsActivityFinished to true will destroy the current Screen and move to the asynchronously-loaded Screen.
The Set as StartUp Screen menu option allows you to specify the first screen in your game. The StartUp screen will automatically load when the game is run, and it will be highlighted in red in Glue.