Dragging objects with the mouse on branching paths

Hello,

So I have sort of a special situation, since I can't find any existing solutions online. I am programming a Drag and Drop puzzle game and I need to drag an object around in a grid. Here's a snapshot so you can picture my goal:

Unbenannt2.JPG

So I need to drag the circle along this grid and get it to the exit seen on the right. My problem is I tried many approaches for doing this and none of them works properly. For example, I tried to put walls in between the paths (marked red in the following picture), mark it and the ball (hitbox = same size as wall blocks) as solid and to work with the place_free() command:

Unbenannt3.JPG

The problem with this is that the movement is very chunky and if you don't line the mouse correctly on that single pixel, the box does not move. I don't want to make the hitbox smaller because I want the circle to stay on one clearly defined, straight path while moving. I tried to implement a system for snapping the ball to a position if it's nearby and not exactly but just near the path, but that also does not work very well:

Code:
//Create:

moving = false;

y_lanes = [240, 400, 560, 720, 880]; // Positions of all horizontal lanes
x_lanes = [1520, 1360, 1200, 1040, 880, 720, 560, 400]; Positions of all vertical lanes

//Step:
if (position_meeting(mouse_x, mouse_y, self) && mouse_check_button_pressed(mb_left)) {
    moving = true;
}

if (moving) {
    target_x = mouse_x;
    target_y = mouse_y;
    
    if (place_free(target_x, y) && point_distance(x, y, target_x, y) < 100) x = target_x;
    else {
        for (i = 0; i < array_length(x_lanes); i++) {
            if (target_x < x_lanes[i] + 30) && (target_x > x_lanes[i] - 30) && (point_distance(x, y, target_x, target_y) < 100) {
                x = x_lanes[i];
                break;
            }
        }
    }
    if (place_free(x, target_y) && point_distance(x, y, x, target_y) < 100) y = target_y;
    else {
        for (i = 0; i < array_length(y_lanes); i++) {
            if (target_y < y_lanes[i] + 30) && (target_y > y_lanes[i] - 30) && (point_distance(x, y, target_x, target_y) < 100) {
                y = y_lanes[i];
                break;
            }
        }
    }
    
    if (mouse_check_button_released(mb_left)) moving = false;
}
I am sure this can be done better and more functional, so can you suggest a way how to solve this movement problem, please?
Thanks!
 
In the ball object, you can create a flag called "is_clicked", and set it to true on mouse press. You can set it back to false on a GLOBAL mouse release event, and make it follow the mouse position as long as it's flagged "is_clicked".
Works much better than trying to get the mouse to aim spot on on the object as you drag. As you discovered, this is not very reliable, as the mouse can move faster than the game updates and lose track on the object.
for the walls, you don't even need them, just add a conditional to the mouse position, if it's within the coordinates of the inside walls.

EDIT: On second look at the screenshot, you should make your ball hitbox small enough so it's impossible to overlap 2 or more squares. Will save you a lot of headaches down the road.
 
So after hours of trial and error, I figured out a proper way to deal with the problem.

The solution suggested by @Slow Fingers is not really good, because it does the exact opposite of what I wanted to achieve. The ball should follow straight lines when dragged and if you only check if the cursor is inside a wall, this doesn't apply.

However, I came back to my collision-detect solution with place_free() and added a new custom object, seen yellow in the picture:

Unbenannt2.JPG

This path object helps snapping the ball object to the x or y positions of the lanes when the cursor is not exactly on those coordinates. Basically, what I do is check if the place where you want to move is free first and if it isn't, see if you're on a yellow lane with your mouse. If it's a horizontal lane, set the ball position to the y pos of the lane and the x pos of the mouse, if it's vertical, the other way round. Here's my code for anyone who wants to try such a system for themselves:

Code:
if (position_meeting(mouse_x, mouse_y, self) && mouse_check_button_pressed(mb_left)) {
    moving = true;
}

if (moving) {
    target_x = mouse_x;
    target_y = mouse_y;
    
    if (place_free(target_x, y) && point_distance(x, y, target_x, y) < 100) x = target_x;
    else {
        var inst = instance_position(target_x, target_y, oPuzzlePath);
        if (inst != noone) {
            if (inst.image_angle == 90) {
                y = inst.y;
                x = target_x;
            }
        }
    }
    if (place_free(x, target_y) && point_distance(x, y, x, target_y) < 100) y = target_y;
    else {
        var inst = instance_position(target_x, target_y, oPuzzlePath);
        if (inst != noone) {
            if (inst.image_angle == 0) {
                x = inst.x;
                y = target_y;
            }
        }
    }
    
    if (mouse_check_button_released(mb_left)) moving = false;
}
If you do it this way, you have 3 core advantages:
  1. Your cursor doesn't gets stuck on tight edges and moves smoothly around corners
  2. If you move your mouse far away on a neigbouring lane standing perpendicular to the one you stand on, your cursor automatically gets snapped there
  3. At the same time, if you grab the cursor and move your mouse to a parallel lane (which would be on the other side of a wall), the cursor won't follow your mouse since it cannot decide on a direction to "circumnavigate" the wall.
Hope this helps!
 
Glad you found a solution, but don't tell me my dragging code is not good, you just weren't able to implement it.
See for yourself, it works flawlessly :)
 
Glad you found a solution, but don't tell me my dragging code is not good, you just weren't able to implement it.
See for yourself, it works flawlessly :)
Thanks for the video. Just to clarify, I didn't say your suggestion/code was bad, I just pointed out that it doesn't fit my needs. As you may have noticed, unlike the example in your video I not only have an x direction, but a y direction to drag along as well, so it was just kind of unsuitable for that. But anyway, thanks again for your help!
 
Thanks for the video. Just to clarify, I didn't say your suggestion/code was bad, I just pointed out that it doesn't fit my needs. As you may have noticed, unlike the example in your video I not only have an x direction, but a y direction to drag along as well, so it was just kind of unsuitable for that. But anyway, thanks again for your help!
That's just because the bar is supposed to move horizontally in this case, I could easily have a + shape, or a # shape, or anything you could think of and make the cursor follow that "path"
 
Top