0 votes

Hi!

I'm pretty new at godot and i'm trying to prototyping a game. I'm having problems to detect the collision point of my charater's arrows on moving objects.

My character throws arrows and the arrows has to get stucked on platforms and enemies in the collision point.

When the arrow collides i set the arrow velocity to zero, change the arrow scene's parent to the collided object and update arrow position. But the result is not much accurate and the arrow get stucked outside the object sometimes.

enter image description here

In the screenshot you can see the player (green box, KinematicBody2D), the moving object (godot icon, KinematicBody2D) and the arrow (black box, tried Area2D, Raytrace2D). The moving object is moving up and down using a sinusoidal pattern.

I've tried using a Area2D for the arrow.

extends Area2D

var velocity: = Vector2(1000.0, 0.0)

func _physics_process(delta: float) -> void:
    position += velocity * delta


func _on_VisibilityNotifier2D_viewport_exited(viewport: Viewport) -> void:
    queue_free()


func _reparent(body: PhysicsBody2D, anchor: Vector2) -> void:
    #avoid visibility notifier signal while changing parent
    $VisibilityNotifier2D.disconnect("viewport_exited", self, "_on_VisibilityNotifier2D_viewport_exited")
    get_parent().remove_child(self)
    body.add_child(self)
    set_owner(body)
    $VisibilityNotifier2D.connect("viewport_exited", self, "_on_VisibilityNotifier2D_viewport_exited")
    set_position(anchor)


func _handle_hit(body: PhysicsBody2D, anchor: Vector2) -> void:
    $CollisionShape2D.disabled = true
    _reparent(body, anchor)


func _on_Arrow_body_entered(body: PhysicsBody2D) -> void:
    var anchor: = get_global_position() - body.get_global_position()
    $Timer.start()
    velocity = Vector2.ZERO
    call_deferred("_handle_hit", body, anchor)


func _on_Timer_timeout() -> void:
    queue_free()

Or a raycast to project the movement and find the collision point.

extends Node2D

export var velocity: = Vector2(100.0, 0.0)
var direction: = 1.0

func _physics_process(delta: float) -> void:
    _update_ray(velocity.x * delta * direction)
    _check_collisions()
    position += velocity * direction * delta


func _on_VisibilityNotifier2D_viewport_exited(viewport: Viewport) -> void:
    queue_free()

func _check_collisions() -> void:
    $RayCast2D.force_raycast_update()
    var c = $RayCast2D.get_collider()
    if !c:
        return
    $RayCast2D.add_exception(c)
    $Timer.start()
    velocity = Vector2.ZERO
    _reparent(c, $RayCast2D.get_collision_point())


func _reparent(body: PhysicsBody2D, anchor: Vector2) -> void:
    $VisibilityNotifier2D.disconnect("viewport_exited", self, "_on_VisibilityNotifier2D_viewport_exited")
    get_parent().remove_child(self)
    body.add_child(self)
    set_owner(body)
    $VisibilityNotifier2D.connect("viewport_exited", self, "_on_VisibilityNotifier2D_viewport_exited")
    set_global_position(anchor)


func _update_ray(x_velocity: float) -> void:
    var ray_pos_x: float = $RayCast2D.position.x
    $RayCast2D.position.x = ray_pos_x if x_velocity > 0 else -ray_pos_x
    $RayCast2D.cast_to.x = x_velocity

func _handle_hit(body: PhysicsBody2D, anchor: Vector2) -> void:
    $CollisionShape2D.disabled = true
    _reparent(body, anchor)


func _on_Timer_timeout() -> void:
    queue_free()

The result is pretty much the same in both cases. Looks like the collision is detected on the previous frame position or something similar. I've tried raising the physics fps and it gets better but not solves the problem. Any idea about how can i get the correct collision point in the moving object?

Thanks!!!

asked Dec 8, 2019 in Engine by Mostrio (21 points)
retagged Dec 8, 2019 by Mostrio

I found a possible solution turning on the synctophysics checkbox on the moving object. But now i cannot use moveandslide or moveandcollide methods (because those are not compatible with synctophysics).

So i have a new problem because i want to use this mechanic (stucked arrows on objects) with enemies.

Has someone an idea about how to solve this? Do i need to implement my own moveandslide method or is there a simpler solution? How can i implement my own moveandslide (or collide) if needed?

Thanks!!

Please log in or register to answer this question.

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.