• Hey Guest! Ever feel like entering a Game Jam, but the time limit is always too much pressure? We get it... You lead a hectic life and dedicating 3 whole days to make a game just doesn't work for you! So, why not enter the GMC SLOW JAM? Take your time! Kick back and make your game over 4 months! Interested? Then just click here!

Legacy GM [SOLVED]How to draw a (curved) line with mouse?

A

AFD456

Guest
Hi everyone, I'm trying to figure out how to draw a line using your mouse leaving no gaps between points?

I have 2 objects oControl and oPoint. And I use only this simple code:

oControl_Step_event:

if mouse_check_button(mb_left)
{
instance_create(mouse_x,mouse_y,oPoint)
}

If I move mouse fast the code above leaves larger gaps between oPoint instances (picture below). How can I prevent this? Or is there better way to draw a curved line? I know there's draw_point function but I havent been able to use it successfully.
Thank you for your time!
 

Attachments

I assume the actual explanation would involve bezier curves or something like that, but basically the problem is that you can move your mouse more than 1 pixel distance per step. Basically you should store the position of the mouse at the end of a step (mouse_old_x and mouse_old_y or something) and then compare it to the mouse_x and mouse_y at the start of the step, then extrapolate the line between them (a simple draw_line will draw a straight line between them, but as I said at the start, there's probably some fancy way of getting a nice curve by using a bezier curve function and a few more variables, though that 💩💩💩💩 is gonna be pretty complicated and usually unnecessary).
 
M

Maisenberg

Guest
Use a surface.

Create event:
Code:
surf_line = surface_create([dimensions]);
old_mouse_x = mouse_x;
old_mouse_y = mouse_y;
Draw event:
Code:
surface_set_target(surf_line);
draw_line(mouse_x, mouse_y, old_mouse_x, old_mouse_y);
surface_reset_target();

draw_surface(0, 0, surf_line);
old_mouse_x = mouse_x;
old_mouse_y = mouse_y;
By the way, surfaces are volatile so you should make sure they exist before drawing to them.
 
Last edited by a moderator:

Dmi7ry

Member
If you want smooth line, then you can use path. For example:

Create event:
Code:
last_x = 0;
last_y = 0;

path = path_add();
path_set_kind(path, 1);
path_set_closed(path, false);

initialized = false;
Global Left Mouse Button event:
Code:
if point_distance(last_x, last_y, mouse_x, mouse_y) > 10 or !initialized
{
    initialized = true;
  
    last_x = mouse_x;
    last_y = mouse_y;
    path_add_point(path, last_x, last_y, 100);
}
Draw event:
Code:
var step = (1 / path_get_length(path)) * 4; // Change "4" for ajust quality (1 - draw each pixel of the path)
for (var i=0; i<1; i+=step)
{
    var posx = path_get_x(path, i);
    var posy = path_get_y(path, i);
  
    if i > 0
        draw_line(posx_previous, posy_previous, posx, posy);
                  
    var posx_previous = posx;
    var posy_previous = posy;
}
 
A

AFD456

Guest
If you want smooth line, then you can use path. For example:

Create event:
Code:
last_x = 0;
last_y = 0;

path = path_add();
path_set_kind(path, 1);
path_set_closed(path, false);

initialized = false;
Global Left Mouse Button event:
Code:
if point_distance(last_x, last_y, mouse_x, mouse_y) > 10 or !initialized
{
    initialized = true;
 
    last_x = mouse_x;
    last_y = mouse_y;
    path_add_point(path, last_x, last_y, 100);
}
Draw event:
Code:
var step = (1 / path_get_length(path)) * 4; // Change "4" for ajust quality (1 - draw each pixel of the path)
for (var i=0; i<1; i+=step)
{
    var posx = path_get_x(path, i);
    var posy = path_get_y(path, i);
 
    if i > 0
        draw_line(posx_previous, posy_previous, posx, posy);
                 
    var posx_previous = posx;
    var posy_previous = posy;
}
This works almost perfectly! What if I wanted to draw 2 or more independent lines in one room after mouse button release and then mouse button pressed again? If you understand what I mean. Thanks anyway.
 

Dmi7ry

Member
This works almost perfectly! What if I wanted to draw 2 or more independent lines in one room after mouse button release and then mouse button pressed again? If you understand what I mean. Thanks anyway.
It depends on what you want.
For example, on Global Left Mouse Released event you can draw the path on surface, then clear the path. So next time it will be a new line.

Script path_draw_ext:
Code:
/// path_draw_ext(path, precision)

var path = argument0;
var prec = argument1;

var step = (1 / path_get_length(path)) * prec;
for (var i=0; i<1; i+=step)
{
    var posx = path_get_x(path, i);
    var posy = path_get_y(path, i);
   
    if i > 0
        draw_line(posx_previous, posy_previous, posx, posy);
                   
    var posx_previous = posx;
    var posy_previous = posy;
}
Create event:
Code:
last_x = 0;
last_y = 0;

path = path_add();
path_set_kind(path, 1);
path_set_closed(path, false);

initialized = false;

surf = surface_create(room_width, room_height);
Global Left Mouse Button event:
Code:
if point_distance(last_x, last_y, mouse_x, mouse_y) > 10 or !initialized
{
    initialized = true;
   
    last_x = mouse_x;
    last_y = mouse_y;
    path_add_point(path, last_x, last_y, 100);
}
Global Left Mouse Released event:
Code:
surface_set_target(surf);

path_draw_ext(path, 1);

surface_reset_target();

draw_set_colour(irandom(c_white));
path_clear_points(path);
Draw event:
Code:
draw_surface(surf, 0, 0);
path_draw_ext(path, 4);
But you should care about surface (I missed it for shortly code). For example, copy it into buffer after path drawed (after "surface_reset_target") (or any other way) and check that surface exists before draw.
 
A

AFD456

Guest
It depends on what you want.
For example, on Global Left Mouse Released event you can draw the path on surface, then clear the path. So next time it will be a new line.

Script path_draw_ext:
Code:
/// path_draw_ext(path, precision)

var path = argument0;
var prec = argument1;

var step = (1 / path_get_length(path)) * prec;
for (var i=0; i<1; i+=step)
{
    var posx = path_get_x(path, i);
    var posy = path_get_y(path, i);
  
    if i > 0
        draw_line(posx_previous, posy_previous, posx, posy);
                  
    var posx_previous = posx;
    var posy_previous = posy;
}
Create event:
Code:
last_x = 0;
last_y = 0;

path = path_add();
path_set_kind(path, 1);
path_set_closed(path, false);

initialized = false;

surf = surface_create(room_width, room_height);
Global Left Mouse Button event:
Code:
if point_distance(last_x, last_y, mouse_x, mouse_y) > 10 or !initialized
{
    initialized = true;
  
    last_x = mouse_x;
    last_y = mouse_y;
    path_add_point(path, last_x, last_y, 100);
}
Global Left Mouse Released event:
Code:
surface_set_target(surf);

path_draw_ext(path, 1);

surface_reset_target();

draw_set_colour(irandom(c_white));
path_clear_points(path);
Draw event:
Code:
draw_surface(surf, 0, 0);
path_draw_ext(path, 4);
But you should care about surface (I missed it for shortly code). For example, copy it into buffer after path drawed (after "surface_reset_target") (or any other way) and check that surface exists before draw.
Works Great! Thank you very much Dmi7ry.
 
Top