Legacy GM Pixel collision issue at certain angles (UNSOLVED)

G

Gatorchopps

Guest
Hello.

I've been working on a program that draws lines that spawn more lines at various angles to create a sort of art experiment. Stuff like this:



Each line should draw itself to a surface pixel by pixel while checking for collisions with other lines and objects. This works for the most part except at some specific angles it seems. Essentially what I'm having each object do is:

  • Draw a pixel at it's current location
  • Move 1 pixel in a specific direction (using lengthdir_x/y functions)
  • Check new location for pre-existing pixels and if so destroy self
  • repeat until destroyed or it gets to the specified length
Here's a example of what's happening:

You'll notice the lines on the right side terminated themselves for some reason. I'm just stumped on why only some of the lines are doing this. I think it may have something to do with the object moving less then a pixel some steps and detecting the previous steps pixel and destroying it self. I can't seem to find a solution and any help would be appreciated!

Here's the code for the line objects:

Code:
//Length to draw line before spawning more lines
length = 50
//How many new lines to spawn
spawns = 6
//Direction to draw lines
dir = 90
//Color of line
color = c_lime
//Current distance traveled
dist = 0
//If lines should die if they collide
kill = true

Code:
surface_set_target(global.canvas)
//Draw point on canvas
draw_point_color(x,y,color)

//Move object towards it's direction
x+= lengthdir_x(1,dir)
y+= lengthdir_y(1,dir)

//Increase distanc counter
dist +=1
surface_reset_target()

//If object has reached its max length spawn new objects and destroy self
if dist >= length
{
    var inst, inc;
    inc = 360/spawns
    for(i=0;i<spawns;i+=1)
    {
        inst= instance_create(x+round(lengthdir_x(1,dir)),y+round(lengthdir_y(1,dir)),obj_spawn)
        inst.dir = dir
        dir+=inc
    }
    instance_destroy()
}



////////////



var col, alpha;

    if kill = true
    {
        //If there is a pixel at the objects location destroy self
        col = surface_getpixel_ext(global.canvas,x, y);
        alpha = (col >> 24) & 255;
        
        if alpha = 255
        {
        instance_destroy()
        //show_message("alpha")
        }
            
        
        
            // If object is outside the room destroy it (with a buffer of 10 pixels)
    if x>=room_width-10
    {
    instance_destroy()
    //show_message("x>room")
    }
    
    if y>=room_height-10
    {
    instance_destroy()
    //show_message("y>room")
    }
                    
    if x<=10
    {
    instance_destroy()
    //show_message("x<0")
    }
    if y<=10
    {
    instance_destroy()
    //show_message("y<0")
    }
            

    }

I'll attach the .gmz file if needed. Thanks!
 

Nocturne

Friendly Tyrant
Forum Staff
Admin
You probably want to ALWAYS floor the x/y coordinates to make sure that they are always exactly on a pixel position before doing any drawing or collisions. You could probably add in a "move_snap(1, 1)" call in there to make sure it happens before everything else (so after setting the new x/y position, call that).
 
G

Gatorchopps

Guest
Thanks for the response Nocturne. That's similar to a solution I tried the problem is I believe to travel in some angles the object needs to move less then a pixel (stay in the same spot for a step). I tried adding in the move_snap(1,1) anyways and here you can see what I'm talking about:


Now while the objects do not destroy themselves they only travel in right angles.

I've tried rounding the lengthdir command as well with a whole new set of problems and I've tried creating a array of floored positions the object has been to and checked them against the current location before destroying the object and still no luck.

I've been trying to think of another way to detect if another line has drawn in a current position yet but so far I haven't come up with anything.
 
G

Gatorchopps

Guest
Still stumped, I'm wondering how x and y values are handled in functions when they are float types. For example if I enter draw_point (x,y)

And

X= 5.6
Y= 7.2

Are they rounded automatically and if so do they use bankers rounding like the round() command does.

Any input or help would be appricated!
 

TheouAegis

Member
I would do something a little different like

//Create
xx = x;
yy = y;

//Your step
x += lengthdir_x(1,dir);
y += lengthdir_y(1,dir);
if x & ~0 == xx && y & ~0 == yy exit;
xx = x & ~0;
yy = y & ~0;

.... blah blah blah

col = surface_get_pixel_ext(global.canvas, xx, yy);
 
G

Gatorchopps

Guest
I would do something a little different like

//Create
xx = x;
yy = y;

//Your step
x += lengthdir_x(1,dir);
y += lengthdir_y(1,dir);
if x & ~0 == xx && y & ~0 == yy exit;
xx = x & ~0;
yy = y & ~0;

.... blah blah blah

col = surface_get_pixel_ext(global.canvas, xx, yy);
Hmm This helped a bit but I'm still having some problems.


I don't really understand bitwise operations. I looked into them some and at the help document but I'm not quite sure what is going on or how it relates. I plugged it in anyways and it seemed to help some. If you'd care to explain this line of code:
Code:
 x & ~0 == xx

//Especially
 x & ~0
I think it would be very helpful to understanding why I'm still having problems or possibly some other code of mine is conflicting. Thanks for the response!
 

TheouAegis

Member
It's basically round(), but I hate typing out round() all the time.

So if x rounded off is the same as the new position rounded off and y rounded off is the same as the new position rounded off, then don't bother checking for collisions because it'd just be colliding with itself.
 
G

Gatorchopps

Guest
Ahh okay. I think it's close but it seems to still seems to have some odd ones die off. I used the same rounding to you showed me for the point_draw command and that seemed to help some.

The first few seem okay.

Then things seem to start to deviate...

Gets worse as it goes on but I think some of it is due to it missing diagonal lines and slipping through in the next ones.

and finally


Anyways I appreciative your help. I think I'm a step closer for sure.
 
J

Jonathan E. Styles

Guest
Will the code always round up? Depending on the movement (up, down, left, right) of the line rounding up or down may end up with the same coordinates if you are not getting whole numbers, right? If that's the case could we use a quick if comparison of the old x, y and the new x, y to make sure you are not overlapping? This is all speculative based on your assumption that it is being destroyed because it was not progressing. :)

If this has already been resolved for your motion paths, please roll your eyes and disregard. Thanks!
 
G

Gatorchopps

Guest
Post your revised Step Event. Maybe there's more to be seen.
Yeah I'd be happy to, it's a bit messy at the moment but I don't have a lot of time to edit it before work.


//STEP
Code:
surface_set_target(global.canvas)
//Draw point on canvas
xx = x & ~0;
yy = y & ~0;
draw_point_color(xx,yy,color)

//Move object towards it's direction
x+= lengthdir_x(1,dir)
y+= lengthdir_y(1,dir)



    if x & ~0 == xx && y & ~0 == yy
    {
    surface_reset_target()
    exit;
    }
xx = x & ~0;
yy = y & ~0;

//Increase distanc counter
dist +=1
surface_reset_target()




//If object has reached its max length spawn new objects and destroy self
if dist >= length
{
    var inst, inc;
    inc = 360/spawns
    for(i=0;i<spawns;i+=1)
    {
        inst= instance_create(x+round(lengthdir_x(1,dir)),y+round(lengthdir_y(1,dir)),obj_spawn)

        inst.dir = dir
        dir+=inc
     
        //random color changing code
        var v, h, t, f;
        t = 2
        f = 2
        h = colour_get_hue(color);
        v = colour_get_value(color);
        h-=t
        //v-=f
            if v <= 0
            {
            v=0
            }
              inst.color = make_colour_hsv(h, colour_get_saturation(color),v);
            }
 
 
    instance_destroy()
}



//////////// Kill code



var col, alpha;

    if kill = true
    {
        //If there is a pixel at the objects location destroy self
        col = surface_getpixel_ext(global.canvas,xx, yy);
        alpha = (col >> 24) & 255;
     
        if alpha = 255
        {
        instance_destroy()
        //show_message("alpha")
        }
         
     
     
            // If object is outside the room destroy it (with a buffer of 10 pixels)
    if x>=room_width-10
    {
    instance_destroy()
    //show_message("x>room")
    }
 
    if y>=room_height-10
    {
    instance_destroy()
    //show_message("y>room")
    }
                 
    if x<=10
    {
    instance_destroy()
    //show_message("x<0")
    }
    if y<=10
    {
    instance_destroy()
    //show_message("y<0")
    }
 
        if collision_point( xx, yy, obj_spawn, true, true )
        {
        instance_destroy()
        //show_message("collision xx")
        }  
     
        if collision_point( x, y, obj_spawn, true, true )
        {
        instance_destroy()
        //show_message("collision x")
        }  

    }


Will the code always round up? Depending on the movement (up, down, left, right) of the line rounding up or down may end up with the same coordinates if you are not getting whole numbers, right? If that's the case could we use a quick if comparison of the old x, y and the new x, y to make sure you are not overlapping? This is all speculative based on your assumption that it is being destroyed because it was not progressing. :)

If this has already been resolved for your motion paths, please roll your eyes and disregard. Thanks!
I was thinking it could be something related to that as well I've tried a solution similar to what you mentioned and I still ended up having the same issue. That's why I was wondering how some of the functions rounding worked.



As always thanks for your time!
 
G

Gatorchopps

Guest
Had an idea for an edit, but gotta goto work. Not sure if it even will make a difference.
No problem, I'm not in a big rush. Im at work myself. I'm just grateful to be getting so much help. I've pretty much been debugging and trying solution after solution trying to narrow it down myself. Its funny how some problems seem so simple yet I just can't seem to see the solution.
 
J

Jonathan E. Styles

Guest
This is just a shot in the dark since I am at work and my portable export of GMS did not work! (One day, darn it... one day.) So, I can't test. Do you think this would be beneficial?

In your creation code add:
Code:
global.old_x = -1;
global.old_y = -1;
This creates the variables for us to monitor with. I'm not sure how it will work if you are drawing multiple lines at the same time or if it will affect them, we may need to localize the variable.

Modify the collision detection code to look something like:
Code:
if (alpha = 255 and xx != global.old_x and yy != global.old_y)
        {
        instance_destroy()
        //show_message("alpha")
        }
Then after the pixel is drawn make sure to update the tracking variable(s):
Code:
global.old_x = xx;
global.old_y = yy;
If not, let me know. I'll be glad to hack away at it when I get home!
 
G

Gatorchopps

Guest
This is just a shot in the dark since I am at work and my portable export of GMS did not work! (One day, darn it... one day.) So, I can't test. Do you think this would be beneficial?

In your creation code add:
Code:
global.old_x = -1;
global.old_y = -1;
This creates the variables for us to monitor with. I'm not sure how it will work if you are drawing multiple lines at the same time or if it will affect them, we may need to localize the variable.

Modify the collision detection code to look something like:
Code:
if (alpha = 255 and xx != global.old_x and yy != global.old_y)
        {
        instance_destroy()
        //show_message("alpha")
        }
Then after the pixel is drawn make sure to update the tracking variable(s):
Code:
global.old_x = xx;
global.old_y = yy;
If not, let me know. I'll be glad to hack away at it when I get home!
Thanks for the response. I had actually tried something like that localized for each line object but I hadn't had the rounded xx/yy variables that TheouAegis helped come up with. I gave your code a try and it seems to run well but I'm still getting weird final images. I think they should be symmetrical but for some reason they are not.



I have to head to work but I will check in later. Thanks!
 
Top