I found a closed issue about the subject: https://github.com/godotengine/godot/issues/35504 (closed)
Godot version:
3.2.3 RC3 but it happends in 3.2.2 stable.
OS/device including version:
Tested in Windows 7 32 y 64 bit
Issue description:
In a bullet hell game, few times, a raycast impact in an area, and the calculation of the script, taking the normal of the collision, and passing a normalized vector to Vector2.reflect in this way: vector_to_reflect.reflect( normal.normalized() ), spam an error to console:
E 0:00:12.319 reflect: The normal Vector2 must be normalized.
<Error de C++>Condition "!p_normal.is_normalized()" is true. Returned: Vector2()
<Fuente C++> core/math/vector2.cpp:201 @ reflect()
<Stack Trace> Dwarf_Bullet.gd:199 @ _physics_process()
I do not detect bad behavior in the result of the collision and if I export the game in release mode, it doesn麓t stuck, and works well.
Obviously, the Vector is normalized, because it is normalized in the same argument of Vector2.reflect.
Spam rate of the error if about 1-2 times per 100-200 collisions.
I try, not normalize the normal, normalize inside the reflect function, normalize on the assignation of the normal variable... the result is the same (The normal seems to be normalized by default)
Steps to reproduce:
Collide an RayCast with an area from different angles an try to reflect a Vector using the generated Normal.
Minimal reproduction project:
900 MB project, sorry. I put the issue to try to fix before 3.2.3 stable. I will try to reproduce in a empty project.
OK, i got the demo:
GodotReflectBug.zip
Problem seems to be with CollisionShapes not with CollisionPolygons. If the shape is a rectangle, the collision spam the error.
The demo is to show the spammed message, raycast get stuck in the rectangle, if cast_to is only changed in the collision, few bullets get stuck in the collision, but this is not the objetive of the demo, is to show that there is something wrong with "reflect" and the collision shapes.
Modified demo that shows better the problem:
GodotReflectBug2.zip
get_collision_normal() seems to be returning some zero length normals, which is causing the error message (you can't normalize a zero length vector).
So either this is a bug and it shouldn't return an invalid normal, or it is something you should test for and deal with. Maybe there are some situations where it can't calculate a collision normal.
Closing as this is the correct behaviour. get_collision_normal() can return a Vector2() zero length vector.
The normal will be the zero length Vector2() if the ray is completely enclosed in the Rectangle CollisionShape i.e. there isn't an edge intersection. The RayCast is colliding with the Object; so get_collider() is not null, but there is no normal, because it's not intersecting an edge.
The CollisionPolygon behaves differently, because it only detects that it's colliding with the Object if the ray intersects the edge. If it's completely enclosed it does not "collide" with the Object; so get_collider() returns null. See #10110.
Closing as this is the correct behaviour. get_collision_normal() can return a Vector2() zero length vector.
Is this documented anywhere? It strikes me as an issue that will catch many people unawares.
It probably should be a separate issue. The OP was about reflect insisting on a normalised vector, whereas the confusion comes from what to expect from RayCast::get_collision_normal().
The current documentation just says:
Returns the normal of the intersecting object's shape at the collision point.
Interestingly, the collision point returned by get_collision_point(), when there is no edge collision, will just be the origin of the RayCast2D, which I suppose makes sense.
Looking at this more closely, it's only the RectangleShape that returns the Object when calling get_collider() for a RayCast that is completely enclosed by the shape. CapsuleShape, CircleShape and ConvexPolygonShape all return null. The others don't create an enclosure. So it probably makes sense to fix RectangleShape to return null too.
For completeness, in 3D all of the Shapes (BoxShape, CapsuleShape, CylinderShape, SphereShape and ConvexPolygonShape) return null when calling get_collider() if the RayShape is completely enclosed.
Update: In Godot 3D physics, if the RayShape is completely enclosed, the BoxShape and CapsuleShape also (incorrectly?) return the Object when calling get_collider() and a zero length normal Vector3 when calling get_collision_normal(), but the SphereShape and the ConvexPolygonShape don't. (Godot 3D physics doesn't support the CylinderShape.)