美文网首页
Unity 传送曲线

Unity 传送曲线

作者: 烂醉花间dlitf | 来源:发表于2021-05-07 19:58 被阅读0次

    贝塞尔曲线

    关于贝塞尔曲线的介绍可以去看看其他更偏理论的博客,这里默认知道这是啥。一般需要三个点就够了:起点,终点,控制点。下面三种方法主要是针对终点的计算有所不同。(前两种之前写的...懒得找了,第三种应该是最复杂的,能理解的话前面的问题就不大)

    贝塞尔曲线之直线变曲线

    直接使用 transform.position 作为起点,发射 transform.forword 方向上的射线,判断目标是否可传送,可以的话,把控制点吊高(比如计算起点,终点的中间点,再把 y 增加),这样看起来就是一个传送曲线。
    缺点:just 看起来,在 VR 项目中,手柄稍微抬高一点点,与地面没有交点的话,就不能传送了。
    优点:非常省事

    贝塞尔曲线之固定目的地

    如果可传送点就几个地方的话,可以考虑这种方式,效果如下:


    传送

    通过控制朝向,在两个传送点之间切换。思路是先把所有的传送点位置存下来,然后在选择传送点的时候,计算当前朝向与所有传送点的点积(也就是夹角),选点积最大的(也就是夹角最小的)。


    丑丑的图示
    缺点:需要固定目的地
    优点:可以固定目的地

    贝塞尔曲线之计算目的地

    原理就是设置一个最大的传送范围,然后物体抬得最高的时候,也就是图中 180° 的时候,算出一个当前朝向的最远的一个地方,再用从天而降的射线判断目的地是否可以传送,这样便计算出了贝塞尔曲线的目标点,控制点简单点就像这样,跟起点相切,长度为起点和终点一半的距离。
    缺点:要定好最大传送的尺度,也就是说,如果你的地图只有半径 10 米,却设置了 100 的最大距离,那么只有 1/10 的范围是可用的。
    优点:相对于固定目的地传送,这种可以在范围内随意传送,自由度高。


    丑丑的图示
    效果图
    有高度
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    
    public class NewBehaviourScript : MonoBehaviour
    {
        public float MaxTranlateDistance;
        public float MaxTranlateHight;
    
        private LineRenderer _lineRenderer;
    
        private void Start()
        {
            _lineRenderer = GetComponent<LineRenderer>();
            _lineRenderer.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off;
            _lineRenderer.startWidth = 0.04f;
            _lineRenderer.endWidth = 0.04f;
            _lineRenderer.numCapVertices = 5;
            _lineRenderer.numCornerVertices = 5;
            _lineRenderer.positionCount = 30;
        }
    
        private void Update()
        {
            DrawLine();
        }
    
        private void DrawLine()
        {
            Vector3 startPoint = transform.position;
            Vector3 horizontalForward = Vector3.Cross(transform.right, Vector3.up);
            if (Vector3.Dot(horizontalForward, transform.forward) < 0)
            {
                horizontalForward = -horizontalForward;
            }
            Debug.DrawLine(transform.position, transform.position + Vector3.up, color: Color.green);
            Debug.DrawLine(transform.position, transform.position + transform.right, color: Color.red);
            Debug.DrawLine(transform.position, transform.position + horizontalForward, color: Color.blue);
            float horizontal_t = Vector3.Dot(transform.forward, horizontalForward);
            float t = horizontal_t / 2;
            if (transform.forward.y > 0) // 当抬得比较高的时候,要把 t 的范围从 0.5-0 映射到 0.5-1
            {
                t = -t + 1;
            }
            Vector3 endPoint = transform.position + horizontalForward * t * MaxTranlateDistance;
    
            // 注意这里我写了碰撞遮罩的检测,所以在场景中要设置好层级
            if (Physics.Raycast(new Ray(endPoint + Vector3.up * MaxTranlateHight, Vector3.down),
                out RaycastHit hit, 100, 1 << LayerMask.NameToLayer(ConstName.layer_translate_target), QueryTriggerInteraction.Collide))
            {
                endPoint = hit.point;
            }
            else
            {
                _lineRenderer.enabled = false;
                return;
            }
            float d = (endPoint - startPoint).magnitude / 2;
            Vector3 controlPoint = transform.position + transform.forward * d;
            Vector3[] bcList = GetBeizerPathPointList(startPoint, controlPoint, endPoint, 30);
            _lineRenderer.positionCount = bcList.Length + 1;
            _lineRenderer.SetPosition(0, startPoint);
            for (int i = 0; i < bcList.Length; i++)
            {
                Vector3 v = bcList[i];
                _lineRenderer.SetPosition(i + 1, v);
            }
            _lineRenderer.enabled = true;
        }
    
        public static Vector3[] GetBeizerPathPointList(Vector3 startPoint, Vector3 controlPoint, Vector3 endPoint, int pointNum)
        {
            Vector3[] BeizerPathPointList = new Vector3[pointNum];
            for (int i = 1; i <= pointNum; i++)
            {
                float t = i / (float)pointNum;
                Vector3 point = GetBeizerPathPoint(t, startPoint,
                    controlPoint, endPoint);
                BeizerPathPointList[i - 1] = point;
            }
            return BeizerPathPointList;
        }
    
        private static Vector3 GetBeizerPathPoint(float t, Vector3 p0, Vector3 p1, Vector3 p2)
        {
            return (1 - t) * (1 - t) * p0 + 2 * t * (1 - t) * p1 + t * t * p2;
        }
    
    
    }
    

    抛物线

    手撸一个抛物线,之前写的抛物线找不到了...
    缺点:落点不好判断
    优点:比较真实

    球形差值

    TODO

    相关文章

      网友评论

          本文标题:Unity 传送曲线

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