how can I define collision for "AnimatedSprite" node for 2D "fighting games"?

mdswampmdswamp Posts: 53Member
edited September 2 in Programming

Hi everybody. I began to learn Godot 2D recently and until now I have many problem with gdscript :smile: ... I think my Q is obvious. I understand Godot physics, but i couldnt define collision for specific moving frames in animatedsprite. I try to create a fighting game. i use animated frame for hitting (for ex: fist to head). i can move my character, i just cant make this collision in script, i used area2d and connect area_enter/body_enter, but nothing happens, because it seems there is no shape definition for animation sprite. could someone help me please? thanks in advance

p.s: I use KinematicBody2d for players.


Tags :

Answers

  • mdswampmdswamp Posts: 53Member

    ok.. if i use separated sprites instead of animated sprite and create shape for each one of them, how can i code collision when each of them activated after hitting specific key?

  • TwistedTwiglegTwistedTwigleg Posts: 897Admin
    Answer ✓

    Every CollisionShape object in Godot has a disabled property.

    Here is what I would suggest doing: Make polygon collision shapes for each frame of animation (or each frame of animation you want to have a special collision shape for).

    Then disable all of the collision shapes but the collision shape for the for the initial frame in the current animation. For example, disable all of the collision shapes for all of the animations, but leave the collision shape for the first frame in the idle animation enabled.

    When you change animation frames, you disable the currently enabled collision shape (since that was for the last animation frame) and enable the collision shape for the new frame.


    I have no idea on what would be the best way to structure this. Maybe you could do something like what I wrote below?

    extends KinematicBody2D
    var ANIMATION_FRAMES;
    var current_animation_frame;
    ""
    func _ready():
        "Data structure: Name of animation : [animation frame, collision shape node (can be used for multiple frames!)]"
        ANIMATION_FRAMES = {
            "Idle_01":[0, get_node("animation_collision_shapes/idle/shape_01")],
            "Idle_02":[1, get_node("animation_collision_shapes/idle/shape_01")],
            "Idle_03":[2, get_node("animation_collision_shapes/idle/shape_02")],
            "Attack_01":[3, get_node("animation_collision_shapes/attack/shape_01")],
            "Attack_02":[4, get_node("animation_collision_shapes/attack/shape_02")],
        }
        current_animation_frame = "Idle_01"
    ""
    func change_animation(animation_name):
        " Check to see if we need to disable a old collision shape... "
        if (current_animation_frame != null):
            "Disable the old collision shape"
            ANIMATION_FRAMES[current_animation_frame][1].disabled = true
        ""
        " Enable the new collision shape "
        ANIMATION_FRAMES[animation_name][1].disabled = false
        " Change the sprite's animation "
        get_node("sprite").frame = ANIMATION_FRAMES[animation_name][0]
        " Update current_animation_frame so we can disable the collision shape when the animation changes"
        current_animation_frame = animation_name

    Keep in mind this is untested code, I just added it to give an idea on how to go about changing the collision shape. You're needs may be different, and I have no idea if what I wrote below even works, let alone is a good way to achieve collision shape swapping.

    Hopefully this helps!

  • mdswampmdswamp Posts: 53Member

    Hi TwistedTwigleg, it's great, it's really helpful, thank you :)

  • mdswampmdswamp Posts: 53Member
    edited August 30

    ok, somehow i managed collision between two kinematicbody2d with animated sprite (or separate sprites/shapes) [thanks to TwistedTwigleg]. now i have another problem, it seems when kinematicbody2d stops moving and i press hitting buttons, area2d does not detect any collision. this is my script for moving and detecting collision for kinematicbody2d (player1)
    for now i use separated sprite in this code, Any help would be greatly appreciated :)

    extends KinematicBody2D
    
    const speed = 600
    var velocity = Vector2()
    onready var sprite0 = get_node("Idle")
    onready var sprite1 = get_node("RightFist")
    onready var sprite2 = get_node("LeftFist")
    onready var sprite3 = get_node("Hurt")
    onready var shape0 = get_node("IdleShape")
    onready var shape1 = get_node("RightFistShape")
    onready var shape2 = get_node("LeftFistShape")
    
    func _ready():
         set_fixed_process(true)
    
    func _fixed_process(delta):
         velocity = Vector2()
    
         if Input.is_key_pressed(KEY_PERIOD):
            sprite1.show()
            shape1.set_trigger ( false )
            sprite0.hide()
            sprite2.hide()
            sprite3.hide()
            shape0.set_trigger ( true )
            shape2.set_trigger ( true )
    
         elif Input.is_key_pressed(KEY_COLON):
            sprite2.show()
            shape2.set_trigger ( false )
            sprite0.hide()
            sprite1.hide()
            sprite3.hide()
            shape0.set_trigger ( true )
            shape1.set_trigger ( true )
    
         else:
            sprite0.show()
            shape0.set_trigger ( false )
            sprite1.hide()
            sprite2.hide()
            sprite3.hide()
            shape1.set_trigger ( true )
            shape2.set_trigger ( true )
    
         if Input.is_action_pressed("ui_right"):
            velocity.x += 1
         if Input.is_action_pressed("ui_left"):
            velocity.x -= 1
         if Input.is_action_pressed("ui_down"):
            velocity.y += 1
         if Input.is_action_pressed("ui_up"):
            velocity.y -= 1
         if velocity.length() > 0:
            velocity = velocity.normalized() * speed
    
         var motion = move(velocity * delta)
         if (is_colliding()):
            var n = get_collision_normal()
            motion = n.slide(motion)
            velocity = n.slide(velocity)
            move(motion)
    
    func _on_Head02_body_enter( body ):
         shape0.set_trigger ( false )
         shape1.set_trigger ( true )
         shape2.set_trigger ( true )
         if (Input.is_key_pressed(KEY_PERIOD) || Input.is_key_pressed(KEY_COLON)):
            print(get_name())
    
  • TwistedTwiglegTwistedTwigleg Posts: 897Admin

    Quick question: Are you using Godot 3, or Godot 2? The set_trigger function (as far as I know) only works in Godot 2, so that could be why it is not working if you are using Godot 3.

    If you are using Godot 3, I think you need to replace set_trigger(true) and set_trigger(false) with disabled = true or disabled = false for it to work with Godot 3. If you are using Godot 2, then using set_trigger will do the same thing as disabled.


    Looking at the code, I do not see anything obvious that could be causing the problem. Do the sprites change when you press/hold either the colon or period keys?

    It could be that the _on_Head02_body_enter function is disabling the collision shapes, since any collision body that enters Head02 will cause the collision shapes to change, but it's hard to say if that is/could be what is causing the issue.

    One thing you could do to try and find the problem is by printing whenever you change the state of the collision shapes.

    Something like print ("Shape 0 state: ", shape0.is_trigger(), " Shape 1 state:", shape1.is_trigger(), " Shape 2 state:", shape2.is_trigger()) for Godot 2.

    For Godot 3, you could do something like this: print ("Shape 0 state: ", shape0.disabled, " Shape 1 state:", shape1.disabled, " Shape 2 state:", shape2.disabled)


    (Side note: I indented the code part of your post so it shows correctly :smile: . If you have add single tab indent when posting code, the forums will format it correctly)

  • mdswampmdswamp Posts: 53Member
    edited August 30

    Hi Twisted :)
    first of all, Thank you for all your assistance
    second, Im using Godot v2.1.5, godot 3 does not support my old Graphic card :wink:
    A)) i was wrong, i use "print code" you wrote and in output i had reasonable response, but it seems when fists(right or left) enter from sides of the opponent head (i use capsule shape on the head), collision codes response to it, but when it hits straight to the forehead, nothing happens in output. maybe there is conflict between shape1 and shape2 of player1 and idle shape (shape0) of player2, because i think they collide with idle shape of player2 first and then collide with head's area2d.
    B)) when i play with player2 it seems it does not work very well, i think i should put the opponent in another scene to work right, but when i do that, i have another problem.
    C)) when we have multiple scene (for ex main, player1,player2), how can i connect area2d node from player2 to player1?. i searched for it, but i couldnt understand how to do that, i created my separated scenes, but this code did not work right :unamused: ... would you please help me with this?thx in advance

  • mdswampmdswamp Posts: 53Member

    ok, another thing happens when i hit colon/period key (colon/period belong to player1). when collision happens, i see this in output:

    ** Debug Process Started **
    Shape 20 state: False
    Shape 21 state:True
    Shape 22 state:True
    Shape 10 state: False
    Shape 11 state:True
    Shape 12 state:True
    ** Debug Process Stopped **

    shape20,21 and 22 belong to player2 and shape 10,11 and 12 belong to player1.. is this normal to see output from both player when one of them is hitting??

  • TwistedTwiglegTwistedTwigleg Posts: 897Admin
    Answer ✓

    @mdswamp said:

    Hi Twisted :)
    first of all, Thank you for all your assistance

    No problem! I'm happy to try and help :smile:

    second, Im using Godot v2.1.5, godot 3 does not support my old Graphic card :wink:

    Ah, okay! Good to know. It's been awhile since I've used Godot 2, but when I saw set_trigger, I realized that the project could be using Godot 2 and not Godot 3 like I assumed.

    A ...

    Good to know the output is (for the most part) like you would expect. As for the straight punches not working, it's hard to say, but it means the Area2D node's body_entered signal is not being triggered. It could be that the fist (left or right) does not leave the opponents head, and so it does not trigger another body_entered signal because the body never exits.

    But it's hard to say. The fact that the side collisions makes me guess the problem is the Area2D node is not noticing the fists hitting when it's straight. You may be able to check and see if this is happening by moving the player's far enough apart where the fits can only hit when going straight, therefore (in theory) the fists should enter the Area2D and send the body_entered signal, and then sent the body_exited when they leave.

    B ...

    Breaking them out into separate scenes sounds reasonable, though you can (probably) work using one scene if you want to. It may just be the code or scene needs some tweaking.

    C ...

    You should be able to do something like this (it's been awhile since I've used Godot 2.0, but I think this should work):

    "Obviously you are not using a Node2D, but this is just for example!"
    extends Node2D
    "This makes it where you can set the path to the Area2D in the editor!"
    export (NodePath) var path_to_area
    "We'll store the area for later use (optional)"
    var other_area_in_scene;
    func _ready():
        "We can use get_node and that will put the Area into other_area_in_scene"
        other_area_in_scene = get_node(path_to_area);
        "We can connect signals using the connect function"
        "The first argument is the name of the signal we want to connect. The second argument is the"
        "object whose function we want to call, and the third argument is the function that is called when the"
        "Signal is emitted"
        other_area_in_scene.connect("body_entered", self, "other_area_body_entered")
    "Then we can react to the signal like normal!"
    func other_area_body_entered(body):
        print ("Something hit the other area!")
    

    ok, another thing happens when i hit colon/period key (colon/period belong to player1). when collision happens, i see this in output:

    It depends on where the print statement is, but I would guess what is happening is when one player is punched, at some point one of the hands (or something) in the other player hit the original player, making it seem like both players have been hit. It's hard to say for sure though, but that is what I would guess is happening.


    It's been awhile since I've used Godot 2, so I'm not sure how helpful my help will be :lol: Hopefully it helps and gives you an idea on how to fix the problems!

  • mdswampmdswamp Posts: 53Member

    ok, thanks, now i think with these infos, i should play with shapes/codes to make it works. thank you again for your precious infos :)

  • mdswampmdswamp Posts: 53Member

    Hi again.. :)
    after several days of struggling with this simple game, I found that if i hit R/T button which are used for punching, when i press the key and hold it and go to the opponent, opponent area2D feels the punch and print it in output, thats why i thought there is a connection between moving and punching toghether.. but i didnt find any thing to solve this, it seems this engine design for simple collision (i mean when a shape entering or crossing from border of another shape), ik im a beginner in coding, specially in developing game, but i dont understand why a simple task should be so hard to put it in game... still using codes in above comment, if someone wants to help me.. thank you for reading.. :)

Sign In or Register to comment.