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); }
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; } } }