FlatRedBall https://flatredball.com 2D Game Engine Tue, 05 Dec 2023 17:04:47 +0000 en-US hourly 1 https://wordpress.org/?v=6.6.5 https://flatredball.com/wp-content/uploads/2016/02/cropped-logo-1024-32x32.png FlatRedBall https://flatredball.com 32 32 Gum Now Supports SkiaSharp! https://flatredball.com/news/gum-now-supports-skiasharp/ Fri, 30 Dec 2022 22:24:02 +0000 http://flatredball.com/?p=12094 SkiaSharp is a wrapper over the powerful Skia graphics engine. The latest version of FlatRedBall adds support for rendering Skia objects efficiently in your game. The current implementation of Skia provides a number of new primitives fully integrated with Gum.

New Primitives and Effects

The current version (as of this writing) adds support for three new primitive types: RoundedRectangle, ColoredCircle, and Arc. Let’s take a look at each of the three independently.

RoundedRectangle

RoundedRectangle is similar to ColoredRectangle, but adds support for rounded corners and effects as described below.

As the name implies, RoundedRectangle supports rounded corners which are controlled by the CornerRadius property.

ColoredCircle

ColoredCircle provides the ability to fill a circle with a solid color. It also supports effects as shown below.

It fills the width of its bounding rectangle when its size changes.

Arc

The Arc object can be used to draw an arc shape which can be used to draw timers, speedometers, and health.

The Arc object exposes a number:

  • Start Angle – the angle (in degrees) where the angle begins. A value of 0 is equivalent to the 3 o’clock position, and positive values move counterclockwise (just like normal Gum and FlatRedBall rotation).
  • Sweep Angle – the angle controlling the angle drawn by the arc, following the same unit and direction as Start Angle.
  • Is End Rounded – Whether the end caps are round or a straight line.

Future Primitives

Gum currently also supports SVG and Lottie animations. Future versions of FlatRedBall will be adding these as well, but this first version is limited to these 3 primitives.

Effects

These three new primitives also add new effects which can be assigned and previewed in Gum.

Gradients

Gradients can be added to shapes. Gradients are specified using the following values:

  • Gradient Type – Whether to use a linear or radial gradients
  • Use Gradient – whether to use a gradient or solid color
  • Gradient X1 and Y1 – the X and Y position of the first color on the gradient
  • Gradient X2 and Y2 – the X and Y position of the second color on the gradient
  • Red/Green/Blue 1 – the color values used for the first color on the gradient
  • Red/Green/Blue 2 – the color values used for the second color on the gradient
  • Gradient X1 and Y1 Units – the Units used to position the first color values
  • Gradient X2 and Y2 Units – the Units

As shown in the following animation, gradients can be modified and previewed in the editor:

Gradient units are useful if you want the gradients to respond to width or height changes, as shown in the following animation:

Dropshadow

Dropshadows can be added using the Has Dropshadow property. When enabled, drop shadows have a number of variables controlling their appearance:

  • Dropshadow Offset X/Y – The X/Y offset in pixels of the drop shadow relative to the shape.
  • Dropshadow Blur X/Y – The number of pixels to blur the drop shadow. Note that drop shadow blurring uses a normal distribution dropoff. The value indicated here may not precisely contain the drop shadow but it is a fairly close approximation. A value of 0 results in no blur. The blurring for the drop shadow can be controlled independently on the X and Y axes.
  • Dropshadow Alpha – Controls the transparency of the drop shadow.
  • Dropshadow Red/Green/Blue – Allows the drop shadow to be colored. By default the color is black.

Note that the drop shadow renders outside of the shapes bounding rectangle.

Stroke and Fill

Stroke and Fill control whether a shape is filled-in or if it only draws its outline.

Future Effects

Skia supports may additional effects. Over time, additional ones will be added to Gum and they will automatically be available in your games.

Adding Skia to Your Game

Skia can be added to your game in a number of ways:

  1. Add Skia Gum objects to your Gum Screens and Components
  2. Instantiate Skia Gum objects in code
  3. Manually render Skia objects to a Texture2D which is rendered by a Sprite

Working with Skia objects in code provides the ultimate flexibility and enables accessing additional Skia types and effects; however, for this document we’ll focus on working with the Gum tool since it requires minimal additional code.

Important: Skia is still considered to be in beta support. Therefore, some of the steps shown below may change as the feature matures. Furthermore, Skia is not currently part of the FlatRedBall build tools, so to use Skia in your project, you must be linked against FlatRedBall Source. These steps will be shown below.

  1. Verify that you have the Gum and FlatRedBall repositories checked out to your machine. The source is currently required since pre-built Skia FlatRedBall dlls are not yet in distribution at the time of this writing.
  2. Create or open a Desktop GL .NET 6 (or newer) project. Currently Skia Gum requires using the latest version of FlatRedBall. It is possible to add Skia Gum to earlier versions of FlatRedBall (and FlatRedBall iOS/Android projects), but the performance is significantly reduced.

  3. Add FlatRedBall source files to your project. This can be done manually, or you can use the built-in command in the FlatRedBall Editor.
    1. Select Project -> Link Game to FRB Source

    2. Verify that the root folders are correct and check the Include Gum Skia checkbox

    3. Click Link to Source. If successful, the Add FRB Source tab will disappear.

Now your project is set up to support Skia objects in Gum. To add a Skia object to your Gum project:

  1. Open your project in Gum

  2. In Gum, select Plugins -> Add Skia Standard Elements

  3. Your Standard folder should now contain the Skia elements

  4. Add Standard instances to your Screens or Components just like any other type of Standard object

After adding these instances, they will appear in your game.

More to Come!

Stay tuned, Skia introduces a huge set of new features which we’ll be adding to Gum over time.

]]>
Solving MonoGame 3.7.1 missing on FlatRedBall Projects https://flatredball.com/news/solving-monogame-3-7-1-missing-on-flatredball-projects/ Fri, 21 Oct 2022 11:49:41 +0000 http://flatredball.com/?p=11972 Recently a new version of FlatRedBall was released targeting .NET 6.0. This version has a lot of benefits as explained in a previous blog post, but it does introduce one problem for games targeting MonoGame 3.7.1.

You may notice an error that says

Could not load the project <project location> because MonoGame 3.7.1 files are missing.

Fortunately this can be solved fairly easily.

To do so:

  1. Locate your .csproj file on disk
  2. Open the .csproj file in a text editor
  3. Look for and remove the following lines in the .csproj:

Near the top of the file:

<Import Project="$(MSBuildExtensionsPath)\MonoGame\v3.0\MonoGame.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\MonoGame\v3.0\MonoGame.Common.props')" />
Usually in the middle of the file:
<MonoGameContentReference Include="content\Content.mgcb" />
Near the end of the file:
<Import Project="$(MSBuildExtensionsPath)\MonoGame\v3.0\MonoGame.Content.Builder.targets" />

Why is this happening?

It seems as if the version of MSBuild tied to Visual Studio 2022 does not understand the MonoGame content pipeline files. Fortunately, these aren’t needed for most projects because the FlatRedBall Editor automatically handles the building of content pipeline files (such as .wav and .ogg) using the external MonoGame Content Builder. Therefore, the lines shown above are only needed for projects which manually maintain content pipeline files themselves – usually not the case for FlatRedBall projects.

 

]]>
FlatRedBall Moves to .NET 6 and Much More! https://flatredball.com/news/flatredball-moves-to-net-6-and-much-more/ Wed, 12 Oct 2022 15:27:33 +0000 http://flatredball.com/?p=11953 FlatRedBall is now making a big upgrade to .NET and MonoGame 3.8.1. This means the FlatRedBall Editor (aka Glue) and new game projects are on .NET 6. This upgrade brings along a lot of changes to FlatRedBall, so let’s dive in!

Note that some of the changes below require creating a new .NET 6 project or manually upgrading your project to use .NET 6.

.NET 6 Performance Boosts

.NET 6 introduces lots of performance improvements for all C# applications. FlatRedBall games benefit from these improvements. For information, see the .NET 6 blog about performance improvements.

CSharp 8, 9, and 10

Games can now take advantage of the latest C# syntactical improvements. For more information see the following blogs:

New Controller Support

(Requires .NET 6 project) Previous versions of FlatRedBall supported only Xbox controllers (Xbox 360 and Xbox One). Now, FlatRedBall supports virtually all PC USB controllers including:

  • Nintendo Switch Pro Controllers
  • Nintendo Gamecube-style (aka Smash Bros) controllers
  • “Retro” controllers, such as NES and SNES-style controllers
  • Playstation 4 and 5 controllers
  • General PC controllers

These controllers will appear in the InputManager.Xbox360GamePads list. Buttons such as X, Y, A, B will match the face buttons so be aware that they will not be positioned physically in the same spot across Xbox and Switch controllers.

Live Edit Improvements

Live edit continues to be an important feature which is being used internally and continually improved. The latest version addresses more edge cases and helps catch left-over processes. Live edit also does a better job of reporting game crashes in the output window.

ICollidable ItemsCollidedAgainst and LastFrameItemsCollidedAgainst

ICollidable objects (including all generated entities) now have an ItemsCollidedAgainst and LastFrameItemsCollidedAgainst. This allows for custom code to check for collisions rather than performing code in events. This is primarily useful when multiple collision relationships control a single variable. Additionally, Platformer objects also have a GroundCollidedAgainst property which similarly records the items that the player has collided with. For example, a Player may perform logic if on ice. Being on ice may require checking multiple collision relationships as shown in the following snippet:

public bool IsOnIce => 
   GroundCollidedAgainst.Contains(nameof(GameScreen.IceCollision)) || 
   GroundCollidedAgainst.Contains(nameof(GameScreen.IceCloudCollision));

Collision Relationship Improvements

Collision Relationship physics can now be defined in the FRB Editor, but the application of the physics can be controlled manually. This is important if the application of physics is conditional.

For example, consider a ghost enemy which may be able to pass through walls depending on its current state.

In this case, the physics could be defined in the FRB Editor, but not automatically applied:

CollisionRelationships now have a DoCollisionPhysics method which can be called to apply physics, typically performed conditionally in a collision event.

Factory Performance Improvements

Entity lists are often sorted to improve partitioning. The new version of FRB will automatically insert items sorted, rather than at the end of the list to be sorted. For large lists, this can create significant improvements in performance.

… and lots more!

This version also includes dozens of small bug fixes and enhancements. It’s available now, so head on over to the Downloads page and give it a shot.

]]>
How to Fix “The number of tile columns in the tileset ‘TilesetName’ appears to have changed…” https://flatredball.com/news/how-to-fix-the-number-of-tile-columns-in-the-tileset-tilesetname-appears-to-have-changed/ Sat, 01 Jan 2022 15:24:36 +0000 http://flatredball.com/?p=11428 FlatRedBall integrates closely with the fantastic tilemap program Tiled. If you’ve ever resized a PNG file, then you may have received a message notifying you that the number of columns in the tileset have changed.

Tiled is notifying you that the tileset was originally created with a PNG which had a different size compared to its size now. Unfortunately, clicking Yes may result in unexpected (and broken) results.

Fortunately a solution exists to this problem. If you have clicked Yes you will need to undo your changes by closing Tiled without saving your file. If you have saved your file, you will need to revert it in Git (or whatever version control program you are using). Unfortunately if you do not have a way to undo your changes, your file may be permanently corrupted.

To solve the problem:

  1. Click No on the popup

  2. Select whichever tileset references the resized PNG

  3. Click the Edit button to edit the tileset

  4. Make a change to the tileset. The change doesn’t matter, as it will be undone- a change is needed so that Tiled will let you re-save the tileset (TSX) file. For example, change the Type of one of the tiles.

  5. Save the tileset (TSX) file

  6. Undo the change to the Type (or whatever change you made earlier to save the file)

  7. Save the tileset (TSX) file again

After performing these steps, your map will still look like it did before, but Tiled will no longer ask you about the number of columns changing. Also if you look at the TSX file in a diff program, you will some of the values in the TSX have changed.

Once this change has been made, the map should render correctly in FlatRedBall as well.

 

]]>
New FlatRedBall Editor (Part 2) https://flatredball.com/news/new-flatredball-editor-part-2/ Sun, 12 Dec 2021 00:30:26 +0000 http://flatredball.com/?p=11395 Recently a new version of the FlatRedBall Editor (aka Glue) was released with support for embedding a game window (and support for edit mode). Today the FlatRedBall Editor has been updated with many changes to make it easier to work with. Let’s take a look at some of the changes!

New Game Toolbar

The Game window now has a new toolbar to make it easier to control and run your game. Once your game has support for edit mode, the toolbar displays an Edit button:

One click and your game is running in edit mode:

The toolbar icons have all been replaced to be easier to understand and to have a consistent styling. When the game switches to play mode, the toolbar reacts to display more icons for control:

Updated Explorer

The Explorer tab has been updated to match the styling of the rest of the app. New icons are less noisy than previous icons and will show up better on high-DPI devices:

The Explorer tab also includes new functionality. The Collapse All button makes it easier to find entities and screens in a large project:

The Search text box provides real-time searches, keeping the hierarchy of your project:

Filter prefixes let you find what you’re looking for quickly. Just prefix your search with one of the following to find a certain type of content:

  • f – file
  • e – entity
  • s – screen
  • o – object
  • v – variable

Wizard Changes

The New Project window displays an Open New Project Wizard option which is checked by default:

The new wizard now displays icons for each project type, and it now includes a new project type for UI projects using FlatRedBall.Forms:

Get It Now

All of these changes, plus dozens of small fixes and improvements, are available now. Hop over to the downloads page to get the latest.

 

]]>
The New FlatRedBall – The Biggest Change Yet! https://flatredball.com/news/the-new-flatredball-the-biggest-change-yet/ Sun, 10 Oct 2021 20:25:22 +0000 http://flatredball.com/?p=11221 The latest version of FlatRedBall brings together work from the past few months to create a new development experience. The largest of these changes is the integration of the game window.

The game can be played in the FlatRedBall window, or it can be switched into edit mode to make changes to the game.

Embedding the Game Window

By default, games will not appear embedded in Glue. To enable embedding, click the settings icon and check Enable Game Embed And Edit.

Game Controls

Once a game is running, it can be controlled through the game. Many of these controls appear directly above the game, such as the ability to pause, change speed, stop the game, and restart the current screen.

Editing Functionality

The new editing functionality (previously called Glue View) is an embedded experience in the FlatRedBall Editor. When in edit mode, the game can be edited. For example, selected objects can be edited by dragging and moving them in the game tab, or can be edited by typing in new variable values.

Try It Out

The new FlatRedBall Editor is available now, so grab the latest version and give it a shot!

]]>
Announcing Glue Wizard https://flatredball.com/news/announcing-glue-wizard/ Wed, 03 Mar 2021 03:43:33 +0000 http://flatredball.com/?p=9598 FlatRedBall Glue has always been a program for improving the speed of game development. The latest version includes a wizard which greatly simplifies new project setup. Previously, even as recent as a month ago, setting up a new project with levels, a player entity, collision, and tiled map files could take an experienced FlatRedBall user over an hour. For new users, this process could take days.

The new wizard standardizes the setup, and new projects can be created in under a minute!

Running the Wizard

To run the new Glue Wizard, you need to first create a new project. Once the project template has been downloaded, Glue has a Run Glue Wizard button.

Just click the button and the wizard will open.

Choosing Player Control Type

FlatRedBall projects include entities – game objects such as the player, enemies, and power ups. Most games include a Player entity, such as a platformer or top-down character.

The new wizard provides a page dedicated to the creation of this Player entity. For the most part, the defaults can be left unchanged. The most important option is which type of entity control you would like. Currently the two options are Top-down and Platformer.

What’s Included?

Once you finish the wizard, Glue will apply all of the selected options and create a fully functional game. Games which accept all of the defaults will have:

  • A base GameScreen set up with collision and a common Map object which references the Tiled map file for the current level. The Tiled program is used to create tile-based levels in your game.
  • Solid collision objects and a collision relationship between the solid collision and all Players. Solid collision prevents the player from moving beyond the bounds of the level and can be used as walls to control game play.
  • A fully-functional top-down or platformer entity. This is the Player entity which can be controlled with the keyboard or Xbox gamepad
  • Multiple levels, each with their own Tiled map file and a standard gameplay tileset for quick level creation
  • Gum and FlatRedBall.Forms for UI and HUD. Gum is a visual tool for creating UI and HUD, and FlatRedBall.Forms provides functionality for standard UI controls such as Button, TextBox, and ListBox.
  • A camera which follows all Players and stays within the bounds of the level. This behavior can be customized, but the defaults are good enough for starting most games.

In other words, this has all of the pieces needed to get your game developed even faster.

How Fast Can You Make a Game?

It’s currently available in the latest build of FlatRedBall so download it and give it a shot!

 

]]>
Common Math in 2D games https://flatredball.com/news/common-math-in-2d-games/ Tue, 02 Mar 2021 22:44:56 +0000 http://flatredball.com/?p=9595 There are four equations that can solve a large variety of problems in 2D games. But math textbooks or Wikipedia often make it really hard to understand how to use them. This post explains the usage of these equations without going into detail about how they work, and links to the Wikipedia pages if you want to learn more about the mathematics.

Pythagorean Theorem

You probably learned the Pythagorean Theorem at some point in school:

a² + b² = c²

This equation is used to find the distance between two game objects, the linear velocity of an object, or similar problems where you need to find the length of an angle given X and Y components.

The Pythagorean Theorem is the equation to find the hypotenuse of a right triangle, given the length of two sides. Imagine you have two space ships and each of them can fire lasers 200 units. How do you know if they are close enough to hit each other? Using the Pythagorean Theorem, you can find the angular distance (hypotenuse) between the two ships by finding the difference of their vectors and performing the equation on that result (pseudocode):

ship1Position = 100, 300
ship2Position = -150, -50

// This is the A variable
xDifference = 100 - -150 = 250

// This is the B variable
yDifference = 300 - -50 = 350

// Solve for C, the distance
distanceSquared = 250^2 + 350^2 = 62,500 + 122,500 = 185,000
distance = SquareRoot(185,000) = 430.116

The ships are about 430 units apart, which is beyond the range of their weapons – they will not be able to target each other.

Atan2

The function Atan2, or two-argument ArcTangent, is used to find the rotation from one object to another object.

Imagine you have a turret that should always aim at the mouse cursor. How do you find the rotation from the turret’s position to the mouse position that will correctly point at the mouse? The Atan2 function in most languages returns this result (pseudocode):

turretPosition = 100, 150
mousePosition = -50, -30

// Find the difference, or delta, of the positions.
// Note that the turret position is subtracted FROM the mouse position.
deltaX = -50 - -100 = -150
deltaY = -30 - 150 = -180

// now use the Atan2 function to find the angle
// Note that in almost every language, the Y component is specified before the X component
rotation = Atan2(deltaY, deltaX) = Atan2(-180, -150) = -2.265 radians

Most programming languages measure angles in radians: -2.265 radians is approximately 130 degrees. Setting the turret rotation to this value will cause the turret to point at the mouse.

Important note: In most programming languages, angle 0 is facing directly to the right. For the math above to work, the sprite must also face directly right. If your sprite is facing north, for example, you will have to subtract 90 degrees from the result of your math to compensate for the fact that the sprite is already rotated 90 degrees.

Sin and Cos

Sin and Cos are trigonometry functions that are used to find X and Y vector components, given an angle and magnitude. The Cos function provides the X component of an angle, the Sin function provides the Y component of an angle. More simply, if you have a speed and an angle, and want to know how this translates to grid coordinates, these equations do the job!

Imagine you have an object that is going 150 units per second and is rotated at 75 degrees (pseudocode):

// Most programming languages use radians to measure rotation
rotation = 75degrees = 1.3 radians
speed = 150
// extract each component
xMovement = Cos(rotation) * speed = Cos(1.3) * 150 = 40.125
yMovement = Sin(rotation) * speed = Sin(1.3) * 150 = 144.534

The object will have moved roughly 40 units on the X axis, and 145 units on the Y axis over one second.

 

Summary

The majority of the problems in 2D gamedev are about figuring out where things are in space, how they are rotated, and how far apart they are. The equations above can combine in powerful ways to implement velocity, perform targeting and chase logic for NPCs, and much more! To see more about trigonometry in game development, check out the Math:Trigonometry documentation.

]]>
Dear ImGui Integration https://flatredball.com/news/dear-imgui-integration/ Thu, 11 Jun 2020 01:23:11 +0000 http://flatredball.com/?p=9171 The Dear ImGui open source library provides a cross-platform way to quickly make user interfaces.  While it is not as pretty as interfaces made in Gum, it does allow for quick creation of powerful UIs for certain audiences.  It has found significant usage for in-engine game development tools, even in high profile AAA games such as the new Final Fantasy VII Remake, Assassin’s Creed, and Bethesda’s Fallout76.

While Gum will always be the preferred way to create player-focused interfaces in your game Dear ImGui can help you quickly create in-game debug and development tools to help you iterate faster.  While Dear ImGui does not have its own native support for FlatRedBall, it it is easy to integrate Dear ImGui in a FlatRedBall game, and this post will show how.

Rendering

Dear ImGui is built as a C++ library that doesn’t do any rendering on it’s own.  Instead it generates vertex buffers that any rendering engine should be able to display.  Luckily, the open source community has created a .Net wrapper for the library and provide a sample for how to render it with MonoGame.  To use this library you want to add the ImGui.Net nuget package to your project.

Once that the nuget package is installed we just need tell MonoGame to render it.  The easiest way to do this is to grab the ImGuiRenderer.cs and DrawVertDeclaration.cs classes from the ImGui.Net XNA sample and add them to your project.  Make sure everything compiles up to this point (note that this will require at least the .Net Framework 4.6.1).

The next step is to actually display something in your game.  To do this open up the Game1.cs file and make the following modifications:

    public class Game1 : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        private ImGuiRenderer _imGuiRenderer; // Add this declaration here

        // ...

        protected override void Initialize()
        {
            // ....
            IsMouseVisible = true; // So you can see the mouse pointer over the controls
            _imGuiRenderer = new ImGuiRenderer(this); // Initialize the ImGui renderer
            _imGuiRenderer.RebuildFontAtlas(); // Required so fonts are available for rendering
            
            base.Initialize();
        }

        protected override void Draw(GameTime gameTime)
        {
            FlatRedBallServices.Draw();

            // FRB may have altered the rendering state, and this might cause ImGui's textures to render
            // with artifacts.  So we want to reset the render state just for ImGui
            var oldSamplerState = GraphicsDevice.SamplerStates[0];
            GraphicsDevice.SamplerStates[0] = new SamplerState();
            
            _imGuiRenderer.BeforeLayout(gameTime); // Must be called prior to calling any ImGui controls
            ImGui.ShowDemoWindow(); // Render the built in demonstration window
            _imGuiRenderer.AfterLayout(); // Must be called after ImGui control calls

            // Reset the sample state to what FRB originally set
            GraphicsDevice.SamplerStates[0] = oldSamplerState;

            base.Draw(gameTime);
        }
    }

This code intializes the ImGui renderer and calls it in each Monogame render cycle.  If you run your game now you should now see the ImGui demo window where you can explore a lot of the different UI controls that Dear ImGui offers.

And with that you have a fully functioning Dear ImGui window right in your FlatRedBall Game!  All you need to go from here is to add new controls in between the BeforeLayout and AfterLayout calls and you can create any custom UI that you want.

Tighter Integration

So now that you have ImGui integrated you could just go off and start creating user interfaces.  However, as you start working with this you may notice that it will become quite complex to manage even trivial debug user interfaces with this setup.  For example, if all UI rendering and control management is handled from Game1.cs how will you create a UI that’s only relevant when you select a specific unit, or available while in a specific screen?  Furthermore, how will you get values from that UI so you can affect your game entities from the UIs?

This calls for a closer integration into FlatRedBall!  Specifically we need some way to allow screens and entities to be able to create and remove their own ImGui controls.  This consists of two systems, ImGui elements and an ImGui manager.

ImGui Elements

In an idea world we would want to keep our UI organized, and such a system would require it:

  1. Be easy to group a set of ImGui controls together
  2. Be composable, so one grouping can render another grouping inside of it (for example rendering one group inside a tab within a larger group)
  3. Be easy for external code to modify the values of code
  4. Be easy to expose values the user has modified through the UI controls
  5. Be possible for external code to be notified when a value is changed (for MVVM style flows)

We can accomplish this with an ImGuiElement class.  This class intends to make it easy to create complex ImGui layouts while maintaining good separations of concerns from game logic.  For example, lets say you are working on the TownRaiser starter game and you wanted to create a user interface to modify the global data for buildings.  You may create the following class:

    public class GlobalBuildingEditor : ImGuiElement
    {
        public string BuildingId
        {
            get => Get<string>(); 
            set => Set(value);
        }
        
        [HasTextBuffer(25)]
        public string DisplayName
        {
            get => Get<string>();
            set => Set(value);
        }

        public int Health
        {
            get => Get<int>();
            set => Set(value);
        }

        public double BuildTime
        {
            get => Get<double>();
            set => Set(value);
        }

        public int LumberCost
        {
            get => Get<int>();
            set => Set(value);
        }

        public int StoneCost
        {
            get => Get<int>();
            set => Set(value);
        }

        public int Capacity
        {
            get => Get<int>();
            set => Set(value);
        }

        public GlobalBuildingEditor(BuildingData buildingData)
        {
            using (DisablePropertyChangedNotifications())
            {
                BuildingId = buildingData.Name;
                DisplayName = buildingData.NameDisplay;
                Health = buildingData.Health;
                BuildTime = buildingData.BuildTime;
                LumberCost = buildingData.LumberCost;
                StoneCost = buildingData.StoneCost;
                Capacity = buildingData.Capacity;
            }
        }

        protected override void CustomRender()
        {
            if (ImGui.Begin("Global Building Editor Window")) // Define a new window
            {
                // If statement is used to create the inside controls only if the window is not collapsed
                InputText(nameof(DisplayName), "Display Name");
                InputInt(nameof(Health), "Health");
                InputDouble(nameof(BuildTime), "Build time");
                InputInt(nameof(LumberCost), "Lumber Cost");
                InputInt(nameof(StoneCost), "Stone Cost");
                InputInt(nameof(Capacity), "Capacity");
            }

            ImGui.End(); // Ends the grouping of controls for the current window
        }
    }

Of course, this class by itself is not very useful.  It allows you to change values but those values aren’t reflected by the game itself.  Luckily the ImGuiElement class implements the INotifyPropertyChanged interface, allowing you to react to changes in this UI with code such as:

    foreach (var buildingKey in GlobalContent.BuildingData.Keys)
    {
        var buildingInfo = GlobalContent.BuildingData[buildingKey];
        var editor = new GlobalBuildingEditor(buildingInfo);

        editor.PropertyChanged += (sender, args) =>
        {
            switch (args.PropertyName)
            {
                case nameof(GlobalBuildingEditor.DisplayName):
                    buildingInfo.NameDisplay = editor.DisplayName;
                    break;
                
                case nameof(GlobalBuildingEditor.Capacity):
                    buildingInfo.Capacity = editor.Capacity;
                    break;
                
                case nameof(GlobalBuildingEditor.Health):
                    buildingInfo.Health = editor.Health;
                    break;
                
                case nameof(GlobalBuildingEditor.BuildTime):
                    buildingInfo.BuildTime = editor.BuildTime;
                    break;
                
                case nameof(GlobalBuildingEditor.LumberCost):
                    buildingInfo.LumberCost = editor.LumberCost;
                    break;
                
                case nameof(GlobalBuildingEditor.StoneCost):
                    buildingInfo.StoneCost = editor.StoneCost;
                    break;
            }
        };
    }

Just like that we have a debug user interface that can be used to modify global CSV data, allowing you to tweak values in real time without even restarting the screen.

Managing Elements

However, just having an ImGui element is not enough.  We somehow need to render those elements to the screen.  While we could somehow pass these elements to the Game1 class and add calls to their Draw() method in between the ImGuiRenderer calls, that is not very ideal.  Instead what we’d really like is some global manager that not only allows screens and entities to create and destroy ImGui element implementations as they want, but we also need some way to hook ImGui into FlatRedBall’s greater infrastructure.  This will not only give us greater organization for managing ImGui calls, but it will allow screens and entities to have an easy way to know if ImGui has focus or if the game has focus (for input purposes).

A ready made implementation of an ImGui element manager can be found in this ImGuiManager.cs file.  To use this, add the code file to your project and instead of the previous Game1.cs changes we made at the beginning of the post, the only change you need to make to Game1.cs is:

        protected override void Initialize()
        {
            // ...

            // Add this line here to initialize the ImGui manager
            new ImGuiManager(this);

            base.Initialize();
        }

That’s it!  The ImGuiManager constructor takes care about adding itself into FlatRedBall’s rendering pipeline and lets FlatRedBall know when the cursor has focus on an ImGui control.  In your screen or entity you can then create any ImGuiElement instances that you want and add it to the ImGui manager via:

    public void CustomInitialize()
    {
        _debugWindow = new MainDebugWindow {IsVisible = true};
        _debugWindow.PropertyChanged += DebugWindowOnPropertyChanged;
        ImGuiManager.Current.AddElement(_debugWindow);
    }

    public void CustomDestroy()
    {
        ImGuiManager.Current.RemoveElement(_debugWindow);
        _debugWindow.PropertyChanged -= DebugWindowOnPropertyChanged;
    }

 

]]>
Hot Reload and Improved Build in Glue https://flatredball.com/news/hot-reload-and-improved-build-in-glue/ Sat, 23 Nov 2019 04:21:43 +0000 http://flatredball.com/?p=8909 One of the most common task in game development is stopping a game to make small changes, then restarting the game. Of course, doing this just one time is a fast process, but over the course of an entire game this can add up. The latest version of Glue focuses on speeding up the stop/tweak/restart cycle.

This version introduces two big features:

  1. Hot-reload of the project
  2. Communication between Glue and the game

Hot Reload

Glue can now automatically stop, rebuild, and restart a game when it detects a change. Glue will automatically watch for changes and will restart a game as long as the game was launched through Glue.

Just click play here…

…or here…

…and hot reload will be enabled:

While hot reload is enabled, Glue will watch for any changes to your project. If it detects a change, the project will be stopped, rebuilt, and re-launched.

The game will even relaunch but not steal focus, so you can make changes in Visual Studio, save your file, and continue coding while the game compiles and re-launches!

Changing a file referenced by your project will also result in the game reloading. For example, TMX files can be changed in Tiled.

Glue will reload the project if any of the following change:

  • Variables changed in Glue
  • New screens or entities added in Glue
  • New object instances added to a Screen or Entity
  • Custom code changed (if coding in Visual Studio, for example)
  • File changes such as a changed TMX, PNG, or ACHX

As the next section shows, Glue can also inject code into a game project to enhance hot reload and other debugging functionality.

Glue and Game Communication

The latest version of Glue introduces runtime communication between Glue and Game projects. Glue can use a TCP connection to connect to a running game and send commands. This functionality can be enabled by checking the Generate GlueControlManager in Game1 checkbox.

Once enabled, Glue will attempt to connect to the game if it launches your game. You may see a Windows Security Alert indicating that your game is opening a TCP port. Click Allow access to enable communication.

Once enabled, Glue will have extra control over your game.

Play/Pause

Glue can send Pause commands to your game, which will internally call the FlatRedBall Pause function. Once paused, the game can be un-paused by pressing the play button.

Advance One Frame

Once paused, Glue can advance the game by one frame at a time. Internally this sends an un-pause command, lets the game run for one frame, then pauses the game once again.

Fast Forward and Slow Motion

You can change the speed of the game through Glue, from as slow as 10% to as fast as 500% speed.

Restart Current Screen

The red restart icon will stop the game, rebuild it, and restart the game on the same screen. This command is useful if you need to restart the game, but do not want to navigate through menus or levels to continue testing the same part of the game.

If rebuilding/restarting the game is not required, the green restart icon will send a command to the game to restart the current screen.

The functionality of restarting on the same screen will automatically be used if hot reload is enabled, making iteration even faster compared to restarting a game from the first screen.

Future Changes

Communication between Glue and the game at runtime opens the door for many future improvements. Later versions of Glue will include more functionality to speed up iteration and debugging, so stay tuned!

 

]]>