Search Unity

Prevent character move with pickup

Discussion in 'Scripting' started by zibba, Apr 7, 2009.

  1. zibba

    zibba

    Joined:
    Mar 13, 2009
    Posts:
    165
    In my 3rd person game, I have a player which is being controlled with a Character Controller, with a certain radius and it's colliding with the world's walls etc all OK. The problem comes when I try and make the character pickup and drop an object.

    I'm detecting the pickup object with isTrigger and then parenting that object inside the player hierarchy so the character appears to carry it. However, the character + pickup is larger than the original radius, so it's possible to push the carried pickup into a wall. So, in the picked up script I make the radius larger which almost works.

    The problems start when the pickup is dropped close to a wall. In this case, when the radius is enlarged, it will overlap any nearby colliders. This situation isn't detected by the controller.Move function so the player is able to travel through the wall.

    I've tried testing for overlap with Physics.OverlapSphere and then forcing the player away from the wall but of course the movement glitches.

    I'm wondering if anyone has any ideas?
     
  2. cyb3rmaniak

    cyb3rmaniak

    Joined:
    Dec 10, 2007
    Posts:
    162
    How about increasing the radius only after the character moved away from the wall?
    Instead of increasing the radius when you pick up the object, start a coroutine that will check if the character is touching something (Use Physics.OverlapSphere just like you did earlier).
    Only after the character moves away from the wall, the coroutine will not find him touching anything, and in turn increase the radius of the character collider...

    It leaves a chance that right after the character picks up the object, he can move closer to the wall and the item will enter it, but only once. When it's away from the wall the collider will increase and all will be good and dandy.

    If you want to cancel that chance completely, inside the coroutine (after you already picked up the object) you can add a raycast to the move direction of the character and stop it from moving to that direction.
     
  3. zibba

    zibba

    Joined:
    Mar 13, 2009
    Posts:
    165
    Thanks! That gave me some more ideas and sometimes that's all you need :)

    Here's my code, maybe someone else will find this useful too.

    Code (csharp):
    1.  
    2. IEnumerator AdjustRadiusForPickup()
    3. {
    4.     // Enlarge to encompass pickup
    5.     controller.radius = 1.7f;
    6.     controller.center = new Vector3(0, 1.7f, 0);
    7.  
    8.     bool once = true;
    9.  
    10.     // 1. Check for overlapping spheres and adjust radius
    11.     while (once  pickup.transform.parent == pusher.transform)
    12.     {
    13.         // Is there an overlap?
    14.         Collider[] cols = Physics.OverlapSphere(transform.position, 1.7f);
    15.         foreach (Collider col in cols)
    16.         {
    17.             if (col.CompareTag("building") || col.CompareTag("wall"))
    18.             {
    19.                 // Use default radius to prevent movement thru walls
    20.                 controller.radius = 0.5f;
    21.                 controller.center = new Vector3(0, 1, 0);
    22.                 once = false;
    23.  
    24.                 // Prevent dropping the pickup while it's in the wall
    25.                 canDrop = false;
    26.             }
    27.         }
    28.         yield return new WaitForFixedUpdate();
    29.     }
    30.  
    31.     // 2. If moved away from the wall enlarge radius
    32.     bool movedAway = false;
    33.     while (movedAway == false  pickup.transform.parent == pusher.transform)
    34.     {
    35.         Collider[] cols = Physics.OverlapSphere(transform.position, 1.7f);
    36.         bool buildingwall = false;
    37.         foreach (Collider col in cols)
    38.         {
    39.             if (col.CompareTag("building") || col.CompareTag("wall"))
    40.             {
    41.                 buildingwall = true;
    42.             }
    43.         }
    44.         if (buildingwall == false)
    45.         {
    46.             // No longer inside a building or wall enlarge radius
    47.             movedAway = true;
    48.             controller.radius = 1.7f;
    49.             controller.center = new Vector3(0, 1.7f, 0);
    50.         }
    51.         yield return new WaitForFixedUpdate();
    52.     }
    53.  
    54.     // Now allowed to drop pickup again
    55.     canDrop = true;
    56.  
    57.     yield return 0;
    58. }
    59.  
     
  4. GargerathSunman

    GargerathSunman

    Joined:
    May 1, 2008
    Posts:
    1,571
    Or, alternatively, you could give the object a collider and no rigidbody instead. (Or a collider and an isKinematic rigidbody) You'll still collide with it, you'll still be able to pick it up, but it'd be prevented from going through the wall and impact things like a true piece of the player.
     
  5. zibba

    zibba

    Joined:
    Mar 13, 2009
    Posts:
    165
    Yeah I tried that but couldn't get it to work with the Character Controller