- Home /
Mecanim and Camera Problems
Hello guys, here are some scripts,
TP_Camera
using UnityEngine;
using System.Collections;
public class TP_Camera : MonoBehaviour {
public static TP_Camera Instance;
public Transform TargetLookAt;
public float Distance = 5f;
public float DistanceMin = 1f;
public float DistanceMax = 35f;
public float DistanceSmooth = 0.05f;
public float DistanceResumeSmooth = 1f;
public float X_MouseSensitivity = 5f;
public float Y_MouseSensitivity = 5f;
public float MouseWheelSensitivity = 7.5f;
public float X_Smooth = 0.05f;
public float Y_Smooth = 0.1f;
public float Y_MinLimit = -45f;
public float Y_MaxLimit = 90f;
public float OcclusionDistanceStep = 0.5f;
public int MaxOcclusionChecks = 10;
private float MouseX = 0f;
private float MouseY = 0f;
private float velX = 0f;
private float velY = 0f;
private float velZ = 0f;
private float velDistance = 0f;
private float startDistance = 0f;
private Vector3 position = Vector3.zero;
private Vector3 desiredPosition = Vector3.zero;
private float desiredDistance = 0f;
private float distanceSmooth = 0f;
private float preOccludedDistance = 0;
void Awake()
{
Instance = this;
}
void Start()
{
Distance = Mathf.Clamp(Distance, DistanceMin, DistanceMax);
startDistance = Distance;
Reset();
}
void LateUpdate()
{
if (TargetLookAt == null)
return;
HandlePlayerInput();
var count = 0;
do
{
CalculateDesiredPosition ();
count++;
}
while(CheckIfOccluded (count));
UpdatePosition();
}
void HandlePlayerInput()
{
var deadZone = 0.1f;
//if (Input.GetMouseButton(1))
//{
//check for the right mouse button is down or not. Now it is down and get Mouse Axis input
MouseX += Input.GetAxis("Mouse X") * X_MouseSensitivity;
MouseY -= Input.GetAxis("Mouse Y") * Y_MouseSensitivity;
//}
//Clamping limit of Mouse Y
MouseY = Helper.ClampAngle(MouseY, Y_MinLimit, Y_MaxLimit);
if (Input.GetAxis("Mouse ScrollWheel") < -deadZone || Input.GetAxis("Mouse ScrollWheel") > deadZone)
{
desiredDistance = Mathf.Clamp(Distance - Input.GetAxis("Mouse ScrollWheel") * MouseWheelSensitivity,
DistanceMin, DistanceMax);
preOccludedDistance = desiredDistance;
distanceSmooth = DistanceSmooth;
}
}
void CalculateDesiredPosition()
{
ResetDesiredDistance ();
// Evaluate Distance
Distance = Mathf.SmoothDamp(Distance, desiredDistance, ref velDistance, distanceSmooth);
//Calculate desired position
desiredPosition = CalculatePosition(MouseY, MouseX, Distance);
}
Vector3 CalculatePosition(float rotationX, float rotationY, float distance)
{
Vector3 direction = new Vector3(0, 0, -distance);
Quaternion rotation = Quaternion.Euler(rotationX, rotationY, 0);
return TargetLookAt.position + rotation * direction;
}
bool CheckIfOccluded(int count)
{
var isOccluded = false;
var nearestDistance = CheckCameraPoints (TargetLookAt.position, desiredPosition);
if (nearestDistance != -1)
{
if (count < MaxOcclusionChecks) {
isOccluded = true;
Distance -= OcclusionDistanceStep;
;
if (Distance < 0.3f)
{
Distance = 0.3f;
}
}
else
{
Distance = nearestDistance - Camera.main.nearClipPlane;
if (Distance < DistanceMin)
{
Distance = nearestDistance - Camera.main.nearClipPlane;
}
}
desiredDistance = Distance;
distanceSmooth = DistanceResumeSmooth;
}
if (isOccluded = false)
{
Hider.Instance.Show ();
return isOccluded;
}
if (Distance < 1f)
Hider.Instance.Hide();
else
Hider.Instance.Show ();
return isOccluded;
}
float CheckCameraPoints(Vector3 from, Vector3 to)
{
var nearestDistance = -1f;
RaycastHit hitInfo;
Helper.ClipPlanePoints clipPlanePoints = Helper.ClipPlaneAtNear (to);
//Draw lines in editor
Debug.DrawLine(from, to + transform.forward * -camera.nearClipPlane, Color.red);
Debug.DrawLine (from, clipPlanePoints.UpperLeft);
Debug.DrawLine (from, clipPlanePoints.UpperRight);
Debug.DrawLine (from, clipPlanePoints.LowerLeft);
Debug.DrawLine (from, clipPlanePoints.LowerRight);
Debug.DrawLine(clipPlanePoints.UpperLeft, clipPlanePoints.UpperRight, Color.green);
Debug.DrawLine(clipPlanePoints.UpperRight, clipPlanePoints.LowerRight, Color.green);
Debug.DrawLine(clipPlanePoints.LowerRight, clipPlanePoints.LowerLeft, Color.green);
Debug.DrawLine(clipPlanePoints.LowerLeft, clipPlanePoints.UpperLeft, Color.green);
if (Physics.Linecast (from, clipPlanePoints.UpperLeft, out hitInfo) && hitInfo.collider.tag != "Player")
nearestDistance = hitInfo.distance;
if (Physics.Linecast (from, clipPlanePoints.LowerLeft, out hitInfo) && hitInfo.collider.tag != "Player")
if(hitInfo.distance < nearestDistance || nearestDistance == -1)
nearestDistance = hitInfo.distance;
if (Physics.Linecast (from, clipPlanePoints.UpperRight, out hitInfo) && hitInfo.collider.tag != "Player")
if(hitInfo.distance < nearestDistance || nearestDistance == -1)
nearestDistance = hitInfo.distance;
if (Physics.Linecast (from, clipPlanePoints.LowerRight, out hitInfo) && hitInfo.collider.tag != "Player")
if(hitInfo.distance < nearestDistance || nearestDistance == -1)
nearestDistance = hitInfo.distance;
if (Physics.Linecast (from, to + transform.forward * -camera.nearClipPlane, out hitInfo) && hitInfo.collider.tag != "Player")
if(hitInfo.distance < nearestDistance || nearestDistance == -1)
nearestDistance = hitInfo.distance;
return nearestDistance;
}
void ResetDesiredDistance()
{
if (desiredDistance < preOccludedDistance)
{
var pos = CalculatePosition (MouseY, MouseX, preOccludedDistance);
var nearestDistance = CheckCameraPoints (TargetLookAt.position, pos);
if(nearestDistance == -1 || nearestDistance > preOccludedDistance)
{
desiredDistance = preOccludedDistance;
}
}
}
void UpdatePosition()
{
var posX = Mathf.SmoothDamp(position.x, desiredPosition.x, ref velX, X_Smooth);
var posY = Mathf.SmoothDamp(position.y, desiredPosition.y, ref velY, Y_Smooth);
var posZ = Mathf.SmoothDamp(position.z, desiredPosition.z, ref velZ, X_Smooth);
position = new Vector3(posX, posY, posZ);
transform.position = position;
transform.LookAt(TargetLookAt);
}
public void Reset()
{
MouseX = 0f;
MouseY = 10f;
Distance = startDistance;
desiredDistance = Distance;
preOccludedDistance = Distance;
}
public static void UseExistingOrCreateNewMainCamera()
{
GameObject tempCamera;
GameObject targetLookAt;
TP_Camera myCamera;
if( Camera.mainCamera != null)
{
tempCamera = Camera.mainCamera.gameObject;
}
else
{
tempCamera = new GameObject("Main Camera");
tempCamera.AddComponent("Camera");
tempCamera.tag = "MainCamera";
}
tempCamera.AddComponent ("TP_Camera");
myCamera = tempCamera.GetComponent ("TP_Camera") as TP_Camera;
targetLookAt = GameObject.Find("targetLookAt") as GameObject;
if( targetLookAt == null)
{
targetLookAt = new GameObject("targetLookAt");
targetLookAt.transform.position = Vector3.zero;
}
myCamera.TargetLookAt = targetLookAt.transform;
}
}
Hider
using UnityEngine;
using System.Collections;
public class Hider : MonoBehaviour {
public static Hider Instance;
public static SkinnedMeshRenderer renderer;
private ParticleSystem parti;
// Use this for initialization
void Start () {
Instance = this;
renderer = GetComponent<SkinnedMeshRenderer> ();
parti = GetComponent<ParticleSystem> ();
}
// Update is called once per frame
void Update () {
}
public void Hide()
{
renderer.enabled = false;
parti.enableEmission = true;
}
public void Show()
{
renderer.enabled = true;
parti.enableEmission = false;
}
}
Helper
using UnityEngine;
public static class Helper
{
public struct ClipPlanePoints
{
public Vector3 UpperLeft;
public Vector3 UpperRight;
public Vector3 LowerLeft;
public Vector3 LowerRight;
}
public static float ClampAngle(float angle, float min, float max)
{
do
{
if (angle < -360)
angle += 360;
if (angle > 360)
angle -= 360;
}while (angle < -360 || angle > 360);
return Mathf.Clamp(angle, min, max);
}
public static ClipPlanePoints ClipPlaneAtNear(Vector3 pos)
{
var clipPlanePoints = new ClipPlanePoints();
if (Camera.mainCamera == null)
return clipPlanePoints;
var transform = Camera.mainCamera.transform;
var halfFOV = (Camera.mainCamera.fieldOfView / 2) * Mathf.Deg2Rad;
var aspect = Camera.mainCamera.aspect;
var distance = Camera.mainCamera.nearClipPlane;
var height = distance * Mathf.Tan (halfFOV);
var width = height * aspect;
clipPlanePoints.LowerRight = pos + transform.right * width;
clipPlanePoints.LowerRight -= transform.up * height;
clipPlanePoints.LowerRight += transform.forward * distance;
clipPlanePoints.LowerLeft = pos - transform.right * width;
clipPlanePoints.LowerLeft -= transform.up * height;
clipPlanePoints.LowerLeft += transform.forward * distance;
clipPlanePoints.UpperRight = pos + transform.right * width;
clipPlanePoints.UpperRight += transform.up * height;
clipPlanePoints.UpperRight += transform.forward * distance;
clipPlanePoints.UpperLeft = pos - transform.right * width;
clipPlanePoints.UpperLeft += transform.up * height;
clipPlanePoints.UpperLeft += transform.forward * distance;
return clipPlanePoints;
}
}
My scene test web player : https://dl.dropboxusercontent.com/u/103772852/New%20folder/New%20folder.html
if you play the game, you will understand my problem.
Camera is shaking. and the mecanim animartion gets stuck for no reason when running.
targetLookAt is a empty gameobject and my bad the script won't find it and i have to reference it in public.
The camera shakes and animation gets stuck, i first thought it was problem with my mecanim setup, then i used unities own tuto but it doesn't works either.
TP_Camera works great without rigidbody attached to the player and instead of mecanim character controller should be used.
Mecanim works great without TP_Camera script in Camera.
I spent 5 days working, and this is the only thing i can figure out. I have edited many lines changed it but all finally end up being the same problem.
Any pros there ?
By the way, here is The mecanim controller script, not edited and directly from unity.
using UnityEngine;
using System.Collections;
// Require these components when using this script
[RequireComponent(typeof (Animator))]
[RequireComponent(typeof (CapsuleCollider))]
[RequireComponent(typeof (Rigidbody))]
public class BotControlScript : MonoBehaviour
{
[System.NonSerialized]
public float lookWeight; // the amount to transition when using head look
[System.NonSerialized]
public Transform enemy; // a transform to Lerp the camera to during head look
public float animSpeed = 1.5f; // a public setting for overall animator animation speed
public float lookSmoother = 3f; // a smoothing setting for camera motion
public bool useCurves; // a setting for teaching purposes to show use of curves
private Animator anim; // a reference to the animator on the character
private AnimatorStateInfo currentBaseState; // a reference to the current state of the animator, used for base layer
private AnimatorStateInfo layer2CurrentState; // a reference to the current state of the animator, used for layer 2
private CapsuleCollider col; // a reference to the capsule collider of the character
static int idleState = Animator.StringToHash("Base Layer.Idle");
static int locoState = Animator.StringToHash("Base Layer.Locomotion"); // these integers are references to our animator's states
static int jumpState = Animator.StringToHash("Base Layer.Jump"); // and are used to check state for various actions to occur
static int jumpDownState = Animator.StringToHash("Base Layer.JumpDown"); // within our FixedUpdate() function below
static int fallState = Animator.StringToHash("Base Layer.Fall");
static int rollState = Animator.StringToHash("Base Layer.Roll");
static int waveState = Animator.StringToHash("Layer2.Wave");
void Start ()
{
// initialising reference variables
anim = GetComponent<Animator>();
col = GetComponent<CapsuleCollider>();
enemy = GameObject.Find("Enemy").transform;
if(anim.layerCount ==2)
anim.SetLayerWeight(1, 1);
}
void FixedUpdate ()
{
float h = Input.GetAxis("Horizontal"); // setup h variable as our horizontal input axis
float v = Input.GetAxis("Vertical"); // setup v variables as our vertical input axis
anim.SetFloat("Speed", v); // set our animator's float parameter 'Speed' equal to the vertical input axis
anim.SetFloat("Direction", h); // set our animator's float parameter 'Direction' equal to the horizontal input axis
anim.speed = animSpeed; // set the speed of our animator to the public variable 'animSpeed'
anim.SetLookAtWeight(lookWeight); // set the Look At Weight - amount to use look at IK vs using the head's animation
currentBaseState = anim.GetCurrentAnimatorStateInfo(0); // set our currentState variable to the current state of the Base Layer (0) of animation
if(anim.layerCount ==2)
layer2CurrentState = anim.GetCurrentAnimatorStateInfo(1); // set our layer2CurrentState variable to the current state of the second Layer (1) of animation
// LOOK AT ENEMY
// if we hold Alt..
if(Input.GetButton("Fire2"))
{
// ...set a position to look at with the head, and use Lerp to smooth the look weight from animation to IK (see line 54)
anim.SetLookAtPosition(enemy.position);
lookWeight = Mathf.Lerp(lookWeight,1f,Time.deltaTime*lookSmoother);
}
// else, return to using animation for the head by lerping back to 0 for look at weight
else
{
lookWeight = Mathf.Lerp(lookWeight,0f,Time.deltaTime*lookSmoother);
}
// STANDARD JUMPING
// if we are currently in a state called Locomotion (see line 25), then allow Jump input (Space) to set the Jump bool parameter in the Animator to true
if (currentBaseState.nameHash == locoState)
{
if(Input.GetButtonDown("Jump"))
{
anim.SetBool("Jump", true);
}
}
// if we are in the jumping state...
else if(currentBaseState.nameHash == jumpState)
{
// ..and not still in transition..
if(!anim.IsInTransition(0))
{
if(useCurves)
// ..set the collider height to a float curve in the clip called ColliderHeight
col.height = anim.GetFloat("ColliderHeight");
// reset the Jump bool so we can jump again, and so that the state does not loop
anim.SetBool("Jump", false);
}
// Raycast down from the center of the character..
Ray ray = new Ray(transform.position + Vector3.up, -Vector3.up);
RaycastHit hitInfo = new RaycastHit();
if (Physics.Raycast(ray, out hitInfo))
{
// ..if distance to the ground is more than 1.75, use Match Target
if (hitInfo.distance > 1.75f)
{
// MatchTarget allows us to take over animation and smoothly transition our character towards a location - the hit point from the ray.
// Here we're telling the Root of the character to only be influenced on the Y axis (MatchTargetWeightMask) and only occur between 0.35 and 0.5
// of the timeline of our animation clip
anim.MatchTarget(hitInfo.point, Quaternion.identity, AvatarTarget.Root, new MatchTargetWeightMask(new Vector3(0, 1, 0), 0), 0.35f, 0.5f);
}
}
}
// JUMP DOWN AND ROLL
// if we are jumping down, set our Collider's Y position to the float curve from the animation clip -
// this is a slight lowering so that the collider hits the floor as the character extends his legs
else if (currentBaseState.nameHash == jumpDownState)
{
col.center = new Vector3(0, anim.GetFloat("ColliderY"), 0);
}
// if we are falling, set our Grounded boolean to true when our character's root
// position is less that 0.6, this allows us to transition from fall into roll and run
// we then set the Collider's Height equal to the float curve from the animation clip
else if (currentBaseState.nameHash == fallState)
{
col.height = anim.GetFloat("ColliderHeight");
}
// if we are in the roll state and not in transition, set Collider Height to the float curve from the animation clip
// this ensures we are in a short spherical capsule height during the roll, so we can smash through the lower
// boxes, and then extends the collider as we come out of the roll
// we also moderate the Y position of the collider using another of these curves on line 128
else if (currentBaseState.nameHash == rollState)
{
if(!anim.IsInTransition(0))
{
if(useCurves)
col.height = anim.GetFloat("ColliderHeight");
col.center = new Vector3(0, anim.GetFloat("ColliderY"), 0);
}
}
// IDLE
// check if we are at idle, if so, let us Wave!
else if (currentBaseState.nameHash == idleState)
{
if(Input.GetButtonUp("Jump"))
{
anim.SetBool("Wave", true);
}
}
// if we enter the waving state, reset the bool to let us wave again in future
if(layer2CurrentState.nameHash == waveState)
{
anim.SetBool("Wave", false);
}
}
}