Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Implementing a Moving Pad Switch

Discussion in 'Scripting' started by Stevens-R-Miller, Feb 3, 2021.

  1. Stevens-R-Miller

    Stevens-R-Miller

    Joined:
    Oct 20, 2017
    Posts:
    664
    I'm looking for options on how to create a pad that operates as a switch. Lots of games have these, where you stand or put an object on a pad in order to make something happen. The pad is often just a square or circle on the floor, and the action is often opening a door or activating a machine. When the pad itself doesn't move, this is very easy to do with colliders. I'm interested in animating the pad so that it visibly moves downward when something is on it, and visibly moves up again when whatever is on it is removed.

    Now, from my experiences with 3D platformers, I know that a player object that jumps onto a vertically moving platform might end up generating a lot of alternating entry and exit collision events when the platform moves downward. That's because, if the platform moves downward quickly enough, it will leave the player behind. The player then falls downward, accelerating until it hits the platform again.

    One solution is to make the player a child of the platform upon the first collision entry. It's not physically accurate, but the visual results work well and it solves the problem of the platform leaving the player behind when the platform moves downward.

    My problem with the pad is similar. When the player, say, drops a cube onto the pad, the pad will move downward. If the pad moves slowly, there won't be a problem. But if the pad moves quickly enough, it will leave the cube behind and, reacting to the collision exit, the pad will change direction and move back up. This can result in an endless oscillation of entries and exits, with the pad bouncing up and down forever. Making the cube a child of the pad solves the bounce problem, but now the player can't just pick up the cube, because the parented pad would move with the cube.

    I can think of a few ways to deal with this. Nested objects or colliders perhaps, where a slightly smaller inner collider generates the entry that starts the pad moving down while the larger outer collider generates the exit that makes the pad move up would introduce a bit of hysteresis into the physical mechanics of the system. But it strikes me that this mechanic is so common that others must have also dealt with it already, so I'm hoping for a bit of advice before I reinvent (or fail to reinvent) any good wheels.

    Any suggestions?
     
  2. GroZZleR

    GroZZleR

    Joined:
    Feb 1, 2015
    Posts:
    3,201
    Don't tie the visual state of an object to its other states. Put a trigger collider shaped appropriately over your pad. Have all of the actual logic in there, and then play the visual pad's animation.

    BouncePad (trigger collider, bounce pad component, etc.)
    Model (meshrenderer, etc.)
     
  3. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,336
    What you describe is called hysteresis, where the reaction to the input changes the input back and forth.

    One way to handle this is to have separate colliders, one for ON and one for OFF. But with a single button that doesn't really work too well.

    Another way to handle this is to make the reaction delayed by a small amount, such as a quarter of a second or so.

    That way when you leap on it, it does nothing until that time passes, then it changes. When you leap off it, either intentionally or by the jitter, it also does nothing until enough time goes by.

    The key is that it can only consider itself in one state or another, either active or inactive, and the visual presentation of that is gradual. You can tween towards what is considered active or inactive with something like this codelet:

    The code: https://pastebin.com/ePnwWqnM

    You would use the "active or inactive" state to specify the animation height and use that to drive the .localPosition of the button up or down.
     
  4. Stevens-R-Miller

    Stevens-R-Miller

    Joined:
    Oct 20, 2017
    Posts:
    664
    Oh. My. God. That's exactly what I do in Roblox code for lava pits and bodies of water, but I didn't think of using it for a moving object. Damn! That's great, thanks!
     
  5. Stevens-R-Miller

    Stevens-R-Miller

    Joined:
    Oct 20, 2017
    Posts:
    664
    You mean, like this ;) ?
    That's why I was considering nested colliders, one for entry, one for exit. The hysteresis would arise from the gap between them: contact is made when the inner collider is entered, but contact isn't unmade until after the outer collider is exited. That's a lot more complicated than GroZZleR's idea, but it might be somewhat more accurate from a physical perspective.

    That crossed my mind as well, but it feels a bit complicated. Have you ever done it this way? Is it manageable?

    Hey, that's cool, thanks!
     
  6. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,336
    I think so. I've seen bad implementations that are very unmanageable, but that applies to any problem.

    As long as the "data stream" is straight, it's easy.

    Code (csharp):
    1. privatebool OnPad = false;
    2. privatefloat currentPad = 0;
    3. private float desiredPad = 0;
    Then set these up in appropriate functions:

    OnColliderEnter -> OnPad = true
    OnColliderEnter -> OnPad = false

    Then in Update():

    Code (csharp):
    1. desiredPad = OnPad ? 1.0f : 0.0f;
    2.  
    3. // insert the pastebin MoveTowards code above to move currentPad towards desiredPad
    4.  
    5. // finally act on the currentPad value to control the pad
    6.  
    7. if (currentPad < 0.1f)
    8. {
    9.    // drive pad OFF
    10. }
    11.  
    12. if (currentPad > 0.9f)
    13. {
    14.    // drive pad ON
    15. }
    That's it.
     
    Stevens-R-Miller likes this.