Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
FlatRedBall Entities are used in every FlatRedBall Game. An entity is a reusable definition which you can instantiate (create copies) in your screens. Examples of entities are:
Player
Enemy
Coin (something you can collect)
Bullet (something that can deal damage)
To create a new Entity:
Right-click on the Entities folder
Select Add Entity
Select the desired options for the entity in the pop-up window
Click OK
The BaseEntity property controls the inheritance of a given Entity. An Entity can inherit from another Entity, or it can inherit from a FlatRedBall type, like Sprite.
Entities can inherit from other Entities. Entity inheritance is the current recommended approach for creating a variety of common entities, such as multiple Enemy types in a game. To do this:
Click on the Add Entity quick action
Use the Base Entity dropdown to select the base entity. Note that when a Base Entity is selected, most of the options are hidden since the new entity inherits those properties from its base.
Click OK
The new entity now inherits from the selected Base Entity.
A new entity can be created as a derived entity in the new entity window.
Entities can inherit from FlatRedBall types, such as Sprites. By default Entities inherit from PositionedObject, but this inheritance can be modified through Glue. The reason this feature exists is primarily to improve performance and reduce memory consumption. For more information, see the Inheriting from FlatRedBall Types tutorial.
Entities can be created simply by calling their constructors. Entity Constructors provide a number of overrides allowing you to customize how Entities are created. If you have Entities created in Glue then you may not need to instantiate Entities in code. Entities can be created in code if you are dynamically creating Entities (often to put in a list), or if you are creating instances of entities which will be managed purely in custom code. For additional information on creating Entities in custom code, see .
Every Entity in Glue has a ConvertToManuallyUpdated method in generated code. This method will remove all contained objects in the Entity from their managers - including removing the Entity itself from being a managed PositionedObject. ManuallyUpdated Entities with visible objects (such as Sprites will still be rendered. This method is not the equivalent to Destroy, so it should not be used as a substitute for this method. This method also recursively call ConvertToManuallyUpdated on any contained Entity instances. Note that manually-updated Entities will still have their CustomActivity called if they are added to other Entities or Screens through Glue, or if they are a part of PositionedObjectLists which have been added to Glue. For information on how to turn this off, see the CallActivity property.
Assuming myEntity is valid Entity, you can simply call ConvertToManuallyUpdated on it:
Once ConvertToManaullyUpdated is called, objects (such as Sprites) within an Entity will no longer respond to position or rotation changes on the Entity. Therefore, if you plan on calling this method, you should do so *after* you have finished positioning your Entities. For example, we'll assume an Entity type called Tree which you are placing in your level. You would want to do something like this:
ConvertToManuallyUpdated is usually called in CustomInitialize of other Entities or containing Screens. ConvertToManuallyUpdated should be used on Entities which either have no every-frame activity (such as movement),or Entities which are manually updated to improve performance. For example, if an Entity has a large number of contained objects, but only one of them has any activity, it may be beneficial to call ConvertToManuallyUpdated, then manually update the single objects that are moving in the Entity's CustomActivity.
Once an Entity is converted to manually updated, it will not have any automatic properties applied - such as Velocity, Acceleration, or Attachments. If an Entity is manually updated, you can select which updates you care about. For example, if you have an Entity which does not use Acceleration, then you can ignore this property and save some processing time (when compared to automatic FRB updates). This is especially important if you are using a large number of Entities in your game.
The CustomActivity function is a function which is called once per frame (unless the entity is paused). The CustomActivity method is a private method which cannot be directly called, but it is called by an entity's Activity function.
Any Entity which is part of Glue, or part of a PositionedObjectList in Glue will (by default) have its CustomActivity called automatically. Entities will have their CustomActivity methods called in the order that they appear in Glue. So if the structure of Entities is:
A
B
C
Then the order will be first A, then B, then finally C. Entities in a PositionedObjectList will have their CustomActivity called in the order that they exist in the PositionedObjectList. CustomActivity on all contained Entities will be called before the container calls its CustomActivity. In other words, if a Screen contains an instance of an Entity, then the Entity will have its CustomActivity called first, then the Screen will call its CustomActivity.
CustomDestroy is a method that is called once on every Screen/Entity instance when it is no longer needed. Any objects that are created in custom code (as opposed to objects added through Glue) need to be removed/destroyed in CustomDestroy.
Objects which are created in CustomInitialize or CustomActivity must be properly destroyed in CustomDestroy. There are two categories of objects which must be destroyed:
Entities must have their Destroy method
Objects added to the engine (like Sprites) must be removed from the engine
The following example shows a Sprite created in CustomInitialize, then later destroyed in CustomDestroy:
CustomInitialize is called once per entity instance when it is initialized. Initialization happens in any of the following situations:
When an instance is created either in code by using the "new" operator, or if an instance is added through the FRB Editor. See below for more information.
When an instance is created through tiles in a Tiled map (tmx)
When an Entity is recycled through a factory
By default CustomInitialize is an empty function.
Any code can be added to CustomInitialize to prepare an entity for use. Simple entities may not require any code in CustomInitialize, but code can be added for the following:
Preparing animations (using AnimationController )
Dynamically creating FRB objects such as populating a List of Sprites
Adding conditional debug code such as turning on the visibility of collision shapes
CustomInitialize should not include any code that depends on the current screen. For example, if an Enemy entity needs to initialize its logic according to the current PlayerList in GameScreen, CustomInitialize should not access GameScreen. Instead, initialization which requires external context (such as a list in a Screen) should do so in a function which is called by the Screen. This keeps your entity portable, and reduces the chances of errors occurring due to improper casting or unexpected access of lists before they are available.
Using the example of initializing enemy logic, an Enemy entity may have the following code for initialization:
In this case, InitializeAi would be called by the GameScreen, as shown in the following example code:
The CustomInitialize method will only be called when an Entity instance is added to managers.
The most common method of creating entities is to use a factory. For example, creating an Enemy entity with the EnemyFactory will result in the newly-created instance being added to managers and having CustomInitialize called:
The additon of managers can be controlled by calling an Entity's constructor. Of course, doing so may result in the entity being created but not being added to the proper lists. If you are manually creating entities, make sure that you add them to the appropriate lists (such as the GameScreen lists).
Entities and Screens which have base types (inheritance) have two or more CustomInitialize functions depending on the inheritance depth. For example, if an entity Skeleton inherits from Enemy, each class (Skeleton and Enemy) has its own CustomInitialize method. Both are called by generated code - an explicit base.CustomInitialize();
call is not needed. CustomInitialize is called on the base class first, then to more-derived. Using the example above, Enemy.CustomInitialize is called first, then Skeleton.CustomInitialize.
FlatRedBall Editor provides a Camera window which can be used to set the game's resolution and various Camera settings. This can be accessed through the camera icon in the toolbar.
Keep in mind that when the game runs embedded in the FlatRedBall Editor, the Editor window may modify the resolution settings.
By default the resolution of the game is 800 pixels by 600 pixels.
This means that the game will appear at this resolution when running on the desktop.
Notice that the resolution defines the inner size of the game. On Windows, games with a title bar may be a little bit larger than the inner size. The resolution also controls how much of the game world is visible. For example, if the game includes a grid of rectangles each sized 100x100, we can see that we can see 8 rectangles horizontally and 6 rectangles vertically.
This resolution can be changed in the editor by manually typing in a resolution value, or by using the dropdowns to select from a list of common resolution values.
Changing the values to 400x300 (from 800x600) results in the game running as shown in the following image:
Notice that the resolution impacts two things:
The size of the window (when running on desktop)
The visible area in game
The Fixed Aspect Ratio checkbox controls whether the game runs in a forced aspect ratio. By default this value is unchecked which means that the game will run in any aspect ratio rather than forcing a certain aspect ratio. If checked, then the game will letterbox or pillarbox to maintain aspect ratio if the resolution does not match the aspect ratio. For example, the following images shows a game with resolution 800x600 running with a forced fixed aspect ratio of 16:9. Note the gray area displays the game area.
If the game's aspect ratio (default values) do not match the calculated aspect ratio from the resolution width and height (as is the case here), the editor will ask if the resolution width or height values should be preserved. In this case, the Keep game coordinates height at 600 is selected, so the game will always display 600 units on the Y axis, and the width will be adjusted to maintain an aspect ratio. If the Keep game coordinates width at 800 option is checked, then the game will always display 800 units wide, and will adjust the height to match the desired aspect ratio, as shown in the following images:
Notice that if the game resolution and aspect ratio do not match, the window will match the resolution but the game area will match the aspect ratio. This behavior can be important for games which have logic written for a specific aspect ratio such as spawning enemies off-screen.
The Perspective option controls whether the game is using a 2D (Camera Orthogonal is set to true) or 3D (Camera Orthogonal is set to false) perspective. By default FlatRedBall runs in 2D mode. In 2D, the play area matches the Resolution values. In 3D, the play area at Z=0 matches the Resolution values.
Cameras with 3D perspective result in objects with positive Z values drawing larger and objects with negative Z values drawing smaller. For example, the following image shows three sprites with Z values of -100, 0, and 100 (positive).
Texture filtering modifies the way textures are rendered by Sprites. By default, FlatRedBall uses Point filtering. Linear filtering applies a blur effect when objects Sprites are drawn larger than the native resolution, or if the game is zoomed in. The following image shows the difference between Point and Linear filtering:
Note that Linear filtering also applies to tilemap rendering which can cause pixel colors to "bleed".
The Fullscreen checkbox controls whether the game runs in fullscreen or windowed mode. If the game runs in fullscreen on a monitor which does not match the desired game resolution, the game will be zoomed to maintain the same game area. For example, the following image shows a game running at 800x600 resolution on a monitor at 1920x1080:
If the same game runs in fullscreen mode, it is zoomed as shown in the following image:
Notice that the game still displays 6 squares tall, each representing 100 units in-game; however, these 6 are zoomed to display over 1080 screen pixels. Also, note that the game now runs in 16:9 aspect ratio (the aspect ratio of the 1920x1080 resolution), so it displays more game area horizontally. To preserve the same game area vertically and horizontally, the aspect ratio can be forced to 4:3.
Notice that letterboxing is used to preserve the desired 4:3 resolution.
If a game runs in fullscreen mode, it technically is running at the same resolution as the display in borderless mode. This enables a game to alt-tab quickly, and eliminates the need to reload textures when the graphics device is lost due to the game being minimized.
If Allow Window Resizing is checked, the game window can be resized by the user when running in windowed mode.
In the animation above the aspect ratio is not forced, so the game responds to resizes by keeping the height at 600 units (6 squares) while the width is adjusted to match the aspect ratio set from resizing the game. If the aspect ratio is forced then the game will add letterboxing and pillarboxing to maintain the forced aspect ratio as shown in the following animation:
Scale controls the size of the window relative to its resolution. At 100% scale (the default) the game window resolution matches the resolution Resolution values. The following image compares the same game with resolution 360x240 running at 50%, 100%, and 200% Scale:
The scale value impacts only the size of the window (and the internal resolution of the game), but the game still has the same number of in-game units.
Typically the Scale value is useful during development, but finished games rarely rely on the Scale value to control the size of the window for a number of reasons:
If your game supports full screen mode, then the window will be sized to match the monitor's resolution, ovewriting the Scale value
If the user can resize the game, then the window will adjust in response to resizing, also overwriting the Scale value
If your game includes a Gum project then the Display Settings tab will include a Gum Scale text box. By default this value is 100%, so the Gum pixels will match your game 1:1. Note that Gum Scale is a multiple to your Scale value above. This value should be left to 100% in most cases.
For example, under this setting a game of 800 pixels wide and 600 pixels tall would display Gum at native resolution, as shown in the following image:
Changing the Scale (Gum) to 200% doubles the size of all Gum objects, as shown in the following image:
Values less than 100% are also supported. The following image shows the same layout with the Scale (Gum) set to 50%:
The On Resize option sets whether the amount of in-game units visible should change when the game resizes. By default this value is set to Preserve (Stretch) Area which means the in-game units will stretch to preserve the bounds. For example in the following example the height of the in-game area remains 400 units regardless of how the window is resized.
Changing this value to Increase Visible Area enables more of the game world to be seen if the window is made larger.
Note that this may result in unexpected behavior if your game expects the visible area to be of a constant size.
FlatRedBall's camera window provides an easy way to set the default behavior of your game, and it can be used to change camera settings during development. Many games allow the user to customize the window (such as by setting if the game runs in full screen), and the resolution information is then saved in a configuration file. The generated code for camera settings allows changing the code-generated-assigned values prior to the window being created. To modify the settings in initialize:
Open your project in Visual Studio
Open Game1.cs
Find the following line of code in the Game1's Initialize method: CameraSetup.SetupCamera(SpriteManager.Camera, graphics);
Add code to assign values to CameraSetup.Data before the call to SetupCamera
For example, the following code could be used to set the values, assuming configurationData is a valid object:
Camera and resolution values can be changed after initialize. Some games provide control over the resolution in a settings window. The generated CameraSetup object can be modified at any point in the game's execution. For example, the following code could be used to adjust the resolution and camera settings when the user presses the space bar:
Notice that the above code calls both ResetWindow and ResetCamera . Typically modifications to the CameraSetup.Data require both to be called. The two functions are separated because generated code calls ResetCamera inbetween each screen.
The CameraSetup object provides code for toggling between your game running full screen and windowed. Using CameraSetup to toggle full screen is the recommended way as it handles all associated settings such as changing the camera values. The following code shows how to toggle fullscreen and windowed when the space bar is pressed:
The FlatRedBall Editor (also referred to as FRB Editor, FlatRedBall, or FRB) is tool used to create games with FlatRedBall. The FRB Editor provides a variety of functionality, and can be extended and customized with plugins. Some of the most important functions of the FRB Editor include:
Creating new projects
Initial project setup using the New Project Wizard
Creating Screens and Entities
Setting the game's resolution and window size
Managing your csproj file by adding and removing code and content files
Generating code to load files
Providing a visual editor for creating entity instances
Editing and creating variables
Creating and managing collision relationships
Providing a "live editor" for your game
Tracking file dependencies
Reporting common errors
Measuring your game's performance
...and much more
In short, the FRB Editor provides functionality to make game development faster.
Ultimately the FlatRedBall Editor generates code in response to your actions. Therefore, the editor is not required to create games. You can use it to create new projects, but then do all of your coding in Visual Studio. Of course, since the FlatRedBall Editor is built to make game development easier, we recommend using it in your game.
The CreatedByOtherEntities property can be used if instances of an Entity will be created at runtime (such as bullets fired by a Spaceship Entity) in a location other than your current screen.
Setting this property to true does the following:
Glue will generate a factory for the Entity type which includes a CreateNew method that can be used to create new Entity instances.
Glue will automatically add any newly-created instance of the given Entity to any PositionedObjectLists created in any Screens in Glue.
Glue will display an additional property "PooledByFactory" which can be used to enable pooling to reduce post-load memory allocation.
For more information on CreatedByOtherEntities, see the Created by Other Entities tutorial.
The Destroy method is used to completely destroy an entity. Generated code calls Destroy for any entity and any list of entities in your current Screen whenever the Screen is destroyed (when the game moves to a different screen). Destroy may need to be manually called if an entity is created manually in game code.
Destroy can also automatically called on Entities which take or receive damage based on properties assigned in their collision relationship. For more information on destroying entities when taking damage, see the Damage Dealing Tutorials.
When an Entity's Destroy method is called, the following happens:
Generated code will destroy any contained object which has been added through FlatRedBall Editor. For example, if your Entity has a Sprite and a Circle, both will automatically be removed from the engine, resulting in the Entity no longer being visible on screen.
The entity will be removed from any list that it is a part of. For example, if your GameScreen contains a BulletList, calling Destroy on the Bullet will remove the Bullet instance from the BulletList.
The entity will be removed from the engine (SpriteManager) management, so its automatic properties such as Velocity and Acceleration will no longer be applied
If the entity is an IWindow-implementing Entity, the entity will be removed from the GuiManager so it no longer receives clicks or other UI interaction
If the entity is a collidable entity, its collision will be cleared so future collision calls will return false
The entity's CustomDestroy is called, enabling custom code to perform additional object removal.
Note that when writing code in CustomDestroy, the entity should not unload content. The content manager used to load content for the Entity should be provided by the Screen that contains the Entity. Screens automatically unload their content managers, and this will clean up content loaded by the Entity.
As mentioned above, Destroy is automatically called by generated code in the following situations:
Whenever a screen is destroyed, all of the entities added to the screen through the FlatRedBall Editor will also have Destroy called
Whenever a screen is destroyed, all of the entity lists added to the screen through the FlatRedBall Editor will also have their Destroy called. Typically this includes all entities which have been created by a Factory when the GameScreen (or a derived Level Screen) is destroyed.
Whenever an entity is destroyed, any entities that it contains will also be destroyed.
Custom code may need to call Destroy. Usually custom code only needs to destroy entities that it creates on its own. The most common case is when entities should be destroyed as a result of collision, such as when a bullet hits a wall.
The most common situation where Destroy is explicitly called is in collision handling events. For example, consider a game like Pac-Man where the Player is moved around the screen and "eats" pellets. Whenever the player collides with a Pellet, the Pellet instance should be destroyed. In this type of game, the GameScreen would contain two lists: PlayerList and PelletList. A collision relationship between the PlayerList and PelletList would define an event where the destruction of a pellet occurs:
The collision relationship event handler might look like as shown in the following code snippet:
Situations where damage is dealt (such as a bullet hitting a player) should be handled using the IDamageable and IDamageArea interfaces. FlatRedBall provides automatic destruction of entities which use this interface.
The two-way relationship between Entities (and all other PositionedObjects) and the PositionedObjectList class is what enables the Destroy method to remove an Entity from the engine. In fact, the PositionedObjectList (and any class which inherits from PositionedObjectList) is the only reference that Entities know about. If you store a reference to an individual Entity, the reference will still be valid after you call Destroy unless your code handles this case. Let's look at some simple examples. In our first example we'll create some code where the user is keeping track of an individual player and enemy: At class scope:
This piece of code checks for the player attacking the enemy:
This piece of code checks for the player touching and being hurt by the enemy:
The code above has a logic bug which will cause the game to behave improperly. When the Enemy is destroyed (through mEnemy.Destroy();) then all of its components will be removed from the engine. Its visible representation and collision will be removed from the appropriate managers. It will also be removed from the SpriteManager so that it is no longer managed by the Engine. However the collision check between mPlayer and mEnemy is still being done! If you think about it a bit, this makes sense. This is because your code doesn't check if mEnemy is dead. It does the check no matter what. However, since mEnemy is destroyed, it is no longer part of the engine. The result is that mEnemy will seem to completely disappear, but its Collision object will still be sitting there, invisible, in the level. Even though it is not part of the engine, it can still be used to test collisions. There are two solutions to this problem:
(Preferred solution) Create a PositionedObjectList<Enemy> and add your Enemy to that list. Then replace all code which checks against mEnemy to instead loop through your PositionedObjectList<Enemy> and test collision. This should be done for all logic including player attacking enemy and enemy attacking player. When your Enemy is destroyed, it will be removed from the PositionedObjectList<Enemy> and your game will function properly.
(Necessary if you need to keep track of specific Entities) Check your mEnemy's Health before performing collisions. If its health is less than or equal to 0, then it is dead and you shouldn't perform collisions. For example, your collision check should look like:
Many types of entities can die, be collected, or have other types of removal through custom logic. These entities may create additional visuals when removed. Examples include:
A collected coin may create a sparkle
A dead enemy may fall to the ground the flash for a second
A barrel may create an explosion when shot
A boss may explode and break apart gradually
Projects which include entities like the ones listed above are encouraged to destroy the entity immediately rather than modify properties to indicate that the entity is in a destroyed/dead state. For example, when a coin is collected it should be immediately destroyed and a new entity or Sprite should be created in its place to play the sparkle effect. Similarly, a dead enemy should be immediately destroyed, being replaced by an entity (such as DeadEnemy).
This approach is encouraged for a number of reasons:
By destroying entities immediately, collision relationship events can be simplified. If dead enemies are not destroyed immediately, then additional checks may be needed in the collision event handlers to check if an enemy is alive or dead. For example, a dead enemy should probably not damage the player or absorb bullets.
Game state which depends on entity instances (such as a game progressing after all enemies are dead) is simplified since it does not need to consider the state of entities. Instead it can rely on the count in the relevant entity list.
A typical game may have over a dozen collision relationships for entity lists which are core to the game logic, such as PlayerList, EnemyList, or BulletList. Simplifying the collision event handlers can make it easier to maintain the game as it grows.
Keep in mind that even though entities should be destroyed immediately when killed or collected, adding post-removal animations to their AnimationChain file (.achx) is common.
The Entity Performance tab provides options for improving the runtime performance (reducing CPU usage) for an entity. This tab is only needed for games which include a very large number of entities (typically many hundreds or thousands of instances). Common types of entities which benefit from this tab are enemies and bullets.
Entities and objects within entities, such as Sprites, inherit from the PositionedObject class and have default engine-level functionality for applying velocity, rotation, acceleration, drag, and attachments. Although this functionality does not take much time to perform on a single entity, some games may include thousands of entities. In this case, the number of update calls may impact a game's framerate. If a game includes entities which are completely static (do not move after being created), then every instance of this type of entity can be converted to manually updated, which means that engine-level updates are disabled. Manually updated entities have minimal resource requirements, allowing games to instantiate tends of thousands of instances at once. Entities generate a ConvertToManuallyUpdated method which converts the entity itself and any contained objects to manually updated. In many cases entities require some of the automatic update logic provided by the engine, but not all. For example, a Bullet entity which moves along a straight line after being created requires velocity to be applied every frame, but does not require acceleration, drag, rotational velocity, or attachment logic. This mixed-case is very common, and this is the case where the Entity Performance tab can be used. By default, entities are fully-managed by the engine. For example, the following image shows a Bullet entity and its default Entity Performance tab.
Notice that the entity itself has its own management settings, and each object within the entity (SpriteInstance and CircleInstance) also have their own management settings.
As mentioned before, these settings provide all management functionality, but also have the highest performance requirements.
The Entity Performance tab provides a visual interface for selecting which properties are managed. Since every game is different, it does not provide any standard presets, but rather exposes all possible values. An entity which does not require all properties to be managed every frame can use the Select Managed Properties option.
For example, a Bullet entity which requires only velocity values can check just the XVelocity and YVelocity properties. Note that most entities do not require ZVeocity movement, so that option is left unchecked in the following image:
Changes to an entity's managed properties or changes to managed properties on an object inside of an entity result in code generation and storage of these properties in a EntityPerformance.json file. The EntityPerformance.json is necessary to re-generate the code whenever an entity changes, so it should be included in a game's version control repository. The generated code for an entity includes the management of all properties selected the Select Managed Properties option is checked. For example, the following code is generated for the Bullet entity using the options shown above:
Of course, if custom code modifies the entity (such as by re-adding it to be managed by the engine), this generated code can result in double-management. The symptom of this is that an object may move twice as fast, animate twice as fast, or have other variables such as drag applied twice in one frame.
The Implements IClickable property is a property that controls whether the Entity has a HasCursorOver method. In other words, Entities which are IClickable can be tested to see if the user has highlighed or clicked an object with the Cursor
Entities can be created as IClickable in the add entity window.
Existing entities can be converted to IClickable in the Properties
Select the entity in Glue
Click the Properties tab
Set Implements IClickable to True
This method returns whether the Cursor is over any visible part of the Entity. You could use this function to detect UI activity such as Cursor clicks. The following code can be used to perform logic if the user clicks on the Button:
HasCursorOver can be used to select entity instances in a RTS. The following code shows how to handle unit selection in an RTS. It assumes that UnitList is a list of entities which implement IClickable.
Screens and Entities can be exported through Glue and later imported. An exported Screen/Entity can be easily transferred to other projects, sent to other developers, or uploaded to GlueVault.com to be shared with the community.
Once you have a Screen/Entity that you are ready to export, you can:
Navigate to the folder where you would like to save the exported element and click OK
An Explorer window will appear showing you your exported file
You can share the exported Screen/Entity on GlueVault.com
Exported Screens and Entities create .scrz (Screen zip) or .entz (Entity zip) files, respectively. These files are standard zip files which can be unzipped with any unzipper. Of course, Glue understands these files as well so there is no reason to unzip these files if you plan on using them in Glue. Exported Screens and Entities contain the following:
An XML file containing the information set in Glue
A C# code file containing custom code
All referenced files (such as .scnx or .shcx) and any files that the referenced files include
Entities which can collide with other entities or environments (such as terrain in a platformer) can have their ImplementsICollidable property set. Setting this property to true simplifies writing collision code and makes your code more resistant to changes made to collision objects in Glue.
When creating a new Entity, Glue will give you the option to mark it as ICollidable. The most common approach is to add a shape on the entity when creating it. For example, if the AxisAlignedRectangle check box is checked, Glue will automatically check the ICollidable check box.
Assuming that you are dealing with instances of entities which implement ICollidable, you can call CollideAgainst, CollideAgainstMove, and CollideAgainstBounce between them regardless of the shapes that they use for collision. The benefit of this is that you no longer have to explicitly access the collision objects in an Entity - you can write the code the same regardless of the shape type, and you do not have to change your code if you end up changing your shape objects in Glue.
CollideAgainst is useful when you only need to detect if two things are touching, but the objects do not need to be re-positioned in response to the collision. For example, the following code shows how to perform collision between a ship and a list of enemy bullets:
CollideAgainstMove can be used to collide two objects, and re-position them according to their masses, as shown in the following code:
Notice that the code above did not have to access the specific shape(s) in FirstBallInstance or SecondBallInstance to perform the collision.
The IDamageArea interface creates a standard way to define that an entity can deal damage to other entities. It has built-in support for teams and damage over time.
To set an entity as a damage area, set the property on entity in the Properties tab.
A game which has entities implementing IDamageArea will also need entities which implement IDamageable.
For this example uses two entities:
Bullet - an entity which implements IDamageArea and is ICollidable
Enemy - an entity which implements IDamageable and is ICollidable
The GameScreen also has a list for each and a collision relationship with an event.
When the bullet and enemy collide, the ShouldTakeDamage method can be used to determine if the enemy should take damage from the bullet, as shown in the following code snippet.
The ShouldTakeDamage method is available on the Enemy since it implements the IDamageable interface, but the enemy.TakeDamage and bullet.DamageAmount are not provided automatically and must be implemented in custom code.
The IDamageArea interface includes a DamageDealer property which can be used to store a reference to the damage dealer. This is typically used if the damage area is created by another entity, and that entity needs to be referenced upon collision. For example, in a multi-player game, each player may have a separate score. If an enemy is killed by a bullet, then the player who fired that bullet should be awarded points. For example, the following code could be used to assign the DamageDealer on a bullet created inside the Player class:
Right-click on the Screen/Entity and select "Export Screen"/"Export Entity"
If an entity is already created but not yet marked as a ICollidable, it can be marked as ICollidable in its Properties tab. When marking an existing entity as ICollidable, be sure that your entity has a collidable object, such as a circle.
For more information on the ICollidable interface as defined in FlatRedBall, see the page. For more information on colliding Entities and using ImplementsICollidable, see .
The Implements IDrawableBatch tells the FlatRedBall Editor to generate code for custom rendering including:
All necessary properties for the IDrawableBatch interface
Empty implementation for IDrawableBatch.Update and IDrawableBatch.Destroy. These are are empty since entities already have update and destroy methods.
Addition of the entity to the SpriteManager as an IDrawableBatch
Removal of the entity to the SpriteManager as an IDrawableBatch
Setting ImplementsIDrawableBatch to true does not result in code generation writing a Draw method implementation, so this must be implemented in custom code.
The following instructions show how to use the ImplementsIDrawableBatch property to create an entity which is drawn using the SpriteBatch class. Before writing code, the following steps are needed to create an IDrawableBatch entity:
Create an Entity, or select an existing entity which should have is own Draw method
Set the Entity's ImplementsIDrawableBatch property to True
Add a .png file to the entity. This will be used in the Draw call
Once the entity has been created, we must define a Draw call in the entity's code file. Notice that the Draw method has a Camera parameter. This allows entities to perform rendering relative to the current Camera. In this example the entity ignores the Camera for simplicity.
For more information and code samples related to IDrawableBatch, see the IDrawableBatch page.
Marking an entity as implementing IGumCollidable enables the creation of shapes for standard FlatRedBall collision using a Gum object. This can be useful for visually creating complex shapes in Gum, for aligning shapes with visuals created in Gum, or for implementing collision animation using the Gum animation system.
The following example shows how to create shapes in Gum and use them as the entity's collision. This example will use a default Player using the top-down controls, however it can be used on any type of entity.
First, we'll delete the existing collision from the entity since it is not needed - Gum will be responsible for adding collision:
Next, we'll define a Gum object which has collision. Keep in mind - any visuals will also be rendered on the entity, but for this example we'll use only shapes for collision.
Gum objects can contain Circle and Rectangle instances, and these should not be rotated. Notice that the component uses the center alignment. The center of the FlatRedBall entity will line up with the center of the Gum entity. Once a Gum component has been created, it can be added to the Player object:
Right-click on the Player's Objects folder
Select Add Object
Select the Gum Object Type
Scroll down or search for the name of your Gum component - in this case PlayerGumComponentRuntime
Click OK
Finally, verify that the Entity is both an ICollidable and IGumCollidable:
Select the entity
Select the Properties tab
Set ImplementsICollidable to True (this is usually true if the Player object was created by the wizard)
Set ImplementsIGumCollidable to True
Now the Player object will have its Collision populated by any Circle and Rectangle instances from any Gum objects (in this case PlayerGumComponentRuntimeInstance). Setting the collision to Visible can be helpful for debugging. Add this code in the Player's CustomInitialize method:
The Collision ShapeCollection will be visible and collides with solid collision.
The Implements IVisible property controls whether an entity implements the IVisible property. If true the following is performed by the FlatRedBall Editor:
The Entity implements the IVisible interface
The Visible property is available in code
Children of the entity will be hidden if instances of the entity have their Visible property set to false
The entity provides the Visible variable for tunneling and assignment per-instance
IVisible is a code interface defined in FlatRedBall. This interface primarily provides a Visible property. For information on working with IVisible in code, see the IVisible page.
IWindow serves as an interface for creating button-like Entities in Glue. Using the IWindow enables you to do the following:
Respond to clicks (release of mouse-button or touch screen)
Respond to pushes (initial press of a mouse-button or touch screen)
Respond to dragging
Prevent click-throughs on overlapping IWindows
For initial information on how to use IWindows in Glue, check out the IWindow in Glue tutorial page. For more information on IWindow in raw code, check out the IWindow code reference page.
The most commonly-used event when using IWindows in Glue is the Click event. The Click event is an event that is raised whenever the user "clicks" on an IWindow. FlatRedBall considers a Click as occurring if:
The user pushes on a button
The user clicks (releases) while still on the button
When these two events occur, then a button's Click event is raised.
Entities that implement IWindow automatically receive an Enabled property. The Enabled property controls whether the GuiManager's Cursor can interact with the Entity. Disabled Entities will not have their GUI events fired. This Enabled property uses explicit implementation which means you can only access this property by casting an instance of your Entity to IWindow. In other words:
The SlideOnClick event is an event that is raised when the user releases the cursor over a given IWindow, but only if the window was not initially clicked on. To contrast with Click, if the user both pushes and releases the cursor over an IWindow, then Click (or ClickNoSlide) will get raised. If the user pushes the cursor off of an IWindow, then releases it on the IWindow, then SlideOnClick is raised.
SlideOnClick is commonly used for drag+dropping elements onto an IWindow.
Screens and Entities can be exported from Glue. These exported Screens/Entities can then be imported back into a project. You can get exported Screens/Entities from files that you have previously exported, from other Glue users, or from GlueVault.com.
To import a Screen/Entity:
Navigate to the location of the .scrz or .entz file you want to import and click OK
Your Screen/Entity should now appear in your Glue project
Right-click on the "Screens" or "Entities" item in Glue and select "Import Screen"/"Import Entity"
This tutorial will walk you through how to create entities which inherit from FlatRedBall types. More accurately, the process of having Entities inherit from FlatRedBall types is very simple - all you have to do is change the BaseType to the desired type. However, this tutorial will discuss how to work with entities that inherit from FlatRedBall types, and why taking advantage of this feature can be helpful.
First we'll create a simple project with a single Entity that includes a Sprite, and a Screen which includes a large list of instances of this entity.
To create the Entity:
Right-click on Entities
Select "Add Entity"
Name the Entity "SpriteEntity"
Right-click on the newly-created Entity's Objects
Select "Add object"
Select "Sprite" as the type
Click OK
Now that we have an Entity, let's set the Sprite to use a Texture:
Go to the location where you saved the file
Drag+drop the PNG from the location where you saved it into the SpriteEntity's "Files"
Select the SpriteInstance object
Set its Texture to "Bear"
Now that we have an Entity, let's create Screen:
Right-click on Screens
Select "Add Screen"
Name your Screen "MainScreen"
Click OK
Next let's create a List of SpriteEntites:
Right-click on Objects
Select "Add Object"
Select "PositionedObjectList<T>" as the type
Select "Entities\SpriteEntity" as the List Type
Name the list "SpriteEntityList"
Click OK
Finally let's populate the List in code:
In Glue select the "Project"->"View in Visual Studio" menu option
Open MainScreen.cs
Add the following in CustomInitialize:
If you're running this project on a modern computer then it's likely that you may not be noticing any performance problems. However, despite running without problems on the PC, this same project may have significant performance and memory consumption issues on less powerful devices, such as the iPhone. One solution to this problem would be to make the Entities be manually updated; however that may not be so easy in this particular case. The reason is because our Entities are all spinning and require every-frame logic to have their rotation applied. However, making the Entities inherit from sprite can actually improve performance and memory usage. To understand why this is the case, let's first investigate how many manually updated objects are in the FlatRedBall engine. To do this:
Open your MainScreen.cs in Visual Studio
Add the following code to CustomActivity:
Now that we have this set up, let's change our SpriteEntity to inherit from a Sprite. To do this:
Select SpriteEntity in Glue
Change "BaseEntity" to Sprite
Now we can simply have the SpriteInstance inside of SpriteEntity be a reference to the SpriteEntity itself. To do this:
Select SpriteInstance
Set "IsContainer" to true
Download the Bear.png image from here:
You should see a large number of spinning bears:
Now your program will be outputting information about how many automatically updated objects exist in the engine: For more information on this method call, see the WriteAutomaticallyUpdatedObjectInformation page. We can see that we have 4000 Sprites (one for each instance of our SpriteEntity) and also 4000 PositionedObjects (each SpriteEntity inherits from PositionedObject).
Now that the SpriteEntity inherits from a Sprite, and the SpriteInstance is the container, we have essentially eliminated half of our runtime objects. To see this result, run the game again: You can see that since all of the entity instances are Sprites, all PositionedObjects have been removed (the engine reports 0 PositionedObjects).
The LayerProvidedByContainer property gives you access to the layer that the containing Screen or Entity has passed to this through Glue or through the AddToManagers method call. For more information on working with Layers in code, see the Layer page.
You can access the Layer simply by using the LayerProvidedByContainer property:
The LayerProvidedByContainer can be used to add additional objects to the same Layer. The following code shows how to create a new Sprite using an existing entity's LayerProvidedByContainer:
The following code shows how to create new entities using an existing entity's LayerProvidedByContainer:
The MoveToLayer method will place the entity on a Layer (if it is not already on a Layer) or will remove the entity from its current Layer and place it on the argument Layer. This method will assign the entity's LayerProvidedByContainer property, and will move all contained visual elements (such as Sprites) to the new layer.
The following code moves an entity to a layer called HudLayer :
The UseGlobalContent property tells an Entity/Screen to use the "Global" content manager when loading its content. This means that its content will only be loaded the first time it is accessed and it will never be unloaded. The UseGlobalContent is not the same thing as Global Content Files. Global Content Files is a collection of files which by default are pre-loaded when the application starts and are never unloaded. Files which are part of Screens and Entities which UseGlobalContent will not be preloaded, but will never be unloaded once they are loaded. It is possible for a file to both be part of an Entity as well as Global Content Files, as shown here.
The default value for UseGlobalContent is false. Entities will (by default) use the ContentManager given to them by their containing Screen. Screens will by default use a content manager unique to the given Screen. This means that any time a Screen is unloaded, all content referenced by that given Screen and any contained Entities will automatically be unloaded. This unloading behavior reduces the likelihood of accumulating too much memory through content loading, meaning simpler games will be able to ignore content loading and unloading. However, this also means that content may be unnecessarily loaded and unloaded. For example, consider a game which has a number of UI screens which use the same font files. If this font is used in a lot of Screens, it may be beneficial to always keep it in memory rather than to unload and re-load it on every Screen transition. If this font exists in a Text object Entity which is reused in multiple Screens, then the Entity's UseGlobalContent property can be set to true, resulting in it never being unloaded.
UseGlobalContent can be set by:
Selecting an Entity/Screen
Your Entity/Screen will no longer unload files that it uses.
Setting the UseGlobalContent tells an Entity to use the "Global" ContentManager which means it won't unload. If you are familiar with the "Global Content Files" tree item in Glue then you are aware that you can also make files global by adding them to Global Content Files. You may be wondering what the difference between the two approaches is. Here are some characteristics which may help you identify when to use UseGlobalContent and when to use "Global Content Files".
Files added in "Global Content Files" will be loaded immediately when your game begins to run (or asynchronously if the LoadAsynchronously property is set to true). Files which are a part of an Entity that has UseGlobalContent to true will only be loaded when the Entity is first instantiated, or if the Entity's LoadStaticContent method is manually called.
Files added in "Global Content Files" are accessible through the GlobalContent class, which is a standard way to access global content. Files added to an Entity that has UseGlobalContent set to true will be associated specifically with that Entity. This can improve the organization of your project.
As suggested above, files added through "Global Content Files" can be loaded asynchronously. This means you can avoid long load times and delay in application startup by putting files in "Global Content Files".
There may be situations when a file should both be part of "Global Content Files" as well as part of an Entity which has UseGlobalContent set to true. The most common case is if a piece of content is associated with a particular Entity, but should be asynchronously loaded. For example, you may be working on a game that does not load some in-game content (such as the main character's content). If this is the case, making the main character's content exist in "Global Content Files" allows you to begin loading this content at the very beginning of execution. Depending on the menu flow of your game, you may end up loading your character before the player gets to the game Screen. This could improve load times when going into game. If you set an Entity to UseGlobalContent, and also add its files to the "Global Content Files", then the generated code for the Entity will use the GlobalContent class to get reference to the appropriate files. This means that it will obey the async loading, and even update the content lock record if appropriate.
Changing the "UseGlobalContent" property to "True"
The FRB Editor supports the addition of events to screens and entities. The most common types of events include:
Responding to a variable changing. For more info see the Variable Event page.
Responding to collision (on a CollisionRelationship)
Other objects such as IWindows can also expose events, but these are less common.
The only type of event which requires using the FlatRedBall Editor is variable events. All other events can be performed purely in code. CollisionRelationship events are often defined in the FlatRedBall Editor since doing so provides a single place to see all responses to a collision.
Variable events allow for custom code to react to a variable being assigned. To add an event for a variable:
Create a variable on your entity
Drag+drop the variable onto the Events folder
This creates an event in the Event.cs file for the container. For example, if the event is created in the Player entity, then the event handler is added to Player.Event.cs.
Note that IWindows are not used as often in modern FlatRedBall development due to the introduction of FlatRedBall.Forms. However, the following example does show how events can be used for custom implementations of IWindow. The events available to a screen, entity, or object depend on the respective container's properties. For example, if an entity implements IWindow (for more information, see the Implements IWindow page), the entity will have additional events available.
Every event in Glue creates a corresponding method in your code project which can be edited in Visual Studio. For example, consider the example of a GameScreen which has an event ResolutionOrOrientationChanged:
The presence of this event will result in 2 new code files:
GameScreen.Event.cs
GameScreen.Generated.Event.cs
As usual, the file with Generated in the name is a generated file which should not be edited because Glue may overwrite any manual changes. The non-generated file (GameScreen.Event.cs) can be freely edited to modify the logic associated with a given event.
The ResolutionOrOrientationChanged event is an event which is raised whenever the game's resolution or orientation changes. This can happen if:
The orientation changes (on a mobile or tablet)
The user docks your game in Windows 8
The user changes the window resolution - either through a command in the game or by resizing the window
This example assumes a desktop application. It will allow the user to resize a window by dragging the corner/edges. Whenever the user does this the new resolution will be printed to the screen. First, add the following code to your Screen's CustomInitialize:
To add the ResolutionOrOrientationChanged event:
Open or focus on Glue
Right-click on your Screen's Events item
Select "Add Event"
Verify "Expose an existing event" is selected
Use the drop-down to select "ResolutionOrOrientationChanged"
Click OK
Next, go back to Visual Studio and open your screen's Event file. If your screen is called "GameScreen" then the event file will be "GameScreen.Event.cs". Add the following code to OnResolutionOrOrientationChanged:
Any file added to a Screen or Entity will have a corresponding member in code which represents the already-loaded file. You can access this object in custom code without having to worry about whether it has been loaded or when to load it (at least under default settings).
To see how a file is accessed in code:
Create a new Screen called "TestScreen"
Find a .png through windows explorer
Drag+drop the .png into your TestScreen's Files in Glue
Notice that the newly-added File will indicate which type it will load to at runtime
Open TestScreen.cs in Visual Studio
Add the following code to CustomInitialize:
Note:Since the purpose of the code above is to simply show that the file added to TestScreen can be accessed in code, it does not cover removal of the Sprite. In an actual game you would want to keep track of the Sprite at Screen level and remove it in the Screen's CustomDestroy. Not doing so would result in your game crashing when you transition to a different Screen.
The term "Factories" comes from the factory design pattern. Factories are objects which can create new instances of certain types of Entities. Factories provide the following benefits:
Entities created in a factory will automatically be added to screen lists (by default).
Factories provide a standard way to create entities which is especially useful for systems like Tiled to instantiate new entities.
Factories can pool Entities which can greatly reduce allocated memory for Entities which are created and destroyed frequently.
If your game requires the creation of entities in code (such as the player shooting bullets or enemies appearing at an enemy spawn point), then you will want to use factories.
When adding a new entity, the Create Factory checkbox is automatically checked. In most cases this should be left as true since most entities should be created by factories so they can be properly added to their corresponding lists (usually in GameScreen).
As mentioned above, most of the time factories are added automatically when creating an Entity. To add a factory after-the-fact, see the CreatedByOtherEntities property on your Entity.
To use a factory in code, use the CreateNew method when you would like to create a new entity. For example, you can create a Player instance in the CustomInitialize of your screen as shown in the following code:
Glue will automatically generate factories for any entity which has its Created by Other Entities property set to true. For information on this property, see the CreatedByOtherEntities page.
The CreateNew function is used to create a new instance of the Entity corresponding to the calling factory. In simple cases, the only requirement is simply calling this method an a new instance will be created and available for use in your code. For information on CreateNew in the context of a tutorial, see this page.
This code assumes that your project has an Entity called "Enemy" and that it has a corresponding Factory:
Usually entities which are created with factories are created on some condition. Examples include:
Reacting to input. For example, the player presses a button to shoot a bullet.
Reacting to a collision event. For example, the player collides with a trigger to spawn an item.
Reacting to time condition. For example, an enemy spawner creates an enemy once every 10 seconds.
The following code shows how to create a bullet whenever the user presses the space bar.
The CreateNew method also takes a Layer argument. This layer specifies which Layer the created object should be a part of. Entities are usually created in Screen custom code or in the custom code of other Entities.
If you are creating an Entity through a Factory in a Screen, then you can pass the Layer which you would like the newly-created Entity to be a part of in the CreateNew method. This will usually be a Layer which is a part of the Screen (usually created through Glue). The following code assumes a Layer called HudLayer:
If the Entity that is being instantiated through the Factory is to be on the same Layer as the Entity calling the code, then the LayerProvidedByContainer can be used:
If this is not the case, then the creating Entity must have reference to the Layer which is to be used. You may need to set this reference up purely in custom code.
If you are calling CreateNew you may see an exception indicating that you must call Initialize before using the factory. . If you are seeing this exception it means that the factory that you are trying to use when calling CreateNew has not yet been initialized. If you've used factories before then you may be thinking "I never had to call Initialize before, why do I have to now?" Initialize will automatically be called for you if you are using a Screen which contains a list of the given Entity type, and if that list was created through Glue. In other words, if you have an Entity called Bullet, and a factory called BulletFactory, then BulletFactory will automatically be initialized if your game is currently in a Screen which has a list of Bullets added to it in Glue. If you do not have a list of the given object type, but you want to instantiate that object at runtime, then you will manually need to call Initialize on the factory. For more information about Initialize, see this page.
Factories must have their Initialize method called before they are used. In many cases the Initialize method is automatically called in Glue generated code. This article explores when the Initialize method is called for you and when you must call it yourself. The Initialize method also controls which list is populated by a factory. This article also discusses this, specifically as it applies to inheritance. For an in-depth look at using Factories, see the tutorial on "Created by Other Entities"
First we'll look at a very simple scenario. Consider an Entity called "Enemy". In this example, Enemy has its "CreatedByOtherEntities" set to true, meaning Glue will automatically generate a Factory called EnemyFactory. Let's say that there is also a Screen called GameScreen, and that GameScreen has a PositionedObjectList of Enemies. To summarize, if the following conditions are met, then Initialize will be called:
An Entity has CreatedByOtherEntities set to true
A Screen has a PositionedObjectList of the Entity mentioned in the previous point
Glue assumes that newly-created Enemies should be put in the PositionedObjectList in GameScreen (assuming GameScreen is the current Screen). In other words, the EnemyFactory can be used when GameScreen is live; the GameScreen will automatically call Initialize on the EnemyFactory. If GameScreen did not have a list of Enemies, Glue would not automatically Initialize the EnemyFactory. This means that if you intend to use EnemyFactory's CreateNew method in a Screen which does not contain a PositionedObjectList of Enemies, then you must manually call Initialize on EnemyFactory. Also, keep in mind that if you are manually calling Initialize, then you must manually call Destroy on the Factory. Destroy should probably be called in your Screen's CustomDestroy method.
PositionedObjectLists in Entities will not Initialize factories: Entities that include PositionedObjectLists of Entities that have an associated factory will not Initialize the factory. In this case you must either place a PositionedObjectList in your Screen, or you must manually call Initialize on the factory passing in the PositionedObjectList in your Entity. Therefore, if working with a Bullet object in an Entity, your code might look like this:
An Initialize call (whether in custom or generated code) will only put the Factory in a valid state for the given Screen. In other words, if GameScreen automatically calls Initialize on EnemyFactory, other Screens must still call Initialize (and Destroy) on EnemyFactory if your code calls EnemyFactory.CreateNew. The Initialize call expires at the end of the current Screen and must be called again (either manually or through generated code).
In the section above, we discussed that Glue will automatically generate code to call Initialize on a given Factory if the current Screen has a PositionedObjectList of the associated Entity. However, let's consider a more complicated situation: In this example we will use an Entity called Enemy which is the base Entity for three other Entities as shown in the following diagram:
Enemy
Orc
Dragon
Troll
We'll assume that Orc, Dragon, and Troll are all Entities which have matching Factories - that is, they all have CreatedByOtherEntities set to true. As mentioned above, if there is a PositionedObjectList of Orc, Dragon, or Troll, then the associated Factory will automatically have Initialize called. However, it is common to create PositionedObjectLists of base types to simplify custom code. In other words, GameScreen may have a PositionedObjectList of type Enemy. In this case, Glue also assumes that you intend to associate the List of the base type (Enemy in this example) with any of the derived types (Orc, Dragon, and Troll). Therefore, if you have a PositionedObjectList of Enemy, then OrcFactory, DragonFactory, and TrollFactory will all be initialized automatically. Also, they will be initialized using the PositionedObjectList of Enemies, so any Troll, Dragon, or Orc that you create will be put in that list.
Next let's look at a situation where there are three entities in an inheritance chain:
Enemy
Dragon
RedDragon
We'll assume RedDragon is an Entity that is CreatedByOtherEntities, so there is a RedDragonFactory. As explained above, RedDragonFactory will be automatically Instantiated in a Screen if:
The screen includes a PositionedObjectList of type Enemy
-- OR --
The Screen includes a PositionedObjectList of type RedDragon
But what if the Screen only contains a PositionedObjectList of Dragon (the type "inbetween" Enemy and RedDragon)? In this situation, Glue does not assume you intend to have the RedDragonFactory instantiated. Glue will only automatically instantiate the RedDragonFactory if there is a PositionedObjectList of the most base Entity (Enemy in this case) or most derived (RedDragon in this case) in a given Screen. However, you can still customize how the behavior of the Factory works using the EntitySpawned Action and manually adding newly-created Entities to any List.
If your screen contains multiple lists of the same type, Glue will generate code to add entities to all lists. For example, if your game has an entity called Enemy and you have two lists (GroundEnemies and AirEnemies), then any Enemy factory (or factory of entity deriving from Enemy) will insert into both lists. A list can be removed from automatic association with a factory in Glue (this requires GLUX version 3 or greater). This value is true by default, but can be set to false to prevent Glue from automatically associating any factories with the list.
Factory-List association can also be adjusted in code by calling RemoveList. To remove the lists from the factory:
The SortAxis property can be set if a factory is associated with a PositionedObjectList which should remain sorted (typically for performance reasons). By default the SortAxis is null, so no sorting will be performed on insertion.
The code example below assumes the following:
An entity named Entity with the CreatedByOtherEntities value set to True:
A screen with an Enemy list:
The following code in the GameScreen.CustomInitialize method will result in a sorted list of enemies:
This code produces results shown in the following image:
The SortAxis property is null by default. It is reset to null whenever the factory has its Destroy method called. Factories are typically destroyed when a screen is destroyed. Therefore, if SortAxis is assigned to a non-null value in a Screen (such as in CustomInitialize ), this SortAxis value will persist until that Screen is destroyed. This behavior allows multiple screens to use different SortAxis values for the same factory. It also allows the same screen to use different SortAxis values for different levels to improve partitioning efficiency.
SortAxis results in a factory inserting instances of newly-created entities into the target list so that the list is always sorted. While this increases the amount of time that each individual insert takes, it removes the requirement to call a sort function after-the-fact (which can be expensive on large, unsorted lists) This can provide a small performance boost.
Most FlatRedBall files can be used to display something graphical in your game. For example Scene (.scnx) files can be used to display Sprites, Text, and SpriteFrames. However, for an object to be drawn it must be added to the FlatRedBall engine.
In the simplest (and most common) cases, adding objects from files to your game is very simple. The simplest case is when a file (such as a .scnx file) is part of a Screen. In this case the file will automatically show up in your game and in GlueView with no additional changes needed. In other words, if you simply add a .scnx file to a Screen, it should show up automatically in your Screen and in your game.
Entities behave slightly differently from Screens. For a file which has been added to an Entity to appear, it must have an Object which references it. Most of the time Glue will ask you if you want to create an accompanying Object for new files - if you click the default Yes, then the file will automatically appear in your Entity.
The AnimationChainList type is the runtime type for the .achx file type. AnimationChainLists are used to store a collection of animations. Examples of AnimationChainLists might be all of the animations for a Player in a game. The easiest way to add an AnimationChainList to your game is to add a new .achx file to a Screen, Entity, or global content:
For information on how to add a Sprite to your Entity, see this page. For information about how to use the AnimationEditor, see the AnimationEditor documentation. For more information on using AnimationChainList files in the FlatRedBall Editor, see this page.
AnimationChainLists are ultimately lists of textures and texture coordinates. They must be used on an object to be seen in game. Therefore, if you are creating an Entity or Screen which includes an AnimationChainList file, you will likely also need to add a Sprite to view the AnimationChainList.
Files added to the FlatRedBall Editor are managed for you automatically, simplifying the game development process. When a file is added to the FRB Editor the following occurs:
The file is listed in the tree view
The file is added to the proper Visual Studio project(s)
A static member is added for the file in the appropriate screen, entity, or global content
Code for loading the file is generated automatically
png (image files)
achx (animation files)
tmx (tiled map files)
gusx (Gum screen files, usually automatically added when creating a new FRB Screen)
mp3 (music)
ogg (music)
wav (sound)
csv (spreadsheet files for data)
The following types are also supported, but are not commonly used in modern FlatRedBall game development
scnx
shcx
emix
splx
nntx (node network files)
Additional files can be added to the FlatRedBall Editor and supported through plugins. For example, see the Spine plugin for supporting Spine files.
FlatRedBall supports multiple ways to add a file to your project:
Right-click on the Files folder and select to add a new file
Right-click on the Files folder and select to add an existing file
Drag+drop a file from a Windows Explorer window onto the desired Files folder in the FlatRedBall Editor
Usually if a file is loaded in your game, the File should be located relative to the Content folder of your project. This is important so that your game is portable. Therefore, whenever an existing file is added to your project, the FlatRedBall Editor checks if it is already inside the Content folder. If not, it is copied to the desired folder in a Screen, Entity, or Global Content Files.
If you would like to control the organization of your files, then you should always manually copy the files into your Content folder in their desired location first, and then add them to FlatRedBall. By using this approach, the files will remain in the same place after you add them to FlatRedBall. Otherwise, you can drag+drop files from anywhere (such as the desktop) and FlatRedBall will organize them based on where the files are dropped.
For example, if a file is located on the desktop then it will be copied to the game's content folder when it is drag+dropped. The original file is left untouched. Any modifications to the file should be made on the file inside the Content folder rather than the original file.
In this case the file is copied to the game's Content/GlobalContent folder. Note that the prefix "Content" is omitted in the Name property as this is assumed for all content.
If the file is already a part of the project's Content folder, then it is not copied when drag+dropped into FlatRedBall.
For convenience, existing files in the Content folder are shown when adding new files.
Some file types can reference other files. If FlatRedBall understands this file type, then only the root file must be added to the FlatRedBall project - all referenced files will be automatically added to your game project.
This feature is especially useful for file types which can reference lots of other files. For example, consider that a Gum project (.gumx) can reference dozens of other files such as texture files (.png) and font files (.fnt). By adding the .gumx file to your project (which is done automatically when creating a project with the New Project Wizard, all other files are automatically added to your project.
The following screenshot shows a typical game with the GumProject.gumx added to Global Content Files.
Every file referenced by the Gum project (and any of the Screens and Components in the Gum project) is automatically added to your game project (.csproj). For example, all font files are automatically added to the game project, as shown in the following screenshot from Visual Studio.
The FRB Editor also supports adding files using a wildcard pattern. For more information on using wildcards, see the Wildcard Files page.
Files added through the FRB Editor can be accessed in code. Files added to Global Content Files can be accessed in any location through the GlobalContent
class. Files added to screens and entities can safely be accessed within the respective screen or entity's custom code. Files from other screens or entities can be accessed so long as the owning screen or entity has had its LoadStaticContent
method called prior to accessing the file.
Note that files can also be accessed through the generated "Type" class generated by FlatRedBall. For more information on derived types and accessing files, see the Entity Variants Using Inheritance page.
Files added to a Screen or Entity create a member which can be accessed in code. For example, if a .png file is added to an Entity, it can be used to assign a texture on a sprite. In the example below, the FlatRedBall Editor generates code for a Texture2D called MonsterTexture .
This Texture2D can be accessed in custom code, such as to assign a Sprite's Texture. Since MonsterTexture is a static Property of the Monster entity, access to this property is checked at compile time and auto complete displays it as an option when writing code.
Global content files are loaded when the game first starts, and remain in memory for the remainder of a game's execution, so they can be accessed at any time. For example, the following file named MainSpriteSheet.png is part of Global Content Files.
This can be accessed anywhere in a game with the following code:
Single files can be shared across multiple Screens, Entities, and Global Content. For example, a file may be added to Global Content Files, but then also added to an Entity to be accessible by that Entity in the FlatRedBall Editor. This does not create a copy of the file - both Player and Global Content Files reference the same file on disk and in memory:
Files can also be shared between entities and screens. For example, the following shows a single file shared between two entities:
Notice that the file being moved is in the Entities/Player folder. When it is moved to Monster, the file in the Monster files is still named Entities/Player.CharacterSpriteSheet.png. The FlatRedBall Editor does not duplicate the file on disk when it is drag+dropped from one Entity to another. At runtime the image is only loaded once if both Player and Enemy are created in the same screen.
The "Files" tree node supports folders. To add a folder:
Right-click on the "Files" node
Enter the name of the folder
Click OK
This creates a folder both in the FlatRedBall Editor as well as on the file system.
The Name of a file in the FlatRedBall Editor reflects its location. For example, the following shows a file located in the Animations folder of a Ball entity:
Shared files display the name of their location on disk. For example the following shows a file which is located in Global Content, but shared with an entity. When the shared copy is selected the file's actual location is show in the Name property:
Notice that the file above is located in GlobalContent/ball.png, but it appears in both the Global Content Files folder and the Files folder of BallEntity. To view a file in its location on disk, right-click and select View in Explorer.
Files can be deleted by right-clicking on a file and selecting the Remove option.
The Delete key on the keyboard also serves as a shortcut for removing the file.
If a file is removed, the FRB Editor scans the project to determine if the file is still referenced elsewhere. If no refernces are found, then FRB asks what you would like to do with the file.
Nothing - this option removes the file from the FRB Editor, but the file remains part of the Visual Studio project and is not removed from disk. Select this option if you would still like to use this file in code. Note that you must manually load the file in custom code - the FRB Editor no longer generates any code for files which have been removed.
Remove them from the project but keep the files - this option removes the file from the the FRB Editor and also from your game project (.csproj). Select this option if you do not want to use the file in your project, but you want to keep it on disk so you can access it later. Since the file is no longer part of Visual Studio, it will not be copied to your game's bin folder, so it cannot be loaded at runtime - even in custom code.
Remove and delete the file - this option removes all traces of the file including the FRB Editor, your game project (.csproj), and on disk. Select this option if you are sure that you no longer need this file.
If FlatRedBall detects that a file is still used by your project, it does not display the dialog asking you what to do with the file.
For example, if the same file appears in two entities, it can be removed from one safely and FRB will not ask what to do with the file since it is still needed. The following animation shows a file which is part of both the Monster and Player entities. If removed from Monster, you will not be asked to remove it from your project or disk since it is still part of the Player entity.
If the file were to also be removed from Player, then FRB would ask how to treat the file (nothing, remove from project, delete).
A file can have references from other files. For example, a .png file can be referenced by an .achx file. FlatRedBall understands file references in common file types such as .achx, .tmx, and gum files. Therefore, if a file is removed but still referenced by a different file, FRB will not ask about removing the file from Visual Studio or the file system.
For example, the Player's AnimationChainhListFile.achx references the CharacterSpriteSheet.png. If CharacterSpriteSheet is removed from the Player entity, the FRB Editor recognizes that it is still needed and does not ask about whether it should be deleted or removed from the game project.
CSV (comma separated values) is a spreadsheet file format which has extensive support in FlatRedBall.
CSV stands for "comma separated values". If you are familiar with Microsoft Excel, then you may be familiar with the .xlsx or .xls file format. The .csv file format is similar to the .xlsx file format in that they are both spreadsheet file formats. One main difference between the two is that the .csv file format is much easier to read and edit in a text editor. For example, consider the following:
If this were a CSV file viewed in a text editor then it would appear as follows:
You can see above that the values (such as "Column 1" and "Column 2") are separated by commas. This is where the name "comma separated values" comes from.
When you create or modify a CSV which is part of your FlatRedBall project, FRB automatically creates code files (classes) which can be used to store information that is loaded from a CSV in your project. These files/classes are often referred to as "data" files and classes because FRB generates them in the Data namespace of your project. The data file will include a class with the same name as your CSV file. This will include members matching the headers of the columns of your CSV. For example, consider a file EnemyInfo.csv which contains the following:
If this file is added to a Screen, Entity, or Global Content, then Glue will automatically create a file called EnemyInfo.Generated.cs:
As mentioned above, Glue will automatically generate a file based on the CSV. Specifically, Glue looks at the top row (headers) of the CSV file to determine the class members. If a header does not specify a type, then it will default to a string type. For example, The example above has two string members: Name and Texture. Headers can also define the type of a class. For example, the header above Speed (float) results in a the EnemyInfo including a Speed property of type float. Glue supports comments for headers which tells Glue to exclude a particular member from the class. For example, the following CSV would include a single Name property, and the other column is ignored:
Columns in a CSV may be of a list type (such as List<int>). These types can be specified in parenthesis just like any other type. When a CSV includes a list, the required row defines how many entries are in the CSV. For example, the following CSV contains two car definitions, and each car has multiple features.
The generated code file for the data class is marked as "partial". This means that you can add additional code files to add additional variables and functionality to data that is created by Glue. To do this:
Find the data file in Visual Studio
Right-click on the folder containing the Data file
Select "Add"->"Class..."
Enter the name of your CSV file without the extension. For example, if using EnemyInfo.csv, the new Class name would be EnemyInfo (so it matches the class name in the generated file)
Once the file is selected, find the header of the file and make it partial. In other words, change:
to
Now you can things to EnemyInfo to help you work with the generated class. Note that this approach of using partial classes is the same as what Glue automatically does for you when you create a Screen or Entity. Custom code is very common in Screens and Entities, so Glue automatically creates a custom code file for you. Custom code in data classes is less common so Glue does not automatically do this for you; however if you do it manually it will work the same way.
Column 1 | Column 2 | Column 3 |
---|
Name (required) | Speed (float) | Texture |
---|
Name (required) | // Comment |
---|
Name (required) | Features (List<string>) |
---|
Value 1 | Value 2 | Value 3 |
Next Row | Next Row 2 | Next Row 3 |
Bear | 60 | Bear |
Slug | 20 | Slug |
Bear | Bears are strong |
Slug | Slugs are slow |
Accord | Power Windows |
Power Locks |
Anti-lock Brakes |
Leaf | Electric Motor |
Electric Motor |
CSV is a powerful file format which allows for the creation of data in your game. Using CSVs is convenient because you can use any spreadsheet editor to create CSVs. FlatRedBall automatically generates classes for your CSVs (also known as data-first), and these CSVs are loaded automatically in generated code. The CSV format is typically used to define data using a custom format such:
Stats and coefficients, such as damage, price, and weight of weapons in an RPG
Dialog and scripting data
This article will show you how to create instances of objects based off of information in a CSV. CSV stands for "comma separated values". In its raw format it is simply a text file which contains values separated by commas and new lines. For example, the contents of a CSV might appear as follows:
If you were to create a new file, enter that information, and change the extension to a .csv, you'd have a valid CSV file. However, the true power of CSV comes from their standardization. CSV files are most commonly used as a very simple spreadsheet format. Therefore, CSV files can be opened and created by virtually every spreadsheet program including Microsoft Excel, Open Office, and Google Docs.
Note: Need a spreadsheet app? You can get Open Office for free at this website. www.openoffice.org
Not only can you edit CSV files in a spreadsheet, but FlatRedBall also has code to simplify working with CSV files. Furthermore, when you use CSV files in Glue, as we're about to do, Glue will automatically generate the code necessary to load CSV files into your project into a very easy-to-use list. To find out how, keep reading:
The first step in creating your custom data is to add a CSV file to your project. To do this:
Expand your Screens item.
Expand your GameScreen item.
Right-click on your File item under GameScreen.
Select "Add File"->"New File"
Now your project has a new CSV file. The next step is to enter the information we want to use in our game in the CSV file.
A property called StringMember. This member doesn't define a type, so it defaults to string.
A property called TypedMember. This member defines a type in parentheses which is float.
As suggested above, if a property does not define its type, then Glue will default the type as string. However, if you want to make the data a specific type (such as float or bool), then you need to explicitly set the type next to the member name in the same cell. What follows is any number of rows - each one defining an instance of your custom data type. The csv currently has just one instance. This instance has its StringMember set to "StringMemberValue" and its TypedMember set to 100. Let's change the data so that it can be used to specify starting locations for Enemies. To do this:
Change the first member from StringMember to "X (float)"
Change the second member from "TypedMember (float)" to "Y (float)". At this point you could continue to add more variables but for this example we only need X and Y.
Change the value of the first column in the second row from "StringValueMember" to 10.
One very important thing to remember regarding CSV files is that they can be used for any type of data. In this particular case we used CSV files just to define the number of enemies and their individual locations. You could easily add additional information to the CSV file, such as the direction that enemies are facing or the amount of gold the player earns when defeating the enemies. You can also use CSV files for information not necessarily related to Entities. For example, you could define point values for completing various missions in a game. The CSV file can be used to organize and consolidate information that could normally sit in Screen and Entity variables in Glue, but may be easier to edit and compare when used in a spreadsheet. Another useful benefit of using spreadsheets is that values in one cell can included references to other cells and formulas. The CSV file format does not maintain these references and formulas; however, you can save your files as a native format for the application you are working in, then "export" the file to CSV to get the raw values for your game.
Once you save your CSV file, Glue performs actions:
It creates/updates a code file which defines the format of each instance in your CSV
It creates the code to automatically load your CSV file in the Screen or Entity that it is a part of
Since CSV files can define any information, there is no standardized way of converting this data into Entities; however, despite its flexibility the code needed to create Entities from the CSV information is very straight-forward. Since we added the CSV file to our "GameScreen", then this is where we need to add the code to process it. To do this:
Open your project in Visual Studio
Add the following code inside of your CustomInitialize function:
There are a few things to note in the code above:
We used the "EnemyLocationFile" variable which is the same name as the class you've created.
We used the data type "EnemyLocation" which is a class automatically generated for you by Glue. It is the same name as the EnemyLocationFile except it removes the "File" off of the end. It is recommended that you have "File" at the end of your file names so Glue can perform this modification to differentiate between your file and your individual data type.
We created a new Enemy, then set its X and Y positions using the EnemyLocation's X and Y values.
Finally we add the the newly-created Enemy to the Enemies list.
This tutorial covers the basics of using CSVs. There's a lot of functionality in CSVs and special syntax that you can use to achieve things like Lists of primitives inside each instance that is deserialized. For more information, check out the CsvFileManager page.
Now you have worked through the process of adding a list of Entities to your Screen and using CSV files to populate that list, you can create games which have an undefined or large number of Entities. You've also learned how to use CSV files to create custom data quickly through Glue.
Select "Spreadsheet (.csv)" as the file type and enter "EnemyLocationFile" as the file's name
The CSV file can be edited just like any other file in Glue by double-clicking it. This will open the CSV file with the default editor. If you would like to override the default file association that can also be done through the Settings->"File Assocation" menu item. The images of the CSV contents will show Microsoft Excel 2007; however, as mentioned above other spreadsheet applications can be used. Initially the CSV file contains four Entries These default values simply provide an example of how data can exist in a spreadsheet. CSV files have a fairly simple format. The first row defines the properties that will be used for each instance. The default CSV file has two properties:
Change the value of the second column from 100 to 10.
At this point we've specified that we are going to create a new data type that has X and Y variables. We've also created one instance with the values of 10, 10. Additional rows can be added to the spreadsheet to add more instances. Also, additional properties can be added as new columns in the spreadsheet. Simply changing and saving the CSV file will result in the data being updated automatically. To make things more interesting, I'll add one more row to the spreadsheet file.
In Visual Studio, expand your Screens folder
Double-click "GameScreen.cs" to open the code file in the code view window
Scroll down in the file until you find a function called "CustomInitialize". This is a function which gets called when the Screen is first created. This is where you want to perform any one-time game logic such as setting the initial placement of your enemies.
CSVs are often used to define data for games, but it's common for one CSV to need to reference information from another CSV. This tutorial will walk you through creating two CSVs, one which will reference another.
In this situation we will create two CSVs:
The first will define the weapons which exist in your game. The weapons defined for this game will be for a traditional RPG.
The second will define the shops in the game which will contain a list of the weapons which they can sell.
First we'll create a CSV for weapons, which we'll call WeaponInfo:
Right-click on GlobalContent
Select "Add File"->"New File"
Select "Spreadsheet (.csv)" as the type
Enter the name "WeaponInfo" as the new file's name
Click OK
Next create the CSV for StoreInfo:
Right-click on GlobalContent
Select "Add File"->"New File"
Select "Spreadsheet (.csv)" as the type
Enter the name "StoreInfo" as the new file's name
Click OK
Fill the WeaponInfo so it appears as follows:
Fill the StoreInfo so it appears as follows:
**Note we used List<string>:**Note that the StoreInfo CSV file uses a List<string> instead of a List<WeaponInfo> for the WeaponTypes it contains. The reason for this is because we want to simply reference the key from WeaponInfo.csv so that it can change without requiring changes to StoreInfo.csv.
Next we'll need to write some simple code to associate the values in the WeaponTypes column in the StoreInfo CSV to the weapons defined in WeaponInfo.csv. To do this:
Open your project in Visual Studio
Expand the "DataTypes" folder in the Solution Explorer
Right-click on the "DataTypes" folder and select "Add"->"Class..."
Name the class "StoreInfo". This should be the same name as your CSV.
Finally save your project through the "File"->"Save All" option in Visual Studio. This will save changes to the project so that if Glue is open it will reload the changes. Visual Studio may notify you that the project has changed. This may be because Glue has inserted the StoreInfo.Generated.cs file under the StoreInfo.cs in the Solution Explorer.
Next we'll add a property to the StoreInfo.cs file to make it more convenient to access which WeaponInfo's a Store contains. To do this, add the following code to StoreInfo.cs:
Now each ScreenInfo which is loaded into GlobalContent has an IEnumerable of WeaponInfo's that can be used to populate UI, menus, and drive game logic.
You should now have 2 CSVs in your Global Content Files in Glue:
You should now have a file called StoreInfo.cs and a file called StoreInfo.Generated.cs. Next, open the newly-created StoreInfo.cs file and make it a "public partial" class. After you do this, your code should look like:
Name (string, required)
Damage (float)
Sword
3
Spear
4
Dagger
2
Name (string, required)
WeaponTypes (List<string>)
CapitalCity
Sword
Spear
SouthCity
Dagger
Spear
By default Glue creates a new class in the DataTypes namespace for every CSV in your project. For example, consider a game where each enemy can have multiple types of attacks. Each enemy might store the attack information in its own CSV file. In this example the CSV files would be called:
SoldierAttackData.csv
OgreAttackData.csv
SlimeAttackData.csv
ZombieAttackData.csv
We will assume that each CSV file has the same columns, and we would like to have the same code handle enemy attacks regardless of which type of enemy is performing the attack. However, by default Glue will create four classes - one for each CSV. To solve this problem, we can create a common class to be used by all CSV files. This can be done by right-clicking on each of the CSV files and selecting the Set Created Class option.
This example uses enemy entities which each provide their own attack data in CSV files. Each CSV has its Created Class set to Enemy Data.
A new class can be added in the Created Class window.
Once added, classes appear in the list below.
This class can be used for the current CSV by selecting the class and clicking the Use This Class button.
Once a class is added, Glue generates a file for this in the DataTypes folder.
The four CSVs specified above will deserialize into AttackData Dictionaries or Lists.
Glue automatically creates a class called PlatformerValues if a game includes platformer entities. Every entity will store its platformer values in instances of the common PlatformerValues class. Removing this class can cause compile errors.
By default CSVs added to Glue will create a matching class in the DataTypes folder of the game project. For example, adding a file EnemyInfo.csv will create a class GameName.DataTypes.EnemyInfo. While this behavior is convenient it is sometimes too restrictive. For example, games may benefit from fully-defining their data classes by hand - even in other projects completely - rather than letting Glue generate the data classes automatically. Setting Generate Data Class to false allows the code project to specify its own data class.
The following screen shot shows a CSV called EnemyInfo which is tied to a data class with the fully-qualified name of GameProject.DataTypes.EnemyDataClass: The "Custom Namespace" field allows using classes defined outside of the GameName.DataTypes namespace. For example in the following image the class BuildingInfo is placed in the BaseDataTypes.Buildings namespace (resulting in the fully qualified name BaseDataTypes.Buildings.BuildingInfo):
UniformRowType can be used to load the CSV data in a more raw format rather than generating a custom class for the CSV. This is useful if the data in the CSV needs to be accessed by row and column index rather than by class member names. For this guide we'll be using a CSV with the following data:
Before changing the UniformRowType value, we should look at the code generated by Glue for this CSV. The class that contains the CSV will have a dictionary of objects as shown in the following code:
In this case the Csv class is generated as shown in the following snippet:
In this case we could access the CSV data through the CsvFile member. If the CSV were part of GlobalContent we could get the information as shown in the following code:
Note that we access the first column using the Column1 property.
We can change the UniformRowType to string[] to change how Glue generates the CSV code.
This setting tells Glue to generate each row in the CSV as a string[], allowing us to index into each column as shown in the following code:
Glue offers two options for UniformRowType:
String
String[]
The most commonly used value is String[] which tells glue that each row contains multiple values. Since each value in a row may need to be independently accessed, each row is represented as a string array. For example, to access index 3 in a row, your code may look like:
If your CSV has only one column, then the UniformRowType can be String. This can simplify accessing the row. For example, to access the first item in the row at index 2, your code may look like:
The DestroyOnUnload value controls whether music files are destroyed when the Screen is destroyed. This value can be set to false if you want the song to continue playing into the next Screen. For this to occur, the Screen which you are transitioning into must also have a reference to the same Song file.
To add a song that plays on two screens:
Create two screens (such as GameScreen and PostGameScreen)
Drag+drop a .mp3 or .wma file into GameScreen
Write custom code in your game to transition between the two Screens - notice that the song continues to play despite the transition.
Things to remember:
You do not need to manually play Songs that have been added to Screens through Glue. Doing so may make your song restart.
Drag+drop the file from the GameScreen into the PostGameScreen's Files. Be sure that the name of the file is the same in both screens
Set the "DestroyOnUnload" value to "False" on the Song you want to continue playing. If you set it on both, then you will be able to go back and forth between the two Screens and the song will continue playing.
CSVs are a common way to define game data in FlatRedBall games. Examples of game data include the cost, damage, and rarity of weapons or stats of enemies like Orc, Dragon, and Elf. Usually this information is used in game logic to determine information like the maximum speed of a car or how much damage an attack deals. Fortunately Glue provides a flexible, powerful way to use CSV data in your game. This article provides an example of loading a CSV into an entity to control its movement speed.
The type of information can be categorized into three groups:
Simple coefficients like HP or AttackDamage for enemies in an RPG, or like Horsepower and Weight for cars in a racing game
Content information such as which .PNG to use for a enemy, or which .scnx to load for a level
Behavioral classes such as ability classes. Usually this feature requires usage of advanced CSV functionality such as lists and inheritance.
You will need a Glue project to follow along this tutorial. For information on how to create Glue projects, see this page.
In this tutorial we'll use an Entity called Animal. To create the Animal Entity:
Right-click on the Entities item in Glue
Select Add Entity
Enter the name Animal and click OK
Next we'll add a Sprite to the Animal Entity so that it can be seen in our game. To do this:
Expand the Animal Entity
Right-click on Objects
Select Add Object
Select the Sprite type
Enter the name MainSprite and click OK
The default Sprite will not have a Texture associated with it, therefore it won't be visible. To make the Sprite visible:
Select the MainSprite object
Set the ColorOperation value to "Color"
Set the Red value to 1
Set ScaleX to 64
Set ScaleY to 64
Next we'll create a Screen to verify that our Animal is working properly. To do this:
Right-click on the Screens item in Glue
Select "Add Screen"
Enter the name "GameScreen" and click OK
Move the mouse over the Animal Entity and push/hold the mouse button
Drag the mouse down to the newly-created GameScreen and release the button
Click "Yes" when prompted if you want to add an Animal to GameScreen
We will also want to set up our camera to be 2D. To do this:
Click on the Settings menu item
Select "Camera Settings"
Change "Is 2D" to "True"
At this point we have a basic project up and running: We can see our Animal Entity in our screen, although at this point the Animal Entity is simply a red square that doesn't do anything. Next we'll define a few animal types. To do this:
Right-click on the "Global Content Files" item
Select "Add File"->"New File"
Select the "Spreadsheet (.csv)" file type
Enter the name AnimalInfo for the file type
Once the file is created, double-click the file to open it in a spreadsheet editor. Modify the file so it contains the following information:
Save the file to cause Glue to update the AnimalInfo class to match the new data entered in the CSV file.
Next we'll make the AnimalInfo file create a Dictioanry - this will make working with the AnimalInfo easier. To do this:
Select the AnimalInfo.csv file in "Global Content Files"
Change the "CreatesDictionary" property to "True"
If you have used Glue before, you may expect the next step to be adding a variable called "Speed" to the Animal Entity which can be assigned from the CSV. Instead of creating a new variable for Speed, we'll instead add a reference to the entire AnimalInfo inside the Animal Entity. To do this:
Expand the Animal Entity
Right-click on the Variables item
Select "Add Variable"
Select the "Create a new variable" radio button
Select "GlobalContent/AnimalInfo.csv" as the type
Click "OK"
This new AnimalInfo variable can now be set in code or in Glue. For simplicity we'll set it in Glue; however, CSV variables like AnimalInfo are usually set in code according to player actions or game data. To set the variable:
Select the newly-created AnimalInfo variable
Now we can use the AnimalInfo variable in our Animal's behavior code. To do this, add the following code in the CustomActivity in Animal.cs.
Notice that the AnimalInfo and Speed variables are both supported in Visual Studio's autocomplete. Working with these Glue-created types and variables provides full autocomplete support so you know that you're writing the code correctly. Now try running the game and using the arrow keys on the keyboard to move your Animal entity. Also, try changing between the Bear and the Slug and you'll notice the Slug moves much slower. You can also modify the values in the CSV, then run your program again to notice the changes.
Memory Benefits: Since the types defined in CSVs are reference types (classes), then the Entity simply points to a reference of an AnimalInfo. While this might seem like a small gain (in the case of one Entity, it may not be a gain at all), consider a situation where you have numerous variables defined in a CSV, and you may have dozens or even hundreds of Entities that use these CSV values. In this case the reference characteristics of the CSV types is very beneficial. Furthermore, these references are not destroyed or recreated, so you will save on memory allocation and garbage collection if you are creating and destroying Entity instances.
Next we'll look at how to load content dynamically according to information in the AnimalInfo CSV. The approach we're going to show is a very powerful approach because it only loads information as needed. We'll be loading a Texture2D to apply to the Animal Sprite, however this approach can be used for any other data such as AnimationChains, Scenes, and ShapeCollections. Also, keep in mind that this is not limited to Entities - you can also use it on Screens to dynamically load data according to information in a CSV that defines level info. To add the textures to your project:
Return to Glue
Expand the Animal Entity
Right-click on the Files item under Animal
Select "Add File"->"Existing File"
Select the Bear and click OK
Repeat the above 3 steps and add the Slug
Select the Slug and also set its "LoadedOnlyWhenReferenced" to "True"
Now we need to write a little bit of code to modify the Sprite according to the AbilityInfo. To do this:
Open Animal.cs and delete the contents of CustomInitialize - we won't need this code anymore now that we're going to use textures.
Select the AnimalInfo variable under Animal in Glue.
Right-click on the "Events" item under Animal in Glue
Select "Add Event"
Verify "Expose an existing event" is selected
Verify "AfterAnimalInfoSet" is selected as the existing event
Click OK
Expand the Events item and select the "AfterAnimalInfoSet" event
Add the following code to the text box which appears on the left:
Next we'll modify the Sprite's variables. To do this:
Select the MainSprite object in Glue
Right-click on the "ScaleX" variable and select "Reset to Default"
Right-click on the "ScaleY" variable and select "Reset to Default"
Set the PixelSize varaible to .5
Set the ColorOpeartion to "Texture"
Right-click on Variables
Select the "Tunnel a variable in a contained object"
Select "MainSprite" as the Object
Select "Texture" as the Variable
Set the Texture to "Slug"
Set the AnimalInfo to "Bear"
So far we've shown how to set AnimalInfo in Glue. This is very handy for previewing things in GlueView, or for setting initial values; however it is likely that you will want to set values in custom code according to player actions or scripted events. To do this, you can simply access the AnimalInfo variable. To do this:
Create a Screen (you don't need to do this if your game already has a Screen)
Add an instance of Animal in your Screen
Add the following code in your Screen's CustomInitialize:
Note:You may need to fully-qualify
. You can do this with CTRL+dot. More info here
You can change this from Bear to Slug and the AnimalInstance will respond appropriately. Of course, you don't have to do this just in CustomInitialize, you can do this at any point, and on any Entity that supports this pattern, whether it is created in Glue, or created purely in code.
While this example may seem to be simple, the approach we've taken here is incredibly scalable, efficient, and flexible. However, as with all approaches there are some things to consider:
All Entities that are given the same CSV object reference will share the same exact instance. This means that if you change a value (like the Bear's Speed) it will apply to all bears. Also, the CSVs are not destroyed when Entities or Screens are destroyed if put in Global Content Files, so changes will persist until the program is restarted. This can all cause confusing behavior if you are editing the CSV but not seeing changes that you expect to see. You should never change these values in code unless you have a very good reason to do so.
If you intend on modifying values, such as allowing each individual instance to have a speed boost according to the Animal's level, you should make a custom property that uses the base value and returns a modified value.
The texture for the Bear and Slug will not be loaded until either is needed. Since the AnimalInfo is set after content is done loading, it is done on a primary thread. In other words, this means you may notice a slowdown or freeze when loading content if you are loading a lot of content. For simplicity this tutorial only covers how to load the content on the primary thread, but you may want to pre-load content that you know you will need in CustomLoadStaticContent.
Changes in the CSV will immediately show up in code (as long as Glue is open). This means that if you remove a column from the CSV (such as the Speed column), then that variable will be removed from the matching class. Be careful removing or renaming columns as this may break existing code.
Now you can run the game and you should see your Animal appear as a red square:
Enter "AnimalInfo" as the name
Set the DefaultValue to "Bear" using the drop-down
Save the following Bear.png and Slug.png images to your computer
Select the newly-added Bear file and set its "LoadedOnlyWhenReferenced" to "True"
Set its "CreatesEvent" variable to "True"
Run the game and you should see either the Slug or the Bear texture as your Entity.
A very common mistake when working with CSVs is to not properly order your variables. If you followed the tutorial above word-for-word, then your project will not have any variable order issues because there is only one variable - the CSV variable. However in larger Entities variable order problems can emerge. For starters, let's consider the example above where we have a single CSV variable which has a script that sets the Texture on a Sprite. The setup may look like this: Specifically, we have just a CSV variable, and an event that is raised when the CSV variable (called AnimalInfo) is set. Next we'll tunnel in to the Sprite's Texture. To do this:
At this point your Entity will show the Slug. You can verify this by either running GlueView, or by dropping the Animal Entity in a Screen and running the game. If you change the AnimalInfo variable, you will notice that the enemy continues to display the Slug no matter which value you set on AnimalInfo. The reason for this is because order matters. Since MainSpriteTexture appears below the AnimalInfo variable, it is set after. A good way to think about it is that variables are set from top to bottom - the same way that code is executed. You can fix this by right-clicking on the AnimalInfo variable and selecting to move it to bottom: This will make the CSV variable be set last. In general you will want to make CSV variables - and for that matter any variable which has events tied to it - as set last in your Entities and Screens.
Name (required)
Speed (float)
Texture
Bear
60
Bear
Slug
20
Slug
Glue screens and entities support folders inside of their Files object. Folders can be used to organize files and to support multiple files with the same name in a single screen or entity.
To add a folder to an existing screen or entity:
Right-click on the "Files" node under the screen or entity
Select "Add Folder"
Enter the new folder name and click "OK"
The newly-created folder will appear under the Files node. New files can be added to this folder.
Shader Effect Files (.fx) can be added to FlatRedBall projects. At runtime this produces an Effect object which can be used to perform custom rendering. FlatRedBall FNA projects require extra steps to use FX files as explained below.
Effect files require the use of the MonoGame Content Pipeline. If you are using the FlatRedBall Editor, this is automatically handled for you. You can verify that this is the case by checking the UseContentPipeline property.
FNA does not provide a content pipeline, and use of XNA Content Pipeline is discouraged because it does not function in newer versions of Visual Studio.
Instead, FNA recommends compiling shader files in the fxc.exe tool which is available as part of the Windows SDK.
The fxc.exe program can also be downloaded directly from the FlatRedBall repository: https://github.com/vchelaru/FlatRedBall/tree/NetStandard/FRBDK/PrebuiltTools/fxc
fxc.exe can be used to build effect files which can be consumed by FNA (and FlatRedBall FNA) using syntax similar to the following command:
In the command above, ShaderFile.fx
is the input file and ShaderFile.fxb
is the output file. FlatRedBall recommends using the extension fxb as the output file.
Once an .fxb file is built, it can be added to FlatRedBall just like any other file (by drag+dropping it into the FlatRedBall Editor) and it will be loaded into a standard Effect object.
The File Build Tools window allows adding command-line build tools for your files for converting from one file format to another. Conceptually file build tools are similar to the MonoGame or XNA Content Pipeline, but they are run through the command line as a separate process for each file.
File build tools can be used to convert from a custom or app-specific file format to a file format which is understood by FlatRedBall or an external library.
FlatRedBall provides a number of integrations for file build tools, and additional tools can be added to support any file format you would like to use.
To view the file build tools window, select Settings -> File Build Tools in FRB. A window should appear displaying the existing file build tools.
This window displays the existing file build tool assications. The list box on the left displays the file types that can be used as input (such as .odf files), the tool that is being used to conver the file (such as soffice.exe), and the output file format (such as .csv).
To add a new build tool, click the Add new build tool button. A new entry is added to the list box on the left which can be customized. As you fill in the properties for the new build tool, the Example text below is updated to show FlatRedBall will call the build tool for a built file.
If you add a file to your FlatRedBall project which has an associated build tool, then a popup is shown allowing you to select which build tool to use. For example, if you add an .ods file to your project, you will see a window similar to the following image:
You can leave the default, or use the dropdown to select a different builder. If you do not want to use a builder for this particular file, you can change the dropdown to <None>.
If a file has an associated file build tool, then the destination file is displayed in the FRB Editor. For example, if an .ods file is added, the destination file type (csv) shows. At runtime the source file is completely ignored and only the destination file is loaded.
Once a file has been added you can change its BuildTool property in its Properties window.
Any time the source file changes on disk (such as an .ods file), FRB detects this change and automatically performs a build. The command is displayed in the Output window.
Name is common The most common key for data is "Name". Unless you have a reason to not use this, consider using "Name" as your required property.
If you have a CSV without a "required" field, then Glue will not be able to create a Dictionary out of the CSV. Just like any other CSV, once you have saved this file, Glue will generate a class to match the CSV.
You may be wondering if it is a good idea to access objects using strings as the key. For example, let's consider the following line:
As you may have realized, this can be an unsafe line of code. What if, for example, the CSV changes so that it no longer contains the "Imp" object? Then that code would compile, and the error would only be discovered if that particular piece of code was executed. In other words, there is a risk of having hidden bugs associated to this line of code. First, we should mention that the reason the code above uses the hardcoded "Imp" value is to show the connection between code and the CSV. In final game code this is not good practice. Fortunately this type of code is usually not necessary. Let's look at the two most common situations where values are retrieved:
It is common to use values form CSVs in Lists. For example, let's say that the TestCsv used above is being used in a screen where the user picks which enemies to take into battle. Your code may look something like this:
This would dynamically loop through the list and create UI elements for each item in the CSV. If an item is added or removed, your code would automatically adjust to this and only show which values are appropriately.
Dictionary order is undefinedThe order of entries in a dictionary is not always the same as the order of entries in a CSV. For more information on retrieving the order, see this page.
In some cases you may need to access values directly. This can happen if:
You need to set a default value for something in code
You need to create a script in code, such as defining which enemies appear in a particular level
Fortunately the generated code creates const string values to allow you to access values in a compile-time-protected way. For example, the code above to access the imp could be more-safely done as follows:
The TestCsv class has one constant for each entry in the CSV, so the code above will work without any other code.
To load a font file:
Verify that you have the .fnt file and any referenced files already placed in the correct folder. This is important because both files must be part of the project.
Drag+drop the .fnt file into your Files folder - either in Global Content Files or the Files folder of a Screen or Entity
Your font file should appear in the Files folder.
This file can now be referenced on a Text's Font property.
CreatesDictionary is a property that tells Glue whether to deserialize a given CSV file to either a List or Dictionary. If you are accessing entries within a CSV according to some common key (such as the Name of an enemy type), then you should use the CreatesDictionary property to simplify access. The CreatesDictionary property is a property that only appears on CSV files, or TXT files which are treated as CSVs. You will be given the option to create a Dictionary or List when first adding new CSV files through Glue:
Glue must know which property you want to use as the key for the dictionary. Glue does this by looking for the "required" keyword in the header of your CSV. For example, the following CSV marks the "Name" as required:
The next step is to set the CSV file's CreateDictionary property to True in Glue:
Now that you have created a CSV that has CreatesDictionary set to true, you can access the file in code and get instances using the Name property:
IsManuallyUpdated controls whether the object created by loading a given file is manually updated. By default this value is false, indicating that objects are (by default) automatically updated by the engine. Setting this value to true can improve the runtime performance of your game, especially if your file contains a large number of objects. The downside to setting this value to true is that Velocity, Acceleration, Drag, Attachment, and Animations will not apply on any contained objects. Furthermore, any changes to objects (such as changing the position of Sprites manually) may not be reflected in rendering. This property is only available on files in Screens. Entire entities can be converted to manually updated using the method. For more information on manual vs. automatic updates, see .
Font files (.fnt) are produced by AngleCode's Bitmap Font Generator ( ). These files can be loaded through the FlatRedBall Editor and used on FlatRedBall Text objects. Note that the recommended approach for working with files is through Gum. If using Gum, you do not need to explicitly load font files in the FlatRedBall Editor.
FlatRedBall supports the use of a localization CSV file to simplify adding text to your game, whether your game uses a single or multiple langauges. The IsDatabaseForLocalizing property controls whether a CSV file is used as a localization file. When a spreadsheet is marked as IsDatabaseForLocalizing, the FlatRedBall Editor populates the LocalizationManager with the database when the CSV is loaded.
Because of this behavior, creating a game that supports localization requires very little code. Note that prior to FRB Editor (gluj) file version 14, generated code would make LocalizationManager.Translate calls. This functionality was inconsistent and difficult to work with, so as of file version 14, Translate must be called manually. For more information on this change, see the gluj/glux document.
The first step is to create a spreadsheet file that will serve as a localization database. To do this:
Right-click on "Global Content Files". Since most of your game will use text you will want to put the spreadsheet file under "Global Content Files"
Select Add File->New File
Select Spreadsheet (.csv) as the file type
Enter the name LocalizationDatabase for your new file
Click OK
The next step is to tell FRB that this file is a database for localization. To do this:
Select the newly-created LocalizationDatabase file
Change IsDatabaseForLocalizing to True
You will get a popup notifying you that all code needs to be regenerated. Click OK, close, then re-open the FlatRedBall Editor to force a full code regeneration.
The next step is to begin filling out the database. To do this:
Double-click the file to open it in a spreadsheet editing program such as Excel or Open Office
Change the top-left cell to read "ID (required)". Make sure "required" is not capitalized.
Change the first row in the second column to say "English", or whatever you prefer your default language to be.
Enter a string ID under the "ID" column. You may want to use a particular prefix to differentiate between string IDs and actual text - this can help you spot bugs in development. For this tutorial, I'll use "T_" before IDs. Therefore, I'll enter "T_Hello" for my first string.
Enter the English and Spanish versions of this string
Save the spreasheet
Before any localization can happen, you must tell the game which language to use. By default, the LocalizationManager will use index 0 as its default language. This is reserved as an "untranslated" language, which allows you to view string IDs in game. The first language (which is English in our case) begins at index 1. Therefore, to have your database translated, you must set the language index. To do this:
Open Game1.cs (or whatever your Game class is named)
Find GlobalContent.Initialize();
and add the following after it:
Be sure that this is set before ScreenManager.Start is called, or else the Screen will be initialized prior to the language being set.
To translate text, you can use the LocalizationManager's Translate method. For example, if you wanted to translate the string ID "T_Tutorial1" you could do so as follows:
You could then use translatedTutorialString in your game, such as by assigning the string to a Gum object's Text property.
So far we've covered static translations. Of course, you may want to have variables embedded in your text. The LocalizationManager supports this through a syntax that is very similar to the string.Format method. To support variables in your text:
Add an entry to your database spreadsheet using the { and } characters surrounding the variable index. For example, to inform the player of how many goals are left, you might enter: "You have completed {0} goals and you have {1} goals left."
In your code you can use the Translate overload which takes arguments to "format" the string. For example, your code may look like this:
Comments can be added to the ID column by using the //
syntax (similar to C#). Comments are ignored, allowing you to insert notes when creating localization files.
Games which display dialog using a dialog box may need to organize the dialog into mulitple pages. This is important to prevent sentences from being shown on multiple pages based on line wrapping. Also, games may include multiple speakers (see more info below).
Each string ID can contain multiple rows, wher each row serves as a different page. The following image shows three IDs. T_Dialog1 has 7 separate strings, beginning with the first as "Sounds like something crashed!", and ending with "Or aliens!!"
To access the strings, the TranslateMultiple method can be used, as shown in the following code:
By convention the first column in a localization file is the ID, and subsequent columns are for each language. Ofen times dialog requires additional information, such as the speaker of dialog. Keep in mind that each column can be used however you like in your game. For instance, if your game displays dialog along with the name of a speaker, you may want to have a column for the speaker.
The following shows a real-world example of a localization file which includes a column for the speaker, whether to flip the profile, and whether the text is automatically skipped. Note that these columns do not have any built-in behavior on their own. They must be read in and applied in your custom code.
Change the first row in the third column to say "Spanish" or the secondary language. You can continually add columns for any language you may want to support.
A NodeNetwork is a collection of nodes (points in world space), connected by links. A node network is used to perform "pathfinding" - the movement logic for navigating a map with obstacles.
Glue has built-in support for working with NodeNetworks. To add a NodeNetwork to your level screen:
Expand your level Screen in Glue
Right-click on the Files folder
Select Add File -> New File
Use the dropdown to select Node Network (.nntx)
Change the name of the file if desired
Click OK
To edit a NodeNetwork file, double-click the file in Glue and the AIEditor should open. If you have not set up the file associations, you can do this by following these steps:
Right-click on the node network in Glue
Select View in Explorer
Right-click on node network file (.nntx) in Windows Explorer
Select Open with...
Click More Apps to expand the list
Scroll to the bottom of the list and select Look for another app on this PC
Navigate to the location where the FRBDK was unzipped (this is also where Glue is located)
Find the AIEditor.exe and select that as the default application
Note that you may need to install XNA 3.1 Redistributable to run the AIEditor. For more information, see the AIEditor page.
The IncludeDirectoryRelativeToContainer property controls whether the generated code for a file includes the directory name in the property created. By default this is false, but setting it to true allows the addition of multiple files with the same name in the same screen, entity, or global content as long as the files are in different folders.
As mentioned above, by default this value is false. Therefore, files added to folders will not include their folder in the generated property name. For example, consider the InFolderTexture.png file which is contained in Folder1
This produces the following code in GlobalContent:
Notice the name in code does not include Folder1. If this file is copied into Folder2, the FlatRedBall Editor renames the copy as to avoid naming conflicts.
The generated code matches the name:
If the IncludeDirectoryRelativeToContainer can be set to true so that the generated property includes the folder name.
Once this is set, the property generated includes the Folder1 prefix:
This allows the same-named files to exist in different directories, because they will ultimately produce different property names. For example, copying the InFolderTexture.png file into Folder2 now results in the file copied without being renamed.
Each property is now uniquely qualified by its folder.
The LoadedAtRuntime property can be used to tell FlatRedBall whether to load a particular file when its Screen or Entity is created. By default the LoadedAtRuntime property is set to true, which means that an instance of a runtime object for the given file will be created. For example, if a PNG file is added to a Screen, then that Screen will contain a Texture2D instance.
If this value is set to false, then generated code will not contain a property for that file, nor will it automatically load the file. However, the file will still be part of the project, so you can load it and work with it in custom code.
There are a number of reasons to set LoadedAtRuntime to false.
LoadedAtRuntime is often set if a file is to be used in a custom way. For example, your game may include JSON files which you want to handle in custom code. LoadedAtRuntime can be set to false in projects which load file formats which are not natively understood by FlatRedBall (such as custom audio, texture, or model formats).
You can use LoadedAtRuntime if you want to selectively load files at runtime. For example, you may add multiple files to a Screen, but only load one of them depending on the state of the game. However, we recommend using the LoadedOnlyWhenReferenced property.
The LoadedAtRuntime and LoadedOnlyWhenReferenced properties may seem to do similar things, and you may be wondering when to use one or the other. This section will discuss why both properties exist and why to use them. By default LoadedAtRuntime=true and LoadedOnlyWhenReferenced=false. This means that a file will always be loaded whenever its containing Screen/Entity is loaded. LoadedOnlyWhenReferenced=true can be used to either delay the loading of a file, or not load it at all depending on certain conditions in your game. For example, a particular texture for a Sprite may not be used if the player does not pick to use that specific file type. LoadedAtRuntime=false tells FlatRedBall that you want a particular file to be added to Visual Studio, and that the file should be available to your program at runtime, but only through the file system. FlatRedBall will not generate any code to load the file at all. This means that custom code is in charge of loading the file completely, and that custom code can decide what to load the file into. For example, if FlatRedBall generates code to load a .achx file, then it must be loaded into an AnimationChainList. If LoadedAtRuntime is set to false, it can be loaded into a different type like AnimationChainListSave, or even loaded into a string or some other custom type.
A file's name represents its qualified location relative to the project's Content folder. By default, newly-created files will be added to a folder specific to the container Screen, Entity, or Gloabl Content Files. However, a file can exist outside of the default folder, so long as it is in the project's Content folder. For example, the following file is located in the Enemy entity, but its location on disk is <Project Content Folder>/Characters/Enemy_Shooter.achx:
Glue allows renaming of a file by changing the file's Name property. Renaming the file will perform the following actions:
Change the name of the file in the Glue project
Change the name of the file in the Visual Studio project (including all synced projects)
Change the name of the file on disk
Note that if the file is referenced by another file, Glue may not be able to update the reference. For example, changing a .PNG file which is referenced by a .TMX file may result in errors due to the .TMX file still referencing the old .PNG.
The MP3 file format often used for music. All information on this page also applies to the OGG file format. FlatRedBall loads MP3 files as Song instances. For more information on working directly with Songs, see the Song page.
To play an MP3 in your game:
Create or select the screen that you want to have the song
Expand the screen to see the Files item
Drag+drop the MP3 file from the explorer into a Screen's Files node.
Alternatively you can right-click on the Files tree node and select Add File->Existing File and browse to the location of the MP3
Note that by default the dropped song uses the Microsoft.Xna.Framework.Media.Song runtime type. See below for more information on this compared to other types.
The song automatically plays when the Screen starts. The song automatically stops playing when the Screen exits. You do not need write any code to play or stop the music. If a Screen contains multiple audio files, then additional settings and logic are needed to select which song should be played.
The song that is played uses the AudioManager.PlaySong method, so any properties set on the AudioManager (such as MasterSongVolume) apply to the playing of the song. For more information, see the AudioManager.PlaySong page.
FlatRedBall provides sample songs which you can use to test song playing. To add a new song to your game:
Right-click on the Files folder in a Screen
Select Add File -> New File
Search for Song
Select one of the song types and click OK
For more information on NAudio, see below.
FlatRedBall provides simple song controls in the Song tab. To view the Song tab:
Add a song file to your game (as shown above)
Select the newly-created song
Select the Song tab
By default a Song added to a Screen plays when the Screen starts and stops when the screen is destroyed. To have songs persist between Screen transitions, check the Keep Playing After Leaving Screen checkbox. Note that if this is checked, the song continues to play only if either of the following conditions are true:
The new screen does not specify a song to play
The new screen does specify a song to play, but the song is the same as the song that was playing in the previous screen
If the new screen specifies a different song, then the new screen's song begins playing even if the old song's Keep Playing After Leaving Screen checkbox is checked.
You can add multiple songs to your Screen if you would like to select which one to play in custom code. To do this:
Create a Screen
Add any number of .mp3 files to your Screen
Set each of them to LoadedOnlyWhenReferenced. For more information on this property, see the LoadedOnlyWhenReferenced page.
In custom code, play the song you would like to play. For example, if your song is called MySong, then add the following code:
For more information on the AudioManager, see the AudioManager page.
FlatRedBall provides built-in support for NAudio. When a new song is added through the Add File -> New File right-click option, a window allows the selection of NAudio or (MonoGame) Songs.
Already-added songs can be changed between Song and NAudio_Song by changing the runtime type on the file's properties.
Both MonoGame/FNA Song
and NAudio_Song
share much of the same functionality. Both:
Can be managed through the Song tab in FlatRedBall
Can be played through AudioManager.PlaySong
Respond to the AudioManager's MasterSongVolume if played through AudioManager.PlaySong
NAudio provides additional functionality for playing songs, so games which need more control over music playing may want to use NAudio_Song.
By default, files added to Glue will automatically be added to all associated Visual Studio projects. Some files, however, are only needed on some platforms. Files can be excluded from certain projects through the Platform Inclusions tab. Note that this tab will only appear when a file is selected in Glue project which has more than one code solution (added through Project Sync).
Excluding a file from a project will exclude the project from the Visual Studio .csproj or .contentproj, but the code generation currently does not consider whether the file has been excluded. This means that code generation may throw a file not found exception (or equivalent) when the project executes on a platform from which the file has been excluded. For this reason, files should only be excluded when LoadedAtRuntime is set to false.
The "Project Specific Files" entry allows you to create files which are specific to a project. While most FlatRedBall types can load on all platforms, your project may need certain files to only be loaded on certain platforms. Reasons for this include:
Certain platforms may not support certain file types. For example, at the time of this writing iOS does not support loading .WMA files as Songs.
Certain platforms may use different size or quality of content for performance or download reasons. For example, your game may use a larger resolution on the PC than on Windows Phone 7.
You may be using synced projects to create demo or kiosk projects with limited content. In this case you may exclude content from your data (such as reducing the number of characters available in a CSV).
UNDER CONSTRUCTION
Most files in Glue are automatically loaded. When these files are loaded, the information which is loaded is stored in an object so that you and the FlatRedBall engine can access this information. The RuntimeType property sets which type of object the file will load into. In most cases the RuntimeType will be automatically set for you by Glue to the most common object type for a given file; however in some cases you may need to change this.
ShapeCollections can be created through files. To add a ShapeCollection to a Screen or Entity:
Create a Screen or Entity which will contain the ShapeCollection file
Right-click on the Files item
Select "Add File"->"New file"
Select "Shape Collection (.shcx)" as the file type
Click OK
Files in Glue can support "external" or "source" files. A source file is a file which must be processed before it can be used by Glue/FlatRedBall. Source files enable using files created by 3rd-party applications to be used in FlatRedBall. For example, the source file functionality would allow you to use a .psd file (Photoshop file) as a texture file. However, for a source file to be usable, a specific program (which is often referred to as a "builder") must exist to convert the source file to a file format which is understood by Glue/FlatRedBall. For example if the source file were a .psd file, then the destination might be a .png, and a PSD to PNG builder would be needed.
To add a file with a source file:
Right-click on the "Files" item under a Screen or entity
Select "Add Externally Built File"
Glue must be told how to convert a source file to the file type that Glue understands. To do this builders must be set up. To set up a builder, see the article on builders.
The .splx file format is an XML file that stores a list of Splines. For more information on using Splines in code, see the Spline page.
To add a new SplineList file:
Create a Screen or Entity which will contain the SplineList file
Right-click on the Files item
Select "Add File"->"New file"
Select "Spline List (.splx)" as the file type
Click OK
Texture2D instances can be created through Glue by adding image files to entities, screens, or global content. By default, any image file added to Glue will be loaded when the containing screen/entity is created. Files added to Global Content can be accessed as soon as the game launches from any screen or entity.
Texture2D's which are added to a screen or entity can be accessed by objects in the same screen or entity. The following steps show how to add a Texture2D to an entity and reference it on a sprite:
Create an entity with a Sprite object. See the Sprites in Glue page for more information.
Drag+drop a .png file from any location on your computer onto the entity's Files object. Note that if the file is not located outside of your game's Content folder, the file will be copied.
Select the Sprite object
Locate the "Texture" property
Use the drop-down to select the desired texture
The sprite will now use the selected texture.
Texture2D instances added to Glue can be accessed in code. If a Texture2D is added to a screen then the custom code for that screen can access the Texture2D variable name matching the name of the file (excluding extension). Similarly, if a Texture2D is added to an entity, then the custom code for that entity can access the Texture2D as well. If a Texture2D is added to global content, then any code in the entire game can access the Texture2D at any time. For this example, consider the CharacterEntity shown in the example above. The custom code for CharacterEntity can access the Character PNG as follows:
Similarly, files added to global content can be accessed in code through the GlobalContent object. For example, consider a file Background.png which could be added to global content:
This file could be accessed in code as shown in the following snippet:
The UseContentPipeline property on files controls whether a file is loaded using the content pipeline. By default files do not use the content pipeline - they load "from file".
Files which are added to Glue (such as .scnx and .png) are considered "raw" files. These are files which generally use a standard file format which can be edited in a variety of applications. For example, .png files can be opened in any image editing software. The .scnx file format is a simple XML file which can be opened in many of the FRBDK tools as well as in any text editor. Content pipeline files are "processed" when the program builds to create .xnb files. These files often are smaller and load faster in your game. There is also a small security benefit to using the .xnb file format. Therefore you may want to use the content pipeline on your files prior to shipping your game.
If .xnb files are smaller, faster, and safer you may wonder why Glue offers a from-file option...and why it defaults to from-file. The first reason is build time. By default files which are built as from-file do not have to built when the game is built - they are simply copied to the output directory. This process is much faster than using the content pipeline. Another reason is not all files support a content pipeline option. For example, Gum and Tiled plugins produce files which are loaded "raw" and currently do not support using the content pipeline. The recommended approach is to use from-file loading whenever possible throughout development, and switch to using the content pipeline near the end of development for file formats which support it.
To switch to the content pipeline:
Select a file in your project
Your game will now load this file from content pipeline.
Note: Not all file formats support using the content pipeline. Also, not all platforms support the content pipeline.
Many files (like .scnx files) depend on other files (like .png files). When you switch between using the content pipeline or loading "from file", dependent files must also be modified in your Visual Studio project. Glue will handle this for you - you just have to set whether the file in Glue is part of the content pipeline or not and Glue will automatically manage your content project for you.
Change the "UseContentPipeline" property to True
Wav files can be used for sound effects in FRB. Wav files, which are uncompressed, are used because compression can introduce latency (delay before the sound plays).
The FRB Editor can use .wav files to create two types of objects:
SoundEffect
SoundEffectInstance
By default .wav files are loaded as a SoundEffect, which is the simplest object to work with. The SoundEffect object allows fire-and-forget sound effects. Once a .wav file is added to FRB, the SoundEffect it creates can be used with a Play call as shown in the following code:
Once a SoundEffect Play call is made, the sound cannot be modified. It will play to completion and then stop. By contrast, SoundEffectInstances are single-instance sounds which can be played, and manipulated after playing. For example, the following code plays a sound, but then adjusts its volume after 0.5 seconds:
To change whether a .wav file is loaded as a SoundEffect or SoundEffectInstance, change its RuntimeType as shown in the following image:
To add a .wav file to FRB:
Right-click on a Screen or Entity's Files item
Select Add File->Existing File
Navigate to the location of the .wav that you would like to use and click OK
You should see the .wav file in your project:
Alternatively you can drop WAV files into your project from Windows Explorer:
Open your project in the FRB Editor
Locate the WAV file you would like to use on disk
Drag+drop the file from Windows Explorer into your project in the desired Files folder. Note that if the file is not already a child of your Content folder, the file will be copied to the desired folder and the original file will be left on disk in its original location.
Once a .wav file has been added to your FRB project, your Screen, Entity, or GlobalContent includes an instance of a SoundEffect in generated code.
The following example assumes a file named GunShotSound.wav, so the code instance is named GunShotSound. The following code can be added to CustomActivity to play the sound when the space bar is pressed:
For the full SoundEffect documentation, see the MonoGame SoundEffect page.
For more information on SoundEffect in FlatRedBall, see the SoundEffect page.
FlatRedBall MonoGame requires WAV files to be built and loaded from XNB files. XNB files are built by the MonoGame content pipeline. This happens automatically when a WAV file is added to your FlatRedBall project, and will also happen if the WAV file ever changes.
WAV files are added as XNB files to your Visual Studio project. For example, the following SoundEffectFile.wav is part of GameScreen:
This file is automatically added to your Visual Studio project by FlatRedBall, as shown in the following screenshot:
WAV files can be explicitly rebuilt in the FRB Editor by right-clicking on the file and selecting Rebuild Content Pipeline File (.xnb).
When the file is built, the output window displays information about the build so you can diagnose problems.
FlatRedBall supports wildcard files in the .gluj file. At the time of this writing wildcard files are only supported in Global Content, but future versions of FlatRedBall may expand this. Wildcard enable the automatic adding of files to your FlatRedBall project based in their location on disk. This can make managing a large number of files much easier than manually managing the files.
The easiest way to add a Wildcard entry in the FlatRedBall is to first add a single file to your project which has all of the desired settings. For example, consider the following project which has a single file added to Global Content Files named TextureFile.png:
Currently, wildcard entries must be manually added to the FlatRedBall project (.gluj). To do this:
Open the folder location of the project
Open your game's .gluj file in a text editor such as Visual Studio Code
Locate the file entry of the file in your project. It should appear under the GlobalFiles section.
Change the file's Name property to be a wildcard file.
Save the file in the text editor
After you save the file the FlatRedBall Editor displays the file with a wildcard (*) icon to indicate that it is added as a wildcard file.
Now you can add new files to disk and they will automatically appear in the FlatRedBall Editor (assuming they match the wildcard pattern.
Be careful - wildcard files are added automatically even if their name violates the naming convention of FlatRedBall. In other words, normally files cannot contain spaces or dashes, but FlatRedBall will add these files to your project even if the file names contain invalid characters. For example, if you copy and paste a file, Windows automatically appends " - Copy" to the name of the file, and this will appear in the FlatRedBall Editor.
The code generator will attempt to remove invalid characters when generating the GlobalContent code.
Of course, since characters are either removed (such as spaces) or converted to valid C# property characters (such as underscores), it is possible to have multiple properties with the same name which would result in a compile error. We recommend keeping your file names named as valid C# properties.
FlatRedBall supports a number of wildcard patterns for adding files to your projects. The following examples explain the possible wildcard patterns:
Name": "GlobalContent/*.png
- Add all files in the GlobalContent folder with the PNG extension
Name": "GlobalContent/*.*
- Add all files in the GlobalContent folder with any extension
Name": "GlobalContent/*
- Add all files in the GlobalContent folder with any extension. Note that this is the same as Name": "GlobalContent/*.*
.
Name": "GlobalContent/**/*.png
- Add all files in the GlobalContent folder and any subfolder of GlobalContent with the PNG extension
Name": "GlobalContent/**/*.*
- Add all files in the GlobalContent folder and any subfolder of GlobalContent with any extension
If a file is included explicitly and also through a wildcard, then the file will appear twice in the FRB Editor and this will produce an error. For example, consider a project with the file MyTexture.png added to the GlobalContent folder through a wildcard and also explicitly added. The JSON for the project might look like this:
This results in the file appearing twice in the FRB Editor, and in an error appearing in the Errors tab.
If wildcards are needed, then the explicitly-added file must be removed. It can be removed by editing the .gluj, or by removing it through the tree view in FRB. If your project needs an explicitly-added file while also using wildcards, then you must organize your content in such a way as to exclude the explicitly-added file from the wildcard pattern, such as by adding all wildcard files to a subfolder.
Global Content Files is a special FlatRedBall folder used to store files which are always available when a game is running.
Global Content Files are loaded right when the game starts running, and are never unloaded when transitioning between screens. By contrast, files which are tied to specific screens or entities may not be available until the screen is created, or until an instance of the entity is created, and these files may get unloaded when the screen is destroyed.
The LoadAsynchronously property tells Glue to load all content in Global Content Files asynchronously. In other words, the first screen (StartUp Screen) will load even if Global Content Files hasn't yet finished loading its content.
By default LoadAsynchronously is false, which means all content must finish loading before the first screen is displayed.
LoadAsynchronously is safe to use even if the first screen depends on content in Global Content Files. If any code asks the GlobalContent object for a file, but the file has not yet loaded, the primary thread will be stopped until the content is loaded. Therefore, the content will either already be loaded (since it may have been loaded asynchronously prior to the request for the content) or the primary thread may pause until that particular content is finished loaded. If the primary thread is paused, it will be resumed once the requested content has been loaded, rather than waiting for all files in GlobalContent.
Glue generates a Reload function in GlobalContent which simplifies reloading CSV files. Reload can only be used to reload CSV files from disk.
Reload is useful for games which may change CSVs during execution, such as games that download new data from a remote server. Reload will change the member that is passed to the function but will not re-assign properties that have been set from rows in the CSV. In other words, any objects that reference the old CSV must be re-assigned to values in the new CSV.
The following assumes that the Global Content Files folder in Glue contains a file called EnemyDefinition.csv:
CSV files are used by Glue to control which file types are available, and to tell Glue how to generate code to load them and create instances in code. Standard FlatRedBall types (such as Scene and AnimationChainList) are represented in a CSV file which is stored in the following location: Global content types:
Project-specific types:
Glue allows for the creation of additional CSVs which can define how to load and generate code for custom content types. The New Content CSV menu option creates a new CSV file which Glue will automatically load on startup (Glue must be restarted for new or changed files to be used).
To create a new CSV file:
Select the Content->"Additional Content"->"New Content CSV..." menu option
Enter the name of the CSV to add. Since Glue can support any number of CSVs we recommend creating new CSVs for categories of objects rather than continually appending to existing CSVs.
Select whether you would like this new CSV to apply to all projects or only your current project. This will impact the location of where the CSV is saved.
An explorer window will appear displaying the newly created CSV (along with any other existing CSVs)
Objects can be instantiated directly inside the Objects folder of Screens or Entities. Typically these instances are of standard types such as Sprite or TileShapeCollection. Also, the type of instances can be entity types, such as an instance of a Player in the GameScreen. If your game includes a special type which is not an entity type, the FlatRedBall Editor can display this type by adding it to a custom type CSV.
As an example, consider a custom PositionedObject class. The class doesn't need to have any functionality, it just needs to be defined in your project so that generated code can work with it. Therefore, an empty class will do, as shown in the following snippet:
Now we can add this type to a custom CSV.
Select Content -> Additional Content -> New Content CSV...
Enter the name ProjectSpecificContent and click OK
A folder should open displaying the newly-created ProjectSpecificContent.csv. Double-click it to open it in the default spreadsheet application installed on your machine
Enter the values for properties as specified below:
Friendly Name: CustomType
CanBeObject: true
QualifiedRuntimeTypeName: QualifiedType = CustomTypeProject.CustomType (this should be your qualified name)
AddToManagersMethod: FlatRedBall.SpriteManager.AddPositionedObject(this)
DestroyMethod: FlatRedBall.SpriteManager.RemovePositionedObject(this)
ShouldAttach: true
IsPositionedObject: true
AdjustRelativeZ: this.RelativeZ += value
For examples on how to work with this CSV file, see the ContentTypes.csv file which is located relative to the GlueFormsCore.exe project, or in the Visual Studio project if you are building from source. Once you have modified and saved the CSV, shut down and restart the FlatRedBall Editor. If the file was loaded correctly you will see output which looks similar to the following text:
You can now right-click on the Objects under any Screen or Entity and you should see your type.
Since this type is also a PositionedObject, your entities can use it as their base.
By default instances of new types that you create do not have any variables visible in the Variables tab. You can change this by adding variables which you would like automatically visible by modifying the VariableDefinitions column. The standard ContentTypes.csv file provides a great example of how to define VariableDefinitions. One of the largest set of variables is on the Sprite's VariableDefinitions column.
Add as many variables as you would like available. Also, you are not limited to PositionedObject properties. If you add new properties to your type in code, you can expose these to the FlatRedBall Editor by modifying the VariableDefinitions column.
All files in GlobalContent have a getter and a setter. This means that you are able to set files at runtime if you would like to update them in custom code. This section will discuss the details of setting files, and why you may want to do this in your projects.
Setting files in GlobalContent at runtime is usually done in situations where you would like the files in global content to be set according to some condition in your game such as being in a demo vs. fullly purchased mode, or if you are going to be downloading updated versions of files from a remote server. The example we will use here is a situation where your game has a demo and full version. Specifically, the demo version only provides access to a few levels, while the full version provides access to all levels in your game.
To create a new project, do the following:
Open Glue
Create a new XNA 4 PC project
Name the project CsvReloadTest
To create our CSV files:
Right-click on Global Content Files and select "Add File"->"New File"
Select "Spreadsheet (.csv)" as the file type
Name the file LevelInfo.csv
Repeat the above steps to create a new CSV file called DemoLevelInfo.csv
Next we'll want to make sure that both CSVs have the same columns - since one will replace the other they both need the same columns to be compatible. Mine look like this:
DemoLevelInfo.csv:
LevelInfo.csv:
We have two files - LevelInfo.csv (which contains all of our levels) and DemoLevelInfo.csv which will contain demo levels. If the game is in demo mode, we will replace LevelInfo with the contents of DemoLevelInfo at runtime.
We want DemoLevelInfo.csv to use the same class as LevelInfo.csv. To do this:
Right-click on DemoLevelInfo.csv
Select "Set Created Class"
Click "New Class"
Enter the name "LevelInfo"
Select the newly-created LevelInfo class
Click Use This Class
Click "Yes" if asked if you should remove unused file
Click Done
For more info on Set Created Class, see this page.
First, let's create a Screen that uses LevelInfo to display which levels are currently available in the game:
In Glue, right-click on Screens
Select "Add Screen"
Name your Screen "LevelSelectScreen"
Now let's make a Text object in our Screen. This Text object will display available levels, as determined by looking at LevelInfo in GlobalContent:
Right-click on the LevelSelectScreen's "Objects"
Select "Add Object"
Verify "FlatRedBall or Custom Type" is selected
Select "Text"
Click OK
Now that we have a Text object, let's set its Text in CustomInitialize of our Screen:
Open your project in Visual Studio
Navigate to LevelSelectScreen.cs
Add the following code to CustomInitialize:
All files in GlobalContent have setters. This means that you can simply set the properties and the rest of your project should use the new instance - assuming you do so before your project accesses these files. We'll add some code to Game1.cs to set our game into demo mode. To do this:
Open Game1.cs in your project in Visual Studio
Add the following code after GlobalContent.Initialize and before ScreenManager.Start in Game1.cs:
In this case our code is simply setting the LevelInfo to DemoLevelInfo - overwriting our LevelInfo without making any checks. If this were a real game, we might want to check if the game should really be in demo mode or not. Therefore, you would wrap this assignment in some checks. Also, we had to put our replacement in a very specific place in the Initialize function in Game 1:
It had to be after GlobalContent.Initialize because we needed DemolevelInfo to already be loaded
It had to be before the ScreenManager's Start function because this had to be set prior to the first Screen being initialized.
Although we assigned one CSV in GlobalContent to another CSV in GlobalContent, this is not a requirement. The LevelInfo could be assigned from a completely different file using the CsvFileManager. This means that you could download a CSV from a server somewhere, and assign LevelInfo to a new Dictionary<string, LevelInfo>, then deserialize the file into that dictionary using CsvDeserializeDictionary. If you are doing any form of assignment on an object in GlobalContent, and you are assigning to something that is not part of GlobalContent, then you can assign the property in GlobalContent before GlobalContent is initialized. GlobalContent will respect this assignment and will not overwrite it when initializing.
If you run your game now you will see that the game has 5 levels (according to LevelInfo):
Now if you run your game you'll see that only the first level is available:
Name (string, required)
TimeLimit (float)
Level1
100
Name (string, required)
TimeLimit (float)
Level1
100
Level2
125
Level3
125
Level4
160
Level5
200
This article discusses how to modify your content CSV to support creating a "runtime object" from a file. A runtime object is an object which typically has the following characteristics:
It has every-frame activity
It has some kind of membership in the FlatRedBall managers (such as it adds Sprites to the SpriteManager, PositionedObjects to the SpriteManager, or Text instances to the TextManager)
It must be removed or destroyed
To distinguish between the two, a non-runtime object would be an object that simply represents the contents of a file such as a Texture2D or a "save" object. A runtime object is an object that is typically visible or has collision, and interacts with other runtime objects ( for example Sprites, Entities, or shapes).
For this article we'll start with a very simple setup:
Create a Glue project
Create a single Screen in this Glue project
Create a file for the desired type you're working with
Place the file under your newly-created Screen's files folder on disk
For this article we'll assume your file is called MyFile.ext and the Screen is called MyScreen.
Next we'll add/modify the CSV to handle this new file. For this we'll assume that the runtime object made by MyFile.ext is "MyRuntimeObject" and the save object is "MyRuntimeSave". Therefore, the CSV should look like this:
Now that you have MyScreen and MyFile.ext created:
Right-click on your MyScreen's Files item
Select "Add File"->"Existing File"
Select MyFile.ext
At this point your object should be loaded, created as an instance, and added to managers. You can verify this by either looking in the generated code for "AddToManagers" or running the game (assuming AddToManagers will properly make your object visible).
Note: So far this example uses a Screen. The reason for this is because creating runtime objects from files is slightly easier to do in Screens. If an object that can be a runtime object is added as a file to a Screen, Glue assumes that you intend to add the object to managers. Therefore, no additional work is needed aside from simply adding the file to a Screen. Entites require a little more work, as we will see in the following section.
Entities require a small amount more of work to create objects. Specifically you must both add a file and also add an object to be created from this file. To do this:
Create a new Entity. I'll use the name "MyEntity"
Right-click on the Entity's "Files" item
Select "Add File"->"Existing File"
Select MyFile.ext
Right-click on MyEntity's "Objects" item
Select "Add Object"
Select the "From File" option
Select MyFile.ext (which will probably include a folder path"
Name the object appropriately. I'll use the name "MyFileObject"
Change the newly-created Object's "SourceName" to "Entire File (MyRuntimeObject)
Files loaded by Glue can be used to either create "save objects" and "runtime objects". Save objects are objects which can be loaded directly from file. Save objects are typically not added to the FlatRedBall Engine, nor do they require loading other files which use content managers (such as Texture2Ds). Runtime objects are typically used in games. Runtime objects can be used for one or more of the following purposes:
To render graphics to the screen
To perform collision
To position or manage other runtime objects
An "add to managers" method which is responsible for adding the object and any contained objects to the FlatRedBall Engine
A "remove from managers" or "destroy" method which removes the object and all contained objects from FlatRedBall managers
Objects which follow a number of guidelines regarding add to managers and destroy can be used in Glue in advanced and useful scenarios. This article discusses these guidelines which can be used when constructing runtime objects to be loaded by glue.
The code which adds an object and its contained objects to FlatRedBall managers should:
Be a separate call from the code that instantiates the runtime object
Should either not be called by the code that instantiates the runtime object, or should be optionally called
Should be a public method.
Should not load any data from-file. All from-file loading should be done in instantiation/initialization. .
The reason for the separation between initialization and add to managers enables Glue to do the following when your runtime object is contained in a Screen or Entity:
Instantiation of Screens and Entities on a non-primary thread.
Pooling of Entities.
The ability to be added to a Layer (instantiation and layering are typically done on two separate calls for FlatRedBall objects)
All runtime objects should have some type of destroy method/logic. The destroy method is responsible for removing the object and all contained objects from FlatRedBall managers.
Runtime objects which are created from files should support a Clone method. The reason for this is because a single instance may be loaded from file, but then multiple instances may be needed if multiple Entities use the same file.
The "Scan for Unreferenced Files" menu option performs a scan of all files referenced by the currently loaded Visual Studio project. Any file which is not directly or indirectly referenced by a file in Glue will be identified as unreferenced. Glue does not do a source-code scan of your project as it would be difficult and in many cases impossible to do so, so files referenced only by code may still be considered unreferenced. To keep this list accurate game projects should include all relevant files in Glue, especially as this helps make content loading/unloading more predictable. Once the scan completes Glue will present a window with all unreferenced files. Once a file is selected it can be removed from all projects (main and synced) by clicking the "Remove references" button:
Runtime objects are often either directly added to FlatRedBall managers (if they inherit from the or include objects which are added to managers). In this case the runtime object needs two calls:
FriendlyName (required)
CanBeObject(bool)
QualifiedRuntimeTypeName
QualifiedSaveTypeName
Extension
AddToManagersMethod
CustomLoadMethod
DestroyMethod
CanBeCloned
CustomCloneMethod
MyRuntimeObject (.ext)
TRUE
QualifiedType = ProjectNamespace.RuntimeTypes.MyRuntimeObject
ProjectNamespace.SaveTypes.MyRuntimeSave
ext
this.AddToManagers()
{THIS} = ProjectNamespace.SaveObjects.MyRuntimeSave.FromFile("{FILE_NAME}").ToRuntime()
this.Destroy()
TRUE
this.Clone()
The Content Pipeline Settings menu item opens the Content Pipeline tab in Glue. This tab controls settings for content pipeline behavior in Glue.
This plugin is still in the early stages. Additional options may be added in the future to control how content is built.
This checkbox controls whether all PNGs in the project will be loaded using the content pipeline. By default this value is false. Checking this value will perform the following actions:
Glue will build all PNGs into .XNB files in a special folder depending on the project type. Each project will have a separate folder with XNBs
Glue will change all PNG references for all projects to point to the built XNB files
Glue will generate aliases for all PNGs so that no code changes are required when referencing the PNGs
Using the content pipeline for PNG files has some benefits, but these benefits also have some downsides. Fortunately, your project can switch switch between using the content pipeline and loading PNG's directly at any point simply by checking or unchecking the Load all PNGs using Content Pipeline checkbox.
The biggest benefit of using the Content Pipeline is that image files loaded from XNB will load faster compared to using PNGs. Note that the slower-loading of PNGs is a FlatRedBall-specific cost. Readers who are using MonoGame without using FlatRedBall may not see speed improvements when moving to XNB loading. The reason for the improved load time is because FlatRedBall performs extra processing when loading PNG files so Texture2Ds include premultiplied alpha. If a Texture2D is loaded from a content pipeline XNB, no additional processing is necessary. This additional processing can result in a significant load time increase - in some cases more than doubling the amount of time a screen takes to load. Content Pipeline XNBs may also use hardware compression (depending on the platform), which results in Texture2D instances using less video memory, and rendering more quickly due to improved caching.
When using the Content Pipeline, PNG files must be converted to XNB files. This conversion is performed whenever a PNG is changed (either when saved locally or when downloaded through version control). Large projects with multiple platforms may take some time (such as over 1 minute) to process all XNB files. Some platforms do not compress image XNBs, which means a corresponding XNB may take more space on disk than the original PNG. Fortunately, this is not as important on some platforsm such as Android because the .apk file itself is zipped.
Typically FlatRedBall loads files using extensions, such as: var texture = FlatRedBallServices.Load<Texture2D>("myImage.png"); However, in XNA/MonoGame, files loaded through the content pipeline do not use an extension. For example, to load a texture from a .XNB file (a processed content file), the extension would be omitted, as shown in the following code: var texture = FlatRedBallServices.Load<Texture2D>("myImage"); The content pipeline settings in Glue are intended to be swapped without requiring any changes to custom or generated code. Therefore, even when using the content pipeline, the code must be able to load a file with its extension, such as "myImage.png". To resolve this, Glue generates a method called SetFileAliases . This method will associate the file with its extension with the file without its extension. Internally when FlatRedBall is told to load a file, it will check if that file exists in the FileAliases list, and if so, it will use the alias. Therefore, any code written which may reference a file by extension does not need to change when switching to the content pipeline.
Each entry (usually one row) in a CSV defines how a file type is loaded into a runtime object. This code tells Glue how to generate code to load and interact with various file formats. Before creating an entry in a CSV, you will first need to create a new file format (or use an existing file format) which can be loaded along with an object that the file can be loaded into. For example, if you are using a custom XML file to define the layout of a level in a puzzle game, you may first create an XML file which can contain information about the level, then a class which can hold the information loaded from the XML file. Once you have created this file format and a class to hold its information, will want to test out the loading of this data in custom code first to verify that it is working correctly before you begin to integrate it into Glue.
Note: There are typically two types of objects that a file is loaded into in FlatRedBall. The general terms for these types of objects are "save objects" and "runtime objects". Save objects are objects which are typically not used directly in games. They serve as objects which can hold data in a format that is very similar to how the data is stored in a serialized (XML, CSV, or other format) state. Runtime objects are typically objects which are used in actual games. Runtime objects typically have some type of graphical component, often require a content manager to create, and have some component which is added to FlatRedBall managers.
For an example, we'll use custom file format (.lin) and load it into a new class called LinesOfText which will be a class that contains a string array. The LinesOfText object is somewhat of a trivial class, but again we'll create and use this for the sake of keeping the tutorial simple.
For this example we'll use the following LinesOfText class:
If you're following along, create a new class in your project called LinesOfText, then paste the text above into the newly-created class.
Now that we have the runtime type (the LinesOfText class) defined and in our project, we can information to a custom CSV file. To create the CSV file:
Open Glue
Select the Content->"Additional Content"->New Content CSV..." menu item
Enter the name LinesOfTextContent. Typically you would call the CSV to indicate the library or game that is associated with the content types.
Click OK
Next we'll add information to the new CSV:
Open the newly-created CSV file in a spreadsheet program (such as Excel or OpenOffice Calc)
Add data to the following columns:
The CSV file contains many fields which can be used to customize the way Glue interacts with your file and runtime types, but the list above is the minimum requirement for loading a custom file type. In other words, we don't cover all available columns in this tutorial, just the necessary ones. The columns are listed together in the table above to keep the example smaller, but they may be spaced out in the CSV. Let's look at the individual columns to understand what they mean.
The "FriendlyName (required)" column specifies the name of the file type as it appears in the new file window's drop down. It is marked as "(required)" because each entry can contain multiple values for some of the add methods (which we don't cover in this tutorial). The most common format is to list the runtime class name along with its extension in parenthesis. In our case: "LineOfText (.lin)"
The QualifiedRuntimeTypeName column specifies the name of the runtime object that is created when the file is loaded. This is the type of the member that will be added to the Screen or Entity that contains the class. The name must be fully-qualified as to avoid conflicts with same-named types in different namespaces, and to enable Glue to add instances to generated code without generating compile errors. The reason "QualifiedType = " must be prefixed is because as of September 10, 2012 Glue supports platform-specific runtime types. We won't cover how to use that functionality in this tutorial.
The QualifiedSaveTypeName is the name of the class that is responsible for loading the file from its file format and creating an instance of the runtime object. In our case we simply use the same class (LinesOfText) as both the "Save" object as well as the runtime object, so the two types are the same. Some types (like Scene) have separate "Save" objcts (like SceneSave).
The extension tells Glue which extensions to associate to the runtime type. This is used when creating new files, when adding existing files, and if multiple types use the same extension, to allow the user to specify the type. In our case the extension is "lin".
This is the line of code (or multiple lines of code) which Glue will use to instantiate the runtime object. In this case two parts of the line are replaced. {THIS} is replaced by the name of the instance that is being created, and {FILE_NAME} is replaced by the file name to load.
Once you have created/modified the content CSV file, you will need to restart Glue. After Glue starts, you can add a .lin file to your project as follows:
Create a Screen or Entity to hold the new file
Right-click on Files and select "Add File"->"New File"
The drop-down under "Select the file type:" should include an entry for the .lin file type. Select "LineOfText (.lin)"
Click OK
How does Glue make new files? Since Glue does not understand the structure of custom files, it will create an empty file with the given extension. Many applications will automatically open up when you create a file with extensions that they handle, so this is often desirable behavior.
Once a file has been added to your Screen or Entity it is immediately available in code. The instance added to code will match the name of the object in Glue - which by default will be LineOfTextFile. For example, to access each line of text in the loaded file, you could add the following code to the custom code of your Screen/Entity:
**File members are static:**By default files be static when added to Screens and Entities. Keep this in mind if typing "this" before the "LineOfTextFile".
FriendlyName (required)
QualifiedRuntimeTypeName
QualifiedSaveTypeName
Extension
CustomLoadMethod
LineOfText (.lin)
QualifiedType = ProjectNamespace.RuntimeTypes.LinesOfText
ProjectNamespace.RuntimeTypes.LinesOfText
lin
{THIS} = ProjectNamespace.RuntimeTypes.LinesOfText.FromFile("{FILE_NAME}")
The Live Edit feature in FlatRedBall enables making a change to your game when in edit mode and applying those changes without restarting your application. It enables a variety of types of editing, and this list is continually growing.
To enable Live Edit in your game:
Click the Editor Settings button. This brings up the Editor Settings tab
Check the option to Enable Live Edit
Once this option is checked, FlatRedBall generates the necessary code to enable Live Edit in your game. This includes a connection between the FlatRedBall Editor and your game, using the port specified in the Port Number text box. Usually you do not need to change this port, but it can be changed if it conflicts with other applications. Once Live Edit is enabled, you can run your game and enable live edit in a number of ways.
Run in Edit Mode - You can directly launch your game by clicking the Run in Edit Mode button
Alternatively, you can launch your game in the FRB Editor...
... and then switch to edit mode
Run your game in Visual Studio. FRB automatically detects when the game is running and displays the edit mode button. You can run your game in edit mode even if you didn't launch it through FRB
As shown above, you can tell that your game is in edit mode if it displays a grid. You can switch between Edit and Play mode anytime by toggling the play and edit buttons.
If in edit mode, the selected level displays in the game. You can change selections and the game will switch what is displayed in realtime.
Select a Screen (or Level)
Select an entity to view it in game. The game creates a preview screen allowing you to view and edit the entity by itself.
Select an object in a Screen or Entity to highlight it
Select a state to preview it
States can also be previewed by selecting a state in the StateData editor grid to preview it as well
Select an object in a screen by clicking on it in game and it will select in the tree view
Double-click to punch through and select overlapping objects
The Camera in Edit mode can be controlled using the following methods:
Hold the middle mouse button to pan
Hold the CTRL key and press the arrow keys. Holding the arrow keys will continue to pan.
Push+hold the left mouse button and move to the edge of the screen
Scroll the mouse wheel to zoom in and out
Hold the CTRL key and press + or - to zoom in and out
Changes in FlatRedBall immediately apply if the game is in edit mode. The following edits are supported in Live Edit:
Change a value (such as X or Y) in the Variables tab to see the change in your game
Push+drag to move objects in the game - the variables will update automatically in Glue to match the new position
Drag objects to the edge of the screen to pan the camera if they need to be placed off screen
Multiple objects can be selected and moved at once by holding down the CTRL key and clicking each object
Pushing the left mouse button in a blank space and dragging results in a rectangle which can be used to select multiple objects
Math operations can be used to change numerical values
Along with primitive types (such as numerical values), states can also be set on instances
Creating a new object in FlatRedBall automatically updates the game with the new object. New objects can be added to levels or entities.
New level objects can be added through the Add Object Quick Action
Glue also supports Drag+drop to add objects to a level
New objects can also be added by selecting their list and using the Quick Action button
New objects can be created by using the CTRL+C, CTR+V shortcut in game. This is especially useful when placing multiple objects in game. When pasting a grabbed object, the new object will be placed at the location of the crusor.
Objects added to Entities will automatically appear on instances of that entity
FlatRedBall supports adding files at runtime and automatically updating to changes.
New files can be added from the file system to Screens or Entities. If these files are then referenced by an object (such as a Sprite), they will be displayed in game.
External changes to files are automatically reloaded
Changes to TMX files which can create entities and collision will automatically update these objects so they can be tested immediately. For example, painting collision tiles immediately allows testing the new level without restarting.
The Manage Plugins menu item lets you view which plugins are installed, whether these plugins are out of date, and whether any plugins have failed.
The Camera Settings (also known as Display Settings) in Glue allows you to set your Camera and resolution project-wide. To access the settings click the camera icon.
Clicking the Settings-> Camera Settings menu item brings up the same menu as well.
For more information, see the Display Settings page.
The "New Project" menu item allows you to create a new project. When creating a new project, Glue provides two categories:
Starter Project - a fully functional FlatRedBall game including art. Starter projects let you see how FlatRedBall works with a complete game which can be modified.
Empty Project - an empty project for any platform
Both empty and starter projects are covered in the FlatRedBall Tutorials page.
The "New Project" menu item brings up a new program called "NewProjectCreator". For more information see the NewProjectCreator page.
The File Associations window allows you to customize the file associations for file types commonly used in FlatRedBall. All values initially start as <DEFAULT> meaning that those files will be opened with whatever the default for a given file is in Windows. Setting a specific file association in FRB results in the FRB Editor using the specified application to open a file rather than the default Windows default. Changing this value will not change behavior when double-clicking the file outside of FRB.
File Build Tools are runnable files (.exe or .bat) which take command line arguments and are used to convert files from one format into another format. Usually the conversion is made from a file format that is native to a particular 3rd party application (such as a .psd in Photoshop) to either a standard file format or a format understood by the FlatRedBall Game Engine (such as a .png or a .scnx).
To add a new File Build Tool:
Click the Settings->File Build Tools menu item
Click "Add new build tool"
Add the source and destination extensions of whatever your file build tool supports. For example, the source might be "psd" and the destination might be "png".
Click the BuildTool text field, then click the browse button
Select your build tool in the file window
Click OK
File build tools are command-line applications which can convert a file from one format to another. File build tools require at least one parameter - the source file (the file to be converted). To help understand how file build tools are used by Glue, consider a simple with the following values:
BuildTool = "BuildTool.exe"
IsBuildToolAbsolute = false
SourceFileType = "source"
DestinationFileType = "dest"
IncludeDestination = true
SourceFileArgumentPrefix = ""
DestinationFileArgumentPrefix = ""
ExternalArguments = ""
The values above specify that the build tool accepts a file with a "dest" extension, and it produces a file with a "source" extension. For this example, also consider a Glue file with the absolute path of "c:/folder/file.source". Building this file with the above variables would produce the following command:
The Performance Settings window controls performance-related code generation behavior. By default performance settings values are disabled (set to false). To access the Performance Settings window, select the Settings -> Performance Settings.
For information on RecordInitializeSegments, see the FlatRedBall Profiler page.
The "Find File References..." item lets you search your entire project's content files for references to a particular file. For example, if you search for a specific .png file, Glue will return all files (.scnx, .emix, .achx, and so on) that reference this file. This feature can be helpful in debugging and replacing file references.
To find file references:
Click Edit->Find File References...
Enter the file name you are searching for. You need to include the extension of the file, but not the path. For example, "MyImage.png" is valid, "MyImage" is not, and "Content/Entities/MyImage.png" is not valid.
You will see a popup that shows you which files are referencing the file you entered.
The View Projects menu item displays the current Visual Studio projects for the current Glue project. Initially only one project will appear in the Projects tab when selecting View Projects. The following image shows the Projects tab with a single XNA 4 project named TownRaiser:
Synced projects are used to develop multi-platform games. For example, a single Glue project may contain a main PC (XNA 4) project, a synced project for iOS, and a second synced project for Android, as shown in the following image:
To open a project, click on the icon for the IDE for a given project. For example, the following icon can be used to open the TownRaiser XNA 4 Project:
New platforms can be added to an existing project at any point in development by adding a new synced project. To add a new synced project to an existing Glue project:
Open the Projects tab
Click the New Synced Project button
The FlatRedBall Project Creator will appear. Select the desired platform (such as Windows UWP)
Enter a name for the project. Typically the name matches the original project's name with the platform appended. For example, TownRaiserUwp.
Click the Make My Project! button.
After creating the new synced project, it will appear in the Projects tab.
Since FlatRedBall is designed to be syntactically identical across all platforms, most new synced projects will compile and run with little or no modifications.
[subpages depth="1"]
LoadedOnlyWhenReferenced is a property which tells Glue to not load a file until it is referenced in code. This is can be used for optionally loaded content - that is, content which will only be loaded based off of certain conditions in the game (such as the current level being played).
LoadedOnlyWhenReferenced is very useful if you have content in your game which is optionally loaded depending on the state of your game. For example, you may have a game where levels are represented by .scnx files. You may add multiple .scnx files to your Screen and mark them as LoadedOnlyWhenReferenced. This means that by default no files will be loaded when your Screen is created. However, if you access any properties created for the files in the Screen, then the corresponding file will be loaded.
Optionally Loaded Content tutorial - Basic tutorial on how to use optionally loaded content.
Optionally Loaded Scenes - Discusses how to create optionally loaded Scenes (.scnx files) to load levels dynamically.
The Add UpdateAllAndRun.bat command adds a batch file to the project which will update FlatRedBall, build it, and run it. This is a convenient way to build and run FlatRedBall from source rather than relying on the prebuilt binaries.
When this command is executed a .bat file is created. The location of this bat file is shown in the output window so it can be inspected. For instance, the output window may display the following text:
The contents of .bat may look like this:
This script assumes your current Glue project, FlatRedBal, and Gum are all in the same parent folder. To specify a different location for those source code folders, change the folders in the various cd commands.
GlobalContent is a category of content which is available anywhere in your project as opposed to being tied to a specific Screen or Entity. All content that is added as GlobalContent is available at all times. Globalcontent doesn't have a lifespan tied to any ContentManager - normally content is loaded and tied to a ContentManager associated with the active Screen which is unloaded when the current Screen is Destroyed. Content can also be globally loaded if an Entity's UseGlobalContent property is true. For information on this property and also on how it interacts with GlobalContent, see this page.
Adding GlobalContent to your game is the same as adding content to any Screen or Entity. To do this:
Right-click on "Global Content Files" in Glue
Enter the type and name just like a regular file
Global Content Files are usually used:
For data that is needed across multiple Screens, like a localization database.
For data that is not tied to any particular Screen or Entity.
The GlobalContent object may take a while to load depending on your game. This can both be inconvenient for players and it can also cause to fail meeting requirements for certain platforms - for example something must render to the screen within 5 seconds of a game's launch on Windows Phone 7. Fortunately you can make GlobalContent load asynchronously. To do this:
Select the "Global Content Files" tree node
That's all you need to do - your GlobalContent will now load asynchronously.
"Lock contention" occurs when one thread has to sit and wait because another thread has locked a piece of code. This can commonly occur when dealing with async GlobalContent Initialization. Let's look at why this is the case. Imagine a situation where you have 10 CSV files, each representing a level in your game. You've decided to put them in "Global Content Files". You've also decided to put a click sound effect in your game for when the user clicks on a button. For this example we'll say that the Click sound effect will get loaded after the 10 level CSV files. To help the example, we'll also say that the CSV files take a long time to load, and that the first Screen contains a button that the user must click on to proceed. It is possible for the user to click on the button before the level CSVs are loaded. Of course, this would mean that the click sound effect must play; however, since it's loaded after the level CSVs, it won't be ready to play. So what happens in this case? The generated code for GlobalContent recognizes that you are trying to access a property (specifically the click sound effect) which hasn't been loaded yet. But since this content will be loaded, the primary thread waits for the sound to be loaded before playing it. Of course, this means your entire game will appear to freeze until the sound is loaded. This may not be an issue at all depending on how quickly your content loads and depending on how quickly the user can get to the button to click; however, when dealing with very large projects you may have dozens of files under Global Content, and if you encounter a data contention, this can make your application appear to stall. The worst case would be a situation where you are trying to access the very last-loaded property in a starting Screen. This may result in a contention that freezes your application as long as it would freeze if you didn't even use async loading. Fortunately, Glue can generate code to help you solve this.
The RecordLockContention property can be very useful on larger projects when you are trying to improve load times by eliminating lock contention. To use this to improve load times:
Select the "Global Content Files" tree node
Open your GlobalContent.Generated.cs file in Visual Studio
Run your game
Once you've identified lock contentions, you can easily reorder your content to help eliminate - or at least reduce - lock contentions. To do this:
Right-click on the "Global Content Files" tree item
Right-click and select one of the movement options, or click+drag to reorder the content files.
Depending on the order of your content, you may find that you have a particular file causing data contention. For example, the very last file in "Global Content Files" may be needed early in your game, and this could cause a very long lock contention. Once you resolve this by moving it to the top (so it is loaded first), you may actually see more, not fewer lock contentions. Don't worry, the important thing is not the number of contentions, but the amount of time spent in them. As you reorganize and run your code, you may find different contentions. Keep the following in mind:
Keep running, changing, and re-running your game to minimize the amount of time spent in contentions
You may not be able to eliminate contentions completely, but you can definitely reduce them. For example, if you have a contention on the very first file in your "Global Content Files", then there's probably nothing else you can do - it's just that the file is needed before it's finished loading.
Check for contentions from time to time throughout development. As you add more content to Global Content Files you may create a new lock contention that didn't exist before.
Modern FlatRedBall projects are saved as a collection of json files. The root file uses the .gluj (Glue JSON) extension. Screens use the .glsj (Glue Screen JSON) extension while entities use the .glej (Glue Entity JSON) extension. Note that older FlatRedBall projects use an XML format with the extension .glux and use only a single file for the entire project.
This document discusses details about the glue data files. Versions which display the green checkbox ✅ can typically be upgraded to without any additional modifications to the project. Versions which display the red exclamation ❗ typically require modifications to a project to prevent compile or logical errors.
The main Glue file (gluj for modern projects) contains a file version. This version is used by the FlatRedBall editor to determine which features to enable and disable. Generally new file versions are created whenever a feature is introduced which may break old projects. Old projects can be manually upgraded to a new version, but each upgrade may require manual changes. The property controlling the file version is FileVersion. For example, the following project is using file version 11:
To upgrade to a new version, the gluj/glux file can be opened in a text editor and manually updated.
Important: Upgrades may require additional changes to a project as described below. Furthermore, upgrading may have unexpected consequences, so using version control to undo large changes is recommended. Upgrades should be performed one version at a time rather than multiple versions at once.
This is the initial version which began tracking FileVersion.
This version introduces Game1.Generated.cs which enables additional code to be injected into Game1 without the risk of introducing errors in custom code.
❗ To update to this version you may need to remove portions of code from Game1.cs which are handled by Game1.Generated.cs. Review the generated code and compare it with your custom code.
This version automatically associates Lists in Screens with their corresponding factories. Older games may manually associate the lists with factories.
❗ To upgrade to this version, remove custom code which associates lists to factories to prevent double-adds. Also, note that you need to check your screens to make lists in the screens have AssociateWithFactory set to true on any items you wish to have associated with factories. This is default to true on newer projects, but older projects may not have this set to true automatically.
This version introduces FlatRedBall.Forms and the GetAnimation method to Gum objects.
✅ To upgrade to this version, either link to the FlatRedBall Engine source code and update the repository, or update the pre-built binaries through the FlatRedBall Editor.
CSVs can now inherit from other CSVs. This is used to allow derived platformer and top-down objects to access movement variables defined in their base classes.
✅ To upgrade to this version, either link to the FlatRedBall Engine source code and update the repository, or update the pre-built binaries through the FlatRedBall Editor.
New FlatRedBall csproj files now have nuget packages as part of the csproj enabling the FlatRedBall Editor to modify these. As of version 6 this is only used to add Newtonsoft Json.Net for live editing.
❗ To upgrade to this version, manually add the Newtonsoft.Json nuget packages to your project.
Edit mode is now enabled. This adds a lot of generated files enabling the editor to communicate with the game, and the game automatically opens a port for the editor to connect.
This adds a new function to screens and entities (partial).
✅ No changes are needed to upgrade to this version since these changes have no side effects on a game. The new methods are partial so no modifications are necessary to custom code.
FlatRedBall Editor now saves its files in json format rather than xml.
✅ To upgrade to this, open the glux file and change file version to 9, then open the FlatRedBall editor. Note that the glux file will not be deleted and will remain on disk. The editor prefers to load gluj if one exists, and if not, it falls back on glux.
This adds code generation to implement the IEntity interface for all entities.
✅ To upgrade to this version, either link to the FlatRedBall Engine source code and update the repository, or update the pre-built binaries through the FlatRedBall Editor.
This version separates all screen and entity data into their own json files. This change reduces the chances of destructive merge conflicts.
✅ To upgrade to this version, either link to the FlatRedBall Engine source code and update the repository, or update the pre-built binaries through the FlatRedBall Editor. Versions manually converting to this should first upgrade to version 9. Once a project is on version 9 or higher, it can safely be upgraded to version 11 and FlatRedBall will automatically break apart the main json file into separate Screen/Entity json files.
This version automatically adds the AnimateSelf call on Gum screens. For example, a project may have the following added to Screen Activity methods:
❗ Projects updating to this version should remove custom calls to their GumScreen's AnimateSelf, or explicit AnimateSelf calls on any component instances owned by Gum screens, otherwise animation logic will run multiple times per frame.
This version removes the generation of startup screen and camera setup from Game1.cs into Game1.Generated.cs. Projects upgrading to this version should remove code from Game1.cs Initialialize which sets the startup screen and which calls CameraSetup.SetupCamera. For example, before a change, Game1 Initialize may appear as shown in the following snippet:
After the change, Game1 Initialize may appear as shown in the following snippet
This change brings the following benefits:
Changes to the StartUp screen no longer modify custom code, reducing the chances of having merge conflicts
This change enables generated code to handle parameters for camera and resolution setup, which will be used when the game is started embedded in the game window
Establishes a pattern for additional startup functionality which will be added in future versions.
❗ To update to this version, modify Game1.cs as shown in the code snippet above.
FlatRedBall Editor supports localization through CSV files. If a localization file is added, then it will attempt to localize string variables. The current implementation is problematic for a few reasons:
It is inconsistent - some variables are assigned and some aren't. Of course, this inconsistency could be fixed, but it would take some time.
Sometimes variables should not be localized. It is common to create string variables for types which are enums at runtime, but are not available in the FRB Editor. When a localization file is added, all of these values will get set to localized values, and this can break a game in unexpected ways.
Localization may not be desirable on some strings. For example, text objects which display health or currency should not be localized.
Localization has no support for string interpolation. This requires code to perform properly.
The Gum tool supports localization files. This is where most games should perform their localization, not in the FlatRedBall editor.
Rather than completely shutting off localization in the FRB Editor, a new version is being added since it introduces a breaking change.
❗ To update to this version, you must manually add calls to LocalizationManager.Translate wherever generated code was doing so. This can be done by doing a search in generated code and identifying where this occurs. Once this version is enabled, all generated code will not contain LocalizationManager.Translate calls, so these must be done manually in code as necessary. Note that the call to LocalizationManager.AddDatabase will still be done by generated code if a localization CSV has been added to the editor in Global Content. For more information on localization, see the LocalizationManager page.
The UseAnimationTextureFlip property was added to the FlatRedBall Source on April 1 2022. The FRB Editor needs to know if this property exists in the engine so it can be shown in the property grid. If not, then it should not be shown.
✅ To update to this version, either link your game against FRB source and update the source, or update libraries to get the latest libraries which include Sprite.UseAnimationTextureFlip.
The IsScrollableEntityList property is an old property which has not been maintained or tested for many years. It is likely broken and similarly, modern projects probably do not use this property. Furthermore, this property mainly existed to support lists which are now handled by FlatRedBall.Forms. Therefore, this is being removed from the UI in Version 16. Earlier file versions will still display this property, but it may not work correctly.
✅ To upgrade to this version, verify that you do not rely on this functionality. No other work is needed.
The FlatRedBall engine now has a PersistentPolygons list which can be used to keep Polygons persistent across screens without throwing errors. This is used by the edit-mode to display the selection. If this is false, then the polygon is not made persistent, and edit mode can crash when switching between screens. However, this is only needed if running in edit mode. Games which do not develop in edit mode do not need this.
✅ To upgrade to this version, either link to the FlatRedBall Engine source code and update the repository, or update the pre-built binaries through the FlatRedBall Editor.
Normally when assigning a Sprite's CurrentChainName, if the animation is not present the code throws an exception. This can be problematic when in edit mode. This version allows the generation of Sprite.HasTolerateMissingAnimations to false when going into edit mode so that the game does not crash when assigning missing animation names.
✅ To upgrade to this version, either link to the FlatRedBall Engine source code and update the repository, or update the pre-built binaries through the FlatRedBall Editor.
AnimationLayer has Name
This version results in the PlatformerAnimationController generating AnimationLayers and assigning their Name property. Older versions of the FlatRedBall engine did not include a Name property.
IPlatformer is Generated
This version also generates the IPlatformer interface into projects. This is used to apply the new Platformer AnimationController. Projects which do not use the Platformer entity type will not be impacted by this change.
❗ To upgrade to this version, either link to the FlatRedBall Engine source code and update the repository, or update the pre-built binaries through the FlatRedBall Editor. Make sure you do not have an existing IPlatformer interface in your project. If so, you may get class/namespace conflicts.
This version introduces a new set of FlatRedBall.Forms controls.
These controls provide more flexibility, and the defaults are cleaner and look better overall. New FlatRedBall projects will automatically add these controls when Gum/Forms is added (usually through the wizard).
✅ Upgrading to this version is safe under a number of conditions:
If you do not intend to use FlatRedBall.Forms at all, then you can safely upgrade to this version.
If you have not yet added FlatRedBall.Forms to your game project, you can upgrade to this version first, and then add FlatRedBall.Forms through the Gum tab by selecting the .gumx file.
If you have already added FlatRedBall.Forms to your project, you can upgrade to this version if you do not intend to re-create all of the default forms controls. Upgrading to this version will not do anything to your project unless you re-add all controls through the Gum tab.
If you have already added FlatRedBall.Forms to your project and would like to replace existing .Forms controls, you can delete all default controls from your project and then re-add all Forms controls through the Gum tab. You may also be able to add all controls without deleting your existing default controls, but this has not been tested, so do so with the ability to undo your changes using version control.
This version introduces support for the IStackable interface.
✅ To upgrade to this version, either link to the FlatRedBall Engine source code and update the repository, or update the pre-built binaries through the FlatRedBall Editor.
This version adds two new properties to ICollidable to make it easier to track collision every frame. These properties will be filled automatically by CollisionRelationships and can be used in an entity's CustomActivity. Since these properties are being added to the FlatRedBall Engine, games which compile directly against the engine have two options:
Increase the .gluj file version to 22. This tells the FlatRedBall Editor to codegen these properties.
Manually add these properties in custom code to entities. This is a fallback if upgrading a file version is inconvenient.
Note that this is a breaking change to projects linking against the engine, so one of these two changes must be performed.
✅ If projects would like to upgrade to this version, keeping the engine and FlatRedBall Editor (Glue) together will prevent compile errors.
This version adds the ability for CollisionRelationship physics to be defined in the FlatRedBall Editor in the Collision Physics UI, but to have those physics only apply if DoCollisionPhysics is called in code.
✅ To upgrade to this version, either link to the FlatRedBall Engine source code and update the repository, or update the pre-built binaries through the FlatRedBall Editor.
This version adds code generation support for the StackSpacing property in Gum.
✅ To upgrade to this version, either link to the FlatRedBall Engine source code and update the repository, or update the pre-built binaries through the FlatRedBall Editor.
This version adds limited support for MoveSoft collision. This will be expanded in future versions, but the codegen is being introduced here.
✅ To upgrade to this version, either link to the FlatRedBall Engine source code and update the repository, or update the pre-built binaries through the FlatRedBall Editor.
The CameraSetup.cs file is a generated file, so it should be named as such. Previous versions did not name it as a generated file, so it was often included in repositories. This version changes the file so it is named as a generated file.
❗ To upgrade to this version, either remove Setup/CameraSetup.cs, or rename it to Setup/CameraSetup.Generated.cs. Relaunch the FlatRedBall Editor and it will generate to CameraSetup.Generated.cs.
This version adds support for using ShapeCollection.MaxAxisAlignedRectanglesRadiusX and MaxAxisAlignedRectanglesRadiusY in the TileShapeCollection generated code. This enables TileShapeCollections to have AxisAlignedRectangles which are not squares.
✅ To upgrade to this version, either link to the FlatRedBall Engine source code and update the repository, or update the pre-built binaries through the FlatRedBall Editor.
This version reduces the length of CollisionRelationships which are auto-named. "List" will be removed from the name of CollisionRelationships between lists to make it easier to read in the tree view and generated code. For example, previously a CollisionRelationship named PlayerListVsBulletList will now be named PlayerVsBullet. Similarly the generated events for when the collision occurs no longer include the word "List.
✅ To upgrade to this version, be aware that changing the object or sub-collision objects may result in a change to the collision relationship which previously had the word List. Projects do not need any changes to the underlying libraries.
This version does not change any interface for the code, but depends on the Gum Text object being able to update its internal character positions even if the argument for updating children depth is 0. Previously the check for children depth was performed by the Gum layout engine to prevent unnecessary Texture churn on a Text object. This is no longer needed for two reasons:
Often, Text objects render character-by-character. When performing character-by-character rendering, updating the characters is not as expensive because a Texture2D must not be created and disposed.
GraphicalUiElements (the base class for Gum objects) now have more advanced checks in their properties to prevent Layout calls from propagating.
Since the setters on GraphicalUiElement properties often prevent Layout propagation, passing a non-0 children layout depth on TextRuntime.Text changes causes more layouts. Version 29 depends on the internal GraphicalUiElement allowing text to update even if 0 child depth is passed so that TextRuntime.Text can pass a 0 depth and improve performance when updating text.
✅ To upgrade to this version, either link to the FlatRedBall Engine source code and update the repository, or update the pre-built binaries through the FlatRedBall Editor.
This version introduces the FrameworkElementManager class which can call Activity on FlatRedBall.Forms FrameworkElements. This is useful for FrameworkElements which require every-frame activity, such as the PlayerJoinView which must query Xbox360GamePad button presses for joining and unjoining.
✅ To upgrade to this version, either link to the FlatRedBall Engine source code and update the repository, or update the pre-built binaries through the FlatRedBall Editor.
✅ This version introduces the ability to add GumSkia elements. You can safely upgrade to this version without any changes to your project.
This version introduces the ITiledTileMetadata interface. This interface has a property which lets your code respond to the creation of an entity from its texture coordinates.
✅ To upgrade to this version, either link to the FlatRedBall Engine source code and update the repository, or update the pre-built binaries through the FlatRedBall Editor.
This version introduces lots of changes to IDamageable and IDamageArea. If this is enabled, the FlatRedBall Editor will generate new properties for IDamageable and IDamageArea Entities. This version also allows the editor to generate additional code on CollisionRelationships between IDamageable and IDamageArea lists.
✅ To upgrade to this version, either link to the FlatRedBall Engine source code and update the repository, or update the pre-built binaries through the FlatRedBall Editor.
Version 34 enables additional code generation in Game1 with the addition of GenerateInitializeEarly and GenerateDrawEarly. These methods are called before standard FlatRedBall initialize and draw calls, enabling FlatRedBall Editor plugins to inject code before FlatRedBall standard calls. This is used to eliminate needing to add manual code for SkiaGum. This also removes the need to keep GlobalContent.Initialize in Game1.
❗ To update to this version, a number of changes are required. First, update the partial block at the top of Game1.cs by adding the two new Early calls as shown in the following code:
Next, remove GlobalContent.Initialize from the Initialize method and replace it with a call to GeneratedDrawEarly as shown in the following code. Note that GeneratedInitializeEarly should come before FlatRedBallServices.InitializeFlatRedBall:
Finally, update Draw as shown in the following code:
This version expands properties introduced in version 22 by adding ObjectsCollidedAgainst and LastFrameObjectsCollidedAgainst. These properties make it easier to track collision every frame. These will be filled autoamtically by CollisionRelationships and can be used in an entity's CustomActivity. Since these properties are being added to the FlatRedBall Engine, games which compile directly against the engine have two options:
Increase the .gluj file version to 35. This tells the FlatRedBall Editor to codegen these properties.
Manually add these properties in custom code to entities. This is a fallback if upgrading a file version is inconvenient.
Note that this is a breaking change to projects linking against the engine, so one of these two changes must be performed.
✅ If projects would like to upgrade to this version, keeping the engine and FlatRedBall Editor (Glue) together will prevent compile errors.
This version adds the IRepeatPressableInput interface which provides checks for repeated press inputs. This is used in the IInputDevice interface to standardize repeat presses when navigating through UI. For example, this is used when holding down the DPad to cycle between letters when entering a name in an arcade-style high score list.
✅ If projects would like to upgrade to this version, keeping the engine and FlatRedBall Editor (Glue) together will prevent compile errors.
Previous versions of FlatRedBall generated all Tiled files without the .Generated.cs suffix. This causes a lot of version control noise, especially when FlatRedBall changed portions of the Generated code. Now all Tiled files are properly generated.
❗ To update to this version:
Open your project in Visual Studio
Close the FlatRedBall Editor
Remove all non-generated Tiled files. You can remove the individual files or even the entire folders which contain these files. Be careful in case you have manually added additional files here:
Save your project (csproj) in Visual Studio
Update your .gluj file version in a text editor
Open your project in the FlatRedBall Editor
After code generation finishes, all of the files should be re-added with a .Generated.cs suffix.
This version adds logic to remove redundantly-defined derived objects from Screen and Entity json files. This can reduce file sizes and eliminate diffs in version control.
✅ No changes are required to upgrade to this version, but projects which are not on version control are advised to avoid this version until it has been fully tested for a month or two (probably until after May 2023).
This version introduces protected properties for animation including mCurrentFrameIndex and mTimeIntoAnimation. These protected properties are used by codegen for the SpriteRuntime to add the PlayAnimationsAsync method which work the same as the FlatRedBall Sprite's PlayAnimationsAsync method.
✅ To upgrade to this version, either link to the FlatRedBall Engine source code and update the repository, or update the pre-built binaries through the FlatRedBall Editor.
This version introduces codegen which depends on GraphicalUiElement implementing the INotifyPropertyChanged interface. Initially this is used for real-time variable reference evaluation, but it may be used for additional functionality in the future.
✅ To upgrade to this version, either link to the FlatRedBall Engine source code and update the repository, or update the pre-built binaries through the FlatRedBall Editor.
This version introduces codegen which depends on the Gum Text objects having TextOverflowHorizontalMode and TextOverflowVerticalMode. Projects which are not of this version will not apply these properties as set in the Gum project, so text will continue to overflow as before.
✅ To upgrade to this version, either link to the FlatRedBall Engine source code and update the repository, or update the pre-built binaries through the FlatRedBall Editor.
This version introduces the ability for TileShapeCollections to add themselves to a Layer and to be automatically updated. This is used by Entites which include TileShapeCollections as their collision, such as moving walls in a game.
✅ To upgrade to this version, either link to the FlatRedBall Engine source code and update the repository, or update the pre-built binaries through the FlatRedBall Editor.
This version introduces the usage of ISong, an interface which enables FlatRedBall to work with song files other than MonoGame (XNA). This is currently used for NAudio but it can be expanded for other types of songs in the future.
✅ To upgrade to this version, either link to the FlatRedBall Engine source code and update the repository, or update the pre-built binaries through the FlatRedBall Editor.
This version adds an ExternalEffectManager, enabling Gum and Tiled rendering to use all of the color operations available to normal FlatRedBall Sprites.
✅ To upgrade to this version, either link to the FlatRedBall Engine source code and update the repository, or update the pre-built binaries through the FlatRedBall Editor.
❗ To upgrade to this version and enable rendering using the new shader for Tiled or Gum:
Download the latest DesktopGL template https://files.flatredball.com/content/FrbXnaTemplates/DailyBuild/ZippedTemplates/FlatRedBallDesktopGlNet6Template.zip
Extract the template
Navigate to the Content folder in the unzipped folder
Copy the two Shader files (fx and xnb)
Paste these files into your project's Content folder, overwriting the existing shader fx and xnb files
This version adds a new checkbox to the Sprite Variables tab enabling the generation of collision assignment from the Sprite's AnimationChains.
✅ To upgrade to this version, either link to the FlatRedBall Engine source code and update the repository, or update the pre-built binaries through the FlatRedBall Editor.
This version introduces the IGumScreenOwner interface. If this exists, then all FlatRedBall Screens which have a Gum Screen will implement this interface in generated code. This enables the automatic updating of layouts outside of screen code, such as in the FlatRedBall Editor code.
✅ To upgrade to this version, either link to the FlatRedBall Engine source code and update the repository, or update the pre-built binaries through the FlatRedBall Editor.
This version adds a Name property to FlatRedBall Screens, and allows the code generation to assign this Name property.
✅ To upgrade to this version, either link to the FlatRedBall Engine source code and update the repository, or update the pre-built binaries through the FlatRedBall Editor.
This version adds usage of the SpriteManager's InsertLayer to enable reordering of Layers during live edit.
✅ To upgrade to this version, either link to the FlatRedBall Engine source code and update the repository, or update the pre-built binaries through the FlatRedBall Editor.
This version is a breaking change to Gum - Gum renderable objects no longer use XNA objects such as Color, Vector3, and Matrix for their internals. This change is an effort to make Gum more cross-platform in C# and to eventually support other programming languages without needing to migrate as much XNA syntax.
This change only modifies the Renderables themselves such as Text and Sprite, but does not modify the wrapping codegen objects such as TextRuntime and SpriteRuntime, so most games will not be affected by this change. However, if you are directly working with the renderables then you may be affected by this syntax change.
Note that if your project is linked to source, then the FRB codegen system will automatically generate the new codegen against the System.Drawing and System.Numerics types, so you are not required to upgrade to this version.
❗ To upgrade to this version, either link to the FlatRedBall Engine source code and update the repository, or update the pre-built binaries through the FlatRedBall Editor. If you have compile errors:
Identify the locations where you are having compile errors and make the assignments of the values use the proper types. You may need to convert from XNA to System.Drawing/Numerics types.
Add System.Numerics and System.Drawing references to your project if you are using an older version of FlatRedBall.
This version updates to using the GumCommon code. The engine doesn't reference GumCommon libraries, but the addition of GumCommon shifts where code is located in the files that are being referenced by the engine and also by games which link to source.
This version does not provide any funcitonal changes.
✅ To upgrade to this version, either link to the FlatRedBall Engine source code and update the repository, or update the pre-built binaries through the FlatRedBall Editor.
This version allows Gum projects to use BBCode for specifying inline styles.
✅ To upgrade to this version, either link to the FlatRedBall Engine source code and update the repository, or update the pre-built binaries through the FlatRedBall Editor.
IDamageArea.IsDamageDealingEnabled
IDamageable.IsDamageReceivingEnabled
IDamageable.InvulnerabilityTimeAfterDamage
IDamageable.IsInvulnerable
IDamageable.LastDamageTime
These new properties are generated on Entities which implement IDamageArea and IDamageable automatically for projects which are at least on version 52.
✅ To upgrade to this version, either link to the FlatRedBall Engine source code and update the repository, or update the pre-built binaries through the FlatRedBall Editor.
❗ Note - if your game uses these interfaces which are either implemented in code, or if you have disabled automatic generation of these properties, then you will need to manually add properties as shown in the following code:
If needed you can create these as properties with getters and setters, but the code above matches the behavior prior to version 52.
This version removes the confusing "Type" class for derived entities and replaces it with the name "Variant". This is a breaking changes. For example, if you have a base Enemy entity and derived Enemy entities, then FlatRedBall will have generated a class called EnemyType with all of the derived Enemies.
The reason for this change is to avoid confusion with the C# "Type" class in documentation, discussion, and code. Instead, the word Variant will be used in all documentation and code going forward.
❗ Since the name of the class changes, this upgrade may require you to make manual changes if you have been using the Type class. The following list outlines the changes required. If you have not been using the "Type" classes, then no changes are needed.
Change all partials from "Type" to "Variant" to match the newly-generated class.
Change usage of any "Type" in your custom code to "variant"
Change any instances which may reference "Type" variables to the new type
The last item requires a bit of manual work so the following outlines the steps to make this change.
Before the upgrade, you may have instances which reference the old "Type" variable as shown here:
These will generate incorrectly until, as shown in the following errors in Visual Studio:
To fix these problems:
Use a version control system such as Git, or back up your project. Changing types on variables can cause unintended side effects so it's best to have a backup.
Locate the entity or screen which references the incorrect variable. You can do this by double-clicking the error in Visual Studio to be taken to the generated code with the error.
Find the matching entity or screen in the FRB Editor
Find the variable with the old "Type" type and change it to variant.
FlatRedBall attempts to keep all of your variable values the same, so if all worked okay you should not have any changes on instances aside from the types.
This version adds top down animation support using an AnimationController specifically built for top down entities. Conceptually this is similar to platformer entity animations. It is optional and will not affect existing games with top down entities.
✅ To upgrade to this version, either link to the FlatRedBall Engine source code and update the repository, or update the pre-built binaries through the FlatRedBall Editor.
This version modifies code generation so that it includes the case of file paths rather than calling ToLower on all files. This helps make FRB work better on case-sensitive platforms such as iOS, Android, and Linux.
✅ To upgrade to this version, either link to the FlatRedBall Engine source code and update the repository, or update the pre-built binaries through the FlatRedBall Editor.
❗ Mobile games using Xamarin should not update to this version.
One of the primary technologies that the FRB Editor uses to function is it creates generated code. Some game projects may include more generated code than hand-written code.
This section discusses the details of how generated code works. The details of generated code may be useful to you during development if:
You have encountered a bug related to generated code
You are interested in debugging generated code
You are interested in creating FlatRedBall Editor plugins which generate code
If you are using Visual Studio then you can view all generated code in Visual Studio. All Screens and Entities will have at least one generated file.
Assuming that you have an Entity called MyEntity:
Open your project in Visual Studio
Expand the "Entities" folder in your project
Look for your entity (MyEntity.cs)
Expand the entity and you should see another file called MyEntity.Generated.cs
Double-click this file to see the generated code
FlatRedBall also generates a file called GlobalContent.Generated.cs which is not associated with any particular Screen/Entity. It is responsible for loading and providing access to all files added through the Global Content Files item in the FRB Editor.
This file is located in your project as well, but it is not embedded under any other files:
Select "Add File"->"New file"
Repeat this for as many files as you'd like
Once a file has been added to the "Global Content Files" tree item, it can be accessed anywhere in code at any time after GlobalContent has been initialized. To do this, simply use the same name as the file name after "GlobalContent."
Change the "LoadAsynchronously" property to "True"
Change "RecordLockContention" to "True" (make sure "LoadAsynchronously" is also set to "True")
Scroll to the very bottom where the Intialize method ends and place a breakpoint on the last line of AsyncInitialize which should be "IsInitialized = true;"
Once you hit the breakpoint, add "LockRecord" to your watch window
If you notice that it has a count of 0, then congratulations - you are not experiencing any lock contention in your Global Content's initialization. You can easily create a locking case if you'd like to see the result and how to resolve it. To do this, simply access the very last property in GlobalContent right after the GlobalContent.Initialize call in your Game class: In this case the file "ShapeCollectionFile" is the last property listed under GlobalContent. It is likely that accessing it immediately after the Initialize call will result in a lock contention. Running the game now verifies this: This case was fabricated, and as a result rather trivial; however, if you have multiple locks, this approach can help you reorganize your global content to improve load times. Speaking of reorganizing, keep reading to see how to do this.
Select "View File Order"
A window will appear listing all of the files in "Global Content Files". This window shows the current order of content loading.
Plugins which are downloaded from can be installed through this menu item. Plugins use the extension .plug.
To install a plugin, select the Plugins->Install Plugin menu item. You will see the following window appear: Press the browse button (...) to select the .plug file you wish to install.
Once a plugin has been installed, the Manage Plugins window will list this plugin. For more information, see the .