-1
\$\begingroup\$

I have a game object that has specific boundaries. However, when I have the object meet the boundaries, the object doesn't stop the way it's supposed to, it continues to move past the set boundaries. Can anyone explain why this would be happening and how to fix it?

Player Object public variables

enter image description here

C#

using UnityEngine;
using System.Collections;

public class PlayerController:MonoBehaviour{
    public Rigidbody player;
    public float bankSpeed;
    public float bankRotation;
    public float pitchSpeed;
    public float pitchAngle;
    public float xMin, xMax, yMin, yMax;
    public ChangeCamera changeCamera;
    void Start(){
        player = GetComponent<Rigidbody>();
        changeCamera.isThirdPersonView = false;
        changeCamera.isTopDownView = false;
    }

    void FixedUpdate(){
        if(changeCamera.isThirdPersonView == true){
            changeCamera.isTopDownView = false;
            thirdPersonControls();
        }
        if(changeCamera.isTopDownView == true){
            changeCamera.isThirdPersonView = false;
            topDownControls();
        }
    }

    void topDownControls(){
        float moveVertical = Input.GetAxis("Vertical");
        float moveHorizontal = Input.GetAxis("Horizontal");
        Vector3 bank = new Vector3(moveHorizontal, 0f, 0f);
        Vector3 moveForward = new Vector3(0f, 0f, moveVertical);
        player.AddForce(bank * bankSpeed);
        player.AddForce(moveForward * pitchSpeed);
        topDownRotation();
    }

    void thirdPersonControls(){
        float moveVertical = Input.GetAxis("Vertical");
        float moveHorizontal = Input.GetAxis("Horizontal");
        Vector3 bank = new Vector3(moveHorizontal, 0f, 0f);
        Vector3 pitch = new Vector3(0f, moveVertical, 0f);
        player.AddForce(bank * bankSpeed);
        player.AddForce(pitch * pitchSpeed);
        thirdPersonRotate();
    }

    void topDownRotation(){
        player.rotation = Quaternion.Euler(0f, 0f, (player.velocity.x * -bankRotation));
        player.position = new Vector3(Mathf.Clamp(player.position.x, -15.25f, 15.25f), 0f, Mathf.Clamp(player.position.z, 1f, 18.25f));
    }

    void thirdPersonRotate(){
        player.rotation = Quaternion.Euler((player.velocity.y * -pitchAngle), 0f, (player.velocity.x * -bankRotation));
        player.position = new Vector3(Mathf.Clamp(player.position.x, xMin, xMax), Mathf.Clamp(player.position.y, yMin, yMax), 0f);
    }
}

Basically, the way it works is, the player moves in any direction(up, down, left, right) and when they hit the edge of the screen, they're supposed to stop, which they do, however, if they continue to press the button that moves them, they'll continue to move off screen, very slowly. How do I prevent this from happening?

Dropbox Link

\$\endgroup\$
1
\$\begingroup\$

When you use the Unity rigidbody physics to control the movement of an object (like implied by using AddForce) you should generally not manipulate its transformation directly. Doing so can cause lots of weird behaviours.

If you need to constrain objects, place an invisible object with an appropriately shaped collider in the way.

Regarding why this is happening in this case, what happens every frame is:

  • You add a force to the object with AddForce
  • You set the transform.position
  • Code execution leaves your code and enters the Unity physics engine, which:
    • Checks the current forces added to the object
    • Calculates an acceleration vector
    • Adds that acceleration vector to the current speed vector
    • moves the object by that speed, beyond the position limit you set through clamping
  • The frame is rendered to the screen

The object slowly moves further into the "forbidden zone" every frame because the player adds more and more speed to it which translates to a further and further offset.

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ So, add an invisible bounding box with a rigid body component attached? If I'm not supposed to manipulate the transform directly, what do I need to manipulate? \$\endgroup\$ – Robert May 14 '16 at 14:25
  • \$\begingroup\$ I appreciate the info, but how do I actually stop this from occurring? Adding a box collider is not preventing it from happening \$\endgroup\$ – Robert May 14 '16 at 14:42
  • \$\begingroup\$ @Robert No rigidbody is needed on the bounds, just a collider with isTrigger off. A rigidbody on the bounds would be counter-productive as it would make the bounds themselves be affected by physics. You should not use a box but rather a set of planes around the borders of your playing-field. \$\endgroup\$ – Philipp May 14 '16 at 14:42
  • \$\begingroup\$ So I've added a single plane to test what you're telling me. The trigger is off, there is no rigid body attached to the plane, and the same exact issue I'm having is still occurring. Suggestions? Here's the updated link if you want to take a look. dropbox.com/home?preview=Space+Shooter+2.0.zip \$\endgroup\$ – Robert May 14 '16 at 15:02
-1
\$\begingroup\$

If you don't want to use planes or cubes to set the boundaries for your player object, the simplest way to accomplish this would be to remove the player object's velocity and angular velocity all together. Simply write a conditional which checks to see if the player object's position is at the desired boundary position. If it is, remove the velocity, like so:

if((player.position.x == xMin) || (player.position.x == xMax) || (player.position.y == yMin) || (player.position.y == yMax)){
    player.velocity = new Vector3(0f, 0f, 0f);
    player.angularVelocity = new Vector3(0f, 0f, 0f);
}
| improve this answer | |
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.