SOLVED Help required with rotating laser beam.

I have an object that is sat in the centre of the room which slowly rotates whilst firing a laser beam. I'd like the laser beam to keep going until it hits the wall around the edge of the room so in effect it sweeps the entire room over the course of its rotation.
To start with I'm just drawing a line from the object but can't figure out how to only draw as far as the wall. I'm guessing I need a combination of point_distance and collision_point (maybe?). I feel like it should be fairly straight forward but I can't for the life of me figure it out.
If anyone could give me some help it would be gratefully received.
 

Pixel-Team

Member
What is your wall made of? This matters because it will determine how you make the laser collide with the wall. Is it a tile? Is it simply the edge of the room? The edge of the camera? Is it a instance with a sprite?
 
What is your wall made of? This matters because it will determine how you make the laser collide with the wall. Is it a tile? Is it simply the edge of the room? The edge of the camera? Is it a instance with a sprite?
Ah, It's an object so things can collide with it.
 

Pixel-Team

Member
If I were me, what I would do is starting at the origin of the laser, do checks every few pixels in the laser's direction, and put this coordinate in a variable called check_pos. This would be an array containing an _x and _y. The two cases where the checks prove true is either the laser reaches it's maximum distance, or your check_pos finds an object. Once either of these two conditions is true, you draw the laser from origin to it's check_pos. This would guarantee that only so many checks would happen per frame. I hope this makes sense.
 
OK, so I'm having problems with this...
I've set up a test project (so I don't break anything else) of a single room with a wall on each side (oWall).
A single object in the centre with the following code...

Create
GML:
x = room_width*0.5;
y = room_height*0.5;

rot = 0;
_tx = 0;
_ty = 0;
Step
GML:
var _xx = lengthdir_x(1000, rot);
var _yy = lengthdir_y(1000, rot);
var _wall = collision_line(x, y, _xx, _yy, oWall, 0, 0);

if _wall != noone {
    _tx = _wall.x;
    _ty = _wall.y;
}

rot += 1;
Draw
GML:
draw_line_width_color(x, y, _tx, _ty, 3, c_yellow, c_yellow);
but when it is run the line is drawn from the centre to the wall but then then jumps 90 degrees. I know my knowledge isn't brilliant but I can't figure this out for the life of me.
Could someone please point out what I'm doing wrong :(
 
Nope. I want the beam to go from the centre out to the wall and sweep around the room (like the second hand on a clock).
 

Nidoking

Member
Well, then, you'll have to either recalculate your _tx and _ty when you want the beam to move, or actually use the rot variable to determine how to draw it. You're only ever drawing to the wall's x and y, which is one point per wall. Four walls, four points, 90 degrees apart.
 

Nocturne

Friendly Tyrant
Forum Staff
Admin
Moderator
Here:

GML:
/// @function collision_line_first(x1,y1,x2,y2,object,prec,notme)
/// @param    {real}        x1           first X value on collision line, real
/// @param    {real}        y1           first Y value on collision line, real
/// @param    {real}        x2           second X value on collision line, real
/// @param    {real}        y2           second Y value on collision line, real
/// @param    {real}        object     which objects to look for (or all), real
/// @param    {real}        prec        if true, use precise collision checking, bool
/// @param    {real}        notme    if true, ignore the calling instance, bool
/// @description        Returns the instance id of an object colliding with a given line and
///                     closest to the first point as well as the x/y position of the collision,
///                     or noone if no instance found.
///                     The solution is found in log2(range) collision checks.

function collision_line_first(x1,y1,x2,y2,object,prec,notme)
{
var sx, sy, inst, i;
sx = x2 - x1;
sy = y2 - y1;
inst = collision_line(x1, y1, x2, y2, object, prec, notme);
if (inst != noone)
    {
    while ((abs(sx) >= 1) || (abs(sy) >= 1))
        {
        sx /= 2;
        sy /= 2;
        i = collision_line(x1, y1, x2, y2, object, prec, notme);
        if (i)
            {
            x2 -= sx;
            y2 -= sy;
            inst = i;
            }
        else
            {
            x2 += sx;
            y2 += sy;
            }
        }
    }
var _a = array_create(3);
_a[0] = inst;
_a[1] = y2;
_a[2] = x2;
return _a;
}
I've been using this function for years... It returns an array where the first entry is the ID of the instance found, and then the second two values are the EXACT x/y position of the collision. You would use it like this:

GML:
var _xx = lengthdir_x(1000, rot);
var _yy = lengthdir_y(1000, rot);
var _wall = collision_line_first(x, y, _xx, _yy, oWall, false, false);

if _wall[0] != noone
{
    _tx = _wall[1];
    _ty = _wall[2];
}

rot += 1;

Hope that helps, and save the function for other games, it's one of the most useful functions in my inventory. :)


EDIT: Fixed an error in the function.
 
Last edited:
Thanks for the replies guys.
I find it really difficult to comprehend things (not just programming) just by reading them, whereas if something is explained to me I can more often than not pick it up quite easily.
@Nocturne Thank you so much for that. I'm looking at the code trying to understand exactly what it is doing but to be honest I'm struggling. It doesn't help that maths is one of my major weaknesses.
In the function you say it returns the ID of the object and the precise x & y of the point of the collision, but I can't see where you're getting the dx and dy from.
 

Nocturne

Friendly Tyrant
Forum Staff
Admin
Moderator
In the function you say it returns the ID of the object and the precise x & y of the point of the collision, but I can't see where you're getting the dx and dy from.
Oooooooh! Sorry, I made a mistake copying the code! dx/dy should x2/y2. So sorry! As for how it works, it's really simple... It's checking along the line for a collision. If it finds one, then it goes into a loop and starts splitting the line into chunks of 2, and each iteration it does this until it finds the point of collision with the instance (so first iteration, it divides the line in 2 and checks both halves for a collision. When it finds one, it splits the half that had the collision in two and checks those. Etc.... It's MUCH more efficient than checking every pixel along the length of the whole line). It then takes the last x/y value of this point as well as the instance ID of the collision and adds them to an array which it returns.
 
Top