zoukankan      html  css  js  c++  java
  • 游戏编程精粹学习

    在《游戏编程精粹1》的4.7中,原文主要解决赛车游戏的路程确定问题和光照插值问题。

    但原文中没有提及如何判断四边形区域是否包含的问题,只有提到point-in-sector这个函数名称

    实现是T和L两部分做向量投影,但是不乘以最终方向矢量,而是以两边的点乘结果求得比例。

    那么我对其做了一些修改,改成了横向和纵向二维的单位距离计算,这样可以顺手解决是否包含的判断问题。

    支持两个轴向之后可以对其做是否包含的判断,还可以通过组合做一些复杂区域的判断检测。

    例如运用在游戏BOSS战,或RailCamera中。

    代码如下:

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    namespace Hont
    {
        public class QuadSector : MonoBehaviour
        {
            public struct QuadSector_VecXZ
            {
                public float X { get; set; }
                public float Z { get; set; }
    
    
                public QuadSector_VecXZ(float x, float z)
                {
                    X = x;
                    Z = z;
                }
            }
    
            public Transform p0;
            public Transform p1;
            public Transform p2;
            public Transform p3;
            public bool isRealtimeUpdate;
    
            QuadSector_VecXZ mHPointLeading;
            QuadSector_VecXZ mHPointTrailing;
            QuadSector_VecXZ mHUnitNormalLeading;
            QuadSector_VecXZ mHUnitNormalTrailing;
    
            QuadSector_VecXZ mVPointLeading;
            QuadSector_VecXZ mVPointTrailing;
            QuadSector_VecXZ mVUnitNormalLeading;
            QuadSector_VecXZ mVUnitNormalTrailing;
    
            public QuadSector_VecXZ HPointLeading { get { return mHPointLeading; } set { mHPointLeading = value; } }
            public QuadSector_VecXZ HPointTrailing { get { return mHPointTrailing; } set { mHPointTrailing = value; } }
            public QuadSector_VecXZ HUnitNormalLeading { get { return mHUnitNormalLeading; } set { mHUnitNormalLeading = value; } }
            public QuadSector_VecXZ HUnitNormalTrailing { get { return mHUnitNormalTrailing; } set { mHUnitNormalTrailing = value; } }
    
            public QuadSector_VecXZ VPointLeading { get { return mVPointLeading; } set { mVPointLeading = value; } }
            public QuadSector_VecXZ VPointTrailing { get { return mVPointTrailing; } set { mVPointTrailing = value; } }
            public QuadSector_VecXZ VUnitNormalLeading { get { return mVUnitNormalLeading; } set { mVUnitNormalLeading = value; } }
            public QuadSector_VecXZ VUnitNormalTrailing { get { return mVUnitNormalTrailing; } set { mVUnitNormalTrailing = value; } }
    
    
            public void UpdateHorizontalQuadSectorInfo()
            {
                var pl = (p1.position + p2.position) * 0.5f;
                mHPointLeading = new QuadSector_VecXZ(pl.x, pl.z);
    
                var pt = (p0.position + p3.position) * 0.5f;
                mHPointTrailing = new QuadSector_VecXZ(pt.x, pt.z);
    
                var nl = CalcLineNormal(p1.position, p2.position, Vector3.up, p3.position);
                mHUnitNormalLeading = new QuadSector_VecXZ(nl.x, nl.z);
    
                var nt = CalcLineNormal(p0.position, p3.position, Vector3.up, p1.position);
                mHUnitNormalTrailing = new QuadSector_VecXZ(nt.x, nt.z);
            }
    
            public void UpdateVerticalQuadSectorInfo()
            {
                var pl = (p1.position + p0.position) * 0.5f;
                mVPointLeading = new QuadSector_VecXZ(pl.x, pl.z);
    
                var pt = (p2.position + p3.position) * 0.5f;
                mVPointTrailing = new QuadSector_VecXZ(pt.x, pt.z);
    
                var nl = CalcLineNormal(p1.position, p0.position, Vector3.up, p3.position);
                mVUnitNormalLeading = new QuadSector_VecXZ(nl.x, nl.z);
    
                var nt = CalcLineNormal(p2.position, p3.position, Vector3.up, p0.position);
                mVUnitNormalTrailing = new QuadSector_VecXZ(nt.x, nt.z);
            }
    
            public float CalcHorizontalUnitDistanceIntoSector(float pointX, float pointZ)
            {
                var lp = new QuadSector_VecXZ();
                var tp = new QuadSector_VecXZ();
                var dotL = 0f;
                var dotT = 0f;
    
                lp.X = pointX - HPointLeading.X;
                lp.Z = pointZ - HPointLeading.Z;
    
                tp.X = pointX - HPointTrailing.X;
                tp.Z = pointZ - HPointTrailing.Z;
    
                dotL = lp.X * mHUnitNormalLeading.X + lp.Z * mHUnitNormalLeading.Z;
                dotT = tp.X * mHUnitNormalTrailing.X + tp.Z * mHUnitNormalTrailing.Z;
    
                return dotL / (dotL + dotT);
            }
    
            public float CalcVerticalUnitDistanceIntoSector(float pointX, float pointZ)
            {
                var lp = new QuadSector_VecXZ();
                var tp = new QuadSector_VecXZ();
                var dotL = 0f;
                var dotT = 0f;
    
                lp.X = pointX - VPointLeading.X;
                lp.Z = pointZ - VPointLeading.Z;
    
                tp.X = pointX - VPointTrailing.X;
                tp.Z = pointZ - VPointTrailing.Z;
    
                dotL = lp.X * mVUnitNormalLeading.X + lp.Z * mVUnitNormalLeading.Z;
                dotT = tp.X * mVUnitNormalTrailing.X + tp.Z * mVUnitNormalTrailing.Z;
    
                return dotL / (dotL + dotT);
            }
    
            public bool IsContain(float pointX, float pointZ)
            {
                var x = CalcHorizontalUnitDistanceIntoSector(transform.position.x, transform.position.z);
                var z = CalcVerticalUnitDistanceIntoSector(transform.position.x, transform.position.z);
    
                return x > 0 && x < 1 && z > 0 && z < 1;
            }
    
            Vector3 CalcLineNormal(Vector3 p0, Vector3 p1, Vector3 upAxis, Vector3 comparePoint)
            {
                var dir = (p1 - p0).normalized;
                var normal1 = Vector3.Cross(dir, upAxis);
                var normal2 = Vector3.Cross(dir, -upAxis);
    
                if (Vector3.Dot(normal1, comparePoint - p0) > 0)
                    return normal1;
                else
                    return normal2;
            }
    
            void Awake()
            {
                UpdateHorizontalQuadSectorInfo();
                UpdateVerticalQuadSectorInfo();
            }
    
            void Update()
            {
                if (isRealtimeUpdate)
                {
                    UpdateHorizontalQuadSectorInfo();
                    UpdateVerticalQuadSectorInfo();
                }
            }
    
            void OnDrawGizmos()
            {
                if (p0 == null || p1 == null || p2 == null || p3 == null) return;
    
                if (!Application.isPlaying)
                {
                    UpdateHorizontalQuadSectorInfo();
                    UpdateVerticalQuadSectorInfo();
                }
    
                Gizmos.DrawLine(p0.position, p1.position);
                Gizmos.DrawLine(p1.position, p2.position);
                Gizmos.DrawLine(p2.position, p3.position);
                Gizmos.DrawLine(p3.position, p0.position);
    
                var cacheColor = Gizmos.color;
                Gizmos.color = Color.blue;
    
                var ori = new Vector3(HPointLeading.X, transform.position.y, HPointLeading.Z);
                Gizmos.DrawLine(ori, ori + new Vector3(HUnitNormalLeading.X, transform.position.y, HUnitNormalLeading.Z));
    
                ori = new Vector3(VPointLeading.X, transform.position.y, VPointLeading.Z);
                Gizmos.DrawLine(ori, ori + new Vector3(VUnitNormalLeading.X, transform.position.y, VUnitNormalLeading.Z));
    
                ori = new Vector3(HPointTrailing.X, transform.position.y, HPointTrailing.Z);
                Gizmos.DrawLine(ori, ori + new Vector3(HUnitNormalTrailing.X, transform.position.y, HUnitNormalTrailing.Z));
    
                ori = new Vector3(VPointTrailing.X, transform.position.y, VPointTrailing.Z);
                Gizmos.DrawLine(ori, ori + new Vector3(VUnitNormalTrailing.X, transform.position.y, VUnitNormalTrailing.Z));
    
                Gizmos.color = cacheColor;
            }
        }
    }
    QuadSector

    P0-P3四个点沿顺时针方向排布,如果不勾选实时更新则法线和顶点都不会在运行时修改。

    测试脚本:

    public class TestPlayer : MonoBehaviour
    {
        public QuadSector quadSector;
    
    
        void Update()
        {
            var x = quadSector.CalcHorizontalUnitDistanceIntoSector(transform.position.x, transform.position.z);
            var z = quadSector.CalcVerticalUnitDistanceIntoSector(transform.position.x, transform.position.z);
            Debug.Log("x: " + x + " z: " + z);
        }
    }
  • 相关阅读:
    「Luogu2397」 yyy loves Maths VI (mode)
    「Luogu2014」 选课
    「Luogu2972」 [USACO10HOL]岩石和树木Rocks and Trees
    中国剩余定理
    点双连通分量
    Miller_Rabin大质数检验
    manachaer算法
    Kruskal重构树
    世界,你好!
    [Luogu P1450] [HAOI2008]硬币购物 背包DP+容斥
  • 原文地址:https://www.cnblogs.com/hont/p/8848066.html
Copyright © 2011-2022 走看看