Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
The Skeleton property gives you full access to the underlying Spine object. Simple games can work directly with the SpineDrawableBatch, but more complex games may require directly reading from or manipulating the Skeleton object.
For information about working directly with the Skeleton object, see the Runtime Skeleton documentation on Spine's website.
FlatRedBall integrates with the Spine tool using the Spine plugin.
You must own a license to Spine to use this in your project. For more information see the Spine runtimes license here: https://github.com/EsotericSoftware/spine-runtimes/blob/4.1/spine-monogame/README.md
The Spine integration relies on Spine's official MonoGame integration. Most projects do not need to use this integration, but if you are interested in maintaining the Spine integration or peeking into how it works under the hood, you may want to start at the Spine Runtimes github:
To use Spine in your project, you must do the following high level steps. Each step will be explained in detail below:
Link your game project against FlatRedBall Source
Link your game project against the Spine
Load the Spine shader (.fx) file
You can use Spine purely in code, or you can use Spine in the FlatRedBall Editor by adding the Spine plugin. The FlatRedBall Editor plugin enables adding Spine files (skeleton and atlas) to your FlatRedBall project. The plugin generates code for loading these files.
To use the Spine plugin, you must also install the SpinePlugin .plug file.
The first step is to link your FlatRedBall project to source. To link your game to FlatRedBall Source, see the Building FlatRedBall From Source page.
Once you have linked your game to FlatRedBall Source, you need to link your game to FlatRedBall.Spine.MonoGame.DesktopGL. As of January 15, 2024, MonoGame DesktopGL is the only platform that supports FlatRedBall.Spine. New platforms will likely be added over time. If you are planning on targeting a new platform, make a request on Discord.
To add FlatRedBall.Spine to your project:
Clone the repository for FlatRedBall.Spine https://github.com/flatredball/FlatRedBall.Spine
Open your project in Visual Studio
Right-click on your Solution in the Solution Explorer
Select Add -> Existing Project...
Navigate to the folder where you cloned FlatRedBall.Spine and select <FlatRedBall.Spine Root>/Source/FlatRedBall.Spine.MonoGame.DesktopGL.csproj
Expand your game project and right-click on Dependencies, then select Add Project Reference...
Check FlatRedBall.Spine.MonoGame.DesktopGL to link this library in your game project's dependencies, then click OK.
Your project should now link to FlatRedBall.Spine.MonoGame.DesktopGL.csproj.
After adding the reference, be sure to save your project. You can do this by selecting the File->Save All option in Visual Studio, or by pressing CTRL+SHIFT+S in Visual Studio. Alternatively, you can run your game which saves the .csproj.
This step is important because the .csproj modifications must be saved so the FRB Editor can re-load the .csproj. Forgetting this step can result in the library not being linked.
Although it is not necessary, using the FlatRedBall.Spine plugin is recommended as it can reduce the amount of code necessary to work with Spine. To install the FlatRedBall.Spine plugin:
Download the SpinePlugin.plug file from the Releases page https://github.com/flatredball/FlatRedBall.Spine/releases
Select Plugin->Install Plugin in FlatRedBall
We recommend selecting "For User" so the plugin is installed globally, but you can do it for project if you do not want other projects to use this plugin.
Use the ... button to locate and select the SpinePlugin.plug file, then click OK
Restart the FlatRedBall Editor
Once you have restarted FlatRedBall, you should see Spine listed in the installed plugin. Select Plugins -> Manage Plugins, and scroll down to make sure the plugin has installed.
Alternatively you can clone the Spine plugin if you prefer to build from source and diagnose problems. To do this:
Clone the FlatRedBall.Spine repository https://github.com/flatredball/FlatRedBall.Spine. If you clone both FRB and this repository to the same root Github location, then the file links will work correctly
Open SpinePlugin/SpinePlugin.sln
Build->Rebuild the plugin
The latest plugin .dll will be built and also copied over to the Glue output folder.
The SpineShader is required to render Spine. To load the Spine Shader:
Download SpineEffect.fx file from the Releases page https://github.com/flatredball/FlatRedBall.Spine/releases
Add the SpineEffect.fx file to GlobalContent by drag+dropping the file into your Global Content Files folder in FlatRedBall
Open Game1.cs and add the following code in Initialize after GeneratedInitialize();
:
The type or namespace name 'Spine' does not exist in the namespace 'FlatRedBall' (are you missing an assembly reference?)
If you are missing a Spine reference in FlatRedBall, then you may not have saved the .csproj after adding a reference to the Spine project. To fix this:
Right-click on your game project's Dependencies and select Add Project Reference
Check if the FlatRedBall.Spine.MonoGame.DesktopGL (or appropriate project for your target platform) is selected.
If not, check the project, click ok, then save you project. At this point you can build/run your game and this also saves your .csproj.
The SetCollision function can be used to assign/update collision on an ICollidable through its ShapeCollection. In other words, this method allows the creation of collision through the Spine tool which can be used to create CollisionRelationships, or to perform manual collision checks.
Keep in mind that you are not required to define collision in a Spine file. If your game works well without the precise collision offered by Spine bounding boxes, then you can add shapes such as AxisAlignedRectangles and Circles to your entity.
Spine has support for bounding boxes - which conceptually correspond to FlatRedBall Polygons.
These bounding boxes can be converted to FlatRedBall Polygons which can be used in your project. These polygons are fully-featured, just like polygons created either in the FRB Editor or in code. In other words, these polygons have the following characteristics:
They are attached to the Entity, so solid (move/bounce) collision will result in the entity being repositioned and have its velocity changed according to the physics applied.
They can be added to the Entity's Collision ShapeCollection so they can be used in collision relationships.
They are named and can be exposed in the FRB Editor so that CollisionRelationships with subcollisions can reference them
Furthermore, polygons from Spine have the following features and characteristics:
Polygons can be defined in the FRB Editor to match the names of the polygons, or they can be created at runtime without a corresponding FRB Editor entry
Polygons respond to animations, so if a SpineDrawableBatch changes its rotation or scale, the FlatRedBall Polygon automatically adjusts
To use SpineDrawableBatch collisions, the SetCollision method needs to be called every frame. Typically this is called in the CustomActivity (or derived method) inside an entity which implements ICollidable as shown in the following code snippet:
This method updates the polygons in the argument ShapeCollection (this.Collision
) every frame. The code checks for name matches between the bounding box in Spine and the name of the FlatRedBall Polygon in the ShapeCollection. If a match is found, then the FlatRedBall Polygon is updated to match the Spine object. If a match is not found, then a new FlatRedBall Polygon is created if the last argument (createMissingShapes) is true
.
Typically, if you would like to define the collision in Spine without creating anything in the FlatRedBall Editor, then you can pass true
as the final parameter. In this case, the Objects folder would not contain any FlatRedBall Polygons, and every bounding box in the Spine object would be used in collision relationships.
By contrast if you would like to assign custom collision per-shape (such as by using CollisionRelationship subcollisions), you can define a polygon in the FlatRedBall Editor. You do not need to create the points on the newly-created Polygon in the FlatRedBall Editor since they will be updated every frame by the SetCollision call. The only requirement is that the Polygon that you create has a name that matches one of the bounding boxes in your Spine file.
In this case, the Polygon will automatically be added to the Collision ShapeCollection, and it will be modified by the SetCollision call every frame.
Note that the Polygon must be part of the Collision ShapeCollection. In other words, IncludeInICollidable must remain true, which is the default. If you set this to false in FlatRedBall, then the SetCollision
method will not find this Polygon.
You are free to define as many or as few Polygons as you would like in FlatRedBall. If you define them, then SetCollision will update them. If you do not define them, then SetCollision will either add them (if true
is passed as for createMissingShapes), or they will be completely ignored. Whether you define them, and whether you pass true or false for the createMissingShapes parameter depends on how much explicit control you would like over the definition of your polygons.
Spine supports events which can be handled in code. Events are defined in Spine which can include parameters of different types such as ints, floats, and strings.
These events can be handled in code by subscribing to a SpineDrawableBatch's Event event, or through the FlatRedBall Editor.
To subscribe to an event in FRB Editor:
Create a SpineDrawableBatch object in your Entity
Drag+drop the SpineDrawableBatch into the Events folder
Change the name if desired, then press OK
The new event can be handled in the Events.cs file of your Entity. For example, if your Entity is named Soldier, the event is in Soldier.Event.cs.
The Event event is can be subscribed to just like any event in C#. To do so, simply use the +=
operator to add a handler to the Event, as shown in the following code snippet:
When a Spine event is raised it may have parameters which are passed. The parameter type can differ per event type, so the Event class that is passed to the handler contains the information.
You can decide the meaning of each paramter in your game. For example, you may decide to award points when a particular event occurs by reading the e.Int
value.
The atlas file (with extension .atlas) is produced by Spine. The purpose of an atlas file is to define the coordinates in a PNG file used for different named regions. The atlas file defines both the .png that is used as well as its regions.
By default, atlas files are loaded into the runtime type Spine.Atlas.
You can produce an .atlas file from a FlatRedBall .achx file by using the AchxToSpineAtlas.exe tool.
At the time of this writing you must build this tool yourself. To do this:
Clone the FlatRedBall Repository
Open <FRB Root>\FRBDK\AchxToSpineAtlas\AchxToSpineAtlas.sln
Build the tool which produces a .exe
Once you have built the tool you can use it either in the command line, or you can set up a File Build Tool association.
To run the tool in the command line, run the .exe with two parameters:
The source (.achx) file
The destination (.atlas) file
For example, you can run the tool using the following command to build an .atlas file:
To use the AchxToSpineAtlas.exe tool as a File Build Tool in FlatRedBall:
Open your project in FlatRedBall
Select the Settings -> File Build Tools menu item
Click Add new build tool
Click the ... button to select the BuildTool. Navigate to where AchxToSpineAtlas.exe is located
Set the SourceFileType as achx
(no period before the extension)
Set the DestinationFileType as atlas
After you click the OK button, FlatRedBall understands that .achx files may be used to build .atlas files.
Note that this change now results in FlatRedBall asking you about the build tool whenever you add a new .achx file.
If you are adding a file which you would like to be treated as an AnimationChain, then select the <None> option. For more information on build tools, see the File Build Tools documentation.
How (and why) to change textures on a skeleton dynamically at runtime.
The general pattern in Spine is to create a skeleton that contains animations, and skins for each type of object that might share those animations. For example, you might create a "humanoid" skeleton that has walking and attacking animations. And you might have a skin for "human", "goblin", and "troll" that allow you to create unique types of game creatures that share animations. You can easily set the skin using the SpineDrawableBatch.Skeleton.SetSkin()
method.
In some cases, you may want to have more customized skins. For example, what if humans, goblins, and trolls each have different types of weapons? Spine supports partial skins so you could have folders for skins that set the creature textures, weapon textures, and similar themes on the skeleton. This would allow you to stack unique combinations of skins at runtime.
However, this quickly becomes a combinatorial problem for the artist. They must carefully import every unique weapon, armor, or creature sprite into spine, create a partial skin for it, and re-export the skeleton into the project. It is very easy to make mistakes and accidentally include a goblin arm in a sword skin, for example.
For games that have a large number of partial skins, it may be worth creating a single template skin and dynamically creating the rest of your skins in code! Runtime skins are a recommended approach in Spine documentation.
It is assumed that you already know how to set up a skeleton, create placeholders, and apply textures to those placeholders with a skin. See Spine Skin Documentation for details on this process.
Create a single skin and call it something like "template". Apply default textures to all of the slots in your skeleton so that the template skin is populating all of the slots. You can use these default textures to preview your animations during the art process.
It is possible to create skins completely dynamically at runtime but creating a template skin allows you to visually adjust the offsets, rotations, and other information that would be challenging and slow to do programmatically.
Here's an example of a Spine project with several placeholder slots and a single "template" skin:
The placeholder slots on your skin will be converted to a specific type of Attachment
called a RegionAttachment
which contains atlas texture region information that should be rendered in the slot on the skeleton.
You can change the region attachment on a skin at runtime using the SetDynamicTextureOnSkin
method in the SpineDrawableBatch
. This method takes a Skin
, the placeholder name, an Atlas
, and the atlas texture name. It swaps the texture on the placeholder and optionally applies it immediately to the skin. This method allows you to dynamically change any slot on the skin with any atlas texture you provide. However, it has a major drawback. Skins are shared across skeleton instances in the Spine Runtime for performance reasons. This means, if you change a placeholder on a skin, it changes the skin for every creature in your game using that skin!
NOTE: you can get any skin on a skeleton by calling
Skeleton.FindSkin(skinName)
. Use this to get a skin reference to provide to theSetDynamicTextureOnSkin
method!
To work around the issue of shared skins, you can create a dynamic skin that contains the unique attachment changes you want using the GetOrCreateDynamicSkinFromTemplate
method on the SpineDrawableBatch
. This allows you to create a named dynamic skin, make changes, and apply it to a skeleton instance without affecting other instances. Here is how you could combine these methods to create and apply a dynamic runtime skin in a FlatRedBall entity that contains a spine character (SpineDrawableBatch
).
NOTE: if "myDynamicSkin" already exists on the skeleton, it will be retrieved instead of creating a new skin. This allows you change attachments on the dynamic skin multiple times with accidentally creating a large number of dynamic skins that aren't used! But this also means that multiple instances using the same skin name could change each others' appearance.
The Spine Runtime shares skins for performance reasons. Therefore, it is good to assume that creating a very large number of skins could cause problems. It is recommended that you have a deterministic naming pattern for your dynamic skins that avoids creating duplicate skins with the same information. For example, you might use [creature name]_[weapon_name]
as a convention so you create dynamic skins for "goblin_sword", "goblin_club", "troll_sword", and "troll_club" that are shared across many instances of those creatures without creating a dynamic skin for every single creature instance.
There are three unique approaches to customizing Spine skeletons. This document mentions two but it may be useful to understand each approach and its tradeoffs.
In this approach, the artist creates partial skins for each section of the skeleton (creature, weapons, armor for example). At runtime you apply a skin for each section and they stack. This approach is simple but puts a large workload on the artist.
This is the approach described here. It creates one skin with all slots populated and a skeleton only has this full skin applied. It is relatively simple and takes a lot of pressure off the artist. However, if you have a large number of slots, having a huge number of combinatorial skins may lead to performance problems in the game.
A final approach, which is much more complex and not described here, would be to create partial skins in code and stack them so that the skeleton is wearing a stack of dynamic skins. This approach may be more performant at very large scale but is complex to create and the FlatRedBall implementation doesn't have any specific APIs supporting this approach.
The SpineDrawableBatch class is responsible for drawing Spine in your FlatRedBall game. If you have used Tiled in your FlatRedBall projects, you can think of the SpineDrawableBatch as being similar to a Tiled Layer. In other words, the SpineDrawableBatch has the following characteristics:
It can be positioned explicitly, although this is typically done through attachments in generated code
It has a Z value which controls its sorting
It produces a new render break (this may change in the future)
By contrast, normally Tiled maps are added to Screens; however, SpineDrawableBatches are typically added to Entities.
Spine files are needed to draw a SpineDrawableBatch. Conceptually you can think of these files similar to how you might think of a .achx file - it needs to be loaded as part of an entity or screen before it can be used to display any graphics.
To add a SpineDrawableBatch to an entity:
Create an entity that will contain the SpineDrawableBatch. This example uses an Entity called Soldier
Drag+drop the texture file (.png) used by the Spine atlas into the Entity's files
Drag+drop an Atlas file (.atlas) into the Entity's files
Drag+drop a Spine skeleton file (.json) into the Entity's files
Select the Skeleton entry in FlatRedBall, click on the Spine tab, and change the Atlas property the desired Atlas file. It should appear in the dropdown.
Important: At the time of this writing, the three files must be loaded in the proper order. The order is:
Texture file (.png)
Atlas (.atlas)
Skeleton (.json)
You can re-order the files by holding down the ALT key on the keyboard and pressing the up and down keys.
This requirement may go away in the future as the Spine plugin gets better at tracking dependencies.
Note that the texture file (.png) is loaded when the atlas is created and ultimately uses a FlatRedBall content manager. This means that if your png is already loaded (such as by being in Global Content Files), then you do not need to also have the png in your entity. This is especially useful if your atlas references a shared sprite sheet which is used by other screens and entities.
Now the Spine files have been added to the entity, we need to add them as an object. By adding an object we can control properties such as position (offset) and scale. Also, each individual object can be independently animated. To add and attach the SpineDrawableBatch:
Drag+drop the skeleton file from Files onto Objects
Change the Source name to Entire File (SpineDrawableBatch)
Enter a name such as SpineDrawableBatch
Click OK
You should now have all three files in your Entity as well as a SpineDrawableBatch in the Objects folder.
To see the entity instance in-game, drag+drop the entity onto a Screen, such as GameScreen. Run the game and the Spine Drawable Batch should appear.