Player Walking...

Discussion in 'Programming' started by Explosive Photons, Jan 10, 2017.

  1. I am creating an RPG in the style of the Mother Games and Undertale. I have created separate sprites for my overworld character. One going up, One going down, One going left and One going right. Each contains to images that create a sort of animation. I have programmed it so when you press the left button, it switches the sprite to the left facing one, changes the image speed to 0.2 and using drag and drop moves the player towards -8 y (relative). When you release left, the image_index goes back to 0 and the image speed goes to 0 too. I have used this same idea for all directions and it works well. However, when I try to walk in two directions at once, the player stops. I know this is to do with my programming, so has anyone got any suggestions about how I could program this?
     
  2. matharoo

    matharoo Udemy Instructor

    Joined:
    Jul 9, 2016
    Posts:
    917
    You can use this simple code in the Step event:
    Code:
    if (keyboard_check(vk_left)) x -= 8;
    else
    if (keyboard_check(vk_right)) x+= 8;
    
    if (keyboard_check(vk_up)) y -= 8;
    else
    if (keyboard_check(vk_down)) y+= 8;
    It will allow for your player to walk diagonally (both horizontal and vertical directions).
     
  3. eidobunny

    eidobunny Member

    Joined:
    Jan 10, 2017
    Posts:
    17
    Hello, it just so happens that I'm working on a game heavily inspired by Undertale. I recreated the Undertale movement system to start out, and I don't mind sharing my work. It's a bit complicated because there are some subtleties that aren't immediately obvious as you're playing.

    Feel free to use the code or adapt it to your own needs. The only thing I need to add to my code is directional idle sprites, but it should be fairly simple to implement if you understand the rest of the code. Right now I just have one generic idle sprite.

    It should be noted that I don't use any DnD, only GML. The first two code blocks are code actions in their respective events. The last 3 are scripts.

    Code:
    ///PLAYER OBJECT CREATE EVENT
    
    //Maximum speed
    spd = 4;
    
    //Current movement speed
    hspd = 0;
    vspd = 0;
    
    //Initialize basic properties
    sprite_index = spr_testidle;
    image_speed = 0.5;
    
    //Initialize basic movement state
    state = move_state;
    
    /*
    
    Directions for top-down spritework.
    
    0 = down
    1 = left
    2 = up
    3 = right
    
    */
    
    dir = 0;
    
    Code:
    ///PLAYER OBJECT STEP EVENT
    
    //Get input (keyboard/controller)
    get_input();
    
    //Execute the state (in the basic case, this calls the move_state script)
    script_execute(state);
    
    Code:
    ///get_input()
    
    left = keyboard_check(vk_left);
    right = keyboard_check(vk_right);
    up = keyboard_check(vk_up);
    down = keyboard_check(vk_down);
    
    Code:
    ///move_state
    
    //Set animation speed for movement
    
    image_speed = 1;
    
    //Set default speed if there is no input
    
    hspd = 0;
    vspd = 0;
    
    //Set speed to the direction you are pressing as long as there isn't a wall there
    //Left and up take precedence
    
    if(right && !place_meeting(x+1,y,Solid)) hspd = spd;
    
    if(left && !place_meeting(x-1,y,Solid)) hspd = -spd;
    
    if(down && !place_meeting(x,y+1,Solid)) vspd = spd;
    
    if(up && !place_meeting(x,y-1,Solid)) vspd = -spd;
    
    //Prevent stuttering if against a wall pressing opposite directional buttons
    
    /*
    
    SPECIAL NOTE: The following two lines of uncommented code deviate from Undertale.
    In Undertale if you hold both UP & DOWN at the same time and run into a wall,
    your character will stutter against it. Also if you hold LEFT & RIGHT and run into a wall,
    your character will stop in its tracks. I fixed those issues in the next two lines of uncommented code.
    if you truly wanted an exact replica of Undertale, replace them with this instead:
    
    if(left && right && place_meeting(x-1,y,Solid))
    {
    hspd = 0;
    vspd = 0;
    }
    
    This will replicate the stuttering effect and the freeze effect you encounter in Undertale.
    
    */
    
    if(left && right && place_meeting(x-1,y,Solid)) hspd = 0;
    
    if(up && down && place_meeting(x,y-1,Solid)) vspd = 0;
    
    //Set the sprite to the appropriate direction
    
    if(hspd < 0) sprite_index = spr_testleft;
    
    if(hspd > 0) sprite_index = spr_testright;
    
    if(vspd < 0) sprite_index = spr_testup;
    
    if(vspd > 0) sprite_index = spr_testdown;
    
    //Sprite direction correction in special cases of multiple button press combinations
    
    if((right && down && left && !up) || (right && down && !left && !up && dir == 1) || (left && down && !right && !up && dir == 3)) dir = 0;
    
    if((down && left && up && !right) || (down && left && !up && !right && dir == 2) || (up && left && !right && !down && dir == 0)) dir = 1;
    
    if((left && up && right && !down) || (left && up && !right && !down && dir == 3) || (right && up && !down && !left && dir == 1)) dir = 2;
    
    if((up && right && down && !left) || (up && right && !down && !left && dir == 0) || (down && right && !up && !left && dir == 2)) dir = 3;
    
    //Maintain sprite momentum by checking the previous sprite direction
    
    if(hspd < 0 && dir == 1 && left) sprite_index = spr_testleft;
    
    if(hspd > 0 && dir == 3 && right) sprite_index = spr_testright;
    
    if(vspd < 0 && dir = 2 && up) sprite_index = spr_testup;
    
    if(vspd > 0 && dir = 0 && down) sprite_index = spr_testdown;
    
    //Special checks when you're up against a wall trying to move against or along it
    
    if(sprite_index == spr_testleft)
    {
       if(place_meeting(x-1,y,Solid))
       {
           if(vspd > 0 && !place_meeting(x,y+1,Solid))
           {
               sprite_index = spr_testdown;
               dir = 3;
           }
           else if(vspd < 0 && !place_meeting(x,y-1,Solid))
           {
               sprite_index = spr_testup;
               dir = 1;
           }
           else
           {
               hspd = 0;
               vspd = 0;
           }
       }
       else dir = 1;
    }
    
    if(sprite_index == spr_testright)
    {
       if(place_meeting(x+1,y,Solid))
       {
           if(vspd > 0 && !place_meeting(x,y+1,Solid))
           {
               sprite_index = spr_testdown;
               dir = 3;
           }
           else if(vspd < 0 && !place_meeting(x,y-1,Solid))
           {
               sprite_index = spr_testup;
               dir = 1;
           }
           else
           {
               hspd = 0;
               vspd = 0;
           }
       }
       else dir = 3;
    }
    
    if(sprite_index == spr_testup)
    {
       if(place_meeting(x,y-1,Solid))
       {
           if(hspd > 0 && !place_meeting(x+1,y,Solid))
           {
               sprite_index = spr_testright;
               dir = 3;
           }
           else if(hspd < 0 && !place_meeting(x-1,y,Solid))
           {
               sprite_index = spr_testleft;
               dir = 1;
           }
           else
           {
               hspd = 0;
               vspd = 0;
           }
       }
       else dir = 2;
    }
    
    if(sprite_index == spr_testdown)
    {
       if(place_meeting(x,y+1,Solid))
       {
           if(hspd > 0 && !place_meeting(x+1,y,Solid))
           {
               sprite_index = spr_testright;
               dir = 3;
           }
           else if(hspd < 0 && !place_meeting(x-1,y,Solid))
           {
               sprite_index = spr_testleft;
               dir = 1;
           }
           else
           {
               hspd = 0;
               vspd = 0;
           }
       }
       else dir = 0;
    }
    
    //If there is no input, default to the idle state
    
    if(hspd == 0 && vspd == 0)
    {
       sprite_index = spr_testidle;
       image_speed = 0.5;
    }
    
    //Actually move the player
    
    move(Solid);
    
    Code:
    ///move(collision_object)
    
    var collision_object = argument0;
    
    //Horizontal collisions
    
    if(place_meeting(x+hspd,y,collision_object))
    {
       while(!place_meeting(x+sign(hspd),y,collision_object))
       {
           x += sign(hspd);
       }
       hspd = 0;
    }
    
    x += hspd;
    
    //Vertical collisions
    
    if(place_meeting(x,y+vspd,collision_object))
    {
       while(!place_meeting(x,y+sign(vspd),collision_object))
       {
           y += sign(vspd);
       }
       vspd = 0;
    }
    
    y += vspd;
    
    Obviously just replace spr_testleft (and the others) with the appropriate sprite names. Use the "dir" variable to calculate the correct idle facing direction when writing idle sprite code.

    Hope this helps! It might be a little above your skill level but keep working at it and keep trying to make great things! Good luck.
     
    Last edited: Jan 11, 2017
  4. Thanks! That will really help me. BTW are you good at art?
     

Share This Page

  1. This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
    By continuing to use this site, you are consenting to our use of cookies.
    Dismiss Notice