public void GetFracturesInSphere(ref BoundingSphereD searchSphere, ref List <MyFracturedPiece> output) { var activeFractures = m_piecesTimesOfDeath.Keys; HkShape shape = new HkSphereShape((float)searchSphere.Radius); try { MyPhysics.GetPenetrationsShape(shape, ref searchSphere.Center, ref Quaternion.Identity, m_rigidList, MyPhysics.CollisionLayers.NotCollideWithStaticLayer); foreach (var rigidBody in m_rigidList) { var fracture = rigidBody.GetCollisionEntity() as MyFracturedPiece; if (fracture != null) { output.Add(fracture); } } } finally { m_rigidList.Clear(); shape.RemoveReference(); } }
public static Vector3D?FindFreePlace(Vector3D basePos, float radius, int maxTestCount = 40, int testsPerDistance = 6, float stepSize = 1f, float radiusIncrement = 10f, MyEntity ignoreEnt = null) { Vector3D position = basePos; Quaternion rotation = Quaternion.Identity; HkShape shape = new HkSphereShape(radius); try { if (MyEntities.IsInsideWorld(position) && !MyEntities.IsShapePenetrating(shape, ref position, ref rotation, 15, ignoreEnt)) { BoundingSphereD sphere = new BoundingSphereD(position, radius); MyVoxelBase overlappingWithSphere = MySession.Static.VoxelMaps.GetOverlappingWithSphere(ref sphere); if (overlappingWithSphere == null) { return(position); } if (overlappingWithSphere is MyPlanet) { (overlappingWithSphere as MyPlanet).CorrectSpawnLocation(ref basePos, radius); } return(basePos); } int num = (int)Math.Ceiling((float)maxTestCount / (float)testsPerDistance); float num2 = 0f; for (int i = 0; i < num; i++) { num2 += radius * stepSize + radiusIncrement; for (int j = 0; j < testsPerDistance; j++) { position = basePos + MyUtils.GetRandomVector3Normalized() * num2; if (MyEntities.IsInsideWorld(position) && !MyEntities.IsShapePenetrating(shape, ref position, ref rotation, 15, ignoreEnt)) { BoundingSphereD sphere2 = new BoundingSphereD(position, radius); MyVoxelBase overlappingWithSphere2 = MySession.Static.VoxelMaps.GetOverlappingWithSphere(ref sphere2); if (overlappingWithSphere2 == null) { return(position); } if (overlappingWithSphere2 is MyPlanet) { (overlappingWithSphere2 as MyPlanet).CorrectSpawnLocation(ref basePos, radius); } } } } return(null); } finally { shape.RemoveReference(); } }
private bool CreateOwnerVirtualPhysics() { if (Owner == null) { return(false); } OwnerVirtualPhysics = new MyCharacterVirtualPhysicsBody(Owner, RigidBodyFlag.RBF_KINEMATIC); var massProperties = HkInertiaTensorComputer.ComputeSphereVolumeMassProperties(0.1f, MyPerGameSettings.Destruction ? MyDestructionHelper.MassToHavok(Owner.Definition.Mass) : Owner.Definition.Mass); HkShape sh = new HkSphereShape(0.1f); OwnerVirtualPhysics.InitialSolverDeactivation = HkSolverDeactivation.Off; MatrixD headWorldMatrix = Owner.GetHeadMatrix(false, forceHeadBone: true); OwnerVirtualPhysics.CreateFromCollisionObject(sh, Vector3.Zero, headWorldMatrix, massProperties, Sandbox.Engine.Physics.MyPhysics.NoCollisionLayer); OwnerVirtualPhysics.RigidBody.EnableDeactivation = false; // Character ray casts includes also NoCollision layer shapes so setup property for ignoring the body OwnerVirtualPhysics.RigidBody.SetProperty(HkCharacterRigidBody.MANIPULATED_OBJECT, 0); sh.RemoveReference(); OwnerVirtualPhysics.Enabled = true; return(true); }
/// <summary> /// Handles camera collisions with environment /// </summary> /// <param name="controlledEntity"></param> /// <param name="shakeActive"></param> /// <param name="headPosition"></param> /// <param name="headDirection"></param> /// <returns>False if no correct position was found</returns> private bool HandleIntersection(MyEntity controlledEntity, MyOrientedBoundingBoxD safeOBB, bool requireRaycast, bool shakeActive, Vector3D headPosition, Vector3 headDirection) { var line = new LineD(m_target, m_position); var safeOBBLine = new LineD(line.From, line.From + line.Direction * 2 * safeOBB.HalfExtent.Length()); Vector3D castStartSafe; { MyOrientedBoundingBoxD safeObbWithCollisionExtents = new MyOrientedBoundingBoxD(safeOBB.Center, safeOBB.HalfExtent + 2 * CAMERA_RADIUS, safeOBB.Orientation); double? safeIntersection = safeObbWithCollisionExtents.Intersects(ref safeOBBLine); if (!safeIntersection.HasValue) safeIntersection = safeOBB.HalfExtent.Length(); double safeDistance = safeIntersection.Value; castStartSafe = line.From + line.Direction * safeDistance; } { double? unsafeIntersection = safeOBB.Intersects(ref safeOBBLine); if (!requireRaycast && unsafeIntersection.HasValue) { var castStartUnsafe = line.From + line.Direction * unsafeIntersection.Value; var castEndUnsafe = castStartSafe + line.Direction; // short raycast, not causing problems with asteroids generating geometry Physics.MyPhysics.CastRay(castStartUnsafe, castEndUnsafe, m_raycastList, MyPhysics.DefaultCollisionLayer); if (!IsRaycastOK(m_raycastList)) { return false; } } } if (requireRaycast) { // short raycast, not causing problems with asteroids generating geometry Physics.MyPhysics.CastRay(line.From, castStartSafe + line.Direction, m_raycastList, MyPhysics.DefaultCollisionLayer); if (!IsRaycastOK(m_raycastList)) { return false; } } HkShape shape = new HkSphereShape(CAMERA_RADIUS); try { // small shape, not causing problems with asteroids generating geometry Physics.MyPhysics.GetPenetrationsShape(shape, ref castStartSafe, ref Quaternion.Identity, m_rigidList, 15); if (m_rigidList.Count > 0) { bool sameGrid = false; if (MySession.ControlledEntity != null && m_rigidList[0].Body != null) { sameGrid = m_rigidList[0].GetCollisionEntity() == MySession.ControlledEntity; } if (sameGrid) castStartSafe += line.Direction; } var shapeCastLine = new LineD(castStartSafe, m_position); uint steps = 1; uint stepIdx = 0; if (shapeCastLine.Length > SHAPE_CAST_STEP) { steps = (uint)Math.Ceiling(shapeCastLine.Length / SHAPE_CAST_STEP); if (steps >= SHAPE_CAST_MAX_STEP_COUNT) steps = SHAPE_CAST_MAX_STEP_COUNT - 1; stepIdx = m_updateCount % steps; m_lastShapeCastDistance[stepIdx] = float.PositiveInfinity; Vector3D step = shapeCastLine.Direction * (shapeCastLine.Length / steps); shapeCastLine = new LineD(castStartSafe + stepIdx * step, castStartSafe + (stepIdx + 1) * step); } if (false) { BoundingBoxD bbox = BoundingBoxD.CreateInvalid(); bbox.Include(new BoundingSphereD(shapeCastLine.From, CAMERA_RADIUS)); bbox.Include(new BoundingSphereD(shapeCastLine.To, CAMERA_RADIUS)); VRageRender.MyRenderProxy.DebugDrawAABB(bbox, Color.Crimson, 1f, 1f, true); } var matrix = MatrixD.CreateTranslation(shapeCastLine.From); HkContactPointData? cpd; if (controlledEntity.Physics != null && controlledEntity.Physics.CharacterProxy != null) cpd = MyPhysics.CastShapeReturnContactData(shapeCastLine.To, shape, ref matrix, controlledEntity.Physics.CharacterCollisionFilter, 0.0f); else cpd = MyPhysics.CastShapeReturnContactData(shapeCastLine.To, shape, ref matrix, HkGroupFilter.CalcFilterInfo(MyPhysics.DefaultCollisionLayer,0), 0.0f); if (cpd.HasValue) { var point = shapeCastLine.From + shapeCastLine.Direction * shapeCastLine.Length * cpd.Value.DistanceFraction; m_lastShapeCastDistance[stepIdx] = (float)(castStartSafe - point).Length(); } else { m_lastShapeCastDistance[stepIdx] = float.PositiveInfinity; } float? dist = null; for (int i = 0; i < steps; ++i) { if (m_lastShapeCastDistance[i] != float.PositiveInfinity) dist = Math.Min(m_lastShapeCastDistance[i], dist ?? float.PositiveInfinity); } if (dist.HasValue) { if (dist == 0.0f) { return false; } else { m_positionSafe = castStartSafe + shapeCastLine.Direction * dist.Value; } } else { m_positionSafe = m_position; } return true; } finally { shape.RemoveReference(); } }
private void DoDetection(bool useHead, bool doModelIntersection) { if (Character == MySession.Static.ControlledEntity) { MyHud.SelectedObjectHighlight.RemoveHighlight(); } var head = Character.GetHeadMatrix(false); Vector3D from = head.Translation; Vector3D dir = head.Forward; if (!useHead) { var headPos = head.Translation - (Vector3D)head.Forward * 0.3; // Move to center of head, we don't want eyes (in front of head) if (Character == MySession.Static.LocalCharacter) { from = MySector.MainCamera.WorldMatrix.Translation; dir = MySector.MainCamera.WorldMatrix.Forward; from = MyUtils.LinePlaneIntersection(headPos, (Vector3)dir, from, (Vector3)dir); } else { from = headPos; dir = head.Forward; } } Vector3D to = from + dir * 2.5;//MyConstants.DEFAULT_INTERACTIVE_DISTANCE; StartPosition = from; MatrixD matrix = MatrixD.CreateTranslation(from); HkShape shape = new HkSphereShape(ShapeRadius); IMyEntity hitEntity = null; ShapeKey = uint.MaxValue; HitPosition = Vector3D.Zero; HitNormal = Vector3.Zero; HitMaterial = MyStringHash.NullOrEmpty; HitTag = null; m_hits.Clear(); Vector3 interactivePosition = Vector3D.Zero; try { EnableDetectorsInArea(from); MyPhysics.CastShapeReturnContactBodyDatas(to, shape, ref matrix, 0, 0f, m_hits); m_rayOrigin = from; m_rayDirection = dir; m_hits.Sort(CompareHits); if (m_hits.Count > 0) { bool isValidBlock = false; bool isPhysicalBlock = false; for (int index = 0; index < m_hits.Count; index++) { HkRigidBody body = m_hits[index].HkHitInfo.Body; IMyEntity entity = m_hits[index].HkHitInfo.GetHitEntity(); // Ignore self-interaction if (entity == Character) { continue; } if (entity is VRage.Game.Entity.MyEntitySubpart) { entity = entity.Parent; } isValidBlock = body != null && entity != null && entity != Character && !body.HasProperty(HkCharacterRigidBody.MANIPULATED_OBJECT); isPhysicalBlock = entity != null && entity.Physics != null; if (hitEntity == null && isValidBlock) { hitEntity = entity; ShapeKey = m_hits[index].HkHitInfo.GetShapeKey(0); } // If hit-entity is a grid, raycast it to see which block we hit first if (entity is MyCubeGrid) { MyCubeGrid grid = entity as MyCubeGrid; List <MyCube> cubeList = grid.RayCastBlocksAllOrdered(from, to); if (cubeList != null && cubeList.Count > 0) { var slimblock = cubeList[0].CubeBlock; if (slimblock.FatBlock != null) { entity = slimblock.FatBlock; isPhysicalBlock = true; hitEntity = entity; ShapeKey = 0; } } } // Set hit material etc. only for object's that have physical representation in the world, this exclude detectors if (HitMaterial.Equals(MyStringHash.NullOrEmpty) && isValidBlock && isPhysicalBlock) { HitBody = body; HitNormal = m_hits[index].HkHitInfo.Normal; HitPosition = m_hits[index].GetFixedPosition(); HitMaterial = body.GetBody().GetMaterialAt(HitPosition); interactivePosition = HitPosition; break; } else if (body != null) { interactivePosition = m_hits[index].GetFixedPosition(); break; } index++; } } } finally { shape.RemoveReference(); } bool hasInteractive = false; var interactive = hitEntity as IMyUseObject; DetectedEntity = hitEntity; if (hitEntity != null) { MyUseObjectsComponentBase useObject = null; hitEntity.Components.TryGet <MyUseObjectsComponentBase>(out useObject); if (useObject != null) { interactive = useObject.GetInteractiveObject(ShapeKey); } // Do accurate collision checking on model if (doModelIntersection) { LineD line = new LineD(from, to); var character = hitEntity as MyCharacter; if (character == null) { MyIntersectionResultLineTriangleEx?result; bool success = hitEntity.GetIntersectionWithLine(ref line, out result, IntersectionFlags.ALL_TRIANGLES); if (success) { HitPosition = result.Value.IntersectionPointInWorldSpace; HitNormal = result.Value.NormalInWorldSpace; } } else { bool success = character.GetIntersectionWithLine(ref line, ref CharHitInfo); if (success) { HitPosition = CharHitInfo.Triangle.IntersectionPointInWorldSpace; HitNormal = CharHitInfo.Triangle.NormalInWorldSpace; HitTag = CharHitInfo; } } } } if (UseObject != null && interactive != null && UseObject != interactive) { UseObject.OnSelectionLost(); } if (interactive != null && interactive.SupportedActions != UseActionEnum.None && (Vector3D.Distance(from, interactivePosition)) < interactive.InteractiveDistance && Character == MySession.Static.ControlledEntity) { HandleInteractiveObject(interactive); UseObject = interactive; hasInteractive = true; } if (!hasInteractive) { if (UseObject != null) { UseObject.OnSelectionLost(); } UseObject = null; } DisableDetectors(); }
protected override void DoDetection(bool useHead) { if (Character == MySession.ControlledEntity) { MyHud.SelectedObjectHighlight.Visible = false; } var head = Character.GetHeadMatrix(false); var headPos = head.Translation - (Vector3D)head.Forward * 0.3; // Move to center of head, we don't want eyes (in front of head) Vector3D from; Vector3D dir; if (!useHead) { //Ondrej version //var cameraMatrix = MySector.MainCamera.WorldMatrix; var cameraMatrix = Character.Get3rdBoneMatrix(true, true); dir = cameraMatrix.Forward; from = MyUtils.LinePlaneIntersection(headPos, (Vector3)dir, cameraMatrix.Translation, (Vector3)dir); } else { //Petr version dir = head.Forward; from = headPos; } Vector3D to = from + dir * 2.5f; StartPosition = from; MatrixD matrix = MatrixD.CreateTranslation(from); HkShape shape = new HkSphereShape(ShapeRadius); IMyEntity hitEntity = null; ShapeKey = uint.MaxValue; HitPosition = Vector3D.Zero; HitNormal = Vector3.Zero; m_hits.Clear(); try { EnableDetectorsInArea(from); MyPhysics.CastShapeReturnContactBodyDatas(to, shape, ref matrix, 0, 0f, m_hits); int index = 0; while (index < m_hits.Count && (m_hits[index].HkHitInfo.Body == null || m_hits[index].HkHitInfo.GetHitEntity() == Character || m_hits[index].HkHitInfo.Body.HasProperty(HkCharacterRigidBody.MANIPULATED_OBJECT))) // Skip invalid hits and self character { index++; } if (index < m_hits.Count) { hitEntity = m_hits[index].HkHitInfo.GetHitEntity(); ShapeKey = m_hits[index].HkHitInfo.GetShapeKey(0); HitPosition = m_hits[index].Position; HitNormal = m_hits[index].HkHitInfo.Normal; HitMaterial = m_hits[index].HkHitInfo.Body.GetBody().GetMaterialAt(HitPosition + HitNormal * 0.1f); HitBody = m_hits[index].HkHitInfo.Body; } } finally { shape.RemoveReference(); } bool hasInteractive = false; var interactive = hitEntity as IMyUseObject; DetectedEntity = hitEntity; if (hitEntity != null) { MyUseObjectsComponentBase useObject = null; hitEntity.Components.TryGet <MyUseObjectsComponentBase>(out useObject); if (useObject != null) { interactive = useObject.GetInteractiveObject(ShapeKey); } } if (UseObject != null && interactive != null && UseObject != interactive) { UseObject.OnSelectionLost(); } if (interactive != null && interactive.SupportedActions != UseActionEnum.None && (Vector3D.Distance(from, HitPosition)) < interactive.InteractiveDistance && Character == MySession.ControlledEntity) { MyHud.SelectedObjectHighlight.Visible = true; MyHud.SelectedObjectHighlight.InteractiveObject = interactive; UseObject = interactive; hasInteractive = true; } if (!hasInteractive) { if (UseObject != null) { UseObject.OnSelectionLost(); } UseObject = null; } DisableDetectors(); }
protected override void DoDetection(bool useHead) { if (Character == MySession.ControlledEntity) MyHud.SelectedObjectHighlight.Visible = false; var head = Character.GetHeadMatrix(false); var headPos = head.Translation - (Vector3D)head.Forward * 0.3; // Move to center of head, we don't want eyes (in front of head) Vector3D from; Vector3D dir; if (!useHead) { //Ondrej version var cameraMatrix = MySector.MainCamera.WorldMatrix; dir = cameraMatrix.Forward; from = MyUtils.LinePlaneIntersection(headPos, (Vector3)dir, cameraMatrix.Translation, (Vector3)dir); } else { //Petr version dir = head.Forward; from = headPos; } Vector3D to = from + dir * MyConstants.DEFAULT_INTERACTIVE_DISTANCE; MatrixD matrix = MatrixD.CreateTranslation(from); HkShape shape = new HkSphereShape(SHAPE_RADIUS); IMyEntity hitEntity = null; int shapeKey = -1; Vector3D hitPosition = Vector3D.Zero; m_hits.Clear(); try { MyPhysics.CastShapeReturnContactBodyDatas(to, shape, ref matrix, 0, 0f, m_hits); int index = 0; while (index < m_hits.Count && (m_hits[index].Body == null || m_hits[index].Body.UserObject == Character.Physics || (Character.VirtualPhysics != null && m_hits[index].Body.UserObject == Character.VirtualPhysics) || m_hits[index].Body.HasProperty(HkCharacterRigidBody.MANIPULATED_OBJECT))) // Skip invalid hits and self character { index++; } if (index < m_hits.Count) { hitEntity = m_hits[index].Body.GetEntity(); shapeKey = m_hits[index].ShapeKey; hitPosition = m_hits[index].HitPosition; } } finally { shape.RemoveReference(); } bool hasInteractive = false; var interactive = hitEntity as IMyUseObject; DetectedEntity = hitEntity; if (hitEntity != null) { MyUseObjectsComponentBase useObject = null; hitEntity.Components.TryGet<MyUseObjectsComponentBase>(out useObject); if (useObject != null) { interactive = useObject.GetInteractiveObject(shapeKey); } } if (UseObject != null && interactive != null && UseObject != interactive) { UseObject.OnSelectionLost(); } if (interactive != null && interactive.SupportedActions != UseActionEnum.None && (Vector3D.Distance(from, hitPosition)) < interactive.InteractiveDistance && Character == MySession.ControlledEntity) { MyHud.SelectedObjectHighlight.Visible = true; MyHud.SelectedObjectHighlight.InteractiveObject = interactive; UseObject = interactive; hasInteractive = true; } if (!hasInteractive) { if (UseObject != null) UseObject.OnSelectionLost(); UseObject = null; } }
public void GetFracturesInSphere(ref BoundingSphereD searchSphere, ref List<MyFracturedPiece> output) { var activeFractures = m_piecesTimesOfDeath.Keys; HkShape shape = new HkSphereShape((float)searchSphere.Radius); try { MyPhysics.GetPenetrationsShape(shape, ref searchSphere.Center, ref Quaternion.Identity, m_rigidList, MyPhysics.NotCollideWithStaticLayer); foreach(var rigidBody in m_rigidList) { var fracture = rigidBody.GetCollisionEntity() as MyFracturedPiece; if (fracture != null) output.Add(fracture); } } finally { m_rigidList.Clear(); shape.RemoveReference(); } }
/// <summary> /// Handles camera collisions with environment /// </summary> /// <returns>False if no correct position was found</returns> private void HandleIntersection(MyEntity controlledEntity) { Debug.Assert(controlledEntity != null); MyEntity parentEntity = controlledEntity.GetTopMostParent() ?? controlledEntity; // line from target to eye LineD line = new LineD(m_target, m_position); // oriented bb of the entity MyOrientedBoundingBoxD safeObb = GetEntitySafeOBB(parentEntity); // oriented bb of the entity + camera radius MyOrientedBoundingBoxD safeObbWithCollisionExtents = new MyOrientedBoundingBoxD(safeObb.Center, safeObb.HalfExtent + (controlledEntity.Parent == null ? 0.5 : 2.0) * CAMERA_RADIUS, safeObb.Orientation); // start = target, end = eye // find safe start... LineD safeOBBLine = new LineD(line.From + line.Direction * 2 * safeObb.HalfExtent.Length(), line.From); double? safeIntersection = safeObbWithCollisionExtents.Intersects(ref safeOBBLine); Vector3D castStartSafe = safeIntersection != null ? (safeOBBLine.From + safeOBBLine.Direction * safeIntersection.Value) : m_target; if (controlledEntity.Parent != null && safeIntersection != null) { HkShape hkSphere = new HkSphereShape(CAMERA_RADIUS * 2); //var hitInfo = MyPhysics.CastRay(castStartSafe, m_target); MatrixD shapeCastStart = MatrixD.CreateTranslation(castStartSafe); var hitInfo = MyPhysics.CastShapeReturnContactBodyData(m_target, hkSphere, ref shapeCastStart, 0, 0); MyEntity hitEntity = hitInfo.HasValue ? hitInfo.Value.HkHitInfo.GetHitEntity() as MyEntity : null; MyEntity entity = controlledEntity; var hitEntityWeldingGroup = hitEntity != null?MyWeldingGroups.Static.GetGroup(hitEntity) : null; bool weldingGroupEquals = false; while (entity != null && !weldingGroupEquals) { if (hitEntityWeldingGroup == MyWeldingGroups.Static.GetGroup(entity)) { weldingGroupEquals = true; } entity = entity.Parent; } if (hitInfo.HasValue && hitEntityWeldingGroup != null && weldingGroupEquals) { castStartSafe = hitInfo.Value.Position + line.Direction; } else { safeObb = GetEntitySafeOBB(controlledEntity); safeObbWithCollisionExtents = new MyOrientedBoundingBoxD(safeObb.Center, safeObb.HalfExtent + 0.5f * CAMERA_RADIUS, safeObb.Orientation); safeIntersection = safeObbWithCollisionExtents.Intersects(ref safeOBBLine); castStartSafe = safeIntersection != null ? (safeOBBLine.From + safeOBBLine.Direction * safeIntersection.Value) : m_target; } hkSphere.RemoveReference(); } // raycast against occluders Vector3D safePositionCandidate; //double lastSafeMinimumDistance = m_safeMinimumDistance; m_safeMinimumDistance = controlledEntity is MyCharacter ? 0 : (castStartSafe - m_target).Length(); // store current safe minimum dist m_safeMinimumDistance = Math.Max(m_safeMinimumDistance, MIN_VIEWER_DISTANCE); //if (lastSafeMinimumDistance + 30.0f < m_safeMinimumDistance) //{ // castStartSafe = m_target + (castStartSafe - m_target) / m_safeMinimumDistance * lastSafeMinimumDistance; // m_safeMinimumDistance = lastSafeMinimumDistance; //} Vector3D raycastOrigin = (controlledEntity is MyCharacter) ? m_target : castStartSafe; MyCameraRaycastResult raycastResult = RaycastOccludingObjects(controlledEntity, ref raycastOrigin, ref m_position, ref castStartSafe, out safePositionCandidate); // visual debugging :) if (m_debugDraw) { VRageRender.MyRenderProxy.DebugDrawOBB(safeObb, Color.Red, 0.1f, false, true); VRageRender.MyRenderProxy.DebugDrawOBB(safeObbWithCollisionExtents, Color.Yellow, 0.0f, false, true); VRageRender.MyRenderProxy.DebugDrawArrow3D(safeOBBLine.From, safeOBBLine.To, Color.White, Color.Purple, false); VRageRender.MyRenderProxy.DebugDrawArrow3D(safeOBBLine.From, castStartSafe, Color.White, Color.Red, false); VRageRender.MyRenderProxy.DebugDrawArrow3D(castStartSafe, m_position, Color.White, Color.Orange, false); VRageRender.MyRenderProxy.DebugDrawSphere(castStartSafe, 0.2f, Color.Green, 1.0f, false, true); } switch (raycastResult) { case MyCameraRaycastResult.Ok: case MyCameraRaycastResult.FoundOccluder: m_positionCurrentIsSafe = true; { double distFromCandidateToTarget = (safePositionCandidate - m_target).Length(); if ((distFromCandidateToTarget > m_lastRaycastDist + CAMERA_RADIUS && distFromCandidateToTarget > m_safeMinimumDistance) || raycastResult == MyCameraRaycastResult.Ok) { // now we need it from the other side double newDist = (safePositionCandidate - m_position).Length(); // new safe position is further from target => change over time (zoom out) if (m_positionSafeZoomingOutTimeout <= 0) { float distDiffZoomSpeed = 1 - MathHelper.Clamp((float)Math.Abs(m_lastRaycastDist - newDist), 0.0f, 1.0f - MyEngineConstants.UPDATE_STEP_SIZE_IN_SECONDS); m_positionSafeZoomingOutSpeed += distDiffZoomSpeed; m_positionSafeZoomingOutSpeed = MathHelper.Clamp(m_positionSafeZoomingOutSpeed, 0.0f, 1.0f); Vector3D targetToPosSafe = m_positionSafe - m_target; double lenTargetToPosSafe = targetToPosSafe.Length(); Vector3D rotatedPositionSafe = m_target + Vector3D.Normalize(safePositionCandidate - m_target) * lenTargetToPosSafe; m_positionSafe = Vector3D.Lerp(rotatedPositionSafe, safePositionCandidate, m_positionSafeZoomingOutSpeed); } else { m_positionSafeZoomingOutTimeout -= MyEngineConstants.UPDATE_STEP_SIZE_IN_MILLISECONDS; Vector3D targetToPosSafe = m_positionSafe - m_target; double lenTargetToPosSafe = targetToPosSafe.Length(); m_positionSafe = m_target + Vector3D.Normalize(safePositionCandidate - m_target) * lenTargetToPosSafe; } } else { // new safe position is closer or closer than safe distance => instant change m_positionSafeZoomingOutSpeed = 0.0f; // set zooming out speed to zero for next time m_positionSafe = safePositionCandidate; m_positionSafeZoomingOutTimeout = 0; // controlledEntity.Parent != null ? m_positionSafeZoomingOutDefaultTimeoutMs : 0; m_disableSpringThisFrame = true; } } break; //case MyCameraRaycastResult.FoundOccluderNoSpace: default: m_positionSafeZoomingOutSpeed = 1.0f; // we're in first person, change instantly to third if possible m_positionCurrentIsSafe = false; break; } m_lastRaycastDist = (float)(m_positionSafe - m_position).Length(); if (m_debugDraw) { VRageRender.MyRenderProxy.DebugDrawSphere(m_positionSafe, 0.225f, Color.Purple, 1, false); VRageRender.MyRenderProxy.DebugDrawSphere(safePositionCandidate, 0.2f, Color.Azure, 1, false); } }
protected override void DoDetection(bool useHead) { if (Character == MySession.ControlledEntity) { MyHud.SelectedObjectHighlight.Visible = false; } var head = Character.GetHeadMatrix(false); var headPos = head.Translation - (Vector3D)head.Forward * 0.3; // Move to center of head, we don't want eyes (in front of head) Vector3D from; Vector3D dir; if (!useHead) { //Ondrej version var cameraMatrix = MySector.MainCamera.WorldMatrix; dir = cameraMatrix.Forward; from = MyUtils.LinePlaneIntersection(headPos, (Vector3)dir, cameraMatrix.Translation, (Vector3)dir); } else { //Petr version dir = head.Forward; from = headPos; } Vector3D to = from + dir * MyConstants.DEFAULT_INTERACTIVE_DISTANCE; MatrixD matrix = MatrixD.CreateTranslation(from); HkShape shape = new HkSphereShape(SHAPE_RADIUS); IMyEntity hitEntity = null; int shapeKey = -1; Vector3D hitPosition = Vector3D.Zero; m_hits.Clear(); try { MyPhysics.CastShapeReturnContactBodyDatas(to, shape, ref matrix, 0, 0f, m_hits); int index = 0; while (index < m_hits.Count && (m_hits[index].Body == null || m_hits[index].Body.UserObject == Character.Physics || (Character.VirtualPhysics != null && m_hits[index].Body.UserObject == Character.VirtualPhysics) || m_hits[index].Body.HasProperty(HkCharacterRigidBody.MANIPULATED_OBJECT))) // Skip invalid hits and self character { index++; } if (index < m_hits.Count) { hitEntity = m_hits[index].Body.GetEntity(); shapeKey = m_hits[index].ShapeKey; hitPosition = m_hits[index].HitPosition; } } finally { shape.RemoveReference(); } bool hasInteractive = false; var interactive = hitEntity as IMyUseObject; if (hitEntity != null) { MyUseObjectsComponentBase useObject = null; hitEntity.Components.TryGet <MyUseObjectsComponentBase>(out useObject); if (useObject != null) { interactive = useObject.GetInteractiveObject(shapeKey); } } if (UseObject != null && interactive != null && UseObject != interactive) { UseObject.OnSelectionLost(); } if (interactive != null && interactive.SupportedActions != UseActionEnum.None && (Vector3D.Distance(from, hitPosition)) < interactive.InteractiveDistance && Character == MySession.ControlledEntity) { MyHud.SelectedObjectHighlight.Visible = true; MyHud.SelectedObjectHighlight.InteractiveObject = interactive; UseObject = interactive; hasInteractive = true; } if (!hasInteractive) { if (UseObject != null) { UseObject.OnSelectionLost(); } UseObject = null; } }
protected override void DoDetection(bool useHead) { if (Character == MySession.Static.ControlledEntity) MyHud.SelectedObjectHighlight.RemoveHighlight(); var head = Character.GetHeadMatrix(false); var headPos = head.Translation - (Vector3D)head.Forward * 0.3; // Move to center of head, we don't want eyes (in front of head) Vector3D from; Vector3D dir; if (!useHead) { //Ondrej version var cameraMatrix = MySector.MainCamera.WorldMatrix; //var cameraMatrix = Character.Get3rdBoneMatrix(true, true); dir = cameraMatrix.Forward; from = MyUtils.LinePlaneIntersection(headPos, (Vector3)dir, cameraMatrix.Translation, (Vector3)dir); } else { //Petr version dir = head.Forward; from = headPos; } Vector3D to = from + dir * MyConstants.DEFAULT_INTERACTIVE_DISTANCE; StartPosition = from; MatrixD matrix = MatrixD.CreateTranslation(from); HkShape shape = new HkSphereShape(ShapeRadius); IMyEntity hitEntity = null; ShapeKey = uint.MaxValue; HitPosition = Vector3D.Zero; HitNormal = Vector3.Zero; HitMaterial = MyStringHash.NullOrEmpty; m_hits.Clear(); try { EnableDetectorsInArea(from); MyPhysics.CastShapeReturnContactBodyDatas(to, shape, ref matrix, 0, 0f, m_hits); if (m_hits.Count > 0) { int index = 0; bool isValidBlock = false; bool isPhysicalBlock = false; do { isValidBlock = m_hits[index].HkHitInfo.Body != null && m_hits[index].HkHitInfo.GetHitEntity() != Character && m_hits[index].HkHitInfo.GetHitEntity() != null && !m_hits[index].HkHitInfo.Body.HasProperty(HkCharacterRigidBody.MANIPULATED_OBJECT); isPhysicalBlock = m_hits[index].HkHitInfo.GetHitEntity() != null && m_hits[index].HkHitInfo.GetHitEntity().Physics != null; if (hitEntity == null && isValidBlock) { hitEntity = m_hits[index].HkHitInfo.GetHitEntity(); ShapeKey = m_hits[index].HkHitInfo.GetShapeKey(0); } // Set hit material etc. only for object's that have physical representation in the world, this exclude detectors if (HitMaterial.Equals(MyStringHash.NullOrEmpty) && isValidBlock && isPhysicalBlock) { HitBody = m_hits[index].HkHitInfo.Body; HitPosition = m_hits[index].Position; HitNormal = m_hits[index].HkHitInfo.Normal; HitMaterial = m_hits[index].HkHitInfo.Body.GetBody().GetMaterialAt(HitPosition + HitNormal * 0.1f); } index++; } while (index < m_hits.Count && (!isValidBlock || !isPhysicalBlock)); } } finally { shape.RemoveReference(); } bool hasInteractive = false; var interactive = hitEntity as IMyUseObject; DetectedEntity = hitEntity; if (hitEntity != null) { MyUseObjectsComponentBase useObject = null; hitEntity.Components.TryGet<MyUseObjectsComponentBase>(out useObject); if (useObject != null) { interactive = useObject.GetInteractiveObject(ShapeKey); } } if (UseObject != null && interactive != null && UseObject != interactive) { UseObject.OnSelectionLost(); } if (interactive != null && interactive.SupportedActions != UseActionEnum.None && (Vector3D.Distance(from, HitPosition)) < interactive.InteractiveDistance && Character == MySession.Static.ControlledEntity) { HandleInteractiveObject(interactive); UseObject = interactive; hasInteractive = true; } if (!hasInteractive) { if (UseObject != null) UseObject.OnSelectionLost(); UseObject = null; } DisableDetectors(); }
private void DoDetection(bool useHead, bool doModelIntersection) { if (Character == MySession.Static.ControlledEntity) MyHud.SelectedObjectHighlight.RemoveHighlight(); var head = Character.GetHeadMatrix(false); var headPos = head.Translation - (Vector3D)head.Forward * 0.3; // Move to center of head, we don't want eyes (in front of head) Vector3D from; Vector3D dir; if (!useHead) { //Ondrej version //var cameraMatrix = MySector.MainCamera.WorldMatrix; var cameraMatrix = Character.Get3rdBoneMatrix(true, true); dir = cameraMatrix.Forward; from = MyUtils.LinePlaneIntersection(headPos, (Vector3)dir, cameraMatrix.Translation, (Vector3)dir); } else { //Petr version dir = head.Forward; from = headPos; } Vector3D to = from + dir * 2.5;//MyConstants.DEFAULT_INTERACTIVE_DISTANCE; StartPosition = from; MatrixD matrix = MatrixD.CreateTranslation(from); HkShape shape = new HkSphereShape(ShapeRadius); IMyEntity hitEntity = null; ShapeKey = uint.MaxValue; HitPosition = Vector3D.Zero; HitNormal = Vector3.Zero; HitMaterial = MyStringHash.NullOrEmpty; HitTag = null; m_hits.Clear(); Vector3 interactivePosition = Vector3D.Zero; try { EnableDetectorsInArea(from); MyPhysics.CastShapeReturnContactBodyDatas(to, shape, ref matrix, 0, 0f, m_hits); m_hits.Sort(delegate(MyPhysics.HitInfo info1, MyPhysics.HitInfo info2) { float dot1 = Vector3.Dot(head.Forward, Vector3.Normalize(info1.Position - StartPosition)); float dot2 = Vector3.Dot(head.Forward, Vector3.Normalize(info2.Position - StartPosition)); return dot1.CompareTo(dot2); }); if (m_hits.Count > 0) { int index = 0; bool isValidBlock = false; bool isPhysicalBlock = false; do { HkRigidBody body = m_hits[index].HkHitInfo.Body; IMyEntity entity = m_hits[index].HkHitInfo.GetHitEntity(); if (entity is VRage.Game.Entity.MyEntitySubpart) { entity = entity.Parent; } isValidBlock = body != null && entity != null && entity != Character && !body.HasProperty(HkCharacterRigidBody.MANIPULATED_OBJECT); isPhysicalBlock = entity != null && entity.Physics != null; if (hitEntity == null && isValidBlock) { hitEntity = entity; ShapeKey = m_hits[index].HkHitInfo.GetShapeKey(0); } // Set hit material etc. only for object's that have physical representation in the world, this exclude detectors if (HitMaterial.Equals(MyStringHash.NullOrEmpty) && isValidBlock && isPhysicalBlock) { HitBody = body; HitNormal = m_hits[index].HkHitInfo.Normal; HitPosition = m_hits[index].GetFixedPosition(); HitMaterial = body.GetBody().GetMaterialAt(HitPosition); interactivePosition = HitPosition; } else if (body != null) { interactivePosition = m_hits[index].GetFixedPosition(); } index++; } while (index < m_hits.Count && (!isValidBlock || !isPhysicalBlock)); } } finally { shape.RemoveReference(); } bool hasInteractive = false; var interactive = hitEntity as IMyUseObject; DetectedEntity = hitEntity; if (hitEntity != null) { MyUseObjectsComponentBase useObject = null; hitEntity.Components.TryGet<MyUseObjectsComponentBase>(out useObject); if (useObject != null) { interactive = useObject.GetInteractiveObject(ShapeKey); } // Do accurate collision checking on model if (doModelIntersection) { LineD line = new LineD(from, to); var character = hitEntity as MyCharacter; if (character == null) { MyIntersectionResultLineTriangleEx? result; bool success = hitEntity.GetIntersectionWithLine(ref line, out result, IntersectionFlags.ALL_TRIANGLES); if (success) { HitPosition = result.Value.IntersectionPointInWorldSpace; HitNormal = result.Value.NormalInWorldSpace; } } else { bool success = character.GetIntersectionWithLine(ref line, ref CharHitInfo); if (success) { HitPosition = CharHitInfo.Triangle.IntersectionPointInWorldSpace; HitNormal = CharHitInfo.Triangle.NormalInWorldSpace; HitTag = CharHitInfo; } } } } if (UseObject != null && interactive != null && UseObject != interactive) { UseObject.OnSelectionLost(); } if (interactive != null && interactive.SupportedActions != UseActionEnum.None && (Vector3D.Distance(from, interactivePosition)) < interactive.InteractiveDistance && Character == MySession.Static.ControlledEntity) { HandleInteractiveObject(interactive); UseObject = interactive; hasInteractive = true; } if (!hasInteractive) { if (UseObject != null) UseObject.OnSelectionLost(); UseObject = null; } DisableDetectors(); }
/// <summary> /// Spawns bag around position given by "baseTransform", checks all 4 directions around - forwards (forward, right, backward, left) and on each such direction moves test sphere /// in 3 directions forward (frontChecks), sides (perpendicular to forward direction - rights) and up. If spawn position is not found then position above "worldAabbTopPosition" /// is selected. /// </summary> private static MyEntity SpawnBagAround(MyEntity itemOwner, MyContainerDefinition bagDefinition, int sideCheckCount = 3, int frontCheckCount = 2, int upCheckCount = 5, float stepSize = 1f) { Debug.Assert(Sandbox.Game.Multiplayer.Sync.IsServer); Vector3D? finalPos = null; // Model sphere MyModel bagModel = null; foreach (var componentDef in bagDefinition.DefaultComponents) { if (typeof(MyObjectBuilder_ModelComponent).IsAssignableFrom(componentDef.BuilderType)) { MyComponentDefinitionBase componentDefinition = null; var componentSubtype = bagDefinition.Id.SubtypeId; if (componentDef.SubtypeId.HasValue) componentSubtype = componentDef.SubtypeId.Value; if (MyComponentContainerExtension.TryGetComponentDefinition(componentDef.BuilderType, componentSubtype, out componentDefinition)) { var modelComponentDef = componentDefinition as MyModelComponentDefinition; Debug.Assert(modelComponentDef != null); if (modelComponentDef != null) bagModel = MyModels.GetModelOnlyData(modelComponentDef.Model); } break; } } Debug.Assert(bagModel != null); if (bagModel == null) return null; float bagBoxRadius = bagModel.BoundingBox.HalfExtents.Max(); HkShape sphere = new HkSphereShape(bagBoxRadius); try { Vector3D basePos = itemOwner.PositionComp.WorldMatrix.Translation; float step = bagBoxRadius * stepSize; // Calculate right, up and forward vectors from gravity Vector3 upDir = -MyGravityProviderSystem.CalculateNaturalGravityInPoint(itemOwner.PositionComp.WorldMatrix.Translation); if (upDir == Vector3.Zero) upDir = Vector3.Up; else upDir.Normalize(); Vector3 forwardDir; upDir.CalculatePerpendicularVector(out forwardDir); Vector3 rightDir = Vector3.Cross(forwardDir, upDir); rightDir.Normalize(); Vector3D currentPos; Quaternion rot = Quaternion.Identity; Vector3[] forwards = new Vector3[] { forwardDir, rightDir, -forwardDir, -rightDir }; Vector3[] rights = new Vector3[] { rightDir, -forwardDir, -rightDir, forwardDir }; // All sides for (int i = 0; i < forwards.Length && finalPos == null; ++i) { var forward = forwards[i]; var right = rights[i]; // Move forward for (int frontMove = 0; frontMove < frontCheckCount && finalPos == null; ++frontMove) { Vector3D sidePosBase = basePos + 0.25f * forward + bagBoxRadius * forward + frontMove * step * forward - 0.5f * (sideCheckCount - 1) * step * right; // Move perp to forward for (int sideMove = 0; sideMove < sideCheckCount && finalPos == null; ++sideMove) { // Move up for (int upMove = 0; upMove < upCheckCount && finalPos == null; ++upMove) { currentPos = sidePosBase + sideMove * step * right + upMove * step * upDir; if (MyEntities.IsInsideWorld(currentPos) && !MyEntities.IsShapePenetrating(sphere, ref currentPos, ref rot)) { BoundingSphereD boundingSphere = new BoundingSphereD(currentPos, bagBoxRadius); MyVoxelBase overlappedVoxelmap = MySession.Static.VoxelMaps.GetOverlappingWithSphere(ref boundingSphere); if (overlappedVoxelmap == null) { finalPos = currentPos; break; } } } } } } // If not found position then select position above aabb's top. if (finalPos == null) { MyOrientedBoundingBoxD obb = new MyOrientedBoundingBoxD((BoundingBoxD)itemOwner.PositionComp.LocalAABB, itemOwner.PositionComp.WorldMatrix); Vector3D[] corners = new Vector3D[8]; obb.GetCorners(corners, 0); float dotUp = float.MinValue; foreach (var corner in corners) { var localDot = Vector3.Dot(corner - obb.Center, upDir); dotUp = Math.Max(dotUp, localDot); } finalPos = itemOwner.PositionComp.WorldMatrix.Translation; Debug.Assert(dotUp > 0); if (dotUp > 0) finalPos = obb.Center + dotUp * upDir; } } finally { sphere.RemoveReference(); } Debug.Assert(finalPos != null); MatrixD transform = itemOwner.PositionComp.WorldMatrix; transform.Translation = finalPos.Value; MyEntity bagEntity = MyEntities.CreateFromComponentContainerDefinitionAndAdd(bagDefinition.Id); if (bagEntity == null) return null; bagEntity.PositionComp.SetWorldMatrix(transform); bagEntity.Physics.LinearVelocity = Vector3.Zero; bagEntity.Physics.AngularVelocity = Vector3.Zero; return bagEntity; }
/// <summary> /// Spawns bag around position given by "baseTransform", checks all 4 directions around - forwards (forward, right, backward, left) and on each such direction moves test sphere /// in 3 directions forward (frontChecks), sides (perpendicular to forward direction - rights) and up. If spawn position is not found then position above "worldAabbTopPosition" /// is selected. /// </summary> private static MyEntity SpawnBagAround(MyEntity itemOwner, MyContainerDefinition bagDefinition, int sideCheckCount = 3, int frontCheckCount = 2, int upCheckCount = 5, float stepSize = 1f) { Debug.Assert(Sandbox.Game.Multiplayer.Sync.IsServer); Vector3D?finalPos = null; // Model sphere MyModel bagModel = null; foreach (var componentDef in bagDefinition.DefaultComponents) { if (typeof(MyObjectBuilder_ModelComponent).IsAssignableFrom(componentDef.BuilderType)) { MyComponentDefinitionBase componentDefinition = null; var componentSubtype = bagDefinition.Id.SubtypeId; if (componentDef.SubtypeId.HasValue) { componentSubtype = componentDef.SubtypeId.Value; } if (MyComponentContainerExtension.TryGetComponentDefinition(componentDef.BuilderType, componentSubtype, out componentDefinition)) { var modelComponentDef = componentDefinition as MyModelComponentDefinition; Debug.Assert(modelComponentDef != null); if (modelComponentDef != null) { bagModel = MyModels.GetModelOnlyData(modelComponentDef.Model); } } break; } } Debug.Assert(bagModel != null); if (bagModel == null) { return(null); } float bagBoxRadius = bagModel.BoundingBox.HalfExtents.Max(); HkShape sphere = new HkSphereShape(bagBoxRadius); try { Vector3D basePos = itemOwner.PositionComp.WorldMatrix.Translation; float step = bagBoxRadius * stepSize; // Calculate right, up and forward vectors from gravity Vector3 upDir = -MyGravityProviderSystem.CalculateNaturalGravityInPoint(itemOwner.PositionComp.WorldMatrix.Translation); if (upDir == Vector3.Zero) { upDir = Vector3.Up; } else { upDir.Normalize(); } Vector3 forwardDir; upDir.CalculatePerpendicularVector(out forwardDir); Vector3 rightDir = Vector3.Cross(forwardDir, upDir); rightDir.Normalize(); Vector3D currentPos; Quaternion rot = Quaternion.Identity; Vector3[] forwards = new Vector3[] { forwardDir, rightDir, -forwardDir, -rightDir }; Vector3[] rights = new Vector3[] { rightDir, -forwardDir, -rightDir, forwardDir }; // All sides for (int i = 0; i < forwards.Length && finalPos == null; ++i) { var forward = forwards[i]; var right = rights[i]; // Move forward for (int frontMove = 0; frontMove < frontCheckCount && finalPos == null; ++frontMove) { Vector3D sidePosBase = basePos + 0.25f * forward + bagBoxRadius * forward + frontMove * step * forward - 0.5f * (sideCheckCount - 1) * step * right; // Move perp to forward for (int sideMove = 0; sideMove < sideCheckCount && finalPos == null; ++sideMove) { // Move up for (int upMove = 0; upMove < upCheckCount && finalPos == null; ++upMove) { currentPos = sidePosBase + sideMove * step * right + upMove * step * upDir; if (MyEntities.IsInsideWorld(currentPos) && !MyEntities.IsShapePenetrating(sphere, ref currentPos, ref rot)) { BoundingSphereD boundingSphere = new BoundingSphereD(currentPos, bagBoxRadius); MyVoxelBase overlappedVoxelmap = MySession.Static.VoxelMaps.GetOverlappingWithSphere(ref boundingSphere); if (overlappedVoxelmap == null) { finalPos = currentPos; break; } } } } } } // If not found position then select position above aabb's top. if (finalPos == null) { MyOrientedBoundingBoxD obb = new MyOrientedBoundingBoxD((BoundingBoxD)itemOwner.PositionComp.LocalAABB, itemOwner.PositionComp.WorldMatrix); Vector3D[] corners = new Vector3D[8]; obb.GetCorners(corners, 0); float dotUp = float.MinValue; foreach (var corner in corners) { var localDot = Vector3.Dot(corner - obb.Center, upDir); dotUp = Math.Max(dotUp, localDot); } finalPos = itemOwner.PositionComp.WorldMatrix.Translation; Debug.Assert(dotUp > 0); if (dotUp > 0) { finalPos = obb.Center + dotUp * upDir; } } } finally { sphere.RemoveReference(); } Debug.Assert(finalPos != null); MatrixD transform = itemOwner.PositionComp.WorldMatrix; transform.Translation = finalPos.Value; MyEntity bagEntity = MyEntities.CreateFromComponentContainerDefinitionAndAdd(bagDefinition.Id); if (bagEntity == null) { return(null); } bagEntity.PositionComp.SetWorldMatrix(transform); bagEntity.Physics.LinearVelocity = Vector3.Zero; bagEntity.Physics.AngularVelocity = Vector3.Zero; return(bagEntity); }
private void DoDetection(bool useHead, bool doModelIntersection) { if (Character == MySession.Static.ControlledEntity) MyHud.SelectedObjectHighlight.RemoveHighlight(); var head = Character.GetHeadMatrix(false); Vector3D from = head.Translation; Vector3D dir = head.Forward; if (!useHead) { var headPos = head.Translation - (Vector3D)head.Forward * 0.3; // Move to center of head, we don't want eyes (in front of head) if (Character == MySession.Static.LocalCharacter) { from = MySector.MainCamera.WorldMatrix.Translation; dir = MySector.MainCamera.WorldMatrix.Forward; from = MyUtils.LinePlaneIntersection(headPos, (Vector3)dir, from, (Vector3)dir); } else { from = headPos; dir = head.Forward; } } Vector3D to = from + dir * 2.5;//MyConstants.DEFAULT_INTERACTIVE_DISTANCE; StartPosition = from; MatrixD matrix = MatrixD.CreateTranslation(from); HkShape shape = new HkSphereShape(ShapeRadius); IMyEntity hitEntity = null; ShapeKey = uint.MaxValue; HitPosition = Vector3D.Zero; HitNormal = Vector3.Zero; HitMaterial = MyStringHash.NullOrEmpty; HitTag = null; m_hits.Clear(); Vector3 interactivePosition = Vector3D.Zero; try { EnableDetectorsInArea(from); MyPhysics.CastShapeReturnContactBodyDatas(to, shape, ref matrix, 0, 0f, m_hits); m_rayOrigin = from; m_rayDirection = dir; m_hits.Sort(CompareHits); if (m_hits.Count > 0) { bool isValidBlock = false; bool isPhysicalBlock = false; for (int index = 0; index < m_hits.Count; index++) { HkRigidBody body = m_hits[index].HkHitInfo.Body; IMyEntity entity = m_hits[index].HkHitInfo.GetHitEntity(); // Ignore self-interaction if (entity == Character) continue; if (entity is VRage.Game.Entity.MyEntitySubpart) { entity = entity.Parent; } isValidBlock = body != null && entity != null && entity != Character && !body.HasProperty(HkCharacterRigidBody.MANIPULATED_OBJECT); isPhysicalBlock = entity != null && entity.Physics != null; if (hitEntity == null && isValidBlock) { hitEntity = entity; ShapeKey = m_hits[index].HkHitInfo.GetShapeKey(0); } // If hit-entity is a grid, raycast it to see which block we hit first if (entity is MyCubeGrid) { MyCubeGrid grid = entity as MyCubeGrid; List<MyCube> cubeList = grid.RayCastBlocksAllOrdered(from, to); if (cubeList != null && cubeList.Count > 0) { var slimblock = cubeList[0].CubeBlock; if (slimblock.FatBlock != null) { entity = slimblock.FatBlock; isPhysicalBlock = true; hitEntity = entity; ShapeKey = 0; } } } // Set hit material etc. only for object's that have physical representation in the world, this exclude detectors if (HitMaterial.Equals(MyStringHash.NullOrEmpty) && isValidBlock && isPhysicalBlock) { HitBody = body; HitNormal = m_hits[index].HkHitInfo.Normal; HitPosition = m_hits[index].GetFixedPosition(); HitMaterial = body.GetBody().GetMaterialAt(HitPosition); interactivePosition = HitPosition; break; } else if (body != null) { interactivePosition = m_hits[index].GetFixedPosition(); break; } index++; } } } finally { shape.RemoveReference(); } bool hasInteractive = false; var interactive = hitEntity as IMyUseObject; DetectedEntity = hitEntity; if (hitEntity != null) { MyUseObjectsComponentBase useObject = null; hitEntity.Components.TryGet<MyUseObjectsComponentBase>(out useObject); if (useObject != null) { interactive = useObject.GetInteractiveObject(ShapeKey); } // Do accurate collision checking on model if (doModelIntersection) { LineD line = new LineD(from, to); var character = hitEntity as MyCharacter; if (character == null) { MyIntersectionResultLineTriangleEx? result; bool success = hitEntity.GetIntersectionWithLine(ref line, out result, IntersectionFlags.ALL_TRIANGLES); if (success) { HitPosition = result.Value.IntersectionPointInWorldSpace; HitNormal = result.Value.NormalInWorldSpace; } } else { bool success = character.GetIntersectionWithLine(ref line, ref CharHitInfo); if (success) { HitPosition = CharHitInfo.Triangle.IntersectionPointInWorldSpace; HitNormal = CharHitInfo.Triangle.NormalInWorldSpace; HitTag = CharHitInfo; } } } } if (UseObject != null && interactive != null && UseObject != interactive) { UseObject.OnSelectionLost(); } if (interactive != null && interactive.SupportedActions != UseActionEnum.None && (Vector3D.Distance(from, interactivePosition)) < interactive.InteractiveDistance && Character == MySession.Static.ControlledEntity) { HandleInteractiveObject(interactive); UseObject = interactive; hasInteractive = true; } if (!hasInteractive) { if (UseObject != null) UseObject.OnSelectionLost(); UseObject = null; } DisableDetectors(); }
protected override void DoDetection(bool useHead) { if (Character == MySession.ControlledEntity) MyHud.SelectedObjectHighlight.Visible = false; var head = Character.GetHeadMatrix(false); var headPos = head.Translation - (Vector3D)head.Forward * 0.3; // Move to center of head, we don't want eyes (in front of head) Vector3D from; Vector3D dir; if (!useHead) { //Ondrej version //var cameraMatrix = MySector.MainCamera.WorldMatrix; var cameraMatrix = Character.Get3rdBoneMatrix(true, true); dir = cameraMatrix.Forward; from = MyUtils.LinePlaneIntersection(headPos, (Vector3)dir, cameraMatrix.Translation, (Vector3)dir); } else { //Petr version dir = head.Forward; from = headPos; } Vector3D to = from + dir * 2.5f; StartPosition = from; MatrixD matrix = MatrixD.CreateTranslation(from); HkShape shape = new HkSphereShape(ShapeRadius); IMyEntity hitEntity = null; ShapeKey = uint.MaxValue; HitPosition = Vector3D.Zero; HitNormal = Vector3.Zero; m_hits.Clear(); try { MyPhysics.CastShapeReturnContactBodyDatas(to, shape, ref matrix, 0, 0f, m_hits); int index = 0; while (index < m_hits.Count && (m_hits[index].HkHitInfo.Body == null || m_hits[index].HkHitInfo.GetHitEntity() == Character || m_hits[index].HkHitInfo.Body.HasProperty(HkCharacterRigidBody.MANIPULATED_OBJECT))) // Skip invalid hits and self character { index++; } if (index < m_hits.Count) { hitEntity = m_hits[index].HkHitInfo.GetHitEntity(); ShapeKey = m_hits[index].HkHitInfo.GetShapeKey(0); HitPosition = m_hits[index].Position; HitNormal = m_hits[index].HkHitInfo.Normal; HitMaterial = m_hits[index].HkHitInfo.Body.GetBody().GetMaterialAt(HitPosition + HitNormal * 0.1f); HitBody = m_hits[index].HkHitInfo.Body; } } finally { shape.RemoveReference(); } bool hasInteractive = false; var interactive = hitEntity as IMyUseObject; DetectedEntity = hitEntity; if (hitEntity != null) { MyUseObjectsComponentBase useObject = null; hitEntity.Components.TryGet<MyUseObjectsComponentBase>(out useObject); if (useObject != null) { interactive = useObject.GetInteractiveObject(ShapeKey); } } if (UseObject != null && interactive != null && UseObject != interactive) { UseObject.OnSelectionLost(); } if (interactive != null && interactive.SupportedActions != UseActionEnum.None && (Vector3D.Distance(from, HitPosition)) < interactive.InteractiveDistance && Character == MySession.ControlledEntity) { MyHud.SelectedObjectHighlight.Visible = true; MyHud.SelectedObjectHighlight.InteractiveObject = interactive; UseObject = interactive; hasInteractive = true; } if (!hasInteractive) { if (UseObject != null) UseObject.OnSelectionLost(); UseObject = null; } }
/// <summary> /// Processes previously acquired raycast results. /// Returns safe camera eye position (As far from target as possible, but not colliding, best case = desired eye pos). /// </summary> private MyCameraRaycastResult RaycastOccludingObjects(MyEntity controlledEntity, ref Vector3D raycastOrigin, ref Vector3D raycastEnd, ref Vector3D raycastSafeCameraStart, out Vector3D outSafePosition) { Vector3D rayDirection = raycastEnd - raycastOrigin; rayDirection.Normalize(); outSafePosition = m_position; double closestDistanceSquared = double.PositiveInfinity; bool positionChanged = false; // ray cast - very close objects MyPhysics.CastRay(raycastOrigin, raycastOrigin + CAMERA_RADIUS * rayDirection, m_raycastList); foreach (MyPhysics.HitInfo rb in m_raycastList) { if (rb.HkHitInfo.Body == null || rb.HkHitInfo.Body.UserObject == null || !(rb.HkHitInfo.Body.UserObject is MyPhysicsBody) || rb.HkHitInfo.GetHitEntity() == controlledEntity) { continue; } if (rb.HkHitInfo.GetHitEntity() is IMyHandheldGunObject <Game.Weapons.MyDeviceBase> ) // ignore player weapons { continue; } double distSq = Vector3D.DistanceSquared(rb.Position, raycastOrigin); if (distSq < closestDistanceSquared) { closestDistanceSquared = distSq; float dist = (float)Math.Sqrt(distSq) - CAMERA_RADIUS; outSafePosition = raycastOrigin + rayDirection * dist; positionChanged = true; } } if (m_debugDraw) { foreach (var raycastResult in m_raycastList) { VRageRender.MyRenderProxy.DebugDrawPoint(raycastResult.Position, Color.Red, false); } } // shape cast - further objects if ((raycastEnd - raycastOrigin).LengthSquared() > CAMERA_RADIUS * CAMERA_RADIUS) { HkShape shapeSphere = new HkSphereShape(CAMERA_RADIUS); MatrixD raycastOriginTransform = MatrixD.Identity; raycastOriginTransform.Translation = raycastOrigin + CAMERA_RADIUS * rayDirection; MyPhysics.CastShapeReturnContactBodyDatas(raycastEnd, shapeSphere, ref raycastOriginTransform, 0, 0, m_raycastList); //MyPhysics.CastRay(raycastOrigin + CAMERA_RADIUS * rayDirection, raycastEnd, m_raycastList, 0); foreach (MyPhysics.HitInfo rb in m_raycastList) { IMyEntity hitEntity = rb.HkHitInfo.GetHitEntity(); if (rb.HkHitInfo.Body == null || rb.HkHitInfo.Body.UserObject == null || hitEntity == controlledEntity || !(rb.HkHitInfo.Body.UserObject is MyPhysicsBody)) { continue; } if (hitEntity is IMyHandheldGunObject <Game.Weapons.MyDeviceBase> ) { // ignore player weapons continue; } double distSq = Vector3D.DistanceSquared(rb.Position, raycastOrigin); if (distSq < closestDistanceSquared) { closestDistanceSquared = distSq; float dist = (float)Math.Sqrt(distSq); outSafePosition = raycastOrigin + rayDirection * dist; positionChanged = true; } } shapeSphere.RemoveReference(); } if (m_debugDraw) { foreach (var raycastResult in m_raycastList) { VRageRender.MyRenderProxy.DebugDrawSphere(raycastResult.Position, CAMERA_RADIUS, Color.Red, 1, false); } } if (closestDistanceSquared < (raycastSafeCameraStart - raycastOrigin).LengthSquared() + CAMERA_RADIUS) { return(MyCameraRaycastResult.FoundOccluderNoSpace); // obstacle too close, switch to first person } // last check - isn't there voxel between safe pos and entity pos if (!positionChanged) { //Vector3D entityPos = controlledEntity.PositionComp.GetPosition(); MyPhysics.CastRay(m_target, raycastSafeCameraStart, m_raycastList); if (m_debugDraw) { BoundingBoxD bb = new BoundingBoxD(m_target, raycastSafeCameraStart); VRageRender.MyRenderProxy.DebugDrawAABB(bb, Color.Magenta); } foreach (var collision in m_raycastList) { if (collision.HkHitInfo.GetHitEntity() is MyVoxelBase) { return(MyCameraRaycastResult.FoundOccluderNoSpace); } } } return(positionChanged ? MyCameraRaycastResult.FoundOccluder : MyCameraRaycastResult.Ok); }
/// <summary> /// Processes previously acquired raycast results. /// Returns safe camera eye position (As far from target as possible, but not colliding, best case = desired eye pos). /// </summary> private MyCameraRaycastResult RaycastOccludingObjects(MyEntity controlledEntity, ref Vector3D raycastOrigin, ref Vector3D raycastEnd, ref Vector3D raycastSafeCameraStart, out Vector3D outSafePosition) { Vector3D rayDirection = raycastEnd - raycastOrigin; rayDirection.Normalize(); outSafePosition = m_position; double closestDistanceSquared = double.PositiveInfinity; bool positionChanged = false; // ray cast - very close objects MyPhysics.CastRay(raycastOrigin, raycastOrigin + CAMERA_RADIUS * rayDirection, m_raycastList); foreach (MyPhysics.HitInfo rb in m_raycastList) { if (rb.HkHitInfo.Body == null || rb.HkHitInfo.Body.UserObject == null || !(rb.HkHitInfo.Body.UserObject is MyPhysicsBody) || rb.HkHitInfo.GetHitEntity() == controlledEntity) continue; if (rb.HkHitInfo.GetHitEntity() is IMyHandheldGunObject<Game.Weapons.MyDeviceBase>) // ignore player weapons continue; double distSq = Vector3D.DistanceSquared(rb.Position, raycastOrigin); if (distSq < closestDistanceSquared) { closestDistanceSquared = distSq; double dist = Math.Sqrt(distSq) - CAMERA_RADIUS; outSafePosition = raycastOrigin + rayDirection * dist; positionChanged = true; } } if (m_debugDraw) foreach (var raycastResult in m_raycastList) { VRageRender.MyRenderProxy.DebugDrawPoint(raycastResult.Position, Color.Red, false); } // shape cast - further objects if ((raycastEnd - raycastOrigin).LengthSquared() > CAMERA_RADIUS * CAMERA_RADIUS) { HkShape shapeSphere = new HkSphereShape(CAMERA_RADIUS); MatrixD raycastOriginTransform = MatrixD.Identity; raycastOriginTransform.Translation = raycastOrigin + CAMERA_RADIUS * rayDirection; MyPhysics.CastShapeReturnContactBodyDatas(raycastEnd, shapeSphere, ref raycastOriginTransform, 0, 0, m_raycastList); //MyPhysics.CastRay(raycastOrigin + CAMERA_RADIUS * rayDirection, raycastEnd, m_raycastList, 0); float closestFraction = 1; foreach (MyPhysics.HitInfo rb in m_raycastList) { IMyEntity hitEntity = rb.HkHitInfo.GetHitEntity(); if (rb.HkHitInfo.Body == null || rb.HkHitInfo.Body.UserObject == null || hitEntity == controlledEntity || !(rb.HkHitInfo.Body.UserObject is MyPhysicsBody)) continue; if (hitEntity is IMyHandheldGunObject<Game.Weapons.MyDeviceBase>) // ignore player weapons continue; Vector3D safePos = Vector3D.Lerp(raycastOrigin, raycastEnd - CAMERA_RADIUS * rayDirection, Math.Max(rb.HkHitInfo.HitFraction, 0.0001)); double distSq = Vector3D.DistanceSquared(raycastOrigin, outSafePosition); if (rb.HkHitInfo.HitFraction < closestFraction && distSq < closestDistanceSquared) { outSafePosition = safePos; closestDistanceSquared = distSq; positionChanged = true; closestFraction = rb.HkHitInfo.HitFraction; } } shapeSphere.RemoveReference(); } if (m_debugDraw) foreach (var raycastResult in m_raycastList) { VRageRender.MyRenderProxy.DebugDrawSphere(raycastResult.Position, CAMERA_RADIUS, Color.Red, 1, false); } if (closestDistanceSquared < (raycastSafeCameraStart - raycastOrigin).LengthSquared() + CAMERA_RADIUS) { return MyCameraRaycastResult.FoundOccluderNoSpace; // obstacle too close, switch to first person } // last check - isn't there voxel between safe pos and entity pos if (!positionChanged) { //Vector3D entityPos = controlledEntity.PositionComp.GetPosition(); MyPhysics.CastRay(m_target, raycastSafeCameraStart, m_raycastList); if (m_debugDraw) { BoundingBoxD bb = new BoundingBoxD(m_target, raycastSafeCameraStart); VRageRender.MyRenderProxy.DebugDrawAABB(bb, Color.Magenta); } foreach (var collision in m_raycastList) { if (collision.HkHitInfo.GetHitEntity() is MyVoxelBase) { return MyCameraRaycastResult.FoundOccluderNoSpace; } } } return positionChanged ? MyCameraRaycastResult.FoundOccluder : MyCameraRaycastResult.Ok; }
/// <summary> /// Handles camera collisions with environment /// </summary> /// <returns>False if no correct position was found</returns> private void HandleIntersection(MyEntity controlledEntity) { Debug.Assert(controlledEntity != null); MyEntity parentEntity = controlledEntity.GetTopMostParent() ?? controlledEntity; var parentEntityAsCubeGrid = parentEntity as MyCubeGrid; if (parentEntityAsCubeGrid != null && parentEntityAsCubeGrid.IsStatic) parentEntity = controlledEntity; // cancel previous assignment, topmost parent is a station, we need smaller bounding box // line from target to eye LineD line = new LineD(m_target, m_position); // oriented bb of the entity MyOrientedBoundingBoxD safeObb = GetEntitySafeOBB(parentEntity); // oriented bb of the entity + camera radius MyOrientedBoundingBoxD safeObbWithCollisionExtents = new MyOrientedBoundingBoxD(safeObb.Center, safeObb.HalfExtent + (controlledEntity.Parent == null ? 0.5 : 2.0) * CAMERA_RADIUS, safeObb.Orientation); // start = target, end = eye // find safe start... LineD safeOBBLine = new LineD(line.From + line.Direction * 2 * safeObb.HalfExtent.Length(), line.From); double? safeIntersection = safeObbWithCollisionExtents.Intersects(ref safeOBBLine); Vector3D castStartSafe = safeIntersection != null ? (safeOBBLine.From + safeOBBLine.Direction * safeIntersection.Value) : m_target; if (controlledEntity.Parent != null && safeIntersection != null) { MatrixD shapeCastStart = MatrixD.CreateTranslation(castStartSafe); HkShape hkSphere = new HkSphereShape(CAMERA_RADIUS * 2); var hitInfo = MyPhysics.CastShapeReturnContactBodyData(m_target, hkSphere, ref shapeCastStart, 0, 0); //VRageRender.MyRenderProxy.DebugDrawCapsule(castStartSafe, m_target, CAMERA_RADIUS * 2, Color.Orange, false); MyEntity hitEntity = hitInfo.HasValue ? hitInfo.Value.HkHitInfo.GetHitEntity() as MyEntity : null; MyEntity entity = controlledEntity; var hitEntityWeldingGroup = hitEntity != null ? MyWeldingGroups.Static.GetGroup(hitEntity) : null; bool weldingGroupEquals = false; while (entity != null && !weldingGroupEquals) { if (hitEntityWeldingGroup == MyWeldingGroups.Static.GetGroup(entity)) weldingGroupEquals = true; entity = entity.Parent; } if (hitInfo.HasValue && hitEntityWeldingGroup != null && weldingGroupEquals) { castStartSafe = castStartSafe + hitInfo.Value.HkHitInfo.HitFraction * (m_target - castStartSafe); } else { safeObb = GetEntitySafeOBB(controlledEntity); safeObbWithCollisionExtents = new MyOrientedBoundingBoxD(safeObb.Center, safeObb.HalfExtent + 0.5f * CAMERA_RADIUS, safeObb.Orientation); safeIntersection = safeObbWithCollisionExtents.Intersects(ref safeOBBLine); castStartSafe = safeIntersection != null ? (safeOBBLine.From + safeOBBLine.Direction * safeIntersection.Value) : m_target; } hkSphere.RemoveReference(); } // raycast against occluders Vector3D safePositionCandidate; //double lastSafeMinimumDistance = m_safeMinimumDistance; m_safeMinimumDistance = controlledEntity is MyCharacter ? 0 : (castStartSafe - m_target).Length(); // store current safe minimum dist m_safeMinimumDistance = Math.Max(m_safeMinimumDistance, MIN_VIEWER_DISTANCE); //if (lastSafeMinimumDistance + 30.0f < m_safeMinimumDistance) //{ // castStartSafe = m_target + (castStartSafe - m_target) / m_safeMinimumDistance * lastSafeMinimumDistance; // m_safeMinimumDistance = lastSafeMinimumDistance; //} Vector3D raycastOrigin = (controlledEntity is MyCharacter) ? m_target : castStartSafe; MyCameraRaycastResult raycastResult = RaycastOccludingObjects(controlledEntity, ref raycastOrigin, ref m_position, ref castStartSafe, out safePositionCandidate); // visual debugging :) if (m_debugDraw) { VRageRender.MyRenderProxy.DebugDrawOBB(safeObb, Color.Red, 0.1f, false, true); VRageRender.MyRenderProxy.DebugDrawOBB(safeObbWithCollisionExtents, Color.Yellow, 0.0f, false, true); VRageRender.MyRenderProxy.DebugDrawArrow3D(safeOBBLine.From, safeOBBLine.To, Color.White, Color.Purple, false); VRageRender.MyRenderProxy.DebugDrawArrow3D(safeOBBLine.From, castStartSafe, Color.White, Color.Red, false); VRageRender.MyRenderProxy.DebugDrawArrow3D(castStartSafe, m_position, Color.White, Color.Orange, false); VRageRender.MyRenderProxy.DebugDrawSphere(castStartSafe, 0.2f, Color.Green, 1.0f, false, true); VRageRender.MyRenderProxy.DebugDrawSphere(safePositionCandidate, 1.0f, Color.LightPink, 1, false); } switch (raycastResult) { case MyCameraRaycastResult.Ok: case MyCameraRaycastResult.FoundOccluder: m_positionCurrentIsSafe = true; { double distFromCandidateToTarget = (safePositionCandidate - m_target).Length(); if (m_disableSpringThisFrame) { m_lastRaycastDist = (float) distFromCandidateToTarget; } if (!m_disableSpringThisFrame && ((distFromCandidateToTarget > m_lastRaycastDist + CAMERA_RADIUS && distFromCandidateToTarget > m_safeMinimumDistance) || raycastResult == MyCameraRaycastResult.Ok)) { // now we need it from the other side double newDist = (safePositionCandidate - m_position).Length(); // new safe position is further from target => change over time (zoom out) if (m_positionSafeZoomingOutTimeout <= 0) { float distDiffZoomSpeed = 1 - MathHelper.Clamp((float) Math.Abs(m_lastRaycastDist - newDist), 0.0f, 1.0f - MyEngineConstants.UPDATE_STEP_SIZE_IN_SECONDS); m_positionSafeZoomingOutSpeed += distDiffZoomSpeed; m_positionSafeZoomingOutSpeed = MathHelper.Clamp(m_positionSafeZoomingOutSpeed, 0.0f, 1.0f); Vector3D targetToPosSafe = m_positionSafe - m_target; double lenTargetToPosSafe = targetToPosSafe.Length(); Vector3D rotatedPositionSafe = m_target + Vector3D.Normalize(safePositionCandidate - m_target) * lenTargetToPosSafe; m_positionSafe = Vector3D.Lerp(rotatedPositionSafe, safePositionCandidate, m_positionSafeZoomingOutSpeed); } else { m_positionSafeZoomingOutTimeout -= MyEngineConstants.UPDATE_STEP_SIZE_IN_MILLISECONDS; Vector3D targetToPosSafe = m_positionSafe - m_target; double lenTargetToPosSafe = targetToPosSafe.Length(); m_positionSafe = m_target + Vector3D.Normalize(safePositionCandidate - m_target) * lenTargetToPosSafe; } } else { // new safe position is closer or closer than safe distance => instant change m_positionSafeZoomingOutSpeed = 0.0f; // set zooming out speed to zero for next time m_positionSafeZoomingOutTimeout = 0;// controlledEntity.Parent != null ? m_positionSafeZoomingOutDefaultTimeoutMs : 0; m_positionSafe = safePositionCandidate; m_disableSpringThisFrame = true; m_positionCurrentIsSafe = distFromCandidateToTarget >= m_safeMinimumDistance; } } break; //case MyCameraRaycastResult.FoundOccluderNoSpace: default: m_positionSafeZoomingOutSpeed = 1.0f; // we're in first person, change instantly to third if possible m_positionCurrentIsSafe = false; break; } m_lastRaycastDist = (float)(m_positionSafe - m_position).Length(); if (m_debugDraw) { VRageRender.MyRenderProxy.DebugDrawSphere(m_positionSafe, 0.225f, Color.Purple, 1, false); VRageRender.MyRenderProxy.DebugDrawSphere(safePositionCandidate, 0.2f, Color.Azure, 1, false); } }
protected override void DoDetection(bool useHead) { if (Character == MySession.Static.ControlledEntity) { MyHud.SelectedObjectHighlight.RemoveHighlight(); } var head = Character.GetHeadMatrix(false); var headPos = head.Translation - (Vector3D)head.Forward * 0.3; // Move to center of head, we don't want eyes (in front of head) Vector3D from; Vector3D dir; if (!useHead) { //Ondrej version var cameraMatrix = MySector.MainCamera.WorldMatrix; //var cameraMatrix = Character.Get3rdBoneMatrix(true, true); dir = cameraMatrix.Forward; from = MyUtils.LinePlaneIntersection(headPos, (Vector3)dir, cameraMatrix.Translation, (Vector3)dir); } else { //Petr version dir = head.Forward; from = headPos; } Vector3D to = from + dir * MyConstants.DEFAULT_INTERACTIVE_DISTANCE; StartPosition = from; MatrixD matrix = MatrixD.CreateTranslation(from); HkShape shape = new HkSphereShape(ShapeRadius); IMyEntity hitEntity = null; ShapeKey = uint.MaxValue; HitPosition = Vector3D.Zero; HitNormal = Vector3.Zero; HitMaterial = MyStringHash.NullOrEmpty; m_hits.Clear(); try { EnableDetectorsInArea(from); MyPhysics.CastShapeReturnContactBodyDatas(to, shape, ref matrix, 0, 0f, m_hits); if (m_hits.Count > 0) { int index = 0; bool isValidBlock = false; bool isPhysicalBlock = false; do { isValidBlock = m_hits[index].HkHitInfo.Body != null && m_hits[index].HkHitInfo.GetHitEntity() != Character && m_hits[index].HkHitInfo.GetHitEntity() != null && !m_hits[index].HkHitInfo.Body.HasProperty(HkCharacterRigidBody.MANIPULATED_OBJECT); isPhysicalBlock = m_hits[index].HkHitInfo.GetHitEntity() != null && m_hits[index].HkHitInfo.GetHitEntity().Physics != null; if (hitEntity == null && isValidBlock) { hitEntity = m_hits[index].HkHitInfo.GetHitEntity(); ShapeKey = m_hits[index].HkHitInfo.GetShapeKey(0); } // Set hit material etc. only for object's that have physical representation in the world, this exclude detectors if (HitMaterial.Equals(MyStringHash.NullOrEmpty) && isValidBlock && isPhysicalBlock) { HitBody = m_hits[index].HkHitInfo.Body; HitPosition = m_hits[index].Position; HitNormal = m_hits[index].HkHitInfo.Normal; HitMaterial = m_hits[index].HkHitInfo.Body.GetBody().GetMaterialAt(HitPosition + HitNormal * 0.1f); } index++; } while (index < m_hits.Count && (!isValidBlock || !isPhysicalBlock)); } } finally { shape.RemoveReference(); } bool hasInteractive = false; var interactive = hitEntity as IMyUseObject; DetectedEntity = hitEntity; if (hitEntity != null) { MyUseObjectsComponentBase useObject = null; hitEntity.Components.TryGet <MyUseObjectsComponentBase>(out useObject); if (useObject != null) { interactive = useObject.GetInteractiveObject(ShapeKey); } } if (UseObject != null && interactive != null && UseObject != interactive) { UseObject.OnSelectionLost(); } if (interactive != null && interactive.SupportedActions != UseActionEnum.None && (Vector3D.Distance(from, HitPosition)) < interactive.InteractiveDistance && Character == MySession.Static.ControlledEntity) { HandleInteractiveObject(interactive); UseObject = interactive; hasInteractive = true; } if (!hasInteractive) { if (UseObject != null) { UseObject.OnSelectionLost(); } UseObject = null; } DisableDetectors(); }
/// <summary> /// Handles camera collisions with environment /// </summary> /// <param name="controlledEntity"></param> /// <param name="shakeActive"></param> /// <param name="headPosition"></param> /// <param name="headDirection"></param> /// <returns>False if no correct position was found</returns> private bool HandleIntersection(MyEntity controlledEntity, MyOrientedBoundingBoxD safeOBB, bool requireRaycast, bool shakeActive, Vector3D headPosition, Vector3 headDirection) { var line = new LineD(m_target, m_position); var safeOBBLine = new LineD(line.From, line.From + line.Direction * 2 * safeOBB.HalfExtent.Length()); Vector3D castStartSafe; { MyOrientedBoundingBoxD safeObbWithCollisionExtents = new MyOrientedBoundingBoxD(safeOBB.Center, safeOBB.HalfExtent + 2 * CAMERA_RADIUS, safeOBB.Orientation); double?safeIntersection = safeObbWithCollisionExtents.Intersects(ref safeOBBLine); if (!safeIntersection.HasValue) { safeIntersection = safeOBB.HalfExtent.Length(); } double safeDistance = safeIntersection.Value; castStartSafe = line.From + line.Direction * safeDistance; } { double?unsafeIntersection = safeOBB.Intersects(ref safeOBBLine); if (!requireRaycast && unsafeIntersection.HasValue) { var castStartUnsafe = line.From + line.Direction * unsafeIntersection.Value; var castEndUnsafe = castStartSafe + line.Direction; // short raycast, not causing problems with asteroids generating geometry Physics.MyPhysics.CastRay(castStartUnsafe, castEndUnsafe, m_raycastList, MyPhysics.CollisionLayers.CharacterCollisionLayer); if (!IsRaycastOK(m_raycastList)) { return(false); } } } if (requireRaycast) { // short raycast, not causing problems with asteroids generating geometry Physics.MyPhysics.CastRay(line.From, castStartSafe + line.Direction, m_raycastList, MyPhysics.CollisionLayers.CharacterCollisionLayer); if (!IsRaycastOK(m_raycastList)) { return(false); } } HkShape shape = new HkSphereShape(CAMERA_RADIUS); try { // small shape, not causing problems with asteroids generating geometry Physics.MyPhysics.GetPenetrationsShape(shape, ref castStartSafe, ref Quaternion.Identity, m_rigidList, MyPhysics.CollisionLayers.CharacterCollisionLayer); if (m_rigidList.Count > 0) { bool sameGrid = false; if (MySession.Static.ControlledEntity != null && m_rigidList[0].Body != null) { sameGrid = m_rigidList[0].GetCollisionEntity() == MySession.Static.ControlledEntity; } if (sameGrid) { castStartSafe += line.Direction; } } var shapeCastLine = new LineD(castStartSafe, m_position); uint steps = 1; uint stepIdx = 0; if (shapeCastLine.Length > SHAPE_CAST_STEP) { steps = (uint)Math.Ceiling(shapeCastLine.Length / SHAPE_CAST_STEP); if (steps >= SHAPE_CAST_MAX_STEP_COUNT) { steps = SHAPE_CAST_MAX_STEP_COUNT - 1; } stepIdx = m_updateCount % steps; m_lastShapeCastDistance[stepIdx] = float.PositiveInfinity; Vector3D step = shapeCastLine.Direction * (shapeCastLine.Length / steps); shapeCastLine = new LineD(castStartSafe + stepIdx * step, castStartSafe + (stepIdx + 1) * step); } if (false) { BoundingBoxD bbox = BoundingBoxD.CreateInvalid(); bbox.Include(new BoundingSphereD(shapeCastLine.From, CAMERA_RADIUS)); bbox.Include(new BoundingSphereD(shapeCastLine.To, CAMERA_RADIUS)); VRageRender.MyRenderProxy.DebugDrawAABB(bbox, Color.Crimson, 1f, 1f, true); } var matrix = MatrixD.CreateTranslation(shapeCastLine.From); HkContactPointData?cpd; if (controlledEntity.Physics != null && controlledEntity.GetPhysicsBody().CharacterProxy != null) { cpd = MyPhysics.CastShapeReturnContactData(shapeCastLine.To, shape, ref matrix, MyPhysics.CollisionLayers.CharacterCollisionLayer, 0.0f); } else { cpd = MyPhysics.CastShapeReturnContactData(shapeCastLine.To, shape, ref matrix, MyPhysics.CollisionLayers.DefaultCollisionLayer, 0.0f); } if (cpd.HasValue) { var point = shapeCastLine.From + shapeCastLine.Direction * shapeCastLine.Length * cpd.Value.DistanceFraction; m_lastShapeCastDistance[stepIdx] = (float)(castStartSafe - point).Length(); } else { m_lastShapeCastDistance[stepIdx] = float.PositiveInfinity; } float?dist = null; for (int i = 0; i < steps; ++i) { if (m_lastShapeCastDistance[i] != float.PositiveInfinity) { dist = Math.Min(m_lastShapeCastDistance[i], dist ?? float.PositiveInfinity); } } if (dist.HasValue) { if (dist == 0.0f) { return(false); } else { m_positionSafe = castStartSafe + shapeCastLine.Direction * dist.Value; } } else { m_positionSafe = m_position; } return(true); } finally { shape.RemoveReference(); } }
private void DoDetection(bool useHead, bool doModelIntersection) { if (Character == MySession.Static.ControlledEntity) { MyHud.SelectedObjectHighlight.RemoveHighlight(); } var head = Character.GetHeadMatrix(false); var headPos = head.Translation - (Vector3D)head.Forward * 0.3; // Move to center of head, we don't want eyes (in front of head) Vector3D from; Vector3D dir; if (!useHead) { //Ondrej version //var cameraMatrix = MySector.MainCamera.WorldMatrix; var cameraMatrix = Character.Get3rdBoneMatrix(true, true); dir = cameraMatrix.Forward; from = MyUtils.LinePlaneIntersection(headPos, (Vector3)dir, cameraMatrix.Translation, (Vector3)dir); } else { //Petr version dir = head.Forward; from = headPos; } Vector3D to = from + dir * 2.5;//MyConstants.DEFAULT_INTERACTIVE_DISTANCE; StartPosition = from; MatrixD matrix = MatrixD.CreateTranslation(from); HkShape shape = new HkSphereShape(ShapeRadius); IMyEntity hitEntity = null; ShapeKey = uint.MaxValue; HitPosition = Vector3D.Zero; HitNormal = Vector3.Zero; HitMaterial = MyStringHash.NullOrEmpty; HitTag = null; m_hits.Clear(); Vector3 interactivePosition = Vector3D.Zero; try { EnableDetectorsInArea(from); MyPhysics.CastShapeReturnContactBodyDatas(to, shape, ref matrix, 0, 0f, m_hits); m_hits.Sort(delegate(MyPhysics.HitInfo info1, MyPhysics.HitInfo info2) { float dot1 = Vector3.Dot(head.Forward, Vector3.Normalize(info1.Position - StartPosition)); float dot2 = Vector3.Dot(head.Forward, Vector3.Normalize(info2.Position - StartPosition)); return(dot1.CompareTo(dot2)); }); if (m_hits.Count > 0) { int index = 0; bool isValidBlock = false; bool isPhysicalBlock = false; do { HkRigidBody body = m_hits[index].HkHitInfo.Body; IMyEntity entity = m_hits[index].HkHitInfo.GetHitEntity(); if (entity is VRage.Game.Entity.MyEntitySubpart) { entity = entity.Parent; } isValidBlock = body != null && entity != null && entity != Character && !body.HasProperty(HkCharacterRigidBody.MANIPULATED_OBJECT); isPhysicalBlock = entity != null && entity.Physics != null; if (hitEntity == null && isValidBlock) { hitEntity = entity; ShapeKey = m_hits[index].HkHitInfo.GetShapeKey(0); } // Set hit material etc. only for object's that have physical representation in the world, this exclude detectors if (HitMaterial.Equals(MyStringHash.NullOrEmpty) && isValidBlock && isPhysicalBlock) { HitBody = body; HitNormal = m_hits[index].HkHitInfo.Normal; HitPosition = m_hits[index].GetFixedPosition(); HitMaterial = body.GetBody().GetMaterialAt(HitPosition); interactivePosition = HitPosition; } else if (body != null) { interactivePosition = m_hits[index].GetFixedPosition(); } index++; } while (index < m_hits.Count && (!isValidBlock || !isPhysicalBlock)); } } finally { shape.RemoveReference(); } bool hasInteractive = false; var interactive = hitEntity as IMyUseObject; DetectedEntity = hitEntity; if (hitEntity != null) { MyUseObjectsComponentBase useObject = null; hitEntity.Components.TryGet <MyUseObjectsComponentBase>(out useObject); if (useObject != null) { interactive = useObject.GetInteractiveObject(ShapeKey); } // Do accurate collision checking on model if (doModelIntersection) { LineD line = new LineD(from, to); var character = hitEntity as MyCharacter; if (character == null) { MyIntersectionResultLineTriangleEx?result; bool success = hitEntity.GetIntersectionWithLine(ref line, out result, IntersectionFlags.ALL_TRIANGLES); if (success) { HitPosition = result.Value.IntersectionPointInWorldSpace; HitNormal = result.Value.NormalInWorldSpace; } } else { bool success = character.GetIntersectionWithLine(ref line, ref CharHitInfo); if (success) { HitPosition = CharHitInfo.Triangle.IntersectionPointInWorldSpace; HitNormal = CharHitInfo.Triangle.NormalInWorldSpace; HitTag = CharHitInfo; } } } } if (UseObject != null && interactive != null && UseObject != interactive) { UseObject.OnSelectionLost(); } if (interactive != null && interactive.SupportedActions != UseActionEnum.None && (Vector3D.Distance(from, interactivePosition)) < interactive.InteractiveDistance && Character == MySession.Static.ControlledEntity) { HandleInteractiveObject(interactive); UseObject = interactive; hasInteractive = true; } if (!hasInteractive) { if (UseObject != null) { UseObject.OnSelectionLost(); } UseObject = null; } DisableDetectors(); }