Beispiel #1
0
        private void GetHitEntityAndPosition(LineD line, out IMyEntity entity, out MyHitInfo hitInfoRet, out object customdata)
        {
            entity     = null;
            hitInfoRet = new MyHitInfo();
            customdata = null;

            // 1. rough raycast
            int raycastListIndex = 0;

            do
            {
                if (entity == null)
                {
                    if (raycastListIndex == 0) // cast only the first iteration
                    {
                        ProfilerShort.Begin("MyGamePruningStructure::CastProjectileRay");
                        MyPhysics.CastRay(line.From, line.To, m_raycastResult,
                                          MyPhysics.CollisionLayers.DefaultCollisionLayer);
                        ProfilerShort.End();
                    }

                    if (raycastListIndex < m_raycastResult.Count)
                    {
                        MyPhysics.HitInfo hitInfo = m_raycastResult[raycastListIndex];

                        entity = hitInfo.HkHitInfo.GetHitEntity() as MyEntity;
                        hitInfoRet.Position = hitInfo.Position;
                        hitInfoRet.Normal   = hitInfo.HkHitInfo.Normal;
                        hitInfoRet.ShapeKey = hitInfo.HkHitInfo.GetShapeKey(0);
                    }
                }

                // 2. prevent shooting through characters, retest trajectory between entity and player
                if (!(entity is MyCharacter) || entity == null)
                {
                    // first: raycast, get all entities in line, limit distance if possible
                    LineD lineLimited = new LineD(line.From, entity == null ? line.To : hitInfoRet.Position);
                    if (m_entityRaycastResult == null)
                    {
                        m_entityRaycastResult = new List <MyLineSegmentOverlapResult <MyEntity> >(16);
                    }
                    else
                    {
                        m_entityRaycastResult.Clear();
                    }
                    MyGamePruningStructure.GetAllEntitiesInRay(ref lineLimited, m_entityRaycastResult);
                    // second: precise tests, find best result
                    double    bestDistanceSq = double.MaxValue;
                    IMyEntity entityBest     = null;
                    for (int i = 0; i < m_entityRaycastResult.Count; i++)
                    {
                        if (m_entityRaycastResult[i].Element is MyCharacter)
                        {
                            MyCharacter hitCharacter = m_entityRaycastResult[i].Element as MyCharacter;
                            bool        intersection = hitCharacter.GetIntersectionWithLine(ref line, ref m_charHitInfo);
                            if (intersection)
                            {
                                double distanceSq =
                                    Vector3D.DistanceSquared(m_charHitInfo.Triangle.IntersectionPointInWorldSpace,
                                                             line.From);
                                if (distanceSq < bestDistanceSq && !IsIgnoredEntity(hitCharacter))
                                {
                                    bestDistanceSq      = distanceSq;
                                    entityBest          = hitCharacter;
                                    hitInfoRet.Position = m_charHitInfo.Triangle.IntersectionPointInWorldSpace;
                                    hitInfoRet.Normal   = m_charHitInfo.Triangle.NormalInWorldSpace;
                                    customdata          = m_charHitInfo;
                                }
                            }
                        }
                    }
                    // finally: do we have best result? then return it
                    if (entityBest != null)
                    {
                        entity = entityBest;
                        return; // this was precise result, so return
                    }
                }

                // 3. nothing found in the precise test? then fallback to already found results
                if (entity == null)
                {
                    return;                // no fallback results
                }
                if (entity is MyCharacter) // retest character found in fallback
                {
                    MyCharacter hitCharacter = entity as MyCharacter;
                    bool        intersection = hitCharacter.GetIntersectionWithLine(ref line, ref m_charHitInfo);
                    if (intersection)
                    {
                        hitInfoRet.Position = m_charHitInfo.Triangle.IntersectionPointInWorldSpace;
                        hitInfoRet.Normal   = m_charHitInfo.Triangle.NormalInWorldSpace;
                        customdata          = m_charHitInfo;
                    }
                    else
                    {
                        entity = null; // no hit.
                    }
                }
                else
                {
                    MyCubeGrid grid = entity as MyCubeGrid;
                    if (grid != null)
                    {
                        bool success = grid.GetIntersectionWithLine(ref line, ref m_cubeGridHitInfo);
                        if (success)
                        {
                            hitInfoRet.Position = m_cubeGridHitInfo.Triangle.IntersectionPointInWorldSpace;
                            hitInfoRet.Normal   = m_cubeGridHitInfo.Triangle.NormalInWorldSpace;
                            if (Vector3.Dot(hitInfoRet.Normal, line.Direction) > 0)
                            {
                                hitInfoRet.Normal = -hitInfoRet.Normal;
                            }

                            customdata = m_cubeGridHitInfo;
                        }

                        MyHitInfo info = new MyHitInfo();
                        info.Position = hitInfoRet.Position;
                        info.Normal   = hitInfoRet.Normal;
                    }

                    MyVoxelBase voxel = entity as MyVoxelBase;
                    if (voxel != null)
                    { //get accurate hit because of particles and decals
                        MyIntersectionResultLineTriangleEx?res;
                        if (voxel.GetIntersectionWithLine(ref line, out res, IntersectionFlags.DIRECT_TRIANGLES))
                        {
                            hitInfoRet.Position = res.Value.IntersectionPointInWorldSpace;
                            hitInfoRet.Normal   = res.Value.NormalInWorldSpace;
                            hitInfoRet.ShapeKey = 0;
                        }
                    }
                }
            } while (entity == null && ++raycastListIndex < m_entityRaycastResult.Count);
        }
Beispiel #2
0
        private void GetHitEntityAndPosition(LineD line, out IMyEntity entity, out Vector3D hitPosition, out Vector3 hitNormal, out bool hitHead)
        {
            entity      = null;
            hitPosition = hitNormal = Vector3.Zero;
            hitHead     = false;

            // 1. rough raycast
            if (entity == null)
            {
                ProfilerShort.Begin("MyGamePruningStructure::CastProjectileRay");
                MyPhysics.HitInfo?hitInfo = MyPhysics.CastRay(line.From, line.To, MyPhysics.CollisionLayers.DefaultCollisionLayer);
                ProfilerShort.End();
                if (hitInfo.HasValue)
                {
                    entity      = hitInfo.Value.HkHitInfo.GetHitEntity() as MyEntity;
                    hitPosition = hitInfo.Value.Position;
                    hitNormal   = hitInfo.Value.HkHitInfo.Normal;
                }
            }

            // 2. prevent shooting through characters, retest trajectory between entity and player
            if (!(entity is MyCharacter) || entity == null)
            {
                // first: raycast, get all entities in line, limit distance if possible
                LineD lineLimited = new LineD(line.From, entity == null ? line.To : hitPosition);
                if (m_entityRaycastResult == null)
                {
                    m_entityRaycastResult = new List <MyLineSegmentOverlapResult <MyEntity> >(16);
                }
                else
                {
                    m_entityRaycastResult.Clear();
                }
                MyGamePruningStructure.GetAllEntitiesInRay(ref lineLimited, m_entityRaycastResult);
                // second: precise tests, find best result
                double    bestDistanceSq = double.MaxValue;
                IMyEntity entityBest     = null;
                for (int i = 0; i < m_entityRaycastResult.Count; i++)
                {
                    if (m_entityRaycastResult[i].Element is MyCharacter)
                    {
                        MyCharacter hitCharacter = m_entityRaycastResult[i].Element as MyCharacter;
                        VRage.Game.Models.MyIntersectionResultLineTriangleEx?t;
                        hitCharacter.GetIntersectionWithLine(ref line, out t, out hitHead);

                        if (t != null)
                        {
                            double distanceSq = Vector3D.DistanceSquared(t.Value.IntersectionPointInWorldSpace, line.From);
                            if (distanceSq < bestDistanceSq)
                            {
                                bestDistanceSq = distanceSq;
                                entityBest     = hitCharacter;
                                hitPosition    = t.Value.IntersectionPointInWorldSpace;
                                hitNormal      = t.Value.NormalInWorldSpace;
                            }
                        }
                    }
                }
                // finally: do we have best result? then return it
                if (entityBest != null)
                {
                    entity = entityBest;
                    return; // this was precise result, so return
                }
            }

            // 3. nothing found in the precise test? then fallback to already found results
            if (entity == null)
            {
                return;                // no fallback results
            }
            if (entity is MyCharacter) // retest character found in fallback
            {
                MyCharacter hitCharacter = entity as MyCharacter;
                VRage.Game.Models.MyIntersectionResultLineTriangleEx?t;
                hitCharacter.GetIntersectionWithLine(ref line, out t, out hitHead);
                if (t == null)
                {
                    entity = null; // no hit.
                }
                else
                {
                    hitPosition = t.Value.IntersectionPointInWorldSpace;
                    hitNormal   = t.Value.NormalInWorldSpace;
                    hitHead     = hitHead && m_projectileAmmoDefinition.HeadShot; // allow head shots only for ammo supporting it in definition
                }
            }
            else
            {
                MyCubeGrid grid = entity as MyCubeGrid;
                if (grid != null)
                {
                    MyIntersectionResultLineTriangleEx?result;
                    bool success = grid.GetIntersectionWithLine(ref line, out result);
                    if (success)
                    {
                        hitPosition = result.Value.IntersectionPointInWorldSpace;
                        hitNormal   = result.Value.NormalInWorldSpace;
                    }

                    MyHitInfo info = new MyHitInfo();
                    info.Position = hitPosition;
                    info.Normal   = hitNormal;
                }
            }
        }