zoukankan      html  css  js  c++  java
  • 43. GameProject8 + 碰撞检测

    第一个新文件是BoundingGeometry.h头文件。该头文件包含了3个类和两个函数。第一个类是边界几何图形基类,创建其他边界几何图形时可以从该类派生。第二个类是边界框类,第三个是边界球类。头文件中的两个函数分别是BoxToBoxIntersect()和SphereToSphereIntersect()。这两个函数分别用于检测两个方框和两个球体之间的碰撞。

    每个类中的成员函数分别是CreateFromPoints()、isPointInside()、两个Intersect()、GetPlanes()和isRayInside()。在创建涉及的边界几何图形时,会用到CreateFromPoints()函数。isPointInside()函数和本章演示程序中创建的OnCollision()函数很相似,用于测试一个点是否和一个边界几何图形发生碰撞。从根本上讲,这两个Intersect()函数就是OnCollision()函数,但它们是通过射线检测的。GetPlanes()函数只有在边界框类中才用到,它计算每个框边外的平面(6个平面)。最后一个函数isRayInside()用于查看射线是否真的在边界几何图形中。要记住:射线是无界的,为了和有界物体发生碰撞,射线不必在该对象内部。只要在沿着射线方向的某个位置上射线碰撞到物体,就表示射线与物体发生了碰撞。

    BoundingGeometry.h头文件的完整代码

    #ifndef _UGP_BOUNDINGGEOMETRY_H_
    #define _UGP_BOUNDINGGEOMETRY_H_


    #include
    "MathLibrary.h"



    // 边界几何图形基类
    class CBoundingBase
    {
    public:
    CBoundingBase(){}
    virtual ~CBoundingBase() {}

    virtual void CreateFromPoints(CVector3 *pointList, int numPoints) = 0;

    // 测试一个点是否和一个边界几何图形发生碰撞
    virtual bool isPointInside(CVector3 &v) = 0;

    virtual bool Intersect(CRay ray, float *dist) = 0;
    virtual bool Intersect(CRay ray, float length, float *dist) = 0;

    // 计算每个框边外的平面(6个平面)
    virtual void GetPlanes(CPlane *planes) = 0;

    // 查看射线是否真的在边界几何图形中
    virtual bool isRayInside(CRay &ray, float length) = 0;
    };



    // 边界框类
    class CBoundingBox : public CBoundingBase
    {
    public:
    CBoundingBox() {}
    ~CBoundingBox() {}

    void CreateFromPoints(CVector3 *pointList, int numPoints);
    bool isPointInside(CVector3 &v);

    bool Intersect(CRay ray, float *dist);
    bool Intersect(CRay ray, float length, float *dist);

    void GetPlanes(CPlane *planes);
    bool isRayInside(CRay &ray, float length);

    CVector3 m_min, m_max;
    };



    // 边界球
    class CBoundingSphere : public CBoundingBase
    {
    public:
    CBoundingSphere() : m_radius(
    0) {}
    ~CBoundingSphere() {}

    void CreateFromPoints(CVector3 *pointList, int numPoints);
    bool isPointInside(CVector3 &v);

    bool Intersect(CRay ray, float *dist);
    bool Intersect(CRay ray, float length, float *dist);

    void GetPlanes(CPlane *planes) {}
    bool isRayInside(CRay &ray, float length);

    CVector3 m_center;
    float m_radius;
    };


    // 检测两个方框之间的碰撞
    bool BoxToBoxIntersect(CBoundingBox &bb1, CBoundingBox &bb2);

    // 检测两个球体之间的碰撞
    bool SphereToSphereIntersect(CBoundingSphere &bs1, CBoundingSphere &bs2);

    #endif

      

    BoundingGeometry.cpp

    /*
    Demo Name: Game Project 8
    Author: Allen Sherrod
    Chapter: Chapter 9
    */


    #include
    "BoundingGeometry.h"


    void CBoundingBox::CreateFromPoints(CVector3 *pointList, int numPoints)
    {
    // Loop through all of the points to find the min/max values.
    for(int i = 0; i < numPoints; i++)
    {
    if(pointList[i].x < m_min.x) m_min.x = pointList[i].x;
    if(pointList[i].x > m_max.x) m_max.x = pointList[i].x;

    if(pointList[i].y < m_min.y) m_min.y = pointList[i].y;
    if(pointList[i].y > m_max.y) m_max.y = pointList[i].y;

    if(pointList[i].z < m_min.z) m_min.z = pointList[i].z;
    if(pointList[i].z > m_max.z) m_max.z = pointList[i].z;
    }
    }


    bool CBoundingBox::isPointInside(CVector3 &v)
    {
    if(m_max.x <= v.x) return false;
    if(m_min.x >= v.x) return false;
    if(m_max.y <= v.y) return false;
    if(m_min.y >= v.y) return false;
    if(m_max.z <= v.z) return false;
    if(m_min.z >= v.z) return false;

    return true;
    }


    bool CBoundingBox::Intersect(CRay ray, float *dist)
    {
    float t0, t1, temp;
    float min = -999999.9f;
    float max = 999999.9f;

    // 若射线在y,z轴组成的平面上,则只需判断x坐标
    if(fabs(ray.m_direction.x) < 0.00001f)
    {
    if((ray.m_origin.x < m_min.x) || (ray.m_origin.x > m_max.x))
    return false;
    }

    // 检查x轴方向上是否满足相交的条件
    t0 = (m_min.x - ray.m_origin.x) / ray.m_direction.x;
    t1
    = (m_max.x - ray.m_origin.x) / ray.m_direction.x;

    if(t0 > t1) { temp = t0; t0 = t1; t1 = temp; }
    if(t0 > min) min = t0;
    if(t1 < max) max = t1;
    if(min > max) return false;
    if(max < 0) return false;


    //// 若射线在x,z轴组成的平面上,则只需判断y坐标
    if(fabs(ray.m_direction.y) < 0.00001f)
    {
    if((ray.m_origin.y < m_min.y) ||
    (ray.m_origin.y
    > m_max.y)) return false;
    }

    t0
    = (m_min.y - ray.m_origin.y) / ray.m_direction.y;
    t1
    = (m_max.y - ray.m_origin.y) / ray.m_direction.y;

    if(t0 > t1) { temp = t0; t0 = t1; t1 = temp; }
    if(t0 > min) min = t0;
    if(t1 < max) max = t1;
    if(min > max) return false;
    if(max < 0) return false;


    //// 若射线在x,y轴组成的平面上,则只需判断z坐标
    if(fabs(ray.m_direction.z) < 0.00001f)
    {
    if((ray.m_origin.z < m_min.z) ||
    (ray.m_origin.z
    > m_max.z)) return false;
    }

    t0
    = (m_min.z - ray.m_origin.z) / ray.m_direction.z;
    t1
    = (m_max.z - ray.m_origin.z) / ray.m_direction.z;

    if(t0 > t1) { temp = t0; t0 = t1; t1 = temp; }
    if(t0 > min) min = t0;
    if(t1 < max) max = t1;
    if(min > max) return false;
    if(max < 0) return false;


    if(min > 0)
    if(dist)
    *dist = min;
    else if(dist)
    *dist = max;

    return true;
    }


    bool CBoundingBox::Intersect(CRay ray, float length, float *dist)
    {
    float t0, t1, temp;
    float min = -999999.9f;
    float max = 999999.9f;
    float d = 0;

    if(fabs(ray.m_direction.x) < 0.00001f)
    {
    if((ray.m_origin.x < m_min.x) ||
    (ray.m_origin.x
    > m_max.x)) return false;
    }

    t0
    = (m_min.x - ray.m_origin.x) / ray.m_direction.x;
    t1
    = (m_max.x - ray.m_origin.x) / ray.m_direction.x;

    if(t0 > t1) { temp = t0; t0 = t1; t1 = temp; }
    if(t0 > min) min = t0;
    if(t1 < max) max = t1;
    if(min > max) return false;
    if(max < 0) return false;


    if(fabs(ray.m_direction.y) < 0.00001f)
    {
    if((ray.m_origin.y < m_min.y) ||
    (ray.m_origin.y
    > m_max.y)) return false;
    }

    t0
    = (m_min.y - ray.m_origin.y) / ray.m_direction.y;
    t1
    = (m_max.y - ray.m_origin.y) / ray.m_direction.y;

    if(t0 > t1) { temp = t0; t0 = t1; t1 = temp; }
    if(t0 > min) min = t0;
    if(t1 < max) max = t1;
    if(min > max) return false;
    if(max < 0) return false;


    if(fabs(ray.m_direction.z) < 0.00001f)
    {
    if((ray.m_origin.z < m_min.z) ||
    (ray.m_origin.z
    > m_max.z)) return false;
    }

    t0
    = (m_min.z - ray.m_origin.z) / ray.m_direction.z;
    t1
    = (m_max.z - ray.m_origin.z) / ray.m_direction.z;

    if(t0 > t1) { temp = t0; t0 = t1; t1 = temp; }
    if(t0 > min) min = t0;
    if(t1 < max) max = t1;
    if(min > max) return false;
    if(max < 0) return false;

    if(min > 0) d = min;
    else d = max;

    if(d > length) return false;
    if(dist) *dist = d;

    return true;
    }


    void CBoundingBox::GetPlanes(CPlane *planes)
    {
    // Right.
    planes[0].a = 1.0f; planes[0].b = 0.0f; planes[0].c = 0.0f;
    planes[
    0].d = -(1 * m_max.x + 0 * m_max.y + 0 * m_max.z);

    // Left.
    planes[1].a = -1.0f; planes[1].b = 0.0f; planes[1].c = 0.0f;
    planes[
    1].d = -(-1 * m_min.x + 0 * m_min.y + 0 * m_min.z);

    // Front.
    planes[2].a = 0.0f; planes[2].b = 0.0f; planes[2].c = -1.0f;
    planes[
    2].d = -(0 * m_min.x + 0 * m_min.y + -1 * m_min.z);

    // Back.
    planes[3].a = 0.0f; planes[3].b = 0.0f; planes[3].c = 1.0f;
    planes[
    3].d = -(0 * m_max.x + 0 * m_max.y + 1 * m_max.z);

    // Top.
    planes[4].a = 0.0f; planes[4].b = 1.0f; planes[4].c = 0.0f;
    planes[
    4].d = -(0 * m_max.x + 1 * m_max.y + 0 * m_max.z);

    // Bottom.
    planes[5].a = 0.0f; planes[5].b = -1.0f; planes[5].c = 0.0f;
    planes[
    5].d = -(0 * m_min.x + -1 * m_min.y + 0 * m_min.z);
    }


    bool CBoundingBox::isRayInside(CRay &ray, float length)
    {
    CVector3 endPos
    = ray.m_origin + (ray.m_direction * length);
    return (isPointInside(ray.m_origin) && isPointInside(endPos));
    }


    void CBoundingSphere::CreateFromPoints(CVector3 *pointList, int numPoints)
    {
    CVector3 min, max;
    float dist = 0, maxDistance = 0.0f;

    // Loop through all of the points to find the min/max values.
    for(int i = 0; i < numPoints; i++)
    {
    if(pointList[i].x < min.x) min.x = pointList[i].x;
    if(pointList[i].x > max.x) max.x = pointList[i].x;

    if(pointList[i].y < min.y) min.y = pointList[i].y;
    if(pointList[i].y > max.y) max.y = pointList[i].y;

    if(pointList[i].z < min.z) min.z = pointList[i].z;
    if(pointList[i].z > max.z) max.z = pointList[i].z;
    }

    m_center
    = (max + min) * 0.5f;

    // Find max distance.
    for(i = 0; i < numPoints; i++)
    {
    dist
    = ((pointList[i].x - m_center.x) * (pointList[i].x - m_center.x)) +
    ((pointList[i].y
    - m_center.y) * (pointList[i].y - m_center.y)) +
    ((pointList[i].z
    - m_center.z) * (pointList[i].z - m_center.z));

    if(dist > maxDistance)
    maxDistance
    = dist;
    }

    // Calculate radius.
    m_radius = sqrt(maxDistance);
    }


    bool CBoundingSphere::isPointInside(CVector3 &v)
    {
    // The distance between the two spheres.
    CVector3 intersect = m_center - v;

    // Test for collision.
    if(sqrt(intersect.x * intersect.x + intersect.y * intersect.y +
    intersect.z
    * intersect.z) < m_radius)
    return true;

    return false;
    }


    bool CBoundingSphere::Intersect(CRay ray, float *dist)
    {
    CVector3 RayToSphereDir;

    float RayToSphereLength = 0.0f;
    float IntersectPoint = 0.0f;
    float SquaredPoint = 0.0f;

    // Get the direction of the ray to the object.
    RayToSphereDir = m_center - ray.m_origin;

    // Dot product the direction of the ray to current sphere to get the length.
    RayToSphereLength = RayToSphereDir.DotProduct3(RayToSphereDir);

    // Find intersect distance.
    IntersectPoint = RayToSphereDir.DotProduct3(ray.m_direction);

    // If true, no collision.
    if(IntersectPoint < 0 ) return false;

    // Get the squared sphere intersect distance.
    SquaredPoint = (m_radius * m_radius) - RayToSphereLength +
    (IntersectPoint
    * IntersectPoint);

    // If true, no collision.
    if(SquaredPoint < 0) return false;

    // Else it does hit the sphere and we record the results.
    if(dist) *dist = IntersectPoint - (float)sqrt(SquaredPoint);

    return true;
    }


    bool CBoundingSphere::Intersect(CRay ray, float length, float *dist)
    {
    CVector3 RayToSphereDir;

    float RayToSphereLength = 0.0f;
    float IntersectPoint = 0.0f;
    float SquaredPoint = 0.0f;

    // Get the direction of the ray to the object.
    RayToSphereDir = m_center - ray.m_origin;

    // Dot product the direction of the ray to current sphere to get the length.
    RayToSphereLength = RayToSphereDir.DotProduct3(RayToSphereDir);

    // Find intersect distance.
    IntersectPoint = RayToSphereDir.DotProduct3(ray.m_direction);

    // If true, no collision.
    if(IntersectPoint < 0 ) return false;

    // Get the squared sphere intersect distance.
    SquaredPoint = (m_radius * m_radius) - RayToSphereLength +
    (IntersectPoint
    * IntersectPoint);

    // If true, no collision.
    if(SquaredPoint < 0) return false;

    // Calculate intersection distance.
    float d = IntersectPoint - (float)sqrt(SquaredPoint);

    // If distance is > than the length of the ray return false.
    if(d > length) return false;

    // Else it does hit the sphere and we record the results.
    if(dist) *dist = d;

    return true;
    }


    bool CBoundingSphere::isRayInside(CRay &ray, float length)
    {
    CVector3 endPos
    = ray.m_origin + (ray.m_direction * length);
    return (isPointInside(ray.m_origin) && isPointInside(endPos));
    }


    bool BoxToBoxIntersect(CBoundingBox &bb1, CBoundingBox &bb2)
    {
    if((bb1.m_min.x > bb2.m_max.x) || (bb2.m_min.x > bb1.m_max.x))
    return false;
    if((bb1.m_min.y > bb2.m_max.y) || (bb2.m_min.y > bb1.m_max.y))
    return false;
    if((bb1.m_min.z > bb2.m_max.z) || (bb2.m_min.z > bb1.m_max.z))
    return false;

    return true;
    }


    bool SphereToSphereIntersect(CBoundingSphere &bs1, CBoundingSphere &bs2)
    {
    // The distance between the two spheres.
    CVector3 intersect = bs1.m_center - bs2.m_center;

    // Test for collision.
    if(sqrt(intersect.x * intersect.x + intersect.y * intersect.y +
    intersect.z
    * intersect.z) < bs1.m_radius + bs2.m_radius)
    return true;

    return false;
    }

      

    游戏项目中的最后一个改动是在MathLibrary.h头文件中添加边界几何图形类和头文件。将信息添加到该头文件中,这样就可以访问整个游戏引擎和游戏组件。

    #ifndef _UGP_MATH_LIBRARY_H_
    #define _UGP_MATH_LIBRARY_H_


    #include
    "Vector.h" // 向量相关
    #include"Matrix.h" // 矩阵相关
    #include"Quaternion.h" // 四元组相关
    #include"Physics.h" // 物理学相关

    class CRay; // 射线类
    class CBoundingBox; // 边界框类
    class CBoundingSphere; // 边界球类
    class CPlane; // 平面类
    class CPolygon; // 多边形类

    #include
    "Ray.h"
    #include
    "BoundingGeometry.h"
    #include
    "Plane.h"
    #include
    "Polygon.h"
    #include
    "MathDefines.h"


    #endif

      

  • 相关阅读:
    sourceInsight4 破解笔记(完美破解)
    notepad++ 查找引用(Find Reference)(适用于c c++及各类脚本比如lua、python等)
    notepad++ 插件推荐——快速定位文件
    WebRTC开源项目一览之二
    编译最新版webrtc源码和编译好的整个项目10多个G【分享】
    Neo4j中实现自定义中文全文索引
    NEO4J -模糊查询
    neo4j数据库迁移---------Neo4j数据库导入导出的方法
    使用neo4j图数据库的import工具导入数据 -方法和注意事项
    neo4j采坑记
  • 原文地址:https://www.cnblogs.com/kex1n/p/2176741.html
Copyright © 2011-2022 走看看