Unity 算法功能 日記

来源:互联网 发布:好用的会计软件 编辑:程序博客网 时间:2024/05/29 14:33

Hello ,I am KitStar


1. 相机根据玩家与玩家位置 进行智能跟随 方法

在使用相机跟随玩家对象的时候。往往会使用多种模式进行。本文将介绍两种方式。
其实,就是就是transform.LookAt 不同参数的效果。
但是,都是可以根据玩家与敌人的距离进行相应的 高度,距离变化的。

由于比较简单,所以直接老规矩上脚本吧。

这里写图片描述

using UnityEngine;public class FollowCamera : MyMonoSingleton<FollowCamera>{    public enum CamerMotionMode    {        FollowOnly,  // 只跟随        Trailing    //尾随,会根据玩家旋转进行旋转    }    public CamerMotionMode camerMotionMode = CamerMotionMode.FollowOnly;    [Tooltip("玩家对象")]    public Transform SelfTarget;    [Tooltip("敌人对象")]    public Transform EnemyTarget;    [Tooltip("只用于观察")]    public float spaceBetween = 0; //敌人与自己之间的距离    public float Distance = 10f;  //后方距离    public float Height = 5f;   //高度    public float smooth = 2f;   // 插值系数    private Vector3 tagerPosition; // 目标位置    void Awake()    {        if (Instance != null)            Debug.LogError("Instance FollowCamera x2");        else        {            Instance = this;        }    }     float dis_register = 0;  //寄存距离值     float height_register = 0;  //寄存高度值    void LateUpdate()    {        //根据双方距离调节相机高度以及距离        if(EnemyTarget != null)   // 如果存在敌人。则时刻对自己与敌人的距离进行一个插值        {            dis_register = Vector3.Distance(SelfTarget.position, EnemyTarget.transform.position);            spaceBetween = Mathf.Lerp(spaceBetween, dis_register, Time.deltaTime);        }        else    // 如果不存在敌人,则缓慢的从新回到最初高度。        {            if(spaceBetween > 0 )            {                spaceBetween = Mathf.Lerp(spaceBetween, 0,  Time.deltaTime);            }            else            {                spaceBetween = 0;            }        }        height_register = Height + (spaceBetween / 4);    // 得到最终高度        float currentHeight = Mathf.Lerp(transform.position.y, SelfTarget.position.y + height_register, smooth * Time.deltaTime);    // 对高度进行插值计算。防止出现摄像机位置突然变化        if(camerMotionMode == CamerMotionMode.FollowOnly)        {            // 和下面逻辑一下。            transform.position = SelfTarget.position;  // 得到玩家位置            transform.position -= Vector3.forward * (Distance + (spaceBetween / 1.5f));    // 向玩家位置后方移动            transform.position = new Vector3(transform.position.x, currentHeight, transform.position.z);     // 向上方移动            transform.LookAt(SelfTarget.position);     // 只看向位置        }        else        {            /* 下面的代码和上面的代码 效果差不多。逻辑都是一样的。 得到,玩家位置向后以及向上的 一个 向量。然后对让相机去这个向量的位置。 但是如果,使用下面这个方式            就要对smooth 进行加大,不然,两次插值计算,得到的运动会很慢。或者读者改其他方式,因为这里我不用这个方法所以不多做改动了。哈哈哈 ~ ~ ~ ~            */            tagerPosition = SelfTarget.position + Vector3.up * currentHeight - SelfTarget.forward * (Distance + (spaceBetween / 1.5f));            transform.position = Vector3.Lerp(transform.position, tagerPosition, Time.deltaTime * smooth);            transform.LookAt(SelfTarget);     // 看向位置和更具旋转进行相应变化        }    }    public void SetTarget(Transform target)    {        SelfTarget = target;    }    public void SetParame(float dis, float height, float heightDamp)    {        Distance = dis;        Height = height;        smooth = heightDamp;    }}

2. 对象平滑跟随目标

咱还是直接代码吧.官方案例

using UnityEngine;public class SmoothFollow : MonoBehaviour    {        // The target we are following        [SerializeField]        private Transform target;        // The distance in the x-z plane to the target        [SerializeField]        private float distance = 10.0f;        // the height we want the camera to be above the target        [SerializeField]        private float height = 5.0f;        [SerializeField]        private float rotationDamping;        [SerializeField]        private float heightDamping;        // Use this for initialization        void Start() { }        // Update is called once per frame        void LateUpdate()        {            // Early out if we don't have a target            if (!target)                return;            // Calculate the current rotation angles            var wantedRotationAngle = target.eulerAngles.y;            var wantedHeight = target.position.y + height;            var currentRotationAngle = transform.eulerAngles.y;            var currentHeight = transform.position.y;            // Damp the rotation around the y-axis            currentRotationAngle = Mathf.LerpAngle(currentRotationAngle, wantedRotationAngle, rotationDamping * Time.deltaTime);            // Damp the height            currentHeight = Mathf.Lerp(currentHeight, wantedHeight, heightDamping * Time.deltaTime);            // Convert the angle into a rotation            var currentRotation = Quaternion.Euler(0, currentRotationAngle, 0);            // Set the position of the camera on the x-z plane to:            // distance meters behind the target            transform.position = target.position;            transform.position -= currentRotation * Vector3.forward * distance;            // Set the height of the camera            transform.position = new Vector3(transform.position.x ,currentHeight , transform.position.z);            // Always look at the target            transform.LookAt(target);        }    }

3. 确定一个对象是否在这个对象的锥形范围之内。可以不使用碰撞或者粒子检测

咱还是直接代码吧.

public class GameAlgorithm{    public static bool JudgmentRoundRange(Transform self , Transform tager, float high = 1, float wide = 1,float distance = 100)    {        if (Vector3.Distance(self.position, tager.position) > distance || Vector3.Dot(self.position, (tager.position - self.position)) < 0)    // 距离 范围内部         {            Debug.Log("car of distances : Ok");            return false;        }        else        {            Debug.Log("two of distances : Ok");            Vector3 shootdir = (tager.position - self.position).normalized;  // 射击的方向            Vector3 right = self.transform.right;       // 玩家 右边            Vector3 forward = self.transform.forward;    // 玩家 前面            Vector3 up = self.transform.up;                     //玩家 下面            //算出在xoz方向上的投影            Vector3 dirRight = Vector3.Cross(Vector3.Cross(up, shootdir).normalized, up).normalized;            //yoz方向上的投影            Vector3 dirUp = Vector3.Cross(Vector3.Cross(right, shootdir).normalized, right).normalized;            //左右cos,递减区间(-60,60):(>=)            bool condition3 = Vector3.Dot(forward, dirRight) >= Mathf.Cos(35 * Mathf.Deg2Rad);   // 大于 20 度的 弧            //上下cos(-45,45)            return condition3 && Vector3.Dot(forward, dirUp) >= Mathf.Cos(35 * Mathf.Deg2Rad);            }    }}

4. 获取网络时间(用户软件的限时操作,或者需要网络时间的操作)

哭笑,还是直接代码吧.

 public class NetWorkManage : MonoBehaviour    {        private float timeStamp;        // private string timeStamp_Str;        private StringBuilder timeStamp_Str = new StringBuilder(25, 30);        Double timerStr;        DateTime time = DateTime.MinValue;        DateTime startTime = TimeZone.CurrentTimeZone.ToLocalTime(new DateTime(1970, 1, 1));        public void Awake()        {            StartCoroutine(GetTimeStamp());   //开始 获取网络时间        }        // 获取一次网络时间之后,让时间自己进行累加。不需要重复获取。        private void FixedUpdate()        {            timerStr += Time.deltaTime * 1000;            time = startTime.AddMilliseconds(timerStr);            timeStamp_Str.Remove(0, timeStamp_Str.Length);            timeStamp_Str.Append(time.ToString());            timeStamp_Str.Append("\n");            timeStamp_Str.Append(time.Millisecond.ToString());            //  timeStamp_Str = time.ToString();            timeStamp = time.Millisecond;        }        #region 网络时间        /// <summary>        /// 获取 时间的 当前 秒        /// </summary>        public int GetGameTimeSecond        {            get            {                return time.Second;            }        }        /// <summary>        /// 获取当前时间戳        /// </summary>        public float GetGameTimeStamp        {            get            {                return timeStamp;            }        }        /// <summary>        /// 获取当前时间,以及当前毫秒数值        /// </summary>        public string GetGameTimeStampStr        {            get            {                if (timeStamp_Str != null)                {                    return timeStamp_Str.ToString();                }                else                {                    return null;                }            }        }       float waitTime = 1;       private IEnumerator GetTimeStamp()        {            WWW www = new WWW("http://www.hko.gov.hk/cgi-bin/gts/time5a.pr?a=1");            yield return www;            try            {                if(!Double.TryParse(www.text.Substring(2),out timerStr))                {                    StartCoroutine(GetTimeStamp());                }            }            catch (Exception e)            {                PublicClass.Log("NetWork error : " + e);            }            yield return new WaitForSeconds(waitTime);   // 防止 时间有偏差,刚开始会快速更新。后面十秒间隔更新一次            waitTime++;            waitTime = Mathf.Min(waitTime,10);            StartCoroutine(GetTimeStamp());        }           #endregion 网络时间  }

5.第三人称的人物摄像头控制,中间控制远近,右键滑动控制旋转,如果检测到障碍物,自己调节相机远近距离

咱还是直接代码吧

using UnityEngine; using System.Collections; public class PlayerCamera : MonoBehaviour {     public Transform target;     public  float attackTimer;    public float targetHeight = 1.7f;     public float distance = 5.0f;    public float offsetFromWall = 0.1f;    public float maxDistance = 20;     public float minDistance = .6f;     public float xSpeed = 200.0f;     public float ySpeed = 200.0f;     public int yMinLimit = -80;     public int yMaxLimit = 80;     public int zoomRate = 40;     public float rotationDampening = 3.0f;     public float zoomDampening = 5.0f;     public LayerMask collisionLayers = -1;    private float xDeg = -53.2f;     private float yDeg = 22.4f;     private float currentDistance;     private float desiredDistance;     private float correctedDistance;    void Start ()     {        attackTimer=0.05f;        currentDistance = distance;         desiredDistance = distance;         correctedDistance = distance;         if (GetComponent<Rigidbody>())             GetComponent<Rigidbody>().freezeRotation = true;     }     void LateUpdate ()     {        if(attackTimer>0)            attackTimer-=Time.deltaTime;        if(attackTimer<0)            attackTimer=0;        if(attackTimer==0){            target = GameObject.FindGameObjectWithTag("Player").transform;        }        Vector3 vTargetOffset;        if (!target){             return;         }        if (Input.GetMouseButton(1) )         {             xDeg += Input.GetAxis ("Mouse X") * xSpeed * 0.02f;             yDeg -= Input.GetAxis ("Mouse Y") * ySpeed * 0.02f;         }         yDeg = ClampAngle (yDeg, yMinLimit, yMaxLimit);         xDeg = ClampAngle (xDeg, -360, 360);         Quaternion rotation = Quaternion.Euler (yDeg, xDeg, 0);         desiredDistance -= Input.GetAxis ("Mouse ScrollWheel") * Time.deltaTime * zoomRate * Mathf.Abs (desiredDistance);         desiredDistance = Mathf.Clamp (desiredDistance, minDistance, maxDistance);         correctedDistance = desiredDistance;         vTargetOffset = new Vector3 (0, -targetHeight, 0);        Vector3 position = target.position - (rotation * Vector3.forward * desiredDistance + vTargetOffset);         RaycastHit collisionHit;         Vector3 trueTargetPosition = new Vector3 (target.position.x, target.position.y + targetHeight, target.position.z);         bool isCorrected = false;         if (Physics.Linecast (trueTargetPosition, position, out collisionHit, collisionLayers.value))         {             correctedDistance = Vector3.Distance (trueTargetPosition, collisionHit.point) - offsetFromWall;             isCorrected = true;        }        currentDistance = !isCorrected || correctedDistance > currentDistance ? Mathf.Lerp (currentDistance, correctedDistance, Time.deltaTime * zoomDampening) : correctedDistance;         currentDistance = Mathf.Clamp (currentDistance, minDistance, maxDistance);         position = target.position - (rotation * Vector3.forward * currentDistance + vTargetOffset);         transform.rotation = rotation;         transform.position = position;     }     private static float ClampAngle (float angle, float min, float max)     {         if (angle < -360)             angle += 360;         if (angle > 360)             angle -= 360;         return Mathf.Clamp (angle, min, max);     } } 





6. 在游戏运行的时候,往往需要 在 正交Orthographic (无消失点投影)透视Perspective (有消失点投影) 两个视角中来回转化。 以达到 不同的 2D 与 3D 视角。

So! 今天的 实例代码就是 描述了 这一个功能:


using UnityEngine;public enum Views{    _2DView = 1,    _3DView} public class BackupCameraProjectionChange {    /// <summary>    /// 相机透视改变是否触发(调用只需把此值改为true)    /// </summary>    public bool ChangeProjection = false;    private bool _changing = false;    private float ProjectionChangeTime = 0.5f;    private float _currentT = 0.0f;    private Camera m_Camera;protected Views cur_Views = Views._3DView;public Views GetCurViews{    get    {        return cur_Views;    }}public BackupCameraProjectionChange(Camera camera = null , float speed = 0.5f){    ProjectionChangeTime = speed;    if (m_Camera == null && camera == null)    {        m_Camera = Camera.main;    }    else    {        m_Camera = camera;    }}///这个 Update 需要在 其他继承自 MonoBehaviour 类的 Update 中 调用public void Update(){    if (m_Camera == null)        return;    if (_changing)    {        ChangeProjection = false;    }    else if (ChangeProjection)    {        _changing = true;        _currentT = 0.0f;    }    LateUpdate();}void LateUpdate(){    if (!_changing)    {        return;    }    //将当前的 是否正视图值 赋值给currentlyOrthographic变量    bool currentlyOrthographic = m_Camera.orthographic;    //定义变量存放当前摄像机的透视和正视矩阵信息;    Matrix4x4 orthoMat, persMat;    if (currentlyOrthographic)//如果当前摄像机为正视状态,则切换为3D    {        orthoMat = m_Camera.projectionMatrix; //保留 2D矩阵信息        m_Camera.orthographic = false;  //为 3D        m_Camera.ResetProjectionMatrix();        persMat = m_Camera.projectionMatrix;   //保留 3D 矩阵信息        cur_Views = Views._3DView;    }    else//否则当前摄像机为透视状态, 则切换为2D    {        persMat = m_Camera.projectionMatrix; //保留 3D 矩阵信息        m_Camera.orthographic = true;    //为2D        m_Camera.ResetProjectionMatrix();        orthoMat = m_Camera.projectionMatrix;  //保留 2D矩阵信息        cur_Views = Views._2DView;    }    m_Camera.orthographic = currentlyOrthographic;    _currentT += (Time.deltaTime / ProjectionChangeTime);    if (_currentT < 1.0f)    {        if (currentlyOrthographic)        {            m_Camera.projectionMatrix = MatrixLerp(orthoMat, persMat, _currentT * _currentT);  //从2D 到 3D        }        else        {            m_Camera.projectionMatrix = MatrixLerp(persMat, orthoMat, Mathf.Sqrt(_currentT)); //从3D 到 2D        }    }    else    {        _changing = false;        m_Camera.orthographic = !currentlyOrthographic;  //取反        m_Camera.ResetProjectionMatrix();   // 重置    }}private Matrix4x4 MatrixLerp(Matrix4x4 from, Matrix4x4 to, float t){    t = Mathf.Clamp(t, 0.0f, 1.0f);    Matrix4x4 newMatrix = new Matrix4x4();    newMatrix.SetRow(0, Vector4.Lerp(from.GetRow(0), to.GetRow(0), t));    newMatrix.SetRow(1, Vector4.Lerp(from.GetRow(1), to.GetRow(1), t));    newMatrix.SetRow(2, Vector4.Lerp(from.GetRow(2), to.GetRow(2), t));    newMatrix.SetRow(3, Vector4.Lerp(from.GetRow(3), to.GetRow(3), t));    return newMatrix;}}
原创粉丝点击