• Hey! Guest! The 40th (!!!) GMC Jam will take place between February 25th, 12:00 UTC to March 1st 12:00 UTC. Why not join in this very special anniversary jam! Click here to find out more!

GMS 2.3+ Collisions when moving in mouse direction

Solthall

Member
Hello guys!

Any tips on how I can make collisions work with the following movement code? I'm moving the player with w,a,s,d, all relative to the mouse position. So if I press "W", the player moves towards the mouse pointer, and away if I press "S". "A" and "D" will make the player strafe arround the mouse pointer. This is the movement I want to use.

I have had some collisions in place, as you can see. But that only works if movement is set with "x += walkSpeed" and so on, like I tried recently. But that doesn't result in the movement I want.

*Step event (placed in a script)


angle = point_direction(x,y,mouse_x,mouse_y);
direction = angle;

//Movement direction
if (global.shop == false && obj_stairs.alarm[0] == -1)//dont move if shop open
{
if forward and not place_meeting(x,y-5,obj_solid)
{
speed = walkSpeed;
image_speed = 1;
}

if backward and not place_meeting(x,y+5,obj_solid)
{
speed = -walkSpeed;
image_speed = 1;
}

if right and not place_meeting(x+5,y,obj_solid)
{
direction += 90;
speed = -walkSpeed;
image_speed = 1;
}

if left and not place_meeting(x-5,y,obj_solid)
{
direction -= 90;
speed = -walkSpeed;
image_speed = 1;
}
}

// Stop moving when no key is pressed
if keyboard_check(vk_nokey)
{
speed = 0;
image_index = 0;
image_speed = 0;
}

// Stop moving if multiple inputs detected
if left and right
{
speed = 0;
image_index = 0;
image_speed = 0;
}

// Stop moving if colliding with mouse pointer
if point_distance(x,y,mouse_x,mouse_y) < 15
{
speed = 0;
image_index = 0;
image_speed = 0;
}



My player sprite is created in the draw event, so that the mask doesn't rotate with the sprite, and here's the code for that:

*Draw event


draw_sprite_ext(spr_player_idle, 0, x, y, 1, 1, angle, c_white, 1);



First post, so I hope this gives you enough information, I apologize if not. Probably didn't post the code in the correct fashion either.
 
Last edited:

Solthall

Member
Thanks for the reply. I used lengthdir to calculate my strafing, but switched it up recently. Should the whole movement code be based on the lengthdir or can I use it just to calculate the collision? Sorry, still new to many of these functions.
I have the movement set up so if I press forward (W) the player moves towards the mouse, (S) player moves away from mouse, (A) player strafes left in a circle arround the mouse, (D)player strafes right in a circle arround the mouse. But I don't know how to set up the collision with this.
 
Last edited:
place_meeting only tests whether from the current position going left, for example (x+5) there would be a collision. This doesn't take into account the direction your sprite is actually moving.

You might need to calculate the real x and y values for that movement yourself.
 

Nocturne

Friendly Tyrant
Forum Staff
Admin
Moderator
First, you want to separate the code for moving from the actual movement itself. So, DON'T set the speed and direction variables until the very end. Use variables to capture the input... Then use those variables along with lengthdir_x/y and place_meeting to test for a collision at the location you would MOVE TOO, before actually moving. If there is no collision, then move, if there is then you can either A) do a loop and check how far you can actually move, or B) just not move.

Note this won't be perfect but it'll put you on the correct path where you can start to improve things as you learn more. For now, the most important thing to understand is that you should separate the game logic from the actual actions, and always perform the logic first, then do the action. :)
 

Solthall

Member
First, you want to separate the code for moving from the actual movement itself. So, DON'T set the speed and direction variables until the very end. Use variables to capture the input... Then use those variables along with lengthdir_x/y and place_meeting to test for a collision at the location you would MOVE TOO, before actually moving. If there is no collision, then move, if there is then you can either A) do a loop and check how far you can actually move, or B) just not move.

Note this won't be perfect but it'll put you on the correct path where you can start to improve things as you learn more. For now, the most important thing to understand is that you should separate the game logic from the actual actions, and always perform the logic first, then do the action. :)
Thanks for the reply 🙂 I believe this is some very valuable information you provide, but I struggle a bit to understand it completely. By calling speed and direction at the end, do you mean

If forward and "no collision code"
{
speed = walkSpeed
direction = angle
}

If by input, you mean what button is being pressed, I have it set in a script with variables (forward by pressing "W" and so on).

I suspect that I'm missing the point completely though, could I bother you with a small example of this?
 

Nocturne

Friendly Tyrant
Forum Staff
Admin
Moderator
Right, so, I didn't explain too well I guess! First, I wouldn't use the built in speed variable... Use a custom variable so you have more control (in general, you are always better off using custom vars instead of the built in vars, since how the built-in vars are used is "opaque" to you as the user, since they are dealt with by the engine internally). Second, what I mean is structure the code like this:

1) Get input
2) Check potential collisions
3) Move.

Have a look at this tech blog and see the section #2 "TIP #2: CLEAN UP THAT INPUT CODE!" (although I would read the whole article!): https://www.yoyogames.com/blog/432/buttery-smooth-tech-tips-movement

In that section you'll see that they seperate their input code from their movement code, and for you, you'd do the same only add the collision check in between the two to adjust where the movement can occur before actually moving. That article also talks about collisions too, so it'll probably help with that!
 

TheouAegis

Member
Code:
while place_meeting(x+hspeed,y+vspeed,obj_solid)
    speed -= min(abs(speed),1)*sign(speed);
You can change the 1 to a fraction for more precision.

That's the (rough) equivalent of pixel-perfect collisions using speed.
 

Solthall

Member
[
Code:
while place_meeting(x+hspeed,y+vspeed,obj_solid)
    speed -= min(abs(speed),1)*sign(speed);
You can change the 1 to a fraction for more precision.

That's the (rough) equivalent of pixel-perfect collisions using speed.
[/QUOTE]

Thanks alot, I'll give this a try asap!
 

Solthall

Member
Right, so, I didn't explain too well I guess! First, I wouldn't use the built in speed variable... Use a custom variable so you have more control (in general, you are always better off using custom vars instead of the built in vars, since how the built-in vars are used is "opaque" to you as the user, since they are dealt with by the engine internally). Second, what I mean is structure the code like this:

1) Get input
2) Check potential collisions
3) Move.

Have a look at this tech blog and see the section #2 "TIP #2: CLEAN UP THAT INPUT CODE!" (although I would read the whole article!): https://www.yoyogames.com/blog/432/buttery-smooth-tech-tips-movement

In that section you'll see that they seperate their input code from their movement code, and for you, you'd do the same only add the collision check in between the two to adjust where the movement can occur before actually moving. That article also talks about collisions too, so it'll probably help with that!
Ok, I tried this method in a blank project. Makes it all more understandable.

One error I got was with the move_speed_this_frame. Its an argument in the script, but I dont see where he puts it in the step event when cleaning up the code?!
 
Top