these kind of code should be run from the player, not the other way around.
an enemy or obstacle should not tell the player what to do, the player should react to the environment and execute its own state machine.
there could be a billion reasons why this doesn’t work, and that’s why it’s a bad idea to code it like this.
add metadata damage to each enemy with a number representing the damage type.
this is a very simple example, in an actual game you want to instead change a state machine to hurt or electricity, and the state machine can also be in a mode like “death” or “jumping”, so you would test for that first and do whatever needs to be done with the character.
You have a couple problems with your code, and I think they are worth mentioning.
In your first line, you are changing the accepted arguments from the body_entered signal. Instead of accepting anyNode you are only accepting PlayerController nodes. If your Area2D ever collides accidentally with anything else, your game is going to crash.
On your second line, you check if the node - which can only be a PlayerController node is in the group Player This is redundant checking. Unless have more than one player - which based on your group name, you don’t.
Neither of these things you’ve done are how you should check to see if you collided with a player. Instead, you should be using Physics Collision Masks and Layers. The only thing that should trigger this function is something on the correct collision layer. That’s all you need. Otherwise, you’re doing the same check 3 times and introducing 3 failure points in your code.
You want the PlayerController to be responsible for what happens when it gets damaged like @jesusemora said. In this case , the easiest way is to add a damage function to the player and call it.
Consider using an AnimationTree with your AnimationPlayer to handle animation transitions because that’s likely to be your next problem when you get this working.
ok,ok I believe of having understood . So , about the trap object I set metadata named “Damage” = 1. After that I add script on characterody2D (The player) containing:
func _on_area_2d_body_entered(body):
match body.get_meta("Damage", 1):
1:
animation_player.play("electricity")
mmm, but nothing happen…surely I am missing something…
However despite the animation exists in the AnimationPlayer it is not played…
What looks strange is that within animation player i send to the PlayerController ckass the animation there is…
did you connect an Area2D to your player script? the function should have a symbol next to it.
It’s a better “design” to put the collision detections in a script in the Area2D itself and not the player, and instead call some receive_damage() function in player, that then plays the animation.
this has many advantages, one is that, you can use multiple Area2Ds for collision with different nodes and they will be independent.
one example of how this is useful would be if we had an Area3D for the body of a soldier, and one for the head. the each Area3D could have meta_data wiht how much damage they receive, and then read that number and pass it to a “receive_damage(damage : int)” function in player. you could also swap them around for different effects.
when I said the player should react to the environment and obstacles should not tell the player to do things, think of the Area2Ds as part of the player, but as a sort of nerve. the “nerve” can send a “pain” “sensation” to the player, but the player will decide if it is time to scream or jump, depending on the state they are on at the moment.
the way get_meta works is, the first argument is the name of the metadata you want to retrieve, the second argument (here is 1) is a value that the function will return if the metadata was not found.
this is a great and safe way to do checks, as it will always work with no errors, and you can define the default behaviour when that number is returned. it could be a default damage, or you could use it to test for bugs like if you forgot to set metadata on a node or if it is in the wrong collision layer.
no, you add an Area2D node child to the player scene to use with damage detection.
leave the charactercontroller to collide with walls and obstacles.
are you calling the function?
but also, you are not implementing a state machine.
the problem with animation player is that when you call play it overrides the previous animation. so if you are calling play in process this will never work.
you need a state machine. create an int, called it something like state and test for it in process:
func _process(_delta):
match state:
0:
#move
#move/control code goes here
1:
#dead
animation_player.play("dead")#do nothing
2:
#electrocuted
animation_player.play("electricity")#plays the animation until a condition is met that changes the state back to 0, like a timer.
await get_tree().create_timer(0.5).timeout#wait 0.5 seconds
state = 0#go back to move state
func damage(type : int = 0) -> void:
match type:
ELECTRICITY:
state = 2
it is also a good idea to use enums instead of strings. like this:
into damage function that I defined within PlayerController class, I wrote:
func damage(type: String):
match type:
"electricity":
var curr_anim = $animationEffects/AnimationPlayer.get_current_animation()
print('Current animation is: '+str(curr_anim)) #it tells me "moving" and is correct
$animationEffects/AnimationPlayer.play("electricity")
var followinAnim = $animationEffects/AnimationPlayer.get_current_animation()
print('Following animation : '+str(followinAnim)) #it tells me "electricity" and is correct
The problem is although in the AnimationPlayer animation “electricity” is defined, I dont see playing the animation…
after having looking for info about my problems, I tryed to insert into the damage function I defined, firstly play the RESET anim and then the .advance(0). After all I played the wished animation… but nothing happened