1. Hey! Guest! The 35th GMC Jam will take place between November 28th, 12:00 UTC - December 2nd, 12:00 UTC. Why not join in! Click here to find out more!
    Dismiss Notice

GML [SOLVED] Moving platform collisions

Discussion in 'Programming' started by ChiHelios, May 1, 2017.

  1. ChiHelios

    ChiHelios Guest

    !SOLVED! Thanks everyone for your help
    Solution below for reference

    Thankyou everyone, I got everything working, including staying grounded and sticking. I'm really happy with the result. I set an actor parent object so all my other characters can benefit from the collisions.

    I stuck with place_meeting and instance_place but now thanks to your explanations I understand WHY I'm using it. The actor collisions always set speed to zero, but recognise grounding, then after I update position I put grounded/sticking velocity back in.

    Just like you suggested I did not factor in the platform movements with the player.

    ///Detect collision

    //temporary variables can be used to make sure x and y don't alter
    //until the correct part of the step.
    var i, tempx, tempy;
    tempx = x; tempy = y; canjump = false; sticking = false; grounded = false;
    dColl = false; sideColl = false; dobj = self; sideobj = self;

    /// X collisions
    if (place_meeting(x+vx, y, owall))
    {
    sideColl = true; sideobj = instance_place(x+vx,y,owall)
    while(!place_meeting(tempx+sign(vx),y,owall))
    {tempx += sign(vx);}
    robj = instance_place(x,y+1,owall);
    if sign(vx) = sign(sideobj.vx) and sideobj.vx < 4
    {sticking = true;}
    vx = 0;
    x = tempx;
    }
    ///////////////////////////////////////////////////////////
    // Collisions in the y direction
    if (place_meeting(x, y+vy, owall))
    {
    while(!place_meeting(x,tempy+sign(vy),owall))
    {tempy += sign(vy);}
    if sign(vy)=1 {dobj = instance_place(x,y+vy,owall);
    dColl = true;
    grounded = true;}
    vy = 0;
    y = tempy;
    canjump =true; inair = false;
    }

    ///////////////////////////////////////////////////////////
    // Collisions in x and y direction
    if (place_meeting(x+vx, y+vy, owall))
    {
    //Move to contact
    while(!place_meeting(x+vx,tempy+sign(vy),owall))
    {tempy += sign(vy);}
    y = tempy;
    while(!place_meeting(tempx+sign(vx),y+vy,owall))
    {tempx += sign(vx);}
    x = tempx;
    //UPDATE speeds
    vx = 0;
    vy = 0;
    }

    ///Position

    x += vx;
    y += vy;

    if grounded {vy= dobj.vy;}
    if sticking {vx= sideobj.vx;}

    After getting the player solid, I used this code for the moving walls. The platforms only push actors like the player, and detect if there will be a crush using place_meeting. I'm planning to implement some different crush strategies by giving each object a script to follow. For the moment though, nice and happy, looking forward to seeing the levels I can make with this.

    There was a very specific case where you could be crushed by a corner moving diagonally which caused a bug so I put another clause in which resolves this.

    //
    /*
    Detect if the object is going to collide with an actor
    if the actor can be moved then move it
    If there will be a crush, stop the object
    */

    crushing = false;

    //X collisions
    while instance_place(x+vx,y,oactor)
    {
    //Find the instance to be pushed
    coll_obj = instance_place(x+vx,y,oactor);
    if coll_obj != noone
    with coll_obj
    {
    //Check for crush
    if !place_meeting(x+sign(other.vx),y,owall)
    {
    //no crush then move
    x+=other.vx;
    vx = other.vx;
    }
    else
    {
    //move up to the crush point
    while !place_meeting(x+sign(other.vx),y,owall)
    {x+=sign(other.vx);}
    other.vx = 0; vx = 0;
    }
    }
    }

    //Y collisions
    while instance_place(x,y+vy,oactor)
    {
    //Find the instance to be pushed
    coll_obj = instance_place(x,y+vy,oactor);
    if coll_obj != noone
    with coll_obj
    {
    //Check for crush
    if !place_meeting(x,y+sign(other.vy),owall)
    {
    //no crush then move
    y+=other.vy;
    vy = other.vy;
    }
    else
    {
    //move up to the crush point
    while !place_meeting(x,y+sign(other.vy),owall)
    {y+=sign(other.vy);}
    other.vy = 0; vy = 0;
    }
    }
    }

    //XY collisions
    while instance_place(x+vx,y+vy,oactor)
    {
    //Find the instance to be pushed
    coll_obj = instance_place(x+vx,y+vy,oactor);
    if coll_obj != noone
    with coll_obj
    {
    //Check for x crush
    if !place_meeting(x+sign(other.vx),y,owall)
    {
    //no crush then move
    x+=other.vx;
    vx = other.vx;
    }
    else
    {
    //move up to the crush point
    while !place_meeting(x+sign(other.vx),y,owall)
    {x+=sign(other.vx);}
    other.vx = 0; vx = 0;
    }
    //Check for y crush
    if !place_meeting(x,y+sign(other.vy),owall)
    {
    //no crush then move
    y+=other.vy;
    vy = other.vy;
    }
    else
    {
    //move up to the crush point
    while !place_meeting(x,y+sign(other.vy),owall)
    {y+=sign(other.vy);}
    other.vy = 0; vy = 0;
    }
    }
    }

    I've left the code for reference and will update my first post with my solution. Thanks again for all your help and feel free to offer any suggestions.

    ORIGINAL POST
    ---------------------------------
    Hi all!

    I'm having some trouble with moving platforms in my platformer. I'm using vx and vy as my velocity vector, and this takes place just before I update the x and y values. This is for my player.

    Stationary walls are okay, but when the walls move they overlap the player and it means the wall can pull the player. On top of that, when the moving wall changes moving right to left while pushing the player the player translocates to the right of the screen.

    Any advice?

    Thanks :)


    Code:
    ///Detect collision
    
    //temporary variables can be used to make sure x and y don't alter
    //until the correct part of the step.
    var i, tempx, tempy;
    tempx = x; tempy = y;
    //If no collision to happen, remove existing Coll objects.
    if !place_meeting(x+vx,y,owall) or !place_meeting(x,y+vy,owall) or !place_meeting(x+vx,y+vy,owall)
    {
    rColl = false; dColl = false; uColl = false; lColl = false;
    canjump = false;
    robj = self; lobj = self; uobj = self; dobj = self;
    }
     
    /// X collisions
    if (place_meeting(x+vx, y, owall))
        {
        if sign(vx) > 0
           {rColl = true; robj =instance_place(x+vx,y,owall);
           while(!place_meeting(tempx+sign(vx-robj.vx),y,owall) and sign(vx)=sign(robj.vx) and vx>robj.vx)
                   {tempx += sign(vx-robj.vx);}
           vx = robj.vx;
           }
        else
           {lColl = true; lobj =instance_place(x+vx,y,owall);
           while(!place_meeting(tempx+sign(vx-lobj.vx),y,owall) and sign(vx)=sign(lobj.vx) and vx>robj.vx)
                   {tempx += sign(vx-lobj.vx);}
           vx = lobj.vx;
           }
        x = tempx;
        }
    ///////////////////////////////////////////////////////////
    // Collisions in the y direction
        if (place_meeting(x, y+vy, owall))
        {
        if sign(vy) > 0
           {dColl = true; dobj =instance_place(x,y+vy,owall);
           vy = 1.1*dobj.vy;
           while(!place_meeting(x,tempy+sign(vy-dobj.vy),owall) and sign(vy)=sign(dobj.vy) and vy>dobj.vy)
                   {tempy += sign(vy-robj.vy);}
           if vy>dobj.vy or sign(vy)!=sign(dobj.vy) {vy = dobj.vy;}
           }
        else
           {uColl = true; uobj =instance_place(x,y+vy,owall);
           while(!place_meeting(x,tempy+sign(vy-uobj.vy),owall) and sign(vy)=sign(uobj.vy) and vy>robj.vy)
                   {tempy += sign(vy-lobj.vy);}
           if vy<uobj.vy or sign(vy)!=sign(uobj.vy) {vy = uobj.vy;}
           }
        y = tempy;
        canjump =true; inair = false;
        }
        
     
    Last edited by a moderator: May 5, 2017
  2. TheouAegis

    TheouAegis Member

    Joined:
    Jul 3, 2016
    Posts:
    7,026
    well sounds like your first problem is because you are using place_meeting, but that does not care where in proximity to the player the wall is, it only cares if the wall actually collides with a player.
     
  3. ChiHelios

    ChiHelios Guest

    Thanks for your reply, I'm not sure I follow. As I understand it place_meeting moves the instance to where you specify and checks for a collision, then moves it back. Position_meeting just checks the single point. Is this difference enough to make an impact on my code?

    From my testing the problem seems to be that the player doesn't know it's going to collide with a moving wall if they move towards each other so they overlap. Not sure how to check for that.
     
  4. tomsaram

    tomsaram Member

    Joined:
    Jun 28, 2016
    Posts:
    75
    Well the strategy you are trying to use here will not work for moving platforms anyway, because place_meeting(x+vx,y+vy,owall) takes into account only the movement of the player and not that of the platform. So there will always be missed collisions especially when the player is not moving.

    What I would suggest is a drastic change in which you deal with collisions AFTER the objects has moved and acquired their new position. This way you only need to move the player object out of the wall along the correct direction. The general strategy will look like this:

    obj = instance_place(x,y,owall);
    while( obj >0 )
    {
    while(place_meeting(x,y,obj))
    {
    //move the object by 1 pixel​
    }
    obj = instance_place(x,y,owall);​
    }
     
  5. ChiHelios

    ChiHelios Guest

    Ahh thank you. I knew I needed to account for this but I thought of doing it in the wall code. This would be more manageable. I'll give it a go and update here
     
  6. TheouAegis

    TheouAegis Member

    Joined:
    Jul 3, 2016
    Posts:
    7,026
    Consider this image:
    Code:
                    OO
    XXXXX     OO
                    OO
                XXXXX    
    The X's are the moving platforms, the O's are the player. A check like place_meeting(x,y+1,owall) in this case would not be advisable because it could detect either of the platforms. So the player could be riding on the lower platform and then if he at any time collides even part-way with the upper platform, the upper platform's mechanics could override the one the player is on. place_meeting() cares more about the entire bounding area of the instance than it does about the coordinates. position_meeting() alleviates that issue by ignoring the bounding box and being concerned entirely with the coordinates provided. So (x,y+1) actually means something with position_meeting(), whereas it is almost negligible with place_meeting().

    Then there is scenario 2:
    Code:
           OO
           OO
           OO
    XXXX XXXX
    Which owall is the player colliding with? If one is moving up and the other is moving down, for example, using place_meeting() would tell you the player has a platform under him but doesn't tell you which of the two it is. Logically, the one moving up should take precedence, but you can't know definitively which one that is using place_meeting(). Using position_meeting() or instance_position() you can find out precisely which one is moving up and which one is moving down.
     
  7. Strawbry_jam

    Strawbry_jam Member

    Joined:
    Jun 20, 2016
    Posts:
    217
    How I handle moving platforms:

    1. Move the player treating all walls/platforms as static.

    2. Move the moving platforms pushing the player as they collide or stand on.

    2a. With each moving platforms, check 1 px up for players and enemies. Make a list of them.

    2b. With each moving platform, check 1 px in moving direction for players and enemies. Add those to list if not in list.

    2c. With all in list, move (if possible) 1 px in direction platform is moving.

    2d. Check once more for collision in direction moving 1 px. If there is a collision, decide how to resolve it (kill instance or stop moving platform)

    2e. Move platform, if no collisions, 1 px.

    2f. Repeat for speed of moving platform.

    It's cleaner to move instances up to a collision than to move instances out of a collision. Trying to move instances out of a collision may land that instance into another collision.
     
  8. ChiHelios

    ChiHelios Guest

    Thanks everyone for your help :)

    TheouAegis thanks, that makes sense to me now. Placemeeting includes so much area that I don't want to consider. Thank you for taking the time to write that out. You mentioned things I hadn't considered yet

    So what I can do then too bout need to fully restructure my code is to remove any relative motion from my existing code to treat the other objects as stationary, then build a list of objects which will collide with the player when they move. Then in the players end step I can move the player or implement some crush detection like you said strawberry

    Is that right? Cheers
     
  9. Desix

    Desix Member

    Joined:
    Jun 23, 2016
    Posts:
    435
    Are there any platforms you stand on that move down?

    Just in case:
    That wont work with 'push' code since its not pushing the player its moving away, so you'll get jittering and have the player fall, connect, fall, connect etc.

    Typically what you need to do is just use normal collision code, but you must figure out the instance below you at all times. Then just before you actually move the player due to the collision, add the instance under you's motion to the player's x and y which means it'll move you wherever you need, even down. The platform speeds would need to be calculated before the player's collision code also. To keep this working, you need to check more than one pixel under the player, up to the amount the platforms move down (only if they're still on the ground, only check one under if they're in the air)

    Order of events:
    -Platform moves
    -If grounded (which they are, they're stand on the platform in this example), player checks around 4px below for the object it's on. (This only works if the platform moves no faster than 4px, so change that variable to the maximum downward platform speed, shouldnt be any bigger than 6-7 though or you'll have other issues)
    -Platform is found, player is moved with it's y speed
    -Normal collision code at adjusted position

    With left and right it's the same, but simply move by the platform's x speed, no need for any other crazy checks.

    Not sure if any of this matters but I'm leaving it here as reference anyway.
     
    Last edited: May 2, 2017
  10. ChiHelios

    ChiHelios Guest

    Thanks, I will consider that because I'm hoping to use these 'platforms ' as the base for some big enemies so you can get pushed around and run on top of them.

    It may have been easier with physics but I wanted to do out this way to really understand whatI was doing a bit better. I'm okay with some downward moving objects getting away from the player
     
  11. Yal

    Yal GMC Memer GMC Elder

    Joined:
    Jun 20, 2016
    Posts:
    3,874
    From my experiences, there's several different cases where the player needs to move, and if you don't realize this, it's easy to make mistakes.
    • The platform is moving into a player. (There's 4 cases of this, and you need to check both where the player is compared to the platform AND which direction it's moving in to tell if any of them applies)
    • The player is standing on top of the platform while it moves sideways or down. (When a platform moves diagonally upwards, make sure this case doesn't trigger both this and the previous case)
    So in total, there's 7 cases to care about... less for platforms that will only ever move along one axis.
     
  12. ChiHelios

    ChiHelios Guest

    Thank you everyone, I got everything working, including staying grounded and sticking. I'm really happy with the result. I set an actor parent object so all my other characters can benefit from the collisions.

    I stuck with place_meeting and instance_place but now thanks to your explanations I understand WHY I'm using it. The actor collisions always set speed to zero, but recognise grounding, then after I update position I put grounded/sticking velocity back in.

    Just like you suggested I did not factor in the platform movements with the player.

    ///Detect collision

    //temporary variables can be used to make sure x and y don't alter
    //until the correct part of the step.
    var i, tempx, tempy;
    tempx = x; tempy = y; canjump = false; sticking = false; grounded = false;
    dColl = false; sideColl = false; dobj = self; sideobj = self;

    /// X collisions
    if (place_meeting(x+vx, y, owall))
    {
    sideColl = true; sideobj = instance_place(x+vx,y,owall)
    while(!place_meeting(tempx+sign(vx),y,owall))
    {tempx += sign(vx);}
    robj = instance_place(x,y+1,owall);
    if sign(vx) = sign(sideobj.vx) and sideobj.vx < 4
    {sticking = true;}
    vx = 0;
    x = tempx;
    }
    ///////////////////////////////////////////////////////////
    // Collisions in the y direction
    if (place_meeting(x, y+vy, owall))
    {
    while(!place_meeting(x,tempy+sign(vy),owall))
    {tempy += sign(vy);}
    if sign(vy)=1 {dobj = instance_place(x,y+vy,owall);
    dColl = true;
    grounded = true;}
    vy = 0;
    y = tempy;
    canjump =true; inair = false;
    }

    ///////////////////////////////////////////////////////////
    // Collisions in x and y direction
    if (place_meeting(x+vx, y+vy, owall))
    {
    //Move to contact
    while(!place_meeting(x+vx,tempy+sign(vy),owall))
    {tempy += sign(vy);}
    y = tempy;
    while(!place_meeting(tempx+sign(vx),y+vy,owall))
    {tempx += sign(vx);}
    x = tempx;
    //UPDATE speeds
    vx = 0;
    vy = 0;
    }

    ///Position

    x += vx;
    y += vy;

    if grounded {vy= dobj.vy;}
    if sticking {vx= sideobj.vx;}

    After getting the player solid, I used this code for the moving walls. The platforms only push actors like the player, and detect if there will be a crush using place_meeting. I'm planning to implement some different crush strategies by giving each object a script to follow. For the moment though, nice and happy, looking forward to seeing the levels I can make with this.

    There was a very specific case where you could be crushed by a corner moving diagonally which caused a bug so I put another clause in which resolves this.

    //
    /*
    Detect if the object is going to collide with an actor
    if the actor can be moved then move it
    If there will be a crush, stop the object
    */

    crushing = false;

    //X collisions
    while instance_place(x+vx,y,oactor)
    {
    //Find the instance to be pushed
    coll_obj = instance_place(x+vx,y,oactor);
    if coll_obj != noone
    with coll_obj
    {
    //Check for crush
    if !place_meeting(x+sign(other.vx),y,owall)
    {
    //no crush then move
    x+=other.vx;
    vx = other.vx;
    }
    else
    {
    //move up to the crush point
    while !place_meeting(x+sign(other.vx),y,owall)
    {x+=sign(other.vx);}
    other.vx = 0; vx = 0;
    }
    }
    }

    //Y collisions
    while instance_place(x,y+vy,oactor)
    {
    //Find the instance to be pushed
    coll_obj = instance_place(x,y+vy,oactor);
    if coll_obj != noone
    with coll_obj
    {
    //Check for crush
    if !place_meeting(x,y+sign(other.vy),owall)
    {
    //no crush then move
    y+=other.vy;
    vy = other.vy;
    }
    else
    {
    //move up to the crush point
    while !place_meeting(x,y+sign(other.vy),owall)
    {y+=sign(other.vy);}
    other.vy = 0; vy = 0;
    }
    }
    }

    //XY collisions
    while instance_place(x+vx,y+vy,oactor)
    {
    //Find the instance to be pushed
    coll_obj = instance_place(x+vx,y+vy,oactor);
    if coll_obj != noone
    with coll_obj
    {
    //Check for x crush
    if !place_meeting(x+sign(other.vx),y,owall)
    {
    //no crush then move
    x+=other.vx;
    vx = other.vx;
    }
    else
    {
    //move up to the crush point
    while !place_meeting(x+sign(other.vx),y,owall)
    {x+=sign(other.vx);}
    other.vx = 0; vx = 0;
    }
    //Check for y crush
    if !place_meeting(x,y+sign(other.vy),owall)
    {
    //no crush then move
    y+=other.vy;
    vy = other.vy;
    }
    else
    {
    //move up to the crush point
    while !place_meeting(x,y+sign(other.vy),owall)
    {y+=sign(other.vy);}
    other.vy = 0; vy = 0;
    }
    }
    }

    I've left the code for reference and will update my first post with my solution. Thanks again for all your help and feel free to offer any suggestions.
     
  13. Anton[RUS]

    Anton[RUS] Guest

    How to add this stuff at this code?


    //begin_y_collisions

    var getdown; // jump by combination of two buttons
    if (key_down==1 && key_jump_held==1){getdown = 1};else{getdown = 0};

    //
    troll = instance_place(x,y+vsp,obj_wall);
    insidetheplatform = (instance_place(x,y,troll));
    if (troll != noone){//
    if (y > troll.y){
    while (!place_meeting(x,y+sign(vsp),troll)){y-=1};
    if (troll.platform == 1){};
    if (troll.platform == 0){vsp = 0};
    if (troll.breakable == 1){vsp = 0; instance_destroy(troll)};
    };};//

    troll2 = instance_place(x,y+vsp,obj_wall);
    insidetheplatform2 = (instance_place(x,y,troll2));
    if (troll2 != noone){//
    if (y < troll2.y){
    while (!place_meeting(x,y+sign(vsp),troll2)){y+=1};
    if (troll2.platform == 1) && (getdown != 0){grounded = 0; jumped =1};
    if (troll2.platform == 1) && (insidetheplatform2 != noone){};
    if (troll2.platform == 0){grounded = 1; jumped = 0; jumps = jumps_max; vsp = 0};
    if (troll2.platform == 1) && (getdown == 0) && (insidetheplatform2 == noone) && (troll2.moving == 0)
    {grounded = 1; jumped = 0; jumps = jumps_max; vsp = 0};
    };};//
     
  14. Yal

    Yal GMC Memer GMC Elder

    Joined:
    Jun 20, 2016
    Posts:
    3,874
    I recommend a keyboard, preferably Dvorak but a normal QWERTY layout might be easier to come across.
     
    Desix likes this.
  15. Jumper

    Jumper Member

    Joined:
    Jan 10, 2019
    Posts:
    2
    Do you put the moving wall code in the wall object step? How do you get it to move? I use the follow path and I cant seem to "extract" the velocity values, vx and vy in your code, so it just crashes. Collision code worked flawlessly with only minor adjustments, even alongside my tilecollision, thank you very much for that !!
     

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