实现功能:滑动鼠标旋转视角(水平旋转和垂直旋转有范围限制) 滑动滚轮缩放视角(缩放距离有范围限制)
鼠标右键锁定视角 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 initializationvoid Start () {GetTarget(target.gameObject);}// Update is called once per framevoid 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 initializationvoid Start(){anim = GetComponent<Animator>();camera = GameObject.Find("Main Camera");audio = this.gameObject.AddComponent<AudioSource>();audio.clip = Resources.Load<AudioClip>("Sounds/Foot");}// Update is called once per framevoid 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<SpawnFireRequest>().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的变化发生旋转
这是自己目前所总结的方法,努力寻求更好方法中。。。。。。