Hi in this video we’ll explore
some of what you can do with the spine-unity runtime by checking out
the example scenes that come with it. I’ll start with a Unity project that
already has the spine-unity 4.0 runtime installed using the Unitypackage. You will find the "Spine" and
"Spine Examples" folders under "Assets" in the Project window. In the "Spine Examples" folder, you
will find the "Getting Started" folder. It contains six example scenes that
walk you through the basic runtime components and how they are used. The first scene demonstrates
the SkeletonAnimation component. The SkeletonAnimation component is
the heart of the spine-unity runtime. It allows you to add a Spine skeleton
to a GameObject, animate it, react to animation events, and more. A SkeletonAnimation component
requires a reference to a SkeletonDataAsset that provides the
skeleton data and texture atlas. After exporting JSON or binary
skeleton data and a texture atlas from Spine, a SkeletonDataAsset can
be created by dragging and dropping the files into the Project window. Drag a SkeletonDataAsset into
the Scene or Hierarchy window to create a skeleton GameObject. Besides SkeletonAnimation, there are
two other types of skeleton GameObjects: SkeletonGraphic and SkeletonMecanim. We’ll look at those later. A SkeletonDataAsset can be
used for multiple skeleton GameObjects in your scenes. The data is loaded into memory only once
and is shared by the skeleton GameObjects. For example, if you change the
texture atlas or an animation or other skeleton data for a SkeletonDataAsset,
all the GameObjects that reference that SkeletonDataAsset will change. Once imported, you can update the skeleton
by simply overwriting the modified file. You can quickly see the appearance of
animations in the Preview that appears at the bottom of the Inspector window
when the SkeletonDataAsset is selected. Sometimes Unity collapses the
Preview, so if you don’t see it then it just needs to be resized. The second example scene demonstrates
basic animation code using the C# API. When playing the scene, Spineboy will play
the walk, run, idle, and turn animations. Footstep events will
trigger a sound accordingly. You can inspect the example script
"SpineBeginnerTwo" component that is attached to the Spineboy GameObject. The SkeletonAnimation provides an
AnimationState instance that keeps track of the animations that will be applied. AnimationState has the concepts
of "tracks", where animations with higher track numbers are
applied on top of lower tracks. The example code demonstrates usage of
the SetAnimation and AddAnimation methods. SetAnimation sets the
animation for a track. It has three parameters: track
index, the animation to be set, and whether the animation loops. By default the animation starts
playing from the beginning. If it loops, then it repeats
until another animation is set. If it doesn’t loop, it keeps applying the
last frame of the animation until another animation is set or the track is cleared. SetAnimation replaces any
animation that is already playing or queued on that track. When a track changes from one animation
to another, the "mix duration" determines how much time is used
to crossfade between animations. This is called "mixing" and
helps avoid abrupt changes when setting a new animation. You can set the mix duration between
pairs of animations in the "Mix Settings" of the SkeletonDataAsset. The default mix duration is used
for any animation pairs that don’t have a mix duration set explicitly. AddAnimation queues an animation
to play after other animations. Like SetAnimation, AddAnimation takes a
track index, animation, and loop boolean. It also takes a "delay" that determines
when the queued animation replaces the current animation for the track. When the delay is positive, it’s the time
from the start of the previous animation to when the queued animation starts. For example, if you set an idle animation,
then add a run animation with a delay of 1 second, idle will play for 1
second, then it will be replaced by run. When the delay is zero, which
is most common, then the queued animation will start mixing in so
that it completes the mix when the previous animation has finished. For example, if your idle animation
has a duration of 1 second, then adding a run animation with a delay
of 0 and a mix duration of 0.2 will start mixing in run when idle is at 0.8
seconds, so that the mixing is complete when the idle animation finishes. When the delay is negative, it’s just
like when the delay is zero except the start time is moved back by that much. For example, if the delay was
-0.2 then run will start mixing in at 0.6 seconds instead of 0.8. If the delay is longer than the previous
animation’s duration, then the animation will either loop or display the last
frame until the next animation is set. In some cases you may want to use a mix
duration of zero, so the next animation starts immediately, without any mixing. You can further customize how an animation
is played using the TrackEntry object returned by SetAnimation and AddAnimation. For example, you can set the mix
duration on the TrackEntry instead of setting it in the "Mix Settings"
or to override the mix settings. The TrackEntry has many properties to
customize playback, such as TimeScale to slow down or speed up the animation,
AnimationStart to begin playback in the middle of the animation, and much more. Let's return to the example scene. You may want to play sounds at specific
points in your animation, like when Spineboy’s foot hits the ground. To do this you set up events in
Spine, then you write a little bit of code to play the sounds in Unity. Open the script called
"HandleEventWithAudioExample" attached to the "sound" GameObject. This code shows how to register
an AnimationState.Event callback. Your method will be called whenever
an event occurs in any animation. You can also set a callback on a
TrackEntry for a specific animation. Spineboy's walk and run animations
have event keys named "footstep". When the script sees an event
occurred, it displays the name of that event in the console and
checks if it’s the "footstep" event. If so, it plays a footstep sound. Beside the event name, each event key can
have an Integer, Float, and String value. You can use these to decide what to do. For example, you could decide
which sound to play, how many times to play the sound, adjust the
pitch, or take some other action. Events aren’t limited to playing sounds. You can also use them to show or
hide particle effects, deal damage, change which skin is visible, or
anything else you can think of. The third scene demonstrates how you can
play multiple animations on top of each other by using AnimationState tracks. It also shows how to use
AnimationReferenceAssets as an alternative to animation name strings. When playing the scene, the walk
animation will play in a loop. At the same time, the "gungrab" and
"gunkeep" animations are playing on top of the walk animation. See the example script called
"Raptor" attached to the "raptor Skeleton" GameObject. This script sets a walk animation on
track 0 and "gungrab" and "gunkeep" alternate at random intervals on track 1. "gungrab" grabs the gun from the holster,
and "gunkeep" puts it back in the holster. Since these are played on a higher
track, they override part of the pose from the walk animation. When you set an animation with loop
equal to false, the animation will apply the pose of the last frame
until another animation is set. This is why the "gungrab" animation keeps
the gun out after the animation duration. The fourth scene demonstrates how
you can set up a platformer character following the Model-View-Controller
software design pattern. While this setup might not be ideal
for your game projects, it serves as inspiration for how input,
game logic, and visualization may be separated into components. When playing the scene, you can control
the Spineboy character with the WASD keys, Spacebar, and mouse input. Alternatively you can
control it via a gamepad. You can inspect the script called
SpineboyBeginnerInput attached to the "PLAYER INPUT" GameObject. It is the "controller" in the
model-view-controller design pattern. It modifies the state of the
"model", represented by the "SpineboyBeginnerModel" component
on the "PLAYER Spineboy" GameObject. Visualization of the model is performed
by the "SpineboyBeginnerView" component on the "VIEW Spineboy" GameObject. The crosshair that is displayed when the
mouse clicks is a part of the Spineboy skeleton. Spineboy is set up to look at the
crosshair bone using the IK constraints when the aim animation is played, so
you can control the angle of the upper body by moving the crosshair bone. The script called
"SpineboyTargetController" on the "VIEW Spineboy" GameObject overrides the local
position of the bone called "crosshair" to the mouse position every frame. When setting the shoot
animation, AttachmentThreshold is set on the TrackEntry. AttachmentThreshold determines if
attachment timelines are applied when an animation is being mixed out. By default it is zero, so attachment
timelines are not applied when mixing out. When the shoot animation is
played, the sequential images of the muzzle effect are displayed. If the shoot animation starts
to mix out mid-animation, the muzzle effect disappears. We can see this by starting and stopping
the playback of the shoot animation in the Preview view of the Spine editor. We want to see the muzzle effect even
when shoot is being mixed out, so we set the attachment threshold to 1. As previously mentioned, when an
animation was set with loop equal to false, it will keep applying the last
frame until another animation is set. If you are done applying an animation
and want it to mix back to the setup pose, you can use AddEmptyAnimation. AddEmptyAnimation takes a track
index, mix duration, and delay. Delay works just like AddAnimation. You can reset the pose smoothly
by setting a mixDuration. After the mix duration the skeleton
will have the setup pose and the empty animation is cleared from the track. The fifth example scene demonstrates
the use case of a platformer with typical animations such
as jump, run, fall, and land. It has particles and sound effects
and also shows how Spine meshes can be used to cast shadows in Unity. When playing the scene, you can
control the Hero character with the WASD keys and Spacebar. Alternatively you can
control it via a gamepad. You can inspect the example script
called "BasicPlatformerController" on the Player GameObject. It shows how to use Unity input to
change between a character's states. When the state changes, the
"SkeletonAnimationHandleExample" script sets the appropriate
animation for the new state. The "HeroEffectsHandlerExample"
script is used to play a sound and spawn particle systems. If the current state has an
animation for transition, this script plays the transition
first, then the target animation. The GetCurrent[] method returns
the TrackEntry for the animation that is currently being applied. This is used to determine if there
is a transition animation between the current animation and the next animation. Skeleton GameObjects added to the
scene using SkeletonAnimation or SkeletonMecanim use the MeshRenderer
component, so they will cast shadows onto other 3D objects by default. Note that 2D objects like a
Sprite do not receive shadows. If you don't want to display shadows,
turn off "Cast Shadows" in the Lighting section of the Mesh Renderer component. The default shader does not receive
shadows of other objects, so if you want your skeleton to receive shadows,
please use the Pixel Lit shader. Note that the Pixel Lit Shader requires
Z Spacing and enabling Add Normals or Fixed Normals in the material. If you move the hero to the stairs on
the left side, you can see that the landing positions of the left and right
feet change based on the step's height. This is achieved by programmatically
changing the position of the feet IK bones at runtime. A hierarchy of SkeletonUtilityBone
components allows you to override certain bone positions of your animation. There is an example scene named
SkeletonUtility GroundConstraint where this component is demonstrated. The SkeletonUtility GroundConstraint
example component calculates the target height and uses the
SkeletonUtilityBone component to adjust the bone position accordingly. For details and requirements on how to
automatically setup the hierarchy, please see the spine-unity documentation page. The sixth scene demonstrates the
SkeletonGraphic component and how it can be integrated into a Unity UI. Play the scene and scroll through the
panels to discover Spineboy below. SkeletonGraphic is similar to the
SkeletonAnimation component, except it renders to a Unity UI Canvas. This allows you to render
your skeletons in your UI. Due to limitations of the
CanvasRenderer, SkeletonGraphic is limited to only one texture by default. While you can enable "Multiple
CanvasRenderers" in the "Advanced" section, it is better avoided where
possible for performance reasons. This scene also shows how
"BoneFollowerGraphic" components can be used to attach any UI
component to follow bone positions. They can be found on the "Detached
BoneFollowerGraphic" and "Child BoneFollowerGraphic" GameObjects. If you select another bone in the
"Bone Name" select box, you will see that the text label can be
changed to follow a different bone. The SkeletonMecanim component
is another alternative to the SkeletonAnimation component, but there
is no example scene for SkeletonMecanim. You can simply create a SkeletonMecanim
instance by dragging and dropping the SkeletonDataAsset into the scene, and then
selecting 'SkeletonMecanim' from the menu. This will create a Mecanim Controller
asset automatically which you can edit as normally using the Animator window. Note that SkeletonMecanim comes with some
limitations regarding mixing and requires additional keys in your animations. For details see the
spine-unity documentation page. Due to these limitations we
recommend to use SkeletonAnimation instead whenever possible. While we have looked through the six
scenes in the Getting Started folder, there are still many more example
scenes in the "Spine Examples" folder. So let’s quickly look through the
most important example scenes. The "Mix and Match Skins" project shows
how to combine multiple skins into one to implement a wardrobe setup. Pressing "Done" will optimize
the skin and attachments. It generates a new skin and new
attachments mapped to a new texture atlas that is repacked from the texture
regions of the original attachments. "Mix and Match Equip" shows how to
update the look of a skeleton with Unity Sprite images and repack the
textures using only the images used. "Per Instance Material Properties"
shows how to change the material for each skeleton instance. "BlendModes" shows the correct
settings to apply each blend mode: Multiply, Screen, and Additive. "SkeletonRenderSeparator" shows how to
split the Skeleton render into parts using the SkeletonRenderSeparator component. "Sprite Shaders" shows a "Lit Sprite
Shader" example that uses normal maps. "SkeletonUtility Ragdoll" demonstrates
the example components SkeletonRagdoll and SkeletonRagdoll2D, which can be
used when you want to turn an animated skeleton into a puppet-like ragdoll. "SpriteMask and RectMask2D"
shows how to mask a skeleton using SpriteMask or RectMask2D. "Outline Shaders" demonstrates the Outline
shader feature, which automatically detects and renders outlines of
the skeleton with a colored border. To learn more about each component
and the example scripts, please refer to the spine-unity runtime
documentation and the actual example scenes and comments in the scripts. Feel free to directly use the example
components in your game project. Typically you will base your
own scripts on code from the example components, re-using and
modifying them to fit your project. If you modify an example component
be careful not to later accidentally overwrite your modifications by
re-importing the unitypackage. Besides the examples and
documentation, you will find even more information on the Spine forum. You can post your questions on the
forum if anything still remains unclear. I hope this video has been helpful. Thank you for watching!