美文网首页
从零开始的RPG制作6.1-(摄像机跟随,缩放,旋转)

从零开始的RPG制作6.1-(摄像机跟随,缩放,旋转)

作者: 小蜻蜓队长 | 来源:发表于2019-04-30 17:14 被阅读0次

    首先基础的摄像机跟随写法是。

    1摄像机简单跟随

    初始化:向量A = 摄像机坐标- 需要跟随物的坐标;
    update:摄像机坐标 = 向量A + 需要跟随物的坐标;
    这能基础的得到我们想要的效果。

    2摄像机的远近缩放

    我们一般通过修改上述得到的:
    向量A = 向量A.normalized *向量A.magnitude

    3摄像机绕着物体旋转

    一般我们借用RotateAround函数得到
    摄像机.RotateAround(跟随物体坐标,世界朝上坐标up, 旋转幅度X轴幅度);

    摄像机.RotateAround(跟随物体坐标,摄像机的Right, 旋转幅度Y轴幅度);
    这里你可能会看到第二个参数不太一样,这是因为当随着X转的时候,如果还是按照世界坐标系的right来转就乱了哦,自己画图一下就明白了。

    4摄像机和跟随物之间如果有遮挡物。

    这里我们用了一条从角色射像摄像机的射线来做检测。
    if(检测道遮挡){
    向量A = 遮挡物的坐标-跟随坐标。

    5让我们输入的方向和摄像的前后左右对应。

    将我们的输入的方向 转入摄像机的坐标,接着将装入的坐标在标准世界坐标上进行投影,投影之后在传给我们的角色。

    这里我们新建了一个CameraMessage的类,里面添加很多限制,比如缩进长短,旋转范围之类,不过注解很详细。

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    public class CameraMessage:MonoBehaviour {
    
        struct CameraChangeData {
            public float ScrollWheel;
            public float RotateX;
            public float RotateY;
        }
        CameraChangeData cameraChangeData;
        static public CameraMessage cm;
        private Vector3 offSetPostion;//从目标指向摄像机的向量
        private float offSetPostionDistance;//offSetPostion的长度
        private float scrollSpeed = 1;//向前向后靠近的速度
        private float rotateSpeed = 2f;//转向速度
        private Vector3 followVector;//需要注视的坐标。
        bool isRotate = false;//是否出于旋转状态
        Vector3 lestNewF;//在摄像机发生旋转的时候,我们不希望角色的方向转化到摄像机的坐标系下,继而使用没有转向时候的向量。
        private Transform camareTr;//摄像机
        private Transform followObject;//追随物
        static public CameraMessage getInstance() {
            if (cm == null) {
                cm = GameObject.FindObjectOfType<CameraMessage>();
                cm.init();
            }
            return cm;
        }
    
        void init() {
            camareTr = transform;
            cameraChangeData = new CameraChangeData();
        }
        private void cameraRay() {//如果中间隔着遮挡物。相机应该贴着遮挡物(看了塞尔达的视频,应该也是这么处理的。),如果一旦没有了遮挡物返回到之前设定的状态。
            Vector3 vt = camareTr.position - followVector;
            RaycastHit rayHit;
            if (Physics.Raycast(followVector, vt, out rayHit, LayerMask.GetMask("IsGround"))) {
                offSetPostion = rayHit.point - followVector;
            }
            IDrawGizmos.drawLine(followVector, camareTr.position, Color.red,3);
            IDrawGizmos.drawLine(followVector, followObject.position+followObject.up*5,Color.red,4);
        }
    
        public void setInitOffsetPosittion(Transform followObject, Vector3 targetPos) {//设置相机跟随对象。
            this.followObject = followObject;
            offSetPostion = camareTr.position - targetPos;//计算由角色指向相机的向量
        }
    
        public void setUpdateFollowVector(Vector3 followVector) {
            //如果是PC------
            keyController();
            this.followVector = followVector;//源源不断的获取人物坐标。
            cameraRay();//放入射线
            scrollview();//缩放信息在这一帧中起效
            camareTr.position = followVector + offSetPostion;
            rotateView();//转向消息在下一帧中起效
        }
    
        private void keyController() {//将键盘操作的部分独立出来,将来说不定要换平台呢。
            cameraChangeData.ScrollWheel = Input.GetAxis("Mouse ScrollWheel") * scrollSpeed;
            if (Input.GetMouseButtonDown(1)) {
                isRotate = true;
            } else if (Input.GetMouseButtonUp(1)) {
                isRotate = false;
            }
            cameraChangeData.RotateX = Input.GetAxis("Mouse X") * rotateSpeed;
            cameraChangeData.RotateY = Input.GetAxis("Mouse Y") * rotateSpeed;
        }
    
    
        private void scrollview() {//控制前后缩放
            offSetPostionDistance = offSetPostion.magnitude;
            offSetPostionDistance -= cameraChangeData.ScrollWheel;
            if (offSetPostionDistance < 2 && cameraChangeData.ScrollWheel>0) {//当距离小于2就不能继续放大
                return;
            } else if (offSetPostionDistance > 12 && cameraChangeData.ScrollWheel<0) {
                return;
            }
            Vector3 newOffSetPostion = offSetPostion.normalized * offSetPostionDistance;
            offSetPostion = Vector3.Slerp(offSetPostion, newOffSetPostion, 0.3f);
        }
    
        private void rotateView() {//控制转向
            if (isRotate) {
                camareTr.RotateAround(followVector, Vector3.up, cameraChangeData.RotateX);//在以世界的UP转   
                if (Vector3.Angle(followObject.up, offSetPostion) < 30 && cameraChangeData.RotateY < 0) {//向上转的时候和人物的up不能超过30°
                    cameraChangeData.RotateY = 0;
                } else if (Vector3.Angle(followObject.up, offSetPostion) > 160 && cameraChangeData.RotateY > 0) {//向下转的时候和人物的up不能超过160°,这里可以添加小姐姐捂裙子的操作- .-
                    cameraChangeData.RotateY = 0;
                }
    
                camareTr.RotateAround(followVector, camareTr.TransformDirection(Vector3.right), -cameraChangeData.RotateY);//以摄像机的right转,如果以世界的right转,会受到X轴的干扰,所有用角色right.
    
                offSetPostion = camareTr.position - followVector;
            }
        }
    
    
        public Vector3 DisplacementCoordinates(Vector3 targer) {//将控制方向从世界转到摄像机,即,WASD的移动都按照摄像机在标准世界坐标投影上的向量移动。
            if (isRotate)//视角在发生旋转的时候 人物不应该跟着摄像机走。
                return lestNewF;
            Vector3 ct = camareTr.TransformDirection(targer);//将输入操作转到摄像机坐标
            Vector3 f = Vector3.Project(ct, Vector3.forward);//找到在forward上的投影,
            Vector3 r = Vector3.Project(ct, Vector3.right);//找到在right上的投影
            Vector3 newF = f + r;//两者相加,就是新的面朝方向。
            lestNewF = newF;
            return newF;
        }
    
    }
    

    接着回到我们的PlayerTestView进行调用。

        CameraMessage cm;
        public void init() {
            rig = GetComponent<Rigidbody>();
            pad = new PlayerAnimaId();
            player = transform;
            playerAnimatorInit();
            capsuleCollider = GetComponent<CapsuleCollider>();
            radius = capsuleCollider.radius - 0.01f;
            cm = CameraMessage.getInstance();//新增
            if (cm != null) {
                cm.setInitOffsetPosittion(player,player.position+ player.up* capsuleCollider.height/2);//新增
            }
        }
    
        void animaBlendAction(float right, float forward, bool run) {//设置转向以及速度
            Vector3 vec = (right * Vector3.right + forward * Vector3.forward);//设置方向
            controlDistance = vec.magnitude;
            if (controlDistance < Vector3.kEpsilon) {//停下
                controlDistance = 0;
                lerpSpeed = Mathf.Lerp(lerpSpeed, 0, 0.2f);//速度逐渐归零。
            } else {//开始行动
                vec = cm.DisplacementCoordinates(vec);
                player.forward = Vector3.Slerp(player.forward, vec, 0.2f);//设置转向
                float upperLimit = run ? playerBaseData.runSpeed : playerBaseData.walkSpeed;
                lerpSpeed = Mathf.Lerp(lerpSpeed, upperLimit, 0.1f);//速度逐步上升。
            }
            animator_ChangeIdle();//播放Idle
            animator_PlayBaseAniam();//播放动画
            moveDirection = Vector3.Project(moveDirection, Vector3.up);
            moveDirection += player.forward * lerpSpeed * addSpeed;
        }
    
    
        public void cameraFollow() {//新增
            if (cm != null)
                cm.setUpdateFollowVector(player.position + player.up * capsuleCollider.height / 2);
        }
    

    接着在我们的PlayerTestMediator中进行调用。

        public override void OnRegister() {//绑定成功之后会调用这个API
            Debug.Log("OnRegister");
            playerView.init();
            UpdateManges.add_playerEventList_(keyController);
            UpdateManges.add_playerEventList_(playerAction);
            UpdateManges.add_playerEventList_Fix(accurateDetection);
            UpdateManges.add_playerEventList_Late(cameraContorller);//新增
        }
        public override void OnRemove() {//解除绑定之后调用这个API
            Debug.Log("OnRemove");
            UpdateManges.sub_playerEventList_(keyController);
            UpdateManges.sub_playerEventList_(playerAction);
            UpdateManges.sub_playerEventList_(accurateDetection);
            UpdateManges.sub_playerEventList_Late(cameraContorller);//新增
        }
        void cameraContorller() {//新增
            playerView.cameraFollow();
        }
    
    效果

    这边的效果还没有很完整,还有一个地方没有设置,下一节中我们在提
    上一节
    下一节

    相关文章

      网友评论

          本文标题:从零开始的RPG制作6.1-(摄像机跟随,缩放,旋转)

          本文链接:https://www.haomeiwen.com/subject/ltvvnqtx.html