unity自带脚本ThirdPersonCamera.cs(收藏)

“`
using UnityEngine;
using System.Collections;

/**
* @Author : www.xuanyusong.com
*/

public class ThirdPersonCamera : MonoBehaviour {

public Transform cameraTransform;
private Transform _target;

public static float distance = 10.0f;

public float height = 1.0f;

public float angularSmoothLag = 0.3f;
public float angularMaxSpeed = 15.0f;

public float heightSmoothLag = 0.3f;

public float snapSmoothLag = 0.2f;
public float snapMaxSpeed = 720.0f;

public float clampHeadPositionScreenSpace = 0.75f;

public float lockCameraTimeout = 0.2f;

private Vector3 headOffset = Vector3.zero;
private Vector3 centerOffset = Vector3.zero;

private float heightVelocity = 0.0f;
private float angleVelocity = 0.0f;
private bool snap = false;
private ThirdPersonController controller;
private float targetHeight = 100000.0f;

void Awake ()
{
if(!cameraTransform && Camera.main)
cameraTransform = Camera.main.transform;
if(!cameraTransform) {
Debug.Log(“Please assign a camera to the ThirdPersonCamera script.”);
enabled = false;
}

_target = transform;
if (_target)
{
    controller = _target.GetComponent<ThirdPersonController>();
}

if (controller)
{
    CharacterController characterController  = (CharacterController)_target.collider;
    centerOffset = characterController.bounds.center - _target.position;
    headOffset = centerOffset;
    headOffset.y = characterController.bounds.max.y - _target.position.y;
}
else
    Debug.Log("Please assign a target to the camera that has a ThirdPersonController script attached.");

Cut(_target, centerOffset);

}

void DebugDrawStuff ()
{
Debug.DrawLine(_target.position, _target.position + headOffset);

}

float AngleDistance (float a , float b )
{
a = Mathf.Repeat(a, 360);
b = Mathf.Repeat(b, 360);

return Mathf.Abs(b - a);

}

void Apply (Transform dummyTarget, Vector3 dummyCenter)
{
// Early out if we don’t have a target
if (!controller)
return;

Vector3 targetCenter = _target.position + centerOffset;
Vector3 targetHead = _target.position + headOffset;

// DebugDrawStuff();

// Calculate the current & target rotation angles
float originalTargetAngle = _target.eulerAngles.y;
float currentAngle = cameraTransform.eulerAngles.y;

// Adjust real target angle when camera is locked
float targetAngle = originalTargetAngle; 

// When pressing Fire2 (alt) the camera will snap to the target direction real quick.
// It will stop snapping when it reaches the target
if (Input.GetButton("Fire2"))
    snap = true;

if (snap)
{
    // We are close to the target, so we can stop snapping now!
    if (AngleDistance (currentAngle, originalTargetAngle) < 3.0)
        snap = false;

    currentAngle = Mathf.SmoothDampAngle(currentAngle, targetAngle, ref angleVelocity, snapSmoothLag, snapMaxSpeed);
}
// Normal camera motion
else
{
    //targetÐýתֹͣºó£¬¾­¹ýlockCameraTimeoutÃ룬Ïà»ú¿ªÊ¼×ªÏòtarget
    if (controller.GetLockCameraTimer () < lockCameraTimeout)
    {
        targetAngle = currentAngle;
    }

    // Lock the camera when moving backwards!
    // * It is really confusing to do 180 degree spins when turning around.
    if (AngleDistance (currentAngle, targetAngle) > 160 && controller.IsMovingBackwards ())
        targetAngle += 180;

    currentAngle = Mathf.SmoothDampAngle(currentAngle, targetAngle, ref angleVelocity, angularSmoothLag, angularMaxSpeed);
}

// When jumping don't move camera upwards but only down!
if (controller.IsJumping ())
{
    // We'd be moving the camera upwards, do that only if it's really high
    float newTargetHeight = targetCenter.y + height;
    if (newTargetHeight < targetHeight || newTargetHeight - targetHeight > 5)
        targetHeight = targetCenter.y + height;
}
// When walking always update the target height
else
{
    targetHeight = targetCenter.y + height;
}

// Damp the height
float currentHeight = cameraTransform.position.y;
currentHeight = Mathf.SmoothDamp (currentHeight, targetHeight, ref heightVelocity, heightSmoothLag);

// Convert the angle into a rotation, by which we then reposition the camera
Quaternion currentRotation = Quaternion.Euler (0, currentAngle, 0);

// Set the position of the camera on the x-z plane to:
// distance meters behind the target
cameraTransform.position = targetCenter;
cameraTransform.position += currentRotation * Vector3.back * distance;

// Set the height of the camera
cameraTransform.position = new Vector3(cameraTransform.position.x,currentHeight,cameraTransform.position.z);

// Always look at the target    
SetUpRotation(targetCenter, targetHead);

}

void LateUpdate () {
Apply (transform, Vector3.zero);
}

void Cut (Transform dummyTarget , Vector3 dummyCenter)
{
float oldHeightSmooth = heightSmoothLag;
float oldSnapMaxSpeed = snapMaxSpeed;
float oldSnapSmooth = snapSmoothLag;

snapMaxSpeed = 10000;
snapSmoothLag = 0.001f;
heightSmoothLag = 0.001f;

snap = true;
Apply (transform, Vector3.zero);

heightSmoothLag = oldHeightSmooth;
snapMaxSpeed = oldSnapMaxSpeed;
snapSmoothLag = oldSnapSmooth;

}

void SetUpRotation (Vector3 centerPos,Vector3 headPos)
{
// Now it’s getting hairy. The devil is in the details here, the big issue is jumping of course.
// * When jumping up and down we don’t want to center the guy in screen space.
// This is important to give a feel for how high you jump and avoiding large camera movements.
//
// * At the same time we dont want him to ever go out of screen and we want all rotations to be totally smooth.
//
// So here is what we will do:
//
// 1. We first find the rotation around the y axis. Thus he is always centered on the y-axis
// 2. When grounded we make him be centered
// 3. When jumping we keep the camera rotation but rotate the camera to get him back into view if his head is above some threshold
// 4. When landing we smoothly interpolate towards centering him on screen
Vector3 cameraPos = cameraTransform.position;
Vector3 offsetToCenter = centerPos - cameraPos;

// Generate base rotation only around y-axis
Quaternion yRotation = Quaternion.LookRotation(new Vector3(offsetToCenter.x, 0, offsetToCenter.z));

Vector3 relativeOffset = Vector3.forward * distance + Vector3.down * height;
cameraTransform.rotation = yRotation * Quaternion.LookRotation(relativeOffset);

// Calculate the projected center position and top position in world space
Ray centerRay = cameraTransform.camera.ViewportPointToRay(new Vector3(0.5f, 0.5f, 1f));
Ray topRay = cameraTransform.camera.ViewportPointToRay(new Vector3(0.5f, clampHeadPositionScreenSpace, 1f));

Vector3 centerRayPos = centerRay.GetPoint(distance);
Vector3 topRayPos = topRay.GetPoint(distance);

float centerToTopAngle = Vector3.Angle(centerRay.direction, topRay.direction);

float heightToAngle = centerToTopAngle / (centerRayPos.y - topRayPos.y);

float extraLookAngle = heightToAngle * (centerRayPos.y - centerPos.y);
if (extraLookAngle < centerToTopAngle)
{
    extraLookAngle = 0;
}


else
{
    extraLookAngle = extraLookAngle - centerToTopAngle;
    cameraTransform.rotation *= Quaternion.Euler(-extraLookAngle, 0, 0);
}

}

Vector3 GetCenterOffset ()
{
    return centerOffset;
}

}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值