• 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!

Walking and Collision using Mouse

T

tewpew

Guest
Hi guys! I currently involved in a project as a game designer (mostly art), but 💩💩💩💩 happens and now I have to do coding also. I don't have any programming background, so I'm struggling here, trying to make everything work. Here's my problem:


We have a character who is walking inside the room by clicking (click to move). We have some activated background objects (table, sofa, small table) which have collision with the character. Basically, player should be able to move within "green" area avoiding the "blue" objects. For the "red" chair player has to be able to move in front of it, but also behind it.

The main problem is, that almost every tutorials that I found are made for "WASD" controlling, and for me it's hard to switch to mouse controlling, because I don't understand the principle of movement clearly. Here's the code that I have so far:

Code:
if (xx != mouse.none && yy != mouse.none){
    move_towards_point(xx,yy,spd)

if point_distance(x, y, xx, yy) > 5 {
    mp_potential_step(xx, yy, 0.5, false);
    } else speed = 0;
}
else {
    speed = 0;   
}

x = clamp(x,34,203);
y = clamp(y,107,126);

if (direction >= 90 && direction < 270)
{
    sprite_index = sprProtWalkLeft;
    if (speed = 0){
     sprite_index = spr_ProtIdleLeft;
    }
}
else
{
    sprite_index = sprProtWalkRight;
    if (speed = 0){
     sprite_index = spr_ProtIdleRight;
    }
}
mp_potential_step seems to work, but in a weird way (sometimes character just go through the objects). Using clamp so far was okay, but since we have a "perspective" room the line should be diagonal.

I would like to see any hints (or maybe even video tutorials) that can help me to solve this.

Thanks in advance!
 
I

innercitysumo

Guest
I started off using move_towards_point in my point and click, but switched over to mp_grid_path. This has given me pathfinding that's similar to the old LucasArts games that's more natural than the weird "swarming around obstacles" effect I was getting before.

I just setup a grid for the whole room, block out the forbidden cell areas - e.g. walls, room objects - using blocking objects in the room editor and it takes care of the rest.
 
T

tewpew

Guest
I started off using move_towards_point in my point and click, but switched over to mp_grid_path. This has given me pathfinding that's similar to the old LucasArts games that's more natural than the weird "swarming around obstacles" effect I was getting before.

I just setup a grid for the whole room, block out the forbidden cell areas - e.g. walls, room objects - using blocking objects in the room editor and it takes care of the rest.
Thanks for the suggestion! Could you please upload the image again? It doesn't load for some reason.
 
I

innercitysumo

Guest
It was just supposed to be an animated GIF showing how it moves around objects: https://imgur.com/a/2Zdd5

The way I've done it (and I'm sure there are lots of valid ways) is to have to an invisible object at the feet of the character, and this is what moves / uses mp_grid_path. The character sprite is just pinned to this base object.

Having the base object means I can use it as an easy to visualise footprint for the character, rather than just having the big character sprite object. It makes it easier for things like walking in front of or behind objects - particularly when perspective is involved.

You can see what I mean by the character base object on one of my other posts.

In the Create event for this player base object I create the mp_grid of the room:

Code:
globalvar grid;
grid = mp_grid_create(0, 0, floor(room_width/10), floor(room_height/10), 10, 10);
mp_grid_add_instances(grid, obj_wall, 1);
I block out the restricted areas of the room in the room editor by laying down instances of the invisible object obj_wall. This can be a little time consuming but it works for me.

I have it so that when I click on the screen it creates another invisible object where I've clicked - obj_mouseclick - which the player base object walks towards with this Step event code. With each click obj_mouseclick is destroyed and then recreated in the position of the mouse cursor. You could probably do without this particular object, but I like to have it and it helps me trigger some other things, like idle animations.

Code:
// Mouse click walk movement
if mouse_check_button_pressed(mb_left)
{
    if instance_exists(obj_mouseclick)
    {
            if mp_grid_path(grid, path0, x, y, obj_mouseclick.x, obj_mouseclick.y, 1)
            {
            path_start(path0, walkspeed, path_action_stop, 0);
            }
          
    }      
}
I have a few other bits and pieces in there, but that's the basic principle of the system I use.
 
Last edited by a moderator:
T

tewpew

Guest
Thanks, it works! The only problem is that I have to click within the floor area to move the character. Is it somehow possible to move him towards the closest grid cell when I click outside the area where he's able to move?

PS. Also, how do you change the sprite back to "idle" when the character reaches the end of the path?
 
Last edited by a moderator:
I

innercitysumo

Guest
Well, I'm no expert, but if there's no available path (i.e. if you're clicking on a wall) then you could have it try to recalculate a path at the same point on the X axis until it's successful. As your layout is similar to mine that would usually be a wall, but it could also be an object in the room. So starting from the top of the screen & moving down and, if unsuccessful (e.g. if clicking on a foreground object where it's impossible to go below it), trying again from the bottom up. It's fairly crude but something along these lines might work for you.

Code:
if mp_grid_path(grid, path0, x, y, obj_mouseclick.x, obj_mouseclick.y, 1)
            {
            path_start(path0, walkspeed, path_action_stop, 0);
            }
            else
            {
                var i;
                for (i = obj_mouseclick.y; i <= 460; i += 10)
                {
                   if mp_grid_path(grid, path0, x, y, obj_mouseclick.x, 0+i, 1)
                    {
                    path_start(path0, walkspeed, path_action_stop, 0);
                    break;
                    }
                }
                for (i = obj_mouseclick.y; i > 0; i -= 10)
                {
                   if mp_grid_path(grid, path0, x, y, obj_mouseclick.x, 0+i, 1)
                    {
                    path_start(path0, walkspeed, path_action_stop, 0);
                    break;
                    }
                }
            }
 
I

innercitysumo

Guest
There are probably lots of ways you can handle your sprite animations and idle states. I use the following system (and no doubt someone else will tell you this is a horrible way to do it) in the Step event of my sprite object. I don't have up and down animations - just left and right - so if the player moves directly up or down they are always facing in one direction or the other.

Code:
// Right
if obj_player.xprevious < obj_player.x
{
sprite_index = spr_player_right;
}

// Left
if obj_player.xprevious > obj_player.x
{
sprite_index =spr_player_left;
}

// Up
if (obj_player.xprevious == obj_player.x) and (obj_player.yprevious > obj_player.y)
{
sprite_index = spr_player_right;
}

// Down
if (obj_player.xprevious == obj_player.x) and (obj_player.yprevious < obj_player.y)
{
sprite_index = spr_player_left;
}

// Stopped
if (floor(obj_player.xprevious) == floor(obj_player.x)) and (floor(obj_player.yprevious) == floor(obj_player.y)) and
(global.formersprite == "spr_player_left" or global.formersprite == "spr_player_stood_left")
{
sprite_index = spr_player_stood_left;
}
else if (floor(obj_player.xprevious) == floor(obj_player.x)) and (floor(obj_player.yprevious) == floor(obj_player.y)) and
 (global.formersprite == "spr_player_right" or global.formersprite == "spr_player_stood_right")
{
sprite_index = spr_player_stood_right;
}
I record the global.formersprite variable at the start of the same Step event (it probably looks overly complicated to anyone else, but it makes sense to me and having values like that in globals helps me debug things. My system is actually a little more convoluted because I set a global.playerstate variable instead of just setting the sprite and the value of global.playerstate is *then* used to set the sprite).

Code:
global.formersprite = sprite_get_name(sprite_index);
 
T

tewpew

Guest
There are probably lots of ways you can handle your sprite animations and idle states. I use the following system (and no doubt someone else will tell you this is a horrible way to do it) in the Step event of my sprite object. I don't have up and down animations - just left and right - so if the player moves directly up or down they are always facing in one direction or the other.

Code:
// Right
if obj_player.xprevious < obj_player.x
{
sprite_index = spr_player_right;
}

// Left
if obj_player.xprevious > obj_player.x
{
sprite_index =spr_player_left;
}

// Up
if (obj_player.xprevious == obj_player.x) and (obj_player.yprevious > obj_player.y)
{
sprite_index = spr_player_right;
}

// Down
if (obj_player.xprevious == obj_player.x) and (obj_player.yprevious < obj_player.y)
{
sprite_index = spr_player_left;
}

// Stopped
if (floor(obj_player.xprevious) == floor(obj_player.x)) and (floor(obj_player.yprevious) == floor(obj_player.y)) and
(global.formersprite == "spr_player_left" or global.formersprite == "spr_player_stood_left")
{
sprite_index = spr_player_stood_left;
}
else if (floor(obj_player.xprevious) == floor(obj_player.x)) and (floor(obj_player.yprevious) == floor(obj_player.y)) and
 (global.formersprite == "spr_player_right" or global.formersprite == "spr_player_stood_right")
{
sprite_index = spr_player_stood_right;
}
I record the global.formersprite variable at the start of the same Step event (it probably looks overly complicated to anyone else, but it makes sense to me and having values like that in globals helps me debug things. My system is actually a little more convoluted because I set a global.playerstate variable instead of just setting the sprite and the value of global.playerstate is *then* used to set the sprite).

Code:
global.formersprite = sprite_get_name(sprite_index);
Thanks again, everything works exactly as I need! I'm struggling a bit with stopping the sprite because I have a little bit different system, but I guess I will find the solution. Thank you!
 
I

innercitysumo

Guest
Thanks again, everything works exactly as I need! I'm struggling a bit with stopping the sprite because I have a little bit different system, but I guess I will find the solution. Thank you!
No problem. Good luck with your game, it has a nice style.
 
C

cirin92

Guest
@innercitysumo I have the same problem as you helped resolved in this topic. Could you tell me where and why you creating obj_mouseclick?
 

Nll_0

Member
I know this thread is a few years old, but just wanted to thank you @innercitysumo this is the clearest explanation I've found for a problem I have, similar to the one posted by the OP! Thank you!
 
Top