1
\$\begingroup\$

I found a video on YouTube with a sercol and a beam, and everything seems to be fine, but the beam doubles and flickers after spawning from the mirror, tell me what could be the problem, screenshot and the code is attached.enter image description here enter image description here

extends Node2D

onready var ray = $RayCast2D
onready var lain = $Node2D/Line2D

var vec = Vector2()
var max_bounces = 5

func _process(delta):
    lain.clear_points()
    
    vec.y-=1
    
    lain.add_point(Vector2.ZERO)
    
    ray.global_position = lain.global_position
    ray.cast_to = vec.normalized()*1000
    ray.force_update_transform()
    
    var prev = null
    var bounces = 0
    
    while true:
        if not ray.is_colliding():
            var pt = ray.global_position + ray.cast_to
            lain.add_point(lain.to_local(pt))
            break
        
        var coll = ray.get_collider()
        var pt = ray.get_collision_point()
        
        lain.add_point(lain.to_local(pt))
        
        if not coll.is_in_group("Mirrors"):
            break
            
        var normal = ray.get_collision_normal()
        
        if normal == Vector2.ZERO:
            break
        
        if prev !=null:
            prev.collision_mask = 3
            prev.collision_layer = 3
        prev = coll
        prev.collision_mask = 0
        prev.collision_layer = 0
        
        
        ray.global_position = pt
        ray.cast_to = ray.cast_to.bounce(normal)
        ray.force_raycast_update()
        
        bounces+=1
        if bounces >= max_bounces:
            break
        
    if prev !=null:
        prev.collision_mask = 3
        prev.collision_layer = 3
\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

You should be calling ray.force_raycast_update() when you changed ray.cast_to, and you should be calling ray.force_update_transform() when you changed ray.global_position. Since you changing them together, call these together too. Here:

    ray.global_position = lain.global_position
    ray.cast_to = vec.normalized()*1000
    ray.force_update_transform()
    ray.force_raycast_update()

And here:

        ray.global_position = pt
        ray.cast_to = ray.cast_to.bounce(normal)
        ray.force_update_transform()
        ray.force_raycast_update()

And with that the flickering should be gone.


There are other improvements we can do to the code. Notably it mixes local and global coordinates. The reason being that cast_to is local to ray. Which means instead of this:

var pt = ray.global_position + ray.cast_to

You should do this:

var pt = ray.to_global(ray.cast_to)

And since we have the normal in global coordinates. This is not correct:

ray.cast_to = ray.cast_to.bounce(normal)

Instead, we are going to convert ray.cast_to to global, then bounce it, and back to local:

ray.cast_to = ray.to_local(ray.to_global(ray.cast_to).bounce(normal))

With that, you should be able to move or rotate your Node2D and the laser should go with it.


By the way, instead of switching collision layers and mask, you can add an exception to the ray with:

ray.add_exception(coll)

And remove it with:

ray.remove_exception(prev)

Ah, and if you want to clear the exception, you call clear_exceptions:

ray.clear_exceptions()

I also want to point out that every frame you decrement vec.y:

vec.y-=1

If you keep decrementing vec.y it will eventually go out of representable integers.

You probably want to just give a value once. Don't forget you are normalizing and then scaling by 1000 anyway:

ray.cast_to = vec.normalized()*1000

And yes, that is local of the ray. Which is why moving or rotating it should also move the ray.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .