Object teleporting out of bound when hiting a corner

Godot Version

v4.3.stable.flathub [77dcf97d8]

Question

Hello, rencently I started to implement to ability of throwing a knife to my game. It was working find but recently (after adding code so the knife rotate to match with its velocity) I noticed that throwing it in a corner will make it tp somewhere out of bound… I reduced the engine speed to try understanding it but I still don’t know why it happen.

Does anybody have an idea ??

I assume that little camera on the bottom right is tracking the knife, and when it turns grey that is when its going out of bounds? Are you able to post all the code related to the knife?

Yes exactly, as you can teleport to the knife I thought it would be usefull to see where it go if exiting the screen. Here’s the code:

extends CharacterBody2D

var gravity: float = ProjectSettings.get_setting("physics/2d/default_gravity")

func killViewport() -> void:
	get_tree().get_nodes_in_group("knifeviewport")[0].visible = false

func killKnife() -> void:
	queue_free()
	killViewport()

func init(initPos: Vector2, initVel: Vector2) -> void:
	position = initPos
	velocity = initVel
	z_index = 100

func _physics_process(delta: float) -> void:
	velocity.y += gravity * delta
	if is_on_floor():
		velocity.x /= 1.85
	if is_on_wall() && velocity.y < 0:
		velocity.y /= 1.85
	
	move_and_slide()
	
	if velocity == Vector2(0, 0) && is_on_floor():
		await get_tree().create_timer(0.5).timeout
		killKnife()
	else:
		rotation = atan(velocity.y/velocity.x)+PI/2

The init function is called when throwing the knife.
Thanks for taking time helping me!

I made some other tests and I found something interesting, it looks like the knife do go back down once it touched the roof but:

  • It’s not visible anymore
  • It stop colliding with anything

So my theory is that it’s put back to the original viewport “world”. But it’s make even less sense :sob:

When you view your scene tree, does the knife still show in the tree? You can also try making the knife print its location constantly to see if its actually teleporting, and if so… where its teleporting to.

Because, to me, once it hits the first wall, it looks like it slides, but once it hits the second wall, I’m wondering if the velocity is hitting 0,0 and then the killKnife() is being called and its just being removed from the world.

you could also add a print statement to your killKnife, just make sure its the first line in the function and have it say …

func killKnife() → void:
print(“Killing Knife.”)
queue_free()
killViewport()

this way, if you are seeing that print message in your Godot console, you’ll know the knife is actually killing itself

The knife is still “alive” after hiting the roof, I prevent a death like that by checking if it’s also on the ground when at 0,0 velocity before killing it. And the killKnife function also hide the subviewport when killing the knife so we can be sure when it’s killed or not.
I added a way to check the position and velocity of the knife, and everything seems normal.
As the video show the knife acts as intended, it’s just invisible and with no collisions.

But my theory is false too, I checked if the 2 worlds where the same using
print(knifeViewport.world_2d == get_tree().current_scene.get_viewport().world_2d)
and it always returns true.

I discover something new, it’s not doing it when hiting a corner but when hiting the roof, it don’t have to hit the wall first as in the video.
And when the knife disappear, the knifeViewport.canvas_transform.origin become (nan, nan) so this may have a link with it.

I found the solution!
The error was coming from the rotation:

rotation = atan(velocity.y/velocity.x)+PI/2

If you look closely, when the velocity.x is 0 (i.e. when hiting the roof) the code will try doing a division by 0, leading to all the horrible stuff that follow.

Conclusion:
DON’T DIVIDE BY ZERO

1 Like

I’m glad you found the issue!

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.