I have completed this tutorial, I want to add some features to it for more practice. One of the possibilities is the explosion of mobs. For this, I made a bomb object, when the player hits it, all the mobs in the scene must be destroyed, but before the destruction, the explosion animation must occur.
I wrote the following code, but this animation will be added to the mobs that are added to the scene later!
Player.cs
private void OnBodyEntered(Node2D body)
{
if (body.Name == "Mob")
{
Hide(); // Player disappears after being hit.
EmitSignal(SignalName.Hit);
// Must be deferred as we can't change physics properties on a physics callback.
GetNode<CollisionShape2D>("CollisionShape2D").SetDeferred(CollisionShape2D.PropertyName.Disabled, true);
}
else if (body.Name == "Bomb")
{
EmitSignal(SignalName.ActiveBomb);
}
}
Main.cs
public async void Explosion()
{
var bomb = GetNode<Bomb>("Bomb");
var animatedSprite2D = bomb?.GetNode<AnimatedSprite2D>(nameof(AnimatedSprite2D));
animatedSprite2D?.Play("explosion");
GetTree().CallGroup("mobs", AnimatedSprite2D.MethodName.Play, "explosion");
await ToSignal(GetTree().CreateTimer(0.5), SceneTreeTimer.SignalName.Timeout);
GetTree().CallGroup("mobs", Node.MethodName.QueueFree);
bomb?.QueueFree();
}
It seems that the code is correct in theory, but it does not work correctly in terms of performance.
And a side note, when it uses Task instead of Void, the code does not work properly.
P.S. when you say it “does not work correctly in terms of performance” do you mean that it does not do what you expect; or is there a performance issue?
The player’s ActiveBomb signal is connected to the Explosion method in the script from Main.cs.
I also fixed the problem that when mobs are added to the scene, they are accompanied by the explosion animation. The problem was in the mob script, which was fixed as follows:
Mob.cs
public override void _Ready()
{
var animatedSprite2D = GetNode<AnimatedSprite2D>(nameof(AnimatedSprite2D));
string[] mobType = animatedSprite2D.SpriteFrames.GetAnimationNames();
var animationName = mobType[GD.Randi() % mobType.Length];
animatedSprite2D.Play(animationName == "explosion" ? "walk" : animationName);
}
I didn’t write a script for the bomb because I wanted to keep the structure of the training and act like it
Its name is correct. This problem is not because mobs are instantiated through code?
private void OnMobTimerTimeout()
{
// Note: Normally it is best to use explicit types rather than the `var`
// keyword. However, var is acceptable to use here because the types are
// obviously Mob and PathFollow2D, since they appear later on the line.
// Create a new instance of the Mob scene.
Mob mob = MobScene.Instantiate<Mob>();
// Choose a random location on Path2D.
var mobSpawnLocation = GetNode<PathFollow2D>("MobPath/MobSpawnLocation");
mobSpawnLocation.ProgressRatio = GD.Randf();
// Set the mob's direction perpendicular to the path direction.
float direction = mobSpawnLocation.Rotation + Mathf.Pi / 2;
// Set the mob's position to a random location.
mob.Position = mobSpawnLocation.Position;
// Add some randomness to the direction.
direction += (float)GD.RandRange(-Mathf.Pi / 4, Mathf.Pi / 4);
mob.Rotation = direction;
// Choose the velocity.
var velocity = new Vector2((float)GD.RandRange(150.0, 250.0), 0);
mob.LinearVelocity = velocity.Rotated(direction);
// Spawn the mob by adding it to the Main scene.
AddChild(mob);
}
Exactly as I expected.
The name for your AnimatedSprite2D node is “AnimatedSprite2D” with a capital A. Your code is attempting to find an AnimatedSprite2D with a regular a.
Your scene node: AnimatedSprite2D
Your code request: animatedSprite2D
Don’t use nameof() to retrieve the default name for a node. Compare the node type or use your own string constant when searching for a node.