How to play an animation from one script to another

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By JayH

I’d like to know how to play an animation that is in another Scene/Script.

In other words, I have multiple springs for a Player to launch from.

Scene Tree example:

MainLevel
…Player
…Springs
…Spring1
…Spring2
…Spring3
…Spring4

The Spring script can play it’s animation with:

$AnimatedSprite.play("SpringBounce")

I can’t Hard Reference each node in the Scene, I need a way to trigger the animation in the main Spring script from the Player Script.

Thanks.

does the player know with which spring it is interacting with? if so it is as simple as getting the reference to the spring node and calling whatever method plays the animation

MEDBVLL | 2022-07-29 12:31

Hi,

The Player receives a Signal emitted from The Springs Aera2D collision.

JayH | 2022-07-29 13:06

I might be wrong but in my opinion player script shouldn’t be responsible for triggering animation on springs.

I think I would go with script on spring node with Area2D. If player body enters Area2D then script on spring node plays “SpringBounce” that way it should be flexible and you can make as much spring nodes as u wish. Because they will always work.

Player should be responsible for “player” things.

sporx13 | 2022-07-29 13:33

From what I read and learnd online it should not be the job of the Player to request information from other Scripts/Scenese/Nodes, the other scripts should inform the Player instead.

In the Player script I have a conditional check that requests that the Player is not only touching the Spring (From the emitted Signal from the Springs script), but also falling. That way he’s able to walk through the Spring and can only trigger it when he lands on it.

I can’t believe i can’t find any information on this topic. Most games will have more than one enemy, sipke, springs etc. Being able to reference the main Scene nodes of these multiple objects is vitally important.

An absolute path/Direct path isn’t possible. Using Autoload and Singletons seem over the top. Groups and Signals is all that’s left. But the latter I don’t know how to use to play the animation, there’s no examples anywhere.

I’ve posted this same questions multiple times and rephrased the question, but no one can give me a direct answer.

I can’t move on with Godot until I understand this process :frowning:

JayH | 2022-07-29 13:47

:bust_in_silhouette: Reply From: Gil-Koren

You should use the Spring’s signal of collision.
The same signal that fires in the player when you detect if he should be launched upwards is fired in the Spring scene. Attach a script to your basic spring scene if it doesn’t have one yet, and connect the collision signal to it.
Then add the player node to a group (next to the signals in the inspector) called “Player”
so you can know if it’s the player colliding and add this bit of code in the new function created by the signal:

func _area_entered_spring(area):
    if area.is_in_group("Player"):
        $AnimatedSprite.play("SpringBounce")

If you have anymore questions feel free to ask!
I read the comments to your original question and it seems the concept you are getting stuck with is Signals.
If you want, there should be some great tutorials on youtube on this topic.

I have all this already.

But there isn’t any tutorials online that covers playing an animation from another script in the example I provided.

All the online tutorials only use one instanced scene, where as I have multiple springs.

The other tutorials only focus on collision, which I have done already as I said.

JayH | 2022-07-29 15:31

If you mean playing the spring animation from the player script when it bounces, you can add to the same funciton where you play the player animation for bouncing and change it’s velocity this bit of code after adding the spring scene to a group called Spring:

if area.is_in_group("Spring"):
    area.$AnimatedSprite.play("SpringBounce")

The signal of collision in the player passes the body it interacts with as a paramter and you can call function of that scene by accessing the parammter (I belive the default for the collision is area, change the area in the code block above to whatever is the passed paramter. If you want this to scale better i suggest adding a function in the spring script and every other type of interactable called something along the lines of PlayerInteracted, so you can just add the scenes to a group called “Interactables” and call that function each time

Gil-Koren | 2022-07-29 15:52

Hi, thanks for your reply. Yes, I wish to play the spring animation from the Player script.

Just so we’re on the same page, here’s what I have in the Spring script:

extends Area2D

signal PlayerOnSpring
signal PlayerNotOnSpring


func _on_Spring_body_entered(body: Node) -> void:
	if body.is_in_group ("Player"): #Check if the Player body entered (Player Group)
		emit_signal("PlayerOnSpring") #Emit Signal 
		
		        
func _on_Spring_body_exited(body: Node) -> void:
	if body.is_in_group ("Player"): #Check if the Player body entered (Player Group)
		emit_signal("PlayerNotOnSpring") #Emit Signal 
		

In part of the Player’s script I have which is the received Signals:

#CHECK IF PLAYER ON THE SPRING
func _on_Spring_PlayerOnSpring() -> void:
	playerSpringJump = true
	
	
#CHECK IF PLAYER OFF THE SPRING
func _on_Spring_PlayerNotOnSpring() -> void:
	playerSpringJump = false

And the part in the Player’s script where I’d like to trigger the animation:



#SET IF ON THE GROUND OR NOT
	if is_on_floor():
		if not onGround:
			$FootDust.restart() # Reset the Particle effect so that it's not half way though
			$FootDust.emitting = true
			onGround = true
	else:
		onGround = false
		if myVelocity.y < 0:
			$AnimatedSprite.play("Jump")
		if myVelocity.y > 0 :
			$AnimatedSprite.play("Fall")
			print(myVelocity.y)
			#BOUNCE PLAYER ON SPRING/MUSHROOM
			if playerSpringJump:
				myVelocity.y = -springJumpPower
				#$AnimatedSprite.play("SpringBounce") # Where the animation should play 
				
	
	myVelocity = move_and_slide(myVelocity, FLOOR) #MOVE PLAYER WALKING

The Player can only bounce on the Spring when Overlapping the Spring AND when he is falling. This allows him walk past the spring the rest of the time :wink:

I’m not sure what parameter I require to swap with the ‘area’ you mentioned.

JayH | 2022-07-29 17:26

Ok, i misunderstood the scripts and scene structure. Try this:
In the spring script, pass self as a paramter when emitting the signal, and save this param in the player object as a variable named interacting_object.
Then, you can use interacting_object.PlayerInteracted() as mentioned before. This way you can play the animation on the relevant object everytime without re-connecting every interactable, just by passing self as a param.
Let me know if this is what you ment and if it worked!

Gil-Koren | 2022-07-29 17:37

Thank you for your time.

I’ve added self to the Signal emitter:

func _on_Spring_body_entered(body: Node) -> void:
	if body.is_in_group ("Player"): #Check if the Player body entered (Player Group)
		emit_signal("PlayerOnSpring", self) #Emit Signal with Self
		#print("on Spring!")
		#$AnimatedSprite.play("SpringBounce")

The variable you said to add to the Player’s script:

var interacting_object

Does this need a type?

I’m a little unsure on what you mean exactly when you said:

“Then, you can use interacting_object.PlayerInteracted() as mentioned before.”

If you can, could you clarify a little more please :wink:

JayH | 2022-07-29 19:04

The variable does not need a type.
What i meant is that you can add a function called PlayerInteracted() to every interactable object so you can easily call it each time you want it do something. In this case you should add to the Spring script:

func PlayerInteracted():
    $AnimatedSprite.play("SpringBounce")

And in the Player script, inside the if playerSpringJump you should add:

interacting_object.PlayerInteracted()

Hopefully this was more clear. Update me how it went! :slight_smile:

Gil-Koren | 2022-07-29 19:13

That’s great, so basically calling a function from the Spring script with the Signal.

I have a small issue though, adding self to the Signal from the Spring script has stopped my Player’s received signal from working for the collison of the Spring. The collision works at the Spring end, just not received at the Player’s.

Do I need something to pass in the () brackets of the function?

#CHECK IF PLAYER ON THE SPRING
func _on_Spring_PlayerOnSpring() -> void:
	playerSpringJump = true
	#print("on spring")

JayH | 2022-07-29 19:52

I think the problem here is that you are passing an argument to a function that doesn’t accept any arguments. Also, it does not seem you change the value of interacting_object inside the function. Try this:

    func _on_Spring_PlayerOnSpring(spring) -> void:
        playerSpringJump = true
        interacting_object = spring 

Gil-Koren | 2022-07-30 08:09

Hi,

I was hoping to get back here sooner, but the servers were down.

The animation now plays now, however it only plays the once.

Any ideas?

JayH | 2022-08-01 15:20