Collision point detection on moving object issue

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

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.

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!!!

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

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 move_and_slide method or is there a simpler solution? How can i implement my own move_and_slide (or collide) if needed?

Thanks!!

Mostrio | 2019-12-09 09:32