GameMaker I'm struggling with Grid movement;

Hello,
I've had a basic understanding of how I want my game to run, but although I've seen videos on how grid movement works and how to do it, it isn't exactly what I've been looking for. I'm basically looking for Pokemon Mystery Dungeon- like movement, where the character can choose between the 8 different input options. I've gotten the four inputs as seen,
GML:
/// @description Move Control
//-----GET KEYS INPUT
keyRight = keyboard_check(ord("D"));
keyUp = keyboard_check(ord("W"));
keyLeft = keyboard_check(ord("A"));
keyDown = keyboard_check(ord("S"));

//-----DRAW DEPTH
depth = -y;
    
//-----SET CURRENT POSITION FOR X AND Y
posXCurrent = x;
posYCurrent = y;
    
//----------GET DIRECTION INPUT
moveX = keyRight - keyLeft;
moveY = keyDown - keyUp;

//-----ONE AXIS MOVEMENT CONTROL
if moveX != 0
{
    moveY = 0;
}
else if moveY != 0
{
    moveX = 0;
}
//------Diagonal Movement



//-----IF DIRECTION INPUT
if moveX != 0 or moveY != 0
{
    //-----IF NOT YET MOVING
    if moving == false
    {
        //----------DIRECTION CHANGE
        scr_dirControl();
        
        //----------START MOVEMENT
        scr_setMoving();
    }
}
        
//-----CHECK IF MOVE GOAL REACHED
if moving == true
{
    scr_isMoving();
    image_speed = .5;
}
else
{
    image_speed = 0;
}
And these are the scripts, I do have basic understanding on what's going on, I'm just not very good at figuring this stuff on my own yet.
Code:
function scr_dirControl() {
    //If keyRight is pressed down
    if moveX == 1
    {
        //Change Direction to 0(Right)
        dir = 0;
    }
    //If keyUp is pressed down
    else if moveY == -1
    {
        //Change Direction to 90(Up)
        dir = 90;
    }
    //If keyLeft is pressed down
    else if moveX == -1
    {
        //Change Direction to 180(Left)
        dir = 180;
    }
    //If keyDown is pressed down
    else if moveY == 1
    {
        //Change Direction to 270(Down)
        dir = 270;
    }
Code:
function scr_isMoving() {
    //If there is No 'object_solid' at Goal Position
    if !place_meeting(posXGoal,posYGoal,oWall)
    {
        //If Goal is reached
        if posXCurrent == posXGoal and posYCurrent == posYGoal
            {
                //Stop Movement
                scr_stopMoving();
            }
    }
    // If there is 'object_solid' at Goal Position
    else
    {
        //Stop Movement
        scr_stopMoving();
    }


}
Code:
function scr_setMoving() {
    //Prepare Variables for Moving
    //-----Set Start Position (Start Position is Current Position)
    posXStart = posXCurrent;
    posYStart = posYCurrent;

    //-----Set Goal Position (Goal Position is Current Position + Direction * Size of Step)
    posXGoal = posXCurrent + (moveX * stepSize);
    posYGoal = posYCurrent + (moveY * stepSize);

    //Start Movement
    motion_set(dir,spd);

    //Can't Prepare Movement
    setMove = false;

    //Is now Moving
    moving = true;


}
Code:
function scr_stopMoving() {
    //Stop Movement
    motion_set(dir,0);

    //Is not Moving
    moving = false;



}
Thanks for the help!
 

noxx

Member
If you want to add diagonal movement, you have to first get rid of that block under //One Axis Movement Control, because right now this is cancelling out any diagonal movement.

Then you could change your scr_dirControl() to simply use dir = point_direction(x,y,moveX,moveY).

But there's a problem. Right now you probably have your variables stepSize and spd set up in a way where you can traverse across the grid acurately, for example stepSize = 32; spd = 4;. And when you check //If goal is reached, this works for horizontal and vertical movement, because you know that the player will be exactly at the goal position after 8 steps.

But when you traverse diagonally, you'll have a longer distance. In a 32x32 grid, your diagonal length is 45.25 (the square root of (32²+32²)). That means after 11 steps you'll be close to your goal position, and after 12 steps you'll have passed it. But you'll never be at the exact position.

Using speed and direction isn't ideal to move across the grid. Instead of using motion_set(), a better aproach would be to simply add the amount you want to move each step to your position.

You already have moveX and moveY variables, that hold the direction (left = -1, right = 1, up = -1, down = 1). Just put something in your movement script like x += moveX * stepAmount; y += moveY * stepAmount;. So on a 32x32 grid you would set stepAmount to 4 if you wanted to reach the goal after 8 steps. The important thing here is that stepAmount always fits into your grid evenly or you'll have the same problem as before where you overshoot you goal position.

You can also use the lerp() function. At the beginning of your movent you store the initial x and y position, then you interpolate them to the goal position. Each step you increase the amount until the amount equals 1. For axample something like this x = lerp(startX, goalX, .1) would move the player along 10% of the distance between startX and goalX. So in the next step you'd want the amount to be set to 20%, then 30%, etc.. until it reaches 100%, that's when you've reached the goal position.

Oh and just an after thought, you might run into issues with the diagonal input in terms of timing. Since it's very likely the two keys aren't pressed at exactly the same moment, you may want to add a waiting period for a step or two after the first key press is recognized. That way, if the player presser keyUp in one step and then the next step keyRight is also pressed, they will indeed move diagonally and not have to wait another turn.

Also, changing your movement system should better mimic the look and feel of the game you mentioned. If you watch a video you can see how the diagonal movement seems faster and snappier, due to the longer distance traveled in the same amount of time.
 
Top