unity 记录简易的物理检测

4 篇文章 0 订阅

using System;
using System.Diagnostics;

using UnityEngine;

/// <summary>用于保存aabb包围盒</summary>
public interface ICube : IMyCollider
{
    Vector3 angle { get; }
    Vector3 size { get; }
}

/// <summary>扇形</summary>
public interface IAnnular : ICircle
{
    Vector3 dir { get; }
    /// <summary>弧度</summary>
    float radian { get; }
    [Obsolete]
    float minRadius { get; }
}

/// <summary>胶囊体</summary>
public interface ICapsule : ICircle
{
    //Vector3 angle { get; }
    Vector3 point1 { get; }
    Vector3 point2 { get; }
}

/// <summary>球形</summary>
public interface ICircle : IMyCollider
{
    float radius { get; }
}

/// <summary> </summary>
public interface IMyCollider
{
    /// <summary>AABB包围盒</summary>
    Bounds bounds { get; }
    Transform transform { get; }
    Vector3 center { get; }
}

[DebuggerStepThrough, Serializable]
public struct Cube : ICube
{
    public Transform transform { get; set; }

    public Bounds bounds { get; set; }

    public Vector3 angle { get; set; }

    public Vector3 center { get; set; }

    public Vector3 size { get; set; }

    public static implicit operator Cube(BoxCollider box)
    {
        return new Cube
        {
            transform = box.transform,
            center = box.center + box.transform.position,
            size = box.size.Multiply(box.transform.localScale),
            bounds = box.bounds,
            angle = box.transform.eulerAngles
        };
    }
    public static explicit operator Cube(Bounds bound)
    {
        return new Cube
        {
            center = bound.center,
            size = bound.size,
            bounds = bound
        };
    }
}

[DebuggerStepThrough, Serializable]
public struct Annular : IAnnular
{
    public Vector3 dir { get; set; }

    public float radian { get; set; }
    [Obsolete]
    public float minRadius { get; set; }

    public Vector3 center { get; set; }

    public float radius { get; set; }

    public Bounds bounds { get; set; }

    public Transform transform { get; set; }
}

[DebuggerStepThrough, Serializable]
public struct Capsule : ICapsule
{
    public Vector3 center { get; set; }

    public float radius { get; set; }

    public Transform transform { get; set; }

    public Bounds bounds { get; set; }

    public Vector3 point1 { get; set; }

    public Vector3 point2 { get; set; }

    public static explicit operator Capsule(CapsuleCollider capsule)
    {
        float height = (capsule.height - 2 * capsule.radius) * capsule.transform.lossyScale.y;
        Vector3 vec = capsule.transform.rotation * (Vector3.up * (height / 2));

        Capsule ret = new Capsule
        {
            center = capsule.bounds.center,
            radius = capsule.radius * capsule.transform.lossyScale.y,
            transform = capsule.transform,
            bounds = capsule.bounds,
            point1 = capsule.bounds.center + vec,
            point2 = capsule.bounds.center - vec,
        };

        return ret;
    }                
}

[DebuggerStepThrough, Serializable]
public struct Circle : ICircle
{
    public Vector3 center { get; set; }

    public float radius { get; set; }

    public Transform transform { get; set; }

    public Bounds bounds { get; set; }

    public static implicit operator Circle(SphereCollider sphere)
    {
        return new Circle
        {
            center = sphere.center,
            radius = sphere.radius,
            transform = sphere.transform,
            bounds = sphere.bounds,
        };
    }
}

using System;

using UnityEngine;

public static class PhysicsExtension
{
    public static bool XZIntersects(this IMyCollider self, IMyCollider target)
    {
        if (self is ICapsule cap)
            return cap.XZIntersects(target);
        else if (self is IAnnular ann)
            return ann.XZIntersects(target);
        else if (self is ICircle cir)
            return cir.XZIntersects(target);
        else if (self is ICube cub)
            return cub.XZIntersects(target);
        return target.bounds.XZIntersects(self.bounds);
    }
    public static bool XZIntersects(this IMyCollider self, Bounds bound)
    {
        if (self is ICapsule cap)
            return cap.XZIntersects(bound);
        if (self is IAnnular ann)
            return ann.XZIntersects(bound);
        else if (self is ICircle cir)
            return cir.XZIntersects(bound);
        else if (self is ICube cub)
            return cub.XZIntersects(bound);
        else
            return self.bounds.XZIntersects(bound);
    }
    /// <summary>计算距离</summary> 
    public static float XZDistance(this IMyCollider self, Vector3 target)
    {
        if (self is ICapsule cap)
            return cap.XZDistance(target);
        if (self is IAnnular ann)
            return ann.XZDistance(target);
        else if (self is ICircle cir)
            return cir.XZDistance(target);
        else if (self is ICube cub)
            return cub.XZDistance(target);
        else
            return self.bounds.XZDistance(target);
    }

    public static bool Intersects(this IMyCollider self, IMyCollider target)
    {
        if (self is ICapsule cap)
        {
            if (target is ICapsule tcap)
                return cap.Intersects(tcap);
            if (target is ICircle tcir)
                return cap.Intersects(tcir);
            if (target is ICube tcub)
                return cap.Intersects(tcub);
            return cap.Intersects(target.bounds);
        }
        else if (self is ICircle cir)
        {
            if (target is ICapsule tcap)
                return tcap.Intersects(cir);
            if (target is ICircle tcir)
                return cir.Intersects(tcir);
            if (target is ICube tcub)
                return cir.Intersects(tcub);
            return cir.Intersects(target.bounds);
        }
        else if (self is ICube cub)
        {
            if (target is ICapsule tcap)
                return tcap.Intersects(cub);
            if (target is ICircle tcir)
                return tcir.Intersects(cub);
            if (target is ICube tcub)
                return cub.Intersects(tcub);
            return cub.Intersects(target.bounds);
        }
        return target.bounds.Intersects(self.bounds);
    }
    public static float Distance(this IMyCollider self, Vector3 target)
    {
        if (self is ICapsule cap)
            return cap.Distance(target);
        else if (self is ICircle cir)
            return cir.Distance(target);
        else if (self is ICube cub)
            return cub.Distance(target);
        else
            return self.bounds.Distance(target);
    }
    #region XZ坐标系内
    #region 胶囊体

    public static bool XZIntersects(this ICapsule capsule, IMyCollider target)
    {
        if (target is ICapsule tcap)
            return capsule.XZIntersects(tcap);
        if (target is IAnnular tann)
            return capsule.XZIntersects(tann);
        if (target is ICircle tcir)
            return capsule.XZIntersects(tcir);
        if (target is ICube tcub)
            return capsule.XZIntersects(tcub);
        return capsule.XZIntersects(target.bounds);
    }
    public static bool XZIntersects(this ICapsule capsule1, ICapsule capsule2)
    {
        return XZIntersectsCircle(capsule1.center, capsule1.radius, capsule2.center, capsule2.radius);
    }
    public static bool XZIntersects(this ICapsule capsule, IAnnular annular)
    {
        return annular.XZIntersects((ICircle)capsule);
    }
    public static bool XZIntersects(this ICapsule capsule, ICircle circle)
    {
        return XZIntersectsCircle(capsule.center, capsule.radius, circle.center, circle.radius);
    }

    //先求胶囊体的直线到方块中心点投影,然后按圆形做
    public static bool XZIntersects(this ICapsule capsule, ICube cube)
    {
        return ((ICircle)capsule).XZIntersects(cube);
    }

    public static bool XZIntersects(this ICapsule capsule, Bounds bound)
    {
        return (capsule as ICircle).XZIntersects(bound);
    }

    public static float XZDistance(this ICapsule capsule, Vector3 vec)
    {
        return (capsule as ICircle).XZDistance(vec);
    }
    #endregion
    #region 环形

    public static bool XZIntersects(this IAnnular annular, IMyCollider target)
    {
        if (target is ICapsule tcap)
            return tcap.XZIntersects(annular);
        if (target is IAnnular tann)
            return annular.XZIntersects(tann);
        if (target is ICircle tcir)
            return annular.XZIntersects(tcir);
        if (target is ICube tcub)
            return annular.XZIntersects(tcub);
        return annular.XZIntersects(target.bounds);
    }
    public static bool XZIntersects(this IAnnular annular1, IAnnular annular2)
    {
        return XZIntersectsCircle(annular1.center, annular1.radius, annular2.center, annular2.radius);
    }
    public static bool XZIntersects(this IAnnular annular, ICircle circle)
    {
        if (!XZIntersectsCircle(annular.center, annular.radius, circle.center, circle.radius)) return false;
        Vector3 dir = annular.dir;
        Vector3 vec = circle.center - annular.center;
        dir.y = 0;
        vec.y = 0;
        if (Vector3.Angle(dir, vec) <= annular.radian / 2) return true;
        dir = dir.normalized * annular.radius;
        dir = dir.Rotate(Vector3.up * annular.radian / 2);

        if (circle.XZIntersects(annular.center, annular.center + dir)) return true;
        dir = dir.Rotate(-Vector3.up * annular.radian);
        return circle.XZIntersects(annular.center, annular.center + dir);
    }

    //先求胶囊体的直线到方块中心点投影,然后按圆形做
    public static bool XZIntersects(this IAnnular annular, ICube cube)
    {
        return ((ICircle)annular).XZIntersects(cube);
    }

    public static bool XZIntersects(this IAnnular annular, Bounds bound)
    {
        return (annular as ICircle).XZIntersects(bound);
    }
    #endregion
    #region
    public static bool XZIntersects(this ICircle circle, IMyCollider target)
    {
        if (target is ICapsule tcap)
            return tcap.XZIntersects(circle);
        if (target is IAnnular tann)
            return tann.XZIntersects(circle);
        if (target is ICircle tcir)
            return circle.XZIntersects(tcir);
        if (target is ICube tcub)
            return circle.XZIntersects(tcub);
        return circle.XZIntersects(target.bounds);
    }
    public static bool XZIntersects(this ICircle circle1, ICircle circle2)
    {
        return XZIntersectsCircle(circle1.center, circle1.radius, circle2.center, circle2.radius);
    }

    public static bool XZIntersects(this ICircle circle, ICube cube)
    {
        Vector3 newC = circle.center.RotatePointAroundPivot(cube.center, -cube.angle);
        Vector3 v = (newC - cube.center).Abs();
        Vector3 u = (v - cube.size / 2).ClampMin(0);
        u.y = 0;
        return Vector3.Dot(u, u) <= circle.radius * circle.radius;
    }


    //先全部转换至第一象限
    //再计算点位
    public static bool XZIntersects(this ICircle circle, Bounds bound)
    {
        Vector3 v = (circle.center - bound.center).Abs();
        Vector3 u = (v - bound.extents).ClampMin(0);
        u.y = 0;
        return Vector3.Dot(u, u) <= circle.radius * circle.radius;
    }
    public static float XZDistance(this ICircle circle, Vector3 vec)
    {
        Vector3 v = circle.center - vec;
        v.y = 0;
        return v.magnitude - circle.radius;
    }
    //线段相交
    public static bool XZIntersects(this ICircle circle, Vector3 lStart, Vector3 lEnd)
    {
        Vector3 cirCenter = circle.center;
        cirCenter.y = 0;
        lStart.y = 0;
        lEnd.y = 0;
        Vector3 p1 = cirCenter.GetProjectionOnLine(lStart, lEnd);
        return Vector3.Dot(p1 - cirCenter, p1 - cirCenter) <= circle.radius * circle.radius;
    }
    public static bool XZIntersectsCircle(Vector3 center1, float radius1, Vector3 center2, float radius2)
    {
        Vector3 vec = center1 - center2;
        vec.y = 0;
        return Vector3.Dot(vec, vec) <= Mathf.Pow(radius1 + radius2, 2);
    }
    #endregion
    #region 方形
    public static bool XZIntersects(this ICube cube, IMyCollider target)
    {
        if (target is ICapsule tcap)
            return tcap.XZIntersects(cube);
        if (target is IAnnular tann)
            return tann.XZIntersects(cube);
        if (target is ICircle tcir)
            return tcir.XZIntersects(cube);
        if (target is ICube tcub)
            return cube.XZIntersects(tcub);
        return cube.XZIntersects(target.bounds);
    }
    /// <summary>
    /// OBB算法
    /// https://www.cnblogs.com/lyggqm/p/5386174.html
    /// </summary>
    /// <param name="cube1"></param>
    /// <param name="cube2"></param>
    /// <returns></returns>
    public static bool XZIntersects(this ICube cube1, ICube cube2)
    {
        float r1 = cube1.angle.y * Mathf.PI / 180;
        Vector3 v1 = new Vector3(Mathf.Cos(r1), 0, -Mathf.Sin(r1));
        Vector3 v2 = new Vector3(-v1.z, 0, v1.x);
        float r2 = cube2.angle.y * Mathf.PI / 180;
        Vector3 v3 = new Vector3(Mathf.Cos(r2), 0, -Mathf.Sin(r2));
        Vector3 v4 = new Vector3(-v3.z, 0, v3.x);

        Func<Vector3, Vector3, float> absDot = (v1, v2) => Mathf.Abs(Vector3.Dot(v1, v2));
        //投影长度
        Func<Vector3, Vector3, Vector3, Vector3, float> func = (extent, axis, mAxissx, mAxissz) =>
        {
            return (extent.x * absDot(axis, mAxissx) + extent.z * absDot(axis, mAxissz)) / 2;
        };

        Vector3 dis = cube1.center - cube2.center;
        dis.y = 0;
        return (func(cube1.size, v1, v1, v2) + func(cube2.size, v1, v3, v4) > absDot(dis, v1))
            && (func(cube1.size, v2, v1, v2) + func(cube2.size, v2, v3, v4) > absDot(dis, v2))
            && (func(cube1.size, v3, v1, v2) + func(cube2.size, v3, v3, v4) > absDot(dis, v3))
            && (func(cube1.size, v4, v1, v2) + func(cube2.size, v4, v3, v4) > absDot(dis, v4));
    }

    //计算在X,Z轴上的投影是否相交
    public static bool XZIntersects(this ICube cube, Bounds bound)
    {
        return cube.XZIntersects((Cube)bound);
    }

    public static float XZDistance(this ICube cube, Vector3 vec)
    {
        Vector3 v = vec.RotatePointAroundPivot(cube.center, -cube.angle);
        v = (cube.center - v).Abs();
        Vector3 u = v - cube.size / 2;
        if (u.x > 0 && u.z > 0)
            return Mathf.Sqrt(u.x * u.x + u.z * u.z);
        return Mathf.Max(u.x, u.z);
    }
    #endregion
    #region Bounds
    /// <summary>仅在XZ坐标系内包含</summary>
    public static bool XZContains(this Bounds container, Bounds bound)
    {
        return container.XZContains(bound.max) && container.XZContains(bound.min)
            && container.XZContains(new Vector3(bound.center.x - bound.extents.x, 0, bound.center.z + bound.extents.z))
            && container.XZContains(new Vector3(bound.center.x + bound.extents.x, 0, bound.center.z - bound.extents.z));
    }

    /// <summary>在XZ坐标系内包含</summary>
    public static bool XZContains(this Bounds container, Vector3 point)
    {
        return container.max.x >= point.x && container.min.x <= point.x && container.max.z >= point.z && container.min.z <= point.z;
    }

    public static bool XZIntersects(this Bounds bound1, Bounds bound2)
    {
        return bound1.min.x <= bound2.max.x && bound1.max.x >= bound2.min.x && bound1.min.z <= bound2.max.z && bound1.max.z >= bound2.min.z;
    }
    public static float XZDistance(this Bounds bound, Vector3 vec)
    {
        Vector3 v = (bound.center - vec).Abs();
        Vector3 u = v - bound.extents;
        if (u.x > 0 && u.z > 0)
            return Mathf.Sqrt(u.x * u.x + u.z * u.z);
        return Mathf.Max(u.x, u.z);
    }
    public static bool XZIntersects(this Bounds bound, Vector3 center, float radius)
    {
        Vector3 extents = new Vector3(radius, 0, radius);
        Vector3 max = center + extents;
        Vector3 min = center - extents;
        return bound.min.x <= max.x && bound.max.x >= min.x && bound.min.z <= max.z && bound.max.z >= min.z;
    }
    #endregion
    #endregion
    #region 3D坐标系内
    #region 胶囊体
    public static bool Intersects(this ICapsule capsule1, ICapsule capsule2)
    {
        Vector3Extension.GetCommonPerpendicular(capsule1.point1, capsule1.point2, capsule2.point1, capsule2.point2, out Vector3 point1, out Vector3 point2);
        return IntersectsCircle(point1, capsule1.radius, point2, capsule2.radius);
    }
    /// <summary>
    /// 其中一个转化为圆进行判断
    /// </summary> 
    public static bool Intersects(this ICapsule capsule, ICircle circle)
    {
        Vector3 newCenter = circle.center.GetProjectionOnLine(capsule.point1, capsule.point2);
        return IntersectsCircle(circle.center, circle.radius, newCenter, capsule.radius);
    }

    public static bool Intersects(this ICapsule capsule, ICube cube)
    {
        return capsule.Intersects(cube.bounds);
    }

    public static bool Intersects(this ICapsule capsule, IMyCollider collider)
    {
        return capsule.Intersects(collider.bounds);
    }

    public static bool Intersects(this ICapsule capsule, Bounds bound)
    {
        Vector3 newCenter = bound.center.GetProjectionOnLine(capsule.point1, capsule.point2);
        return new Circle { center = newCenter, radius = capsule.radius }.Intersects(bound);
    }

    public static float Distance(this ICapsule capsule, Vector3 vec)
    {
        Vector3 newCenter = vec.GetProjectionOnLine(capsule.point1, capsule.point2);
        return new Circle { center = newCenter, radius = capsule.radius }.Distance(vec);
    }
    #endregion
    #region 球体
    /// <summary>球体碰撞 </summary>
    public static bool Intersects(this ICircle circle1, ICircle circle2)
    {
        return IntersectsCircle(circle1.center, circle1.radius, circle2.center, circle2.radius);
    }
    public static bool Intersects(this ICircle circle, ICube cube)
    {
        return circle.Intersects(cube.bounds);
    }
    public static bool Intersects(this ICircle circle, IMyCollider collider)
    {
        return circle.Intersects(collider.bounds);
    }
    public static bool Intersects(this ICircle circle, Bounds bound)
    {
        Vector3 v = (circle.center - bound.center).Abs();
        Vector3 u = (v - bound.extents).ClampMin(0);
        return Vector3.Dot(u, u) <= circle.radius * circle.radius;
    }
    public static float Distance(this ICircle circle, Vector3 vec)
    {
        Vector3 v = circle.center - vec;
        return v.magnitude - circle.radius;
    }
    /// <summary> 计算球体碰撞</summary>
    public static bool IntersectsCircle(Vector3 center1, float radius1, Vector3 center2, float radius2)
    {
        Vector3 vec = center1 - center2;
        return Vector3.Dot(vec, vec) <= (radius1 + radius2) * (radius1 + radius2);
    }
    #endregion
    #region 方形
    public static bool Intersects(this ICube cube, ICube cube2)
    {
        return cube.Intersects(cube2.bounds);
    }
    public static bool Intersects(this ICube cube, IMyCollider collider)
    {
        return cube.Intersects(collider.bounds);
    }
    public static bool Intersects(this ICube cube, Bounds bound)
    {
        return cube.bounds.Intersects(bound);
    }
    public static float Distance(this ICube cube, Vector3 vec)
    {
        return cube.bounds.Distance(vec);
    }
    #endregion
    public static float Distance(this Bounds bound, Vector3 vec)
    {
        Vector3 v = vec - bound.center;
        v.x = (Mathf.Abs(v.x));
        v.y = (Mathf.Abs(v.y));
        v.z = (Mathf.Abs(v.z));
        Vector3 u = v - bound.extents;
        int i = 0;
        i += v.x >= 0 ? 1 : 0;
        i += v.y >= 0 ? 1 : 0;
        i += v.z >= 0 ? 1 : 0;
        if (i < 2)
            return Mathf.Max(v.x, v.y, v.z);

        float dis = 0;
        dis += Mathf.Pow(Mathf.Max(v.x, 0), 2);
        dis += Mathf.Pow(Mathf.Max(v.y, 0), 2);
        dis += Mathf.Pow(Mathf.Max(v.z, 0), 2);
        return Mathf.Sqrt(dis);
    }

    #endregion
}
  • 4
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
第1天: 今天是我的第一天实习,来到了公司后,我先跟导师进行了一次简单的面谈,介绍了我的背景和学习情况,并且了解了一些公司的运作情况。然后我的导师分配给我一个小项目,让我熟悉Unity的基本操作和开发流程。我开始学习如何创建场景、添加对象、调整其属性以及如何运行场景。此外,我还学习了如何添加脚本并与对象进行交互,比如如何实现对象的移动和旋转。 第2-5天: 在过去的几天里,我继续学习了Unity的基本操作和开发流程,并进一步学习了如何使用C#编写脚本来实现一些基本的游戏功能,例如:玩家的移动、碰撞检测和触发器等。我还学习了如何在场景中创建和管理物体,以及如何使用Unity的内置编辑器来制作简单的材质和贴图。除此之外,我还在网上查阅了一些教程和资料,以加深对Unity的理解和熟练度。 第6-10天: 在这几天,我主要是负责开发一个简单的2D游戏,这个游戏需要玩家通过躲避障碍物来获取分数。我需要实现游戏的基本逻辑和玩家的控制,同时使用Unity的内置编辑器来设计和创建游戏场景。在这个过程中,我学会了如何使用Unity的动画系统来实现游戏中的角色动画,以及如何使用粒子系统和声音效果来增强游戏的真实感。 第11-15天: 在这几天里,我开始学习如何使用Unity的网络功能来实现多人游戏,以及如何使用Unity物理引擎来模拟真实的物理效果。我还学习了如何使用Unity的UI系统来设计和创建游戏的用户界面,并使用C#编写脚本来实现游戏的逻辑和交互。同时,我还学习了如何使用Git来进行代码管理和版本控制。 第16-20天: 在这几天里,我开始着手开发一个更加复杂的3D游戏,这个游戏需要实现更多的功能和效果。我需要实现玩家的移动和攻击、敌人的AI和动画、各种特效和音效等等。同时,我也需要对游戏进行优化,以确保游戏的性能和流畅度。在这个过程中,我不断地调试和测试游戏,确保它的质量和稳定性,并通过与导师的沟通和交流,不断地改进和完善游戏的设计和代码。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

KamikazePilot

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值