Replace a death animation with a particle effect
by Thomas Buscaglia · in Torque X Platformer Kit · 09/05/2007 (7:08 pm) · 24 replies
This is a question I got via email. I figured I would post it and the response here in the forums rather than in email.
From Zilla:
I want to replace the drill's dying animation with a particle effect.
I posted this problem in the Torque X forums and Dan provided me with enough information that I could replace the animated explosion sprite in the Blaster tutorial with an emitter. But he said that he's not an expert on the platformer kit and his information was too vague and I didn't find a solution for the drill.
Can you give a hint what I should try? Here is the corresponding thread:
www.garagegames.com/mg/forums/result.thread.php?qt=66628
Answer:
The animations in the Platformer Kit are managed by the ActorAnimationManager. You could set the DeathAnimation to a one frame animation of a blank image to get your actor to dissapear when he dies. You could also not specify an death animation and just set the actor's animated sprite invisible when it dies and visible again upon respawn.
That takes care of making the actor dissapear. Then you'll want to create a particle effect for the explosion. There is a virtual method called _die() on ActorComponent. Simply override the method and add your particle effect creation there (as detailed in the above link).
Here's a quick example
Note that this assumes PlayOnLoad is true on the particle effect and that it will eventually delete itself. You can set all that up with the particle editor in TXB.
From Zilla:
I want to replace the drill's dying animation with a particle effect.
I posted this problem in the Torque X forums and Dan provided me with enough information that I could replace the animated explosion sprite in the Blaster tutorial with an emitter. But he said that he's not an expert on the platformer kit and his information was too vague and I didn't find a solution for the drill.
Can you give a hint what I should try? Here is the corresponding thread:
www.garagegames.com/mg/forums/result.thread.php?qt=66628
Answer:
The animations in the Platformer Kit are managed by the ActorAnimationManager. You could set the DeathAnimation to a one frame animation of a blank image to get your actor to dissapear when he dies. You could also not specify an death animation and just set the actor's animated sprite invisible when it dies and visible again upon respawn.
That takes care of making the actor dissapear. Then you'll want to create a particle effect for the explosion. There is a virtual method called _die() on ActorComponent. Simply override the method and add your particle effect creation there (as detailed in the above link).
Here's a quick example
[TorqueXmlSchemaType]
public class ExplodingActorComponent : ActorComponent
{
public T2DParticleEffect ExplosionTemplate
{
get { return _explosionTemplate; }
set { _explosionTemplate = value; }
}
protected override void _die(float damage, T2DSceneObject sourceObject)
{
base._die(damage, sourceObject);
_animatedSprite.Visible = false;
if (_explosionTemplate != null)
{
T2DParticleEffect explosion = _explosionTemplate.Clone() as T2DParticleEffect;
explosion.Position = _sceneObject.Position;
TorqueObjectDatabase.Instance.Register(explosion);
}
}
protected override void _respawn()
{
base._respawn();
_animatedSprite.Visible = true;
}
T2DParticleEffect _explosionTemplate;
}Note that this assumes PlayOnLoad is true on the particle effect and that it will eventually delete itself. You can set all that up with the particle editor in TXB.
About the author
Formerly GarageGames designer and gameplay/engine programmer of 5 years. Founder and President at Flying Mongoose Labs, Lead Gameplay Engineer and Senior Designer at LumaArcade, head of the Las Vegas chapter of the IGDA.
#2
09/06/2007 (5:45 pm)
No man, they shred! 80's hair metal style!
#3
It didn't work and this is what I did:
I copied the above code into ActorComponent.cs.
I created a particle effect in TXB, named it "DieEmitter", checked "Template" and set its "Effect Mode" to KILL.
Where can I set PlayOnLoad is true?
I attached ExplodingActorComponent to the dragon and set "ExplosionTemplate" to "DieEmitter".
In TXB I switched "DieAnim" of the dragon's "PlayerDragonActorComponent" to "None"
The build in Visual C# Express was successful but when I started debugging, I got this error:
09/12/2007 (3:44 am)
Because XNA and TXB are new to me, I will ask these newby question for at least one more year...It didn't work and this is what I did:
I copied the above code into ActorComponent.cs.
I created a particle effect in TXB, named it "DieEmitter", checked "Template" and set its "Effect Mode" to KILL.
Where can I set PlayOnLoad is true?
I attached ExplodingActorComponent to the dragon and set "ExplosionTemplate" to "DieEmitter".
In TXB I switched "DieAnim" of the dragon's "PlayerDragonActorComponent" to "None"
The build in Visual C# Express was successful but when I started debugging, I got this error:
#4
Now just use the ExplodingActorComponent instead of the dragon actor component.
09/12/2007 (4:27 pm)
An actor is a MoveComponent. You can't have more than one on an object, as the assert implies. The solution is to change line 2 in the above code to the following:// change this public class ExplodingActorComponent : ActorComponent // to this public class ExplodingActorComponent : PlayerDragonActorComponent // double-check the name of this one
Now just use the ExplodingActorComponent instead of the dragon actor component.
#5
Thank you very much! It works :-)
Unfortunately, the dragon does not respawn anymore :-(
I also tried to implement the code into the DrillActorComponent but I get the following error:
When I jump on a drill, the particle fx appears only once per drill and the drill does not die. When I jump a second time on the same drill, there is no fx and even no collision detection with the drill. The dragon flies right through the drill, does not touch it and therefore cannot destroy it.
09/14/2007 (2:19 pm)
@ThomasThank you very much! It works :-)
Unfortunately, the dragon does not respawn anymore :-(
I also tried to implement the code into the DrillActorComponent but I get the following error:
When I jump on a drill, the particle fx appears only once per drill and the drill does not die. When I jump a second time on the same drill, there is no fx and even no collision detection with the drill. The dragon flies right through the drill, does not touch it and therefore cannot destroy it.
#6
09/14/2007 (3:20 pm)
Are you sure you put the base._respawn() line in? If not I'm pretty sure it won't respawn. For the player and the drills you should be able to debug any problems by setting a break point and stepping through the code. You'll want to make sure that AllowRespawn is true and that they each have enough lives to successfully respawn. Also, you'll want to make sure that the DrillHeadKillComponent isn't being disabled, or if it is make sure that it is being re-enabled when the drills respawn.
#7
AllowRespawn is checked and the dragon and the drill have 10 lives each.
But the dragon does not respawn and the drill does not die.
09/14/2007 (3:29 pm)
Quote:Are you sure you put the base._respawn() line in?Yes, I am. base._respawn() is there.
AllowRespawn is checked and the dragon and the drill have 10 lives each.
But the dragon does not respawn and the drill does not die.
#8
09/17/2007 (4:07 pm)
Did you step through it to make sure it's all happening in the right order?
#9
Here are some pics of the action:
When I jump on a drill, the particle effect is running fine:

But then I can walk right "through" the enemies.

Here is a video of this behaviour.
09/24/2007 (1:28 pm)
I set some breakpoints but the game never reaches the respawn function of the player and it doesn't jump to the part of the code where the drill should die.Here are some pics of the action:
When I jump on a drill, the particle effect is running fine:

But then I can walk right "through" the enemies.

Here is a video of this behaviour.
#10
09/24/2007 (1:29 pm)
DrillActorComponentusing System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using GarageGames.Torque.Core;
using GarageGames.Torque.T2D;
using GarageGames.Torque.PlatformerFramework;
namespace GarageGames.Torque.PlatformerDemo
{
/// <summary>
/// This component mainly just defines the how the Distance RPC is set for the drill's idle sound. It also makes sure that if a drill
/// was created from a spawn point that the spawn point knows not to respawn this drill after it dies.
/// </summary>
[TorqueXmlSchemaType]
class DrillActorComponent : ActorComponent
{
//======================================================
#region Private, protected, internal methods
protected override void _postUpdate(float elapsed)
{
base._postUpdate(elapsed);
// set the distance variable on the motor sound so the XACT RPC can change the volume
if (_motorSound != null)
_motorSound.SetVariable("Distance", _getDistanceToPlayer());
}
[TorqueXmlSchemaType]
public class ExplodingDrillComponent : DrillActorComponent
{
public T2DParticleEffect ExplosionTemplate
{
get { return _explosionTemplate; }
set { _explosionTemplate = value; }
}
public override void CopyTo(TorqueComponent obj)
{
base.CopyTo(obj);
ExplodingDrillComponent obj2 = (ExplodingDrillComponent)obj;
obj2.ExplosionTemplate = ExplosionTemplate;
}
protected override void _die(float damage, T2DSceneObject sourceObject)
{
base._die(damage, sourceObject);
_animatedSprite.Visible = false;
if (_explosionTemplate != null)
{
T2DParticleEffect explosion = _explosionTemplate.Clone() as T2DParticleEffect;
explosion.Position = _sceneObject.Position;
TorqueObjectDatabase.Instance.Register(explosion);
}
}
protected override void _respawn()
{
base._respawn();
_animatedSprite.Visible = true;
}
T2DParticleEffect _explosionTemplate;
}
protected override void _die(float damage, T2DSceneObject sourceObject)
{
base._die(damage, sourceObject);
// stop the sound, if we have one
if (_motorSound != null)
_motorSound.Stop(AudioStopOptions.AsAuthored);
// if this object was spawned, tell it's spawned object component not to recover
if (_actor.TestObjectType(PlatformerData.SpawnedObjectType))
{
CheckpointSystemSpawnedObjectComponent spawned = _actor.Components.FindComponent<CheckpointSystemSpawnedObjectComponent>();
if (spawned != null)
spawned.Recover = false;
}
}
protected float _getDistanceToPlayer()
{
// get the distance of this drill to from the player
return Vector2.Distance(_actor.Position, (T2DSceneGraph.Instance.Camera as T2DSceneCamera).Position);
}
protected override bool _OnRegister(GarageGames.Torque.Core.TorqueObject owner)
{
if (!base._OnRegister(owner))
return false;
// set this actor to collide with enemy triggers
// enemy triggers are used in the demo to tell the drills when to turn around
_actor.Collision.CollidesWith += PlatformerData.EnemyTriggerObjectType;
// give them a big enough ground Y threshold so they dont jitter
_groundCheckYThreshold = 2.0f;
// creat the drill sound and store the cue so we can control it's volume
_motorSound = SoundManager.Instance.PlaySound(@"data\sound\drill", "drill_motor_loop", _getDistanceToPlayer());
// create a DrillAIController and possess this actor with it
DrillAIController controller = new DrillAIController();
controller.PossessMover(this);
return true;
}
protected override void _OnUnregister()
{
base._OnUnregister();
if (_motorSound != null)
_motorSound.Stop(AudioStopOptions.AsAuthored);
}
protected override void _initAnimationManager()
{
// set the sound bank for this actor
_soundBank = @"data/sound/drill";
// assign the proper sounds for specific animations
_useAnimationManagerSoundEvents = true;
_animationManager.SetSoundEvent(TorqueObjectDatabase.Instance.FindObject("drill_fall_to_rollAnimation") as T2DAnimationData, "land_drill");
_animationManager.SetSoundEvent(DieAnim, "land_drill");
// set the drill_dies sound to play at frame 4 (5th frame) of the assigned DieAnim
_useAnimationStepSoundList = true;
_animationManager.AddStepSoundFrame(DieAnim, 4, "drill_dies");
}
protected override void _resetActor()
{
base._resetActor();
// reset the AI controller to run right
if (Controller != null && Controller is DrillAIController)
FSM.Instance.SetState(Controller as DrillAIController, "runRight");
}
#endregion
//======================================================
#region Private, protected, internal fields
protected Cue _motorSound;
#endregion
}
}
#11
09/24/2007 (1:35 pm)
PlayerDragonActorComponentusing System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Xna.Framework;
using GarageGames.Torque.Core;
using GarageGames.Torque.T2D;
using GarageGames.Torque.XNA;
using GarageGames.Torque.PlatformerFramework;
namespace GarageGames.Torque.PlatformerDemo
{
/// <summary>
/// This is a version of DragonActorComponent that creates a PlayerController and possesses itself during _OnRegister, aswell as
/// sets up an inventory with a slot for items named "Pepper". Also handles demo-specific respawn functionality.
/// </summary>
[TorqueXmlSchemaType]
class PlayerDragonActorComponent : DragonActorComponent
{
//======================================================
#region Public properties, operators, constants, and enums
public int PepperCount
{
get
{
if (_inventory != null)
return _inventory.Item("Pepper").Count;
return 0;
}
}
public Inventory Inventory
{
get { return _inventory; }
}
#endregion
//======================================================
#region Private, protected, internal methods
[TorqueXmlSchemaType]
public class ExplodingActorComponent : PlayerDragonActorComponent
{
public T2DParticleEffect ExplosionTemplate
{
get { return _explosionTemplate; }
set { _explosionTemplate = value; }
}
protected override void _die(float damage, T2DSceneObject sourceObject)
{
base._die(damage, sourceObject);
_animatedSprite.Visible = false;
if (_explosionTemplate != null)
{
T2DParticleEffect explosion = _explosionTemplate.Clone() as T2DParticleEffect;
explosion.Position = _sceneObject.Position;
TorqueObjectDatabase.Instance.Register(explosion);
}
}
protected override void _respawn()
{
base._respawn();
_animatedSprite.Visible = true;
}
T2DParticleEffect _explosionTemplate;
}
protected override void _die(float damage, T2DSceneObject sourceObject)
{
// dismount camera
_dismountCamera();
// turn the Player objec type off while dead
_actor.SetObjectType(PlatformerData.PlayerObjectType, false);
base._die(damage, sourceObject);
// modify the GUI lives count
PlatformerDemoGUI.Instance.LivesCount = _lives;
}
protected override void _tookDamage(float damage, T2DSceneObject sourceObject)
{
// if we're still alive, toss us away from the other object
if (_alive)
{
Vector2 direction = _actor.Position - sourceObject.Position;
direction.Normalize();
_actor.Physics.VelocityY = -60;
_moveSpeed = Vector2.Zero;
_inheritedVelocity = new Vector2(direction.X * 65);
_onGround = false;
}
if (_inventory == null)
return;
// if we have peppers, take them away
// if not, kill the dragon
if (PepperCount > 0)
{
_inventory.Item("Pepper").Count = 0;
FSM.Instance.SetState(_animationManager, "damage");
// update the pepper count in the HUD
PlatformerDemoGUI.Instance.PepperCount = PepperCount;
}
else
{
Kill(sourceObject);
}
}
protected override void _respawn()
{
// make sure we can respawn
if (!_allowRespawn)
return;
// reset demo collectible inventory slot
_inventory.Item("Pepper").Count = 0;
// modify the GUI pepper count
PlatformerDemoGUI.Instance.PepperCount = PepperCount;
// load the last saved checkpoint
CheckpointManager.Instance.LoadCheckPoint();
// call actor respawn
base._respawn();
// remount the camera
_mountCamera();
}
protected override void _respawnAnimFinished()
{
base._respawnAnimFinished();
// turn the Player object type back on when finished respawning
_actor.SetObjectType(PlatformerData.PlayerObjectType, true);
}
protected virtual void _mountCamera()
{
// camera mounting stuff
T2DSceneCamera camera = T2DSceneGraph.Instance.Camera as T2DSceneCamera;
if (camera.IsMounted)
camera.Dismount();
camera.Position = _actor.Position + new Vector2(0, -1);
camera.Mount(_actor, String.Empty, new Vector2(0, -1), 0.0f, true);
camera.UseMountForce = true;
camera.MountForce = 15;
camera.UseCameraWorldLimits = false;
camera.CameraWorldLimitMin = new Vector2(-1000, -1000);
camera.CameraWorldLimitMax = new Vector2(1000, 1000);
}
protected virtual void _dismountCamera()
{
T2DSceneCamera camera = T2DSceneGraph.Instance.Camera as T2DSceneCamera;
camera.Dismount();
camera.WarpToPosition(camera.Position, 0);
}
protected override bool _OnRegister(GarageGames.Torque.Core.TorqueObject owner)
{
if (!base._OnRegister(owner))
return false;
_inventory.Owner = owner;
_inventory.RegisterItemSlot(new PepperCollectibleItemSlot(), "Pepper");
_actor.SetObjectType(PlatformerData.PlayerObjectType, true);
_actor.Collision.CollidesWith += PlatformerData.EnemyObjectType
+ PlatformerData.PlayerTriggerObjectType;
PlayerController controller = new PlayerController();
controller.PossessMover(this);
// make sure armor modifier is set to 0
_armorModifier = 0;
// camera mounting stuff
_mountCamera();
// set initial HUD values
PlatformerDemoGUI.Instance.PepperCount = PepperCount;
PlatformerDemoGUI.Instance.LivesCount = Lives;
return true;
}
#endregion
//======================================================
#region Private, protected, internal fields
protected Inventory _inventory = new Inventory();
#endregion
}
}
#12
I hope that someone else is also interested in this and will have a look at it. :-)))
Thanx in adv!
09/28/2007 (6:00 am)
I'm stuck and cannot find the mistake :-(I hope that someone else is also interested in this and will have a look at it. :-)))
Thanx in adv!
#13
10/04/2007 (1:20 pm)
From the video it looks like the drill actor is removed, but the animation is still there. Maybe it's something in the animation manager. debug the death state and see if the components(animated sprite) are removed. I'm no good at the platformer kit either :).
#14
Sorry for the confusion! >_<
10/05/2007 (5:45 pm)
Baw.. I just realized there's no code to actually delete the actors on death in the kit. In the demo they are just made invisible by the actual animations themselves and then "despawned" by the spawn points when the player leaves range. Add a MarkedForDelete = true (if you're not using the checkpoint/spawner system) to the die method for the drill if Lives == 0 after base._die() is called. Or (if you are using the checkpoint/spawner system) just use a one frame blank animation for the death animation. Either one will fix the problem. Sorry for the confusion! >_<
#15
EDIT: Added this to death state in animation manager:
10/06/2007 (2:23 am)
That's why the FiringActorkept shooting :DEDIT: Added this to death state in animation manager:
if (!actorAnimMgr._actorComponent._animatedSprite.IsAnimationPlaying)
{
if (actorAnimMgr._actorComponent.Actor.TestObjectType(PlatformerData.SpawnedObjectType))
{
CheckpointSystemSpawnedObjectComponent spawned = actorAnimMgr._actorComponent.Actor.Components.FindComponent<CheckpointSystemSpawnedObjectComponent>();
if (spawned != null)
spawned.Recover = false;
actorAnimMgr._actorComponent.Actor.MarkForDelete = true;
}
else
{
actorAnimMgr._actorComponent.Actor.Visible = false;
}
}
#17
Cool! Thank you :-)
But why will the dragon not respawn? Did I miss something?
10/13/2007 (2:05 pm)
@ThomasQuote:Either one will fix the problem.
Cool! Thank you :-)
But why will the dragon not respawn? Did I miss something?
#18
#region Actor animation states =>
public class DieState =>
public override string Execute =>
Then below this line:
if (!actorAnimMgr._actorComponent._animatedSprite.IsAnimationPlaying)
10/15/2007 (6:02 am)
Public partial class ActorComponent =>#region Actor animation states =>
public class DieState =>
public override string Execute =>
Then below this line:
if (!actorAnimMgr._actorComponent._animatedSprite.IsAnimationPlaying)
#20
10/16/2007 (11:15 am)
Doesn't the dragon re spawn ? I just replaced the code in a fresh platformerDemo, it works fine (i think)
Torque Owner Zilla
Thank you very much :-)