+1 vote

I have two kinematic bodies ramming into each other in a scene. I want it so that if one kinematicbody detects the other, it will respond and load a script, however I can't seem to detect the other's presence. (Since the metadata is constantly returning zero). How does one detect collision in kinematicbody.

tool
extends KinematicBody2D
#Characteristics
export var hp = 1
export var damage = 1
#enum statuseffect {normal,damaged,cutting,poison,fire} 
#var priority = 0
export var speed = 1
export var power = 1
export var defense = 1
#Movement
export var playercontroler = 0
export var vel = Vector2()
export var gravity = 0
export var agility = 1000
#Children Nodes
onready var charspr = get_node("colid/sprite")
onready var hitbox = get_node("hitbox")
#Effects
export var speedcolor = Color("07ff00")
export var powercolor = Color("ff0000")
export var defensecolor = Color("1300ff")
export var normalcolor = Color("ffffff")


func _ready():
    set_fixed_process(true)
    pass

func _fixed_process(delta):
    #Input
    var mover = Input.is_action_pressed(str(playercontroler) + "right")
    var movel = Input.is_action_pressed(str(playercontroler) + "left")
    var attspeed = Input.is_action_pressed(str(playercontroler) + "attackspeed")
    var attpower = Input.is_action_pressed(str(playercontroler) + "attackpower")
    var attdefense = Input.is_action_pressed(str(playercontroler) + "attackdefense")
    #Input X axis
    if (mover):#mover
        vel.x = agility
    elif (movel):
        vel.x = -agility
    else:
        vel.x = 0
    #Input Y axis
    vel.y += gravity
    #Input Attack
    if (attspeed):
        add_to_group("speed")
        if charspr != null:
            charspr.set_modulate(speedcolor)
    elif (attpower):
        add_to_group("power")
        if charspr != null:
            charspr.set_modulate(powercolor)
#       add_to_group(priority)
    elif (attdefense):
        add_to_group("defense")
        if charspr != null:
            charspr.set_modulate(defensecolor)
#       add_to_group(priority)
    #MovePlayer
    var motion = vel * delta
    move(motion)
#   print(vel)
    #Slide player if colliding
    if is_colliding():
        var normal = get_collision_normal()
        motion = normal.slide(motion)
        vel = normal.slide(vel)
        move(motion)
        #Collision for hitbox
        #If the metadata comes back 0 it has not collided
        print(str(playercontroler)+" Collider's Metadata is: "+str(get_collider_metadata()))




    pass
in Engine by (266 points)

Metadata is empty, but did you actually got them to collide? Is if is_colliding(): becoming true when that happens?

Yes they are colliding, sorry I did not include that part in the statement.

2 Answers

+1 vote
Best answer

Thank you Zylann for helping me out. I think I get it now.

In generic terms.
You should have the following 3 nodes
---body (anytype)
----------Area (2D or spatial)
----------------Collision (2D or spatial)
---collision (2D or spatial) #This is if you want the character to collide with stuff

while in gdscript

extends (What ever body type you have)

func _ready():
    get_node("Area").connect("area_enter", self, "_on_collision")
    pass

func _on_collision(value):
    collider = value.get_parent()
    #Then your else if ladder

Now In my case, as an example.
---Player (KinematicBody2D)
----------area (Area2D)
----------------hitbox (CollisionShape2D)
----------colid (CollisionPolygon2D)

extends KinematicBody2D

func _ready():
        get_node("area").connect("area_enter", self, "_on_hitbox_collision")
        pass

func _on_hitbox_collision(value):
    collider = value.get_parent()
    if (collider.is_in_group("speed")):
        pass #This is where My code should go if alternate  player is speed type
    elif (collider.is_in_group("power")):
        pass #This is where My code should go if alternate player is power type
    elif (collider.is_in_group("defense")):
        pass #This is where My code should go if alternate  player is defense type
by (266 points)
0 votes

You could try something like:

# Check if we have collided
        if(myCharacter.is_colliding()):         
            # Get node that we are colliding with
            var entity = myCharacter.get_collider()

... then do as you will with entity

note... this is when I'm using a specific class. Yours may look more like:

# Check if we have collided
        if is_colliding():          
            # Get node that we are colliding with
            var entity = get_collider()

I hope I understood you properly, if not just say.

by (810 points)

Wait I can only get collision data from pacific entities? Is there a way to get collision data by a group of nodes.

I have two of these kinematicbodies set up, to collid with each other. And they are both from the same group, and instance scene. Is there a way to tell a collier with groups?

What get_collider returns is the node that collided, so if you put it on a group... just check its group^^ with entity.is_in_group("test") for example.

I have tried using the is_in_group() function before. It failed, But I tried it again anyway and still got

Invalid call. NONEXISTENT FUNCTION 'is_in_group' in base 'Nil'.

the function for some reason doesn't exist in KinematicBody2D. I don't get it. I'm upset. It's really hard to make a game without basic collision.

"in base Nil" suggests that entity is null. The function exists in KinematicBody2D, it's just that get_collider() gave you nothing. Which is unexpected ^^"

I have no idea how to use this function. So I'll show you what i've been using it as. Maybe you can tell me what I am doing wrong.

if is_colliding():
        #Collision for hitbox
        var entity = get_node("hitbox").get_collider()
        if entity.is_in_group("player"):
            entity.sethp(damage)
            print(entity.hp)
            pass
        else:
            print("no entity")

Wait... you are getting the collider from another node? I don't know if it's supposed to work (never tried this setup before), usually my script is on the KinematicBody/RigidBody directly and I use get_collider(), not get_node("hitbox").get_collider().
Also, what is the type of your hitbox node? I thought you had only two KinematicBodies?

Hitbox is a CollisionShape node inside the KinematicBody. This has been changed some. Now it is a area2D node. Well a lot of things has changed

Here's a complete tree
KinematicBody2D "Player"
-CollisionPolygon2D "colid"
-Area2D "area"
--CollisionShape2D "hitbox"

if is_colliding():
        #Collision for hitbox
        var entity = area.get_collider()
        if entity.is_in_group("player"):
            entity.sethp(damage)
            print(entity.hp)
            pass

If this does not help, then I'll upload the project on github.

So if you use Area2D to detect the other's Area2D, you could actually connect the area_enter signal on your Area2D instead of getting collider every frame:

func _ready():
    get_node("hitbox").connect("area_enter", self, "_on_area_enter_hitbox")

# Will be called once when another area collides
func _on_area_enter_hitbox(other_area):

    # Assuming your two objects have the same hierarchy you described,
    # you can get the other's root this way
    var other_kinematic = other_area.get_parent()

    # Do stuff

My project is here.

https://github.com/lavaduderDev/G13-Fighter

I haven't added the area collision to it though, this was upload before you responded.

Welcome to Godot Engine Q&A, where you can ask questions and receive answers from other members of the community.

Please make sure to read How to use this Q&A? before posting your first questions.
Social login is currently unavailable. If you've previously logged in with a Facebook or GitHub account, use the I forgot my password link in the login box to set a password for your account. If you still can't access your account, send an email to webmaster@godotengine.org with your username.

Categories