Search Unity

2D Character Control Issue

Discussion in 'Scripting' started by jesseoffy, Apr 1, 2011.

  1. jesseoffy

    jesseoffy

    Joined:
    Feb 20, 2010
    Posts:
    146
    After reading through the 2D platformer example, I started working on my own platformer character, basing most of the script off of a regular character controller script I wrote a while back. Nevertheless, in my test level (set up to test various mechanics of 2D platformer games), I found a few problems:

    • When the character moves onto a moving platform (exactly the same setup as in the 2D platformer example), I find that, when the platform is moving down, my character can stand on it, but the moment it starts moving upwards, he falls through. I've tested it enough to note that no matter where I get on the platform, if it's moving up, I fall through.
    • How would my character push objects, like a box? I know that a Character Controller, being a non-physics object, does not interact with ridigbodies, but I'm not entirely sure how to make them interact. Should I, on collision, make the box a child of my character, so both move when I make the character move forward? Hopefully some of you have a better solution, as I feel this might hit a few roadblocks when I try to push the box up or down hills.

    Here is the script dealing with the actual movement of the character. I currently have it attached to a capsule with a Character Contoller:
    Code (csharp):
    1. var walkSpeed = 5.0;
    2. var jumpHeight = 8.0;
    3. var gravity = 20.0;
    4. var maxFallSpeed = 10.0;
    5.  
    6. private var lastJumpButtonTime = -10.0;
    7. private var jumpTimeout = 0.15;
    8.  
    9. private var movDir : Vector3 = Vector3.zero;
    10. private var controller : CharacterController;
    11.  
    12. function Start()
    13. {
    14.     controller = GetComponent(CharacterController);
    15. }
    16.  
    17. function Update()
    18. {      
    19.     vertical = Input.GetAxis("Horizontal");
    20.  
    21.     movDir.z = vertical * movement.walkSpeed;
    22.     movDir = transform.TransformDirection(movDir);
    23.    
    24.     if(controller.isGrounded)
    25.     {
    26.         if(Time.time < lastJumpButtonTime + jumpTimeout)
    27.             movDir.y = movement.jumpHeight;
    28.     }
    29.    
    30.     if(Input.GetButtonDown("Jump"))
    31.         lastJumpButtonTime = Time.time;
    32.    
    33.     movDir.y -= movement.gravity * Time.deltaTime;
    34.     movDir.y = Mathf.Max(movDir.y, -movement.maxFallSpeed);
    35.     controller.Move(movDir * Time.deltaTime);
    36. }
     
  2. fireside

    fireside

    Joined:
    Feb 6, 2011
    Posts:
    203
    I had this same problem. What I did was keep track of the ground I was on with
    Code (csharp):
    1.  
    2.     void OnControllerColliderHit (ControllerColliderHit hit)
    3.     {
    4.         if (IsGrounded ()) {
    5.             lastGroundPos = ground.transform.position;
    6.             lastGround = ground;           
    7.             ground = hit.gameObject;
    8.  
    9.         }
    10.     }
    11.  
    12.  
    Then, if I was on the same ground, I did a translation the same amount as the ground before I did the Move() by subtracting last ground position from current ground position. During a jump, I made the ground equal to the game object so it would always show a different ground after a jump even if it was the same.

    This is just new code. I think hit.moveDirection would be a better test for ground collision.

    On the box, I would check for collision and then apply force in the direction the character was moving. I haven't done this or experimented much with rigid bodies on Unity, though.
     
    Last edited: Apr 2, 2011
  3. niosop2

    niosop2

    Joined:
    Jul 23, 2009
    Posts:
    1,059
  4. jesseoffy

    jesseoffy

    Joined:
    Feb 20, 2010
    Posts:
    146
    @niosop - Thanks, that worked perfectly.
    @fireside - So you are saying that you used that script and then, based on that script, moved the CharacterController with the ground if the ground was, for instance, pushing upwards or sideways (I just checked if the character moves with a horizontally-moving platform, and it doesn't)?
    Seeing the script niosop linked, I'm wondering if I could maybe apply that script so that it does the opposite - moves the CharacterController based on the motion of the rigid body. I'll have to mess around with this later. . . .
     
  5. Fidde

    Fidde

    Joined:
    Dec 20, 2010
    Posts:
    109
    When the character touches the platform, just let the platform add its movement changes to the player as well. I.e myPlatform.transform.position += delta; myPlayer.transform.position += delta.
     
  6. fireside

    fireside

    Joined:
    Feb 6, 2011
    Posts:
    203
    Yes. I don't quite see how your second statement is the opposite, it sounds exactly the same. Moving the character controller based on ground(gameObject) or moving character controller based on rigid body position. I've found rigid bodies don't work well for platforms myself. As Fidde said, I should probably just add it to the move direction rather than doing a separate translation. I'm just messing around with it myself. The character moves well on moving platforms anyway without going through, or vibrating as the script that comes with standards does. I'm completely satisfied with it that way, but I haven't really condensed it to the smallest it could be yet.
     
    Last edited: Apr 2, 2011
  7. jesseoffy

    jesseoffy

    Joined:
    Feb 20, 2010
    Posts:
    146
    So while I'm still trying to work through Fidde's solution, I found that making the character a child of the elevator while on the elevator works really well. Still testing for problems that might occur, but it seems like a just-as-good solution. . . .
     
  8. fireside

    fireside

    Joined:
    Feb 6, 2011
    Posts:
    203
    Yeah, I gave up on my solution because it didn't work on horizontal moving platforms and went to the child method. I use it in combination with a tag for movingPlatform. Moving the character without parenting only sort of works horizontally. It seems to change depending on the direction the charater is facing. I didn't try actual positioning, I was using translation and also tried the Move function but neither seemed to work.
     
  9. jesseoffy

    jesseoffy

    Joined:
    Feb 20, 2010
    Posts:
    146
    I noticed using the tag method results in two basic issues - if the trigger box isn't far enough from the actual platform, then the character won't be parented with it when it moves horizontally - of course, this is an easy fix by enlarging the Y-axis of the collider.
    The other is, if you jump while on a horizontally moving platform, the motion from the platform won't be taken into consideration after the jump has started. This isn't too big a problem and could actually be used to help gameplay in certain situations.
    Just though I should point that out so people know what they're getting into, using this method.