Camera shakes when constantly colliding with wall.

When the cameraholder gameobject constantly collides with an invisible wall boundary the camera ends up shaking.

GameObjects
CAMERAHOLDER (RigidyBody - kinematic off, use gravity off | Sphere Collider - radius 0.4)
– CAMERA
BOUNDARY (RigidBody - kinematic on, Box Collider)

What is the easiest way to get around this annoying camera shaking when camera is being pressed up against an invisible boundary wall.

I would take the RigidBody off the CameraHolder. Physics is generally not appropriate for cameras.

1 Like

I tried that, the camera just went through walls as if they weren’t there. I wonder if I’m handling camera collision incorrectly.

Here is a potential fix, it works around the problem and lets me keep the rigidbody on the camera holder. I reduce camera movement when the camera hit’s a boundary, then restore the original speed when they exit the boundary.

void OnCollisionEnter(Collision collision)
  {
  if (collision.transform.tag == "Boundary")
  {
  camMoveSpeed = 1f;
  }
  Debug.Log("enter:" + collision.transform.tag);
  }

  void OnCollisionExit(Collision collision)
  {
  if (collision.transform.tag == "Boundary")
  {
  camMoveSpeed = 45f;
  }
  Debug.Log("exit:" + collision.transform.tag);
  }

Please note, I want to achieve a professional level solution, so if I’m doing this wrong, please tell me.

Cameras shouldn’t generally use physics, because you don’t want them to act like physical objects (banging into things, causing them to move, causing the camera to bounce off, etc.). A camera is invisible and ephemeral, and should just float in the scene wherever needed to give you a good view.

In many games — for example, RTS games — you can limit the camera mathematically, e.g., your map is only so-many by so-many units, so the camera’s point of interest should always stay within those bounds. No physics needed there.

In more complex games, camera control becomes a very deep topic quickly (google “game design camera” and set aside an afternoon for some thoughtful reading). But if you really are in a situation where you have to detect the camera passing through walls, then generally the way to do it is to cast a ray between the camera’s current position and its calculated next position. If that ray hits a wall, then you use that to limit where the camera actually goes.

Okay, so just use basic limits. I’ll post code when I finish, thanks for your expertise. It makes sense to not have any rigidybody on the camera.

The only problem is I’m calling transform.position twice, there’s probably an easy way to combine them, maybe just add them together?

void moveCameraXZ(Vector3 direction)
  {
  Vector3 movementPosition = direction * Time.deltaTime * (camCurrentMoveSpeed + camBoundaryCollideMoveSpeed);
  movementPosition.y = 0;
  transform.position += movementPosition;

  //get specified percentage of the terrain's width (x)
  //example if terrain length is 1024 and specified percentage is 20, then terrainBoundaryLimitX = 204.8
  float terrainBoundaryLimitX = myTerrain.terrainData.size.x * terrainBoundaryPercentX / 100;
  //get specified percentage of the terrain's length (z)
  float terrainBoundaryLimitZ = myTerrain.terrainData.size.z * terrainBoundaryPercentX / 100;

  //get the camera's current position in the game world
  Vector3 limitTerrainMovement = transform.position;
  //ensure the camera's x can only go between a minimum and maximum value
  limitTerrainMovement.x = Mathf.Clamp(transform.position.x, terrainBoundaryLimitX, myTerrain.terrainData.size.x - terrainBoundaryLimitX);
  //ensure the camera's z can only go between a minimum and maximum value
  limitTerrainMovement.z = Mathf.Clamp(transform.position.z, terrainBoundaryLimitZ, myTerrain.terrainData.size.z - terrainBoundaryLimitZ);
  //apply boundary terrain limits to the camera
  transform.position = limitTerrainMovement;

  }

I don’t think there’s anything horrible about assigning to it twice. But you could introduce a local to simplify the code a little.

void moveCameraXZ(Vector3 direction)
  {
  Vector3 movementPosition = direction * Time.deltaTime * (camCurrentMoveSpeed + camBoundaryCollideMoveSpeed);
  movementPosition.y = 0;
  Vector3 pos = transform.position + movementPosition;
  //get specified percentage of the terrain's width (x)
  //example if terrain length is 1024 and specified percentage is 20, then terrainBoundaryLimitX = 204.8
  float terrainBoundaryLimitX = myTerrain.terrainData.size.x * terrainBoundaryPercentX / 100;
  //get specified percentage of the terrain's length (z)
  float terrainBoundaryLimitZ = myTerrain.terrainData.size.z * terrainBoundaryPercentX / 100;
  //get the camera's current position in the game world
  //ensure the camera's x can only go between a minimum and maximum value
  pos.x = Mathf.Clamp(pos.x, terrainBoundaryLimitX, myTerrain.terrainData.size.x - terrainBoundaryLimitX);
  //ensure the camera's z can only go between a minimum and maximum value
  pos.z = Mathf.Clamp(pos.z, terrainBoundaryLimitZ, myTerrain.terrainData.size.z - terrainBoundaryLimitZ);
  //apply boundary terrain limits to the camera
  transform.position = pos;
}

I know this is old, but this was my issue, I had to re-stack my player object where the camera was outside of the object with the rigid body component. This also solved some other collision issues as I think the camera was somehow included or something.

1 Like