实现功能:滑动鼠标旋转视角(水平旋转和垂直旋转有范围限制) 滑动滚轮缩放视角(缩放距离有范围限制)
鼠标右键锁定视角 WSAD或方向键移动人物 (人物正脸朝向由屏幕向里) 移动时滑动鼠标会改动人物转向(相机朝向与人物转向一致)
改进:相机解决了穿墙的影响
注意:部分代码因个人项目需求与本文所介绍内容不相关,可自行再做删除修改!!!
相机脚本如下:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CameraCtrl : MonoBehaviour {
//目标物体
public Transform target;
//相机与目标物体的距离
public float distance;
//横向角度
public float rotDegree = 0;
public float rotSpeed = 0.2f;
float rot; //弧度
//纵向角度
public float rollDegree = 30;
public float rollSpeed = 0.2f;
public float minRollDegree = -15;
public float maxRollDegree = 15;
float roll; //弧度
//摄像机移动速度(滚轮控制)
public float zoomSpeed = 1.5f;
public float minDis = 8;
public float maxDis = 22;
//视角锁定
private bool isLock = false;
//相机和角色之间的距离
private float sourceDis;
// Use this for initialization
void Start () {
GetTarget(target.gameObject);
}
// Update is called once per frame
void LateUpdate () {
if (isLock == false)
{
Rotate();
Roll();
Zoom();
}
//角度转换成弧度
rot = rotDegree * Mathf.PI / 180;
roll = rollDegree * Mathf.PI / 180;
//计算相机的地面投影和相机高度
float d = distance * Mathf.Cos(roll);
float height = distance * Mathf.Sin(roll);
Vector3 cameraPos = Vector3.zero;
//计算相机的坐标
if (target != null)
{
cameraPos.x = target.transform.position.x + d * Mathf.Cos(rot);
cameraPos.z = target.transform.position.z + d * Mathf.Sin(rot);
cameraPos.y = target.transform.position.y + height;
this.transform.position = cameraPos;
this.transform.LookAt(target.transform.position);
}
if (Input.GetMouseButtonDown(1)) {
isLock = !isLock;
}
sourceDis = Vector3.Distance(transform.position, target.position);
CameraDefend();
}
//鼠标水平滑动调整视角
void Rotate() {
float value = Input.GetAxis("Mouse X");
rotDegree -= value * rotSpeed;
}
//鼠标垂直方向调整视角
void Roll() {
float value = Input.GetAxis("Mouse Y");
rollDegree += value * rollSpeed;
rollDegree = Mathf.Clamp(rollDegree, minRollDegree, maxRollDegree);
}
//滚轮调整视角的远近
void Zoom() {
float value = Input.GetAxis("Mouse ScrollWheel");
distance -= value * zoomSpeed;
distance = Mathf.Clamp(distance, minDis, maxDis);
}
//让相机始终跟随目标物体身上的某一点
private void GetTarget(GameObject target) {
if (target.transform.Find("cameraPoint") != null)
{
this.target = target.transform.Find("cameraPoint");
Debug.Log("找到Target点");
}
}
//恢复默认参数
public void DefaultValue() {
distance = 5;
//横向角度
rotDegree = 270;
//纵向角度
rollDegree = -10;
}
public Vector3 temp = new Vector3(0, -0.7f, 0);
private void CameraDefend() {
RaycastHit hit;
//从角色向相机发射一条射线
if (Physics.Linecast(this.target.position + temp, transform.position, out hit)) {
string name = hit.collider.gameObject.tag;
if (name != "MainCamera" || name != "Fire") {
float currentDistance = Vector3.Distance(target.position, hit.point);
//如果射线碰撞点小于玩家与相机本来的距离,就说明角色身后是有东西,为了避免穿墙,就把相机拉近
if (currentDistance < sourceDis) {
//transform.position = hit.point;
transform.position = Vector3.Lerp(transform.position, hit.point,10);
}
}
}
}
}
人物移动控制脚本如下:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CharacterMove : MonoBehaviour {
Animator anim;
float speed = 7;
public bool isCrouch = false;
public bool isWalk;
private GameObject camera;
private float dis = 999999;
private Transform target;
//脚步音效组件
private AudioSource audio;
// Use this for initialization
void Start()
{
anim = GetComponent();
camera = GameObject.Find("Main Camera");
audio = this.gameObject.AddComponent();
audio.clip = Resources.Load("Sounds/Foot");
}
// Update is called once per frame
void FixedUpdate()
{
//if (anim.GetCurrentAnimatorStateInfo(0).IsName("Grounded") == false) return;
if (Input.GetKey(KeyCode.Space)) {
RotateCtrl();
}
FootStep();
float h = Input.GetAxis("Horizontal");
float v = Input.GetAxis("Vertical");
if (Mathf.Abs(h) > 0 || Mathf.Abs(v) > 0)
{
transform.Translate(new Vector3(h, 0, v) * speed * Time.deltaTime, Space.Self);
//transform.rotation = Quaternion.LookRotation(new Vector3(h, 0, v));
//让角色的朝向跟相机的x-o-z面的朝向保持一致
RotateCtrl();
isWalk = true;
anim.SetBool("IsWalk", isWalk);
}
else {
isWalk = false;
anim.SetBool("IsWalk", isWalk);
}
//下蹲
if (Input.GetKeyDown(KeyCode.F))
{
isCrouch = !isCrouch;
anim.SetBool("IsCrouch", isCrouch);
}
//拾取火种的操作
if (Input.GetKeyDown(KeyCode.Space) && target != null && target.GetChild(0).gameObject.activeInHierarchy)
{
dis = Vector3.Distance(transform.position, target.transform.position);
if (dis <= 2.5f)
{
string name = target.GetChild(2).name;
Debug.Log("Name:" + name);
GameObject.Find("FirePos").GetComponent().SendRequest(name);
GameFacade.Instance.PlaynormalSound(AudioManager.Sound_Timer);
//Destroy(target.gameObject);
}
}
}
private void RotateCtrl() {
Vector3 tempRot = camera.transform.position;
tempRot.y = transform.position.y;
Vector3 targetRot = transform.position - tempRot;
transform.rotation = Quaternion.LookRotation(targetRot);
}
public CharacterMove GetCharacterMove() {
return this;
}
void OnTriggerEnter(Collider other) {
if (other.tag == "Weapon") {
target = other.transform;
dis = Vector3.Distance(transform.position, other.transform.position);
}
}
void FootStep() {
if (Input.GetKeyDown(KeyCode.W) || Input.GetKeyDown(KeyCode.S) || Input.GetKeyDown(KeyCode.A) || (Input.GetKeyDown(KeyCode.D))
|| Input.GetKeyDown(KeyCode.UpArrow) || Input.GetKeyDown(KeyCode.DownArrow) || Input.GetKeyDown(KeyCode.LeftArrow)
|| Input.GetKeyDown(KeyCode.RightArrow))
{
audio.Play();
}
else if (Input.GetKey(KeyCode.W) || Input.GetKey(KeyCode.S) || Input.GetKey(KeyCode.A) || (Input.GetKey(KeyCode.D))
|| Input.GetKey(KeyCode.UpArrow) || Input.GetKey(KeyCode.DownArrow) || Input.GetKey(KeyCode.LeftArrow)
|| Input.GetKey(KeyCode.RightArrow))
{
audio.loop = true;
}
else {
audio.loop = false;
}
}
}
值得一提的是如下脚本:
void FixedUpdate () {
float h = Input.GetAxis("Horizontal");
float v = Input.GetAxis("Vertical");
Move(h, v);
RotateCtrl(h, v);
}
void Move(float h, float v) {
pos = new Vector3(h, 0, v);
transform.Translate(pos * Time.deltaTime * speed,Space.World);
}
void RotateCtrl(float h, float v) {
if (h != 0 || v != 0)
{
transform.rotation = Quaternion.LookRotation(pos);
}
也可以控制人物的移动,Quaternion.LookRotation方法控制人物的旋转,即人物在移动的同时会根据 h、v的变化发生旋转
这是自己目前所总结的方法,努力寻求更好方法中。。。。。。