public void Instanciate(MyPhysics physics) { mPosition = this.transform.position; mCollider = GetComponent<Collision>(); mMass = Mathf.Pow (mCollider.size, 3); physics.AddBody (this); Instanciated = true; }
private MyEntity FindBody(out Vector3D pivot) { pivot = Vector3D.Zero; if (CubeGrid.Physics == null) { return(null); } Quaternion orientation; Vector3 halfExtents; foreach (var m in m_lockPositions) { GetBoxFromMatrix(m, out halfExtents, out pivot, out orientation); HkBoxShape boxShape; try { halfExtents *= new Vector3(2.0f, 1.0f, 2.0f); orientation.Normalize(); MyPhysics.GetPenetrationsBox(ref halfExtents, ref pivot, ref orientation, m_penetrations, MyPhysics.CollisionLayers.DefaultCollisionLayer); boxShape = new HkBoxShape(halfExtents); Matrix tranform = Matrix.CreateFromQuaternion(orientation); //tranform.Translation = pivot; //MyOrientedBoundingBoxD obb = new MyOrientedBoundingBoxD(new BoundingBoxD(-halfExtents, halfExtents),tranform); //tranform.Translation = Vector3D.Zero; //MyRenderProxy.DebugDrawOBB(obb, Color.Red, 1, false, false); foreach (var obj in m_penetrations) { var entity = MyPhysicsExtensions.GetCollisionEntity(obj) as MyEntity; if (entity == null)// || entity.Parent != null) { continue; } if (entity.GetPhysicsBody().WeldInfo.Children.Count > 0) { Matrix t2; foreach (var child in entity.GetPhysicsBody().WeldInfo.Children) { var childEnt = child.Entity as MyEntity; t2 = childEnt.GetPhysicsBody().WeldInfo.Transform *entity.Physics.RigidBody.GetRigidBodyMatrix(); t2.Translation = entity.Physics.ClusterToWorld(t2.Translation); //obb = new MyOrientedBoundingBoxD((BoundingBoxD)childEnt.PositionComp.LocalAABB, t2); //MyRenderProxy.DebugDrawOBB(obb, Color.Green, 1, false, false); t2.Translation = t2.Translation - pivot; if (MyPhysics.IsPenetratingShapeShape(boxShape, ref tranform, child.WeldedRigidBody.GetShape(), ref t2)) { if ( CanAttachTo(obj, child.Entity as MyEntity)) { return(child.Entity as MyEntity); } } } t2 = entity.Physics.RigidBody.GetRigidBodyMatrix(); t2.Translation = entity.Physics.ClusterToWorld(t2.Translation) - pivot; if (MyPhysics.IsPenetratingShapeShape(boxShape, ref tranform, entity.GetPhysicsBody().GetShape(), ref t2) && CanAttachTo(obj, entity)) { return(entity); } } else if (CanAttachTo(obj, entity)) { return(entity); } } } finally { boxShape.Base.RemoveReference(); m_penetrations.Clear(); } } return(null); }
protected Vector3D?GetFreeSpacePlacementPosition(bool copyPaste, out bool buildAllowed) { Vector3D?freePlacementIntersectionPoint = null; buildAllowed = false; float gridSize = PreviewGrids[0].GridSize; double shortestDistance = double.MaxValue; double?currentRayInts = MyCubeBuilder.GetCurrentRayIntersection(); if (currentRayInts.HasValue) { shortestDistance = currentRayInts.Value; } Vector3D worldRefPointOffset = Vector3D.Zero; if (copyPaste) { Matrix firstGridOrientation = GetFirstGridOrientationMatrix(); worldRefPointOffset = Vector3.TransformNormal(m_dragPointToPositionLocal, firstGridOrientation); } Vector3D worldRefPoint = PreviewGrids[0].GridIntegerToWorld(Vector3I.Zero); Matrix blockLocalTransform; foreach (var block in PreviewGrids[0].GetBlocks()) { Vector3 halfExt = block.BlockDefinition.Size * PreviewGrids[0].GridSize * 0.5f; Vector3 minLocal = block.Min * PreviewGrids[0].GridSize - Vector3.Half * PreviewGrids[0].GridSize; Vector3 maxLocal = block.Max * PreviewGrids[0].GridSize + Vector3.Half * PreviewGrids[0].GridSize; block.Orientation.GetMatrix(out blockLocalTransform); blockLocalTransform.Translation = 0.5f * (minLocal + maxLocal); MatrixD blockWorldTransform = blockLocalTransform * PreviewGrids[0].WorldMatrix; Vector3D offset = blockWorldTransform.Translation + worldRefPointOffset - worldRefPoint; HkShape shape = new HkBoxShape(halfExt); Vector3D rayStart = MyCubeBuilder.IntersectionStart + offset; double castPlaneDistanceToRayStart = DistanceFromCharacterPlane(ref rayStart); rayStart -= castPlaneDistanceToRayStart * MyCubeBuilder.IntersectionDirection; Vector3D rayEnd = MyCubeBuilder.IntersectionStart + (m_dragDistance - castPlaneDistanceToRayStart) * MyCubeBuilder.IntersectionDirection + offset; MatrixD matrix = blockWorldTransform; matrix.Translation = rayStart; try { float?dist = MyPhysics.CastShape(rayEnd, shape, ref matrix, MyPhysics.CollisionLayers.CollisionLayerWithoutCharacter); if (dist.HasValue && dist.Value != 0f) { Vector3D intersectionPoint = rayStart + dist.Value * (rayEnd - rayStart); const bool debugDraw = false; if (debugDraw) { Color green = Color.Green; BoundingBoxD localAABB = new BoundingBoxD(-halfExt, halfExt); MatrixD drawMatrix = matrix; drawMatrix.Translation = intersectionPoint; MySimpleObjectDraw.DrawTransparentBox(ref drawMatrix, ref localAABB, ref green, MySimpleObjectRasterizer.Wireframe, 1, 0.04f); } double fixedDistance = DistanceFromCharacterPlane(ref intersectionPoint) - castPlaneDistanceToRayStart; if (fixedDistance <= 0) { fixedDistance = 0; shortestDistance = 0; break; } if (fixedDistance < shortestDistance) { shortestDistance = fixedDistance; } buildAllowed = true; } } finally { shape.RemoveReference(); } } float boxRadius = (float)PreviewGrids[0].PositionComp.WorldAABB.HalfExtents.Length(); float dragDistance = 1.5f * boxRadius; if (shortestDistance < dragDistance) { shortestDistance = dragDistance; buildAllowed = false; } if (shortestDistance < m_dragDistance) { freePlacementIntersectionPoint = MyCubeBuilder.IntersectionStart + shortestDistance * MyCubeBuilder.IntersectionDirection; } return(freePlacementIntersectionPoint); }
/// <summary> /// Finds the closest foot support position using raycast - should raycast from start and from end of the foot /// </summary> /// <param name="from">Vector3 from - the world coordinate from witch to ray cast - usually the foot world position on the ground</param> /// <param name="up">Vector3 up - defining the world up vector used to raycast to the ground</param> /// <param name="WorldMatrix">is the world matrix of the model</param> /// <param name="castUpLimit">is the height from where we start casting</param> /// <param name="castDownLimit">is the height to how much deep we cast</param> /// <param name="footDimension">this is the foot dimension, used to create shape cast and also ankle's height, X = width, Z = length, Y = height</param> /// <returns>returns CashHit if hit or null otherwise</returns> public static CastHit?GetClosestFootSupportPosition(MyEntity characterEntity, MyEntity characterTool, Vector3 from, Vector3 up, Vector3 footDimension, Matrix WorldMatrix, float castDownLimit, float castUpLimit, uint raycastFilterLayer = 0) { bool gotHit = false; CastHit hit = new CastHit(); MatrixD matrix = WorldMatrix; Vector3 footTranslationFromAnkle = Vector3.Zero;//new Vector3(0, footDimension.Y, - footDimension.Y + footDimension.X); // assunming the -Z is facing front // set the proper translation matrix.Translation = Vector3.Zero; // just keep the matrix's orientation etc. footTranslationFromAnkle = Vector3.Transform(footTranslationFromAnkle, matrix); // get it to the world matrix.Translation = from + up * castUpLimit + footTranslationFromAnkle; // set the matrix translation to position from where we cast - we need to shift from the ankle // our shape cast returned data structure //HkContactPointData? cpd = null; //// do the foot cast shape, raycast sometimes don't return a value and we need to make sure that we do nut fall into hole //HkShape shape = new HkBoxShape(footDimension * 0.5f); Vector3 capsA = new Vector3(0, footDimension.Y / 2, 0); Vector3 capsB = new Vector3(0, footDimension.Y / 2, -footDimension.Z); //capsA = Vector3.Transform(capsA, WorldMatrix.GetOrientation()); //capsB = Vector3.Transform(capsB, WorldMatrix.GetOrientation()); //HkShape shape = new HkCapsuleShape(capsA, capsB, footDimension.X / 2); Vector3 castFrom = from + up * castUpLimit; Vector3 castTo = from - up * castDownLimit; //cpd = MyPhysics.CastShapeReturnContactData(castTo + footTranslationFromAnkle, shape, ref matrix, Physics.CharacterProxy.CharacterCollisionFilter, 0.0f); //var hit = MyPhysics.CastRay(castFrom, castTo, out position, out normal, Physics.CharacterProxy.CharacterCollisionFilter, true); //LineD castLine = new LineD(castFrom, castTo); //var result = MyEntities.GetIntersectionWithLine(ref castLine, characterEntity, characterTool, true, false, true); //if (result != null) //{ // hit.Position = result.Value.IntersectionPointInWorldSpace; // hit.Normal = result.Value.NormalInWorldSpace; // gotHit = true; // if (MyDebugDrawSettings.ENABLE_DEBUG_DRAW && MyDebugDrawSettings.DEBUG_DRAW_CHARACTER_IK_RAYCASTHITS) // { // VRageRender.MyRenderProxy.DebugDrawSphere(hit.Position, 0.02f, Color.Gray, 1, false); // VRageRender.MyRenderProxy.DebugDrawText3D(hit.Position, "Entity Intersection hit", Color.Gray, 1, false); // } //} if (MyDebugDrawSettings.ENABLE_DEBUG_DRAW && MyDebugDrawSettings.DEBUG_DRAW_CHARACTER_IK_RAYCASTLINE) { VRageRender.MyRenderProxy.DebugDrawText3D(castFrom + footTranslationFromAnkle, "Cast line", Color.White, 1, false); VRageRender.MyRenderProxy.DebugDrawLine3D(castFrom + footTranslationFromAnkle, castTo + footTranslationFromAnkle, Color.White, Color.White, false); } if (MyFakes.ENABLE_FOOT_IK_USE_HAVOK_RAYCAST) { // do the ray cast also, because ground may not be flat and we will use this to correct values just using raycast, this takes in consideration convex shape radius and ignores it MyPhysics.HitInfo hitInfo; if (MyDebugDrawSettings.ENABLE_DEBUG_DRAW && MyDebugDrawSettings.DEBUG_DRAW_CHARACTER_IK_RAYCASTLINE) { VRageRender.MyRenderProxy.DebugDrawText3D(castFrom, "Raycast line", Color.Green, 1, false); VRageRender.MyRenderProxy.DebugDrawLine3D(castFrom, castTo, Color.Green, Color.Green, false); } if (MyPhysics.CastRay(castFrom, castTo, out hitInfo, raycastFilterLayer, true)) { gotHit = true; if (MyDebugDrawSettings.ENABLE_DEBUG_DRAW && MyDebugDrawSettings.DEBUG_DRAW_CHARACTER_IK_RAYCASTHITS) { VRageRender.MyRenderProxy.DebugDrawSphere(hitInfo.Position, 0.02f, Color.Green, 1, false); VRageRender.MyRenderProxy.DebugDrawText3D(hitInfo.Position, "RayCast hit", Color.Green, 1, false); } // this is hack, if RayCast returns a hit above the graphics cast, take this one if (Vector3.Dot(hitInfo.Position, up) > Vector3.Dot(hit.Position, up)) { hit.Position = hitInfo.Position; hit.Normal = hitInfo.HkHitInfo.Normal; } } } // // now we need to recalculate the hit position to center // cp.HitPosition = from - Vector3.Dot(WorldMatrix.Translation - cp.HitPosition, up) * up; // //cp.HitPosition.Interpolate3(castFrom, castTo, cp.DistanceFraction); // //cp.HitPosition -= footTranslationFromAnkle; // if (MyDebugDrawSettings.ENABLE_DEBUG_DRAW && MyDebugDrawSettings.DEBUG_DRAW_CHARACTER_IK_RAYCASTHITS) // { // VRageRender.MyRenderProxy.DebugDrawSphere(cp.HitPosition, 0.03f, Color.Violet, 1, false); // VRageRender.MyRenderProxy.DebugDrawText3D(cp.HitPosition, "ShapeCast hit Centered", Color.Violet, 1, false); // } // // shape cast correction using the normal // //float dotProductAbs = WorldMatrix.Forward.Dot(cp.Normal); // //cp.HitPosition -= WorldMatrix.Up * (1 - dotProductAbs) * footDimension.Y; // // draw shape and ray cast hits // if (MyDebugDrawSettings.ENABLE_DEBUG_DRAW && MyDebugDrawSettings.DEBUG_DRAW_CHARACTER_IK_RAYCASTHITS) // { // matrix.Translation = cp.HitPosition; // VRageRender.MyRenderProxy.DebugDrawOBB(Matrix.CreateScale(footDimension) * matrix, Color.White, 1, false, false); // VRageRender.MyRenderProxy.DebugDrawCapsule(Vector3.Transform(capsA, WorldMatrix.GetOrientation()) + cp.HitPosition, Vector3.Transform(capsB, WorldMatrix.GetOrientation()) + cp.HitPosition, footDimension.X, Color.Red, false); // } // // use raycast to correct position // //if (hit) // //{ // // // draw shape and ray cast hits // // if (MyDebugDrawSettings.ENABLE_DEBUG_DRAW && MyDebugDrawSettings.DEBUG_DRAW_CHARACTER_IK_RAYCASTHITS) // // { // // VRageRender.MyRenderProxy.DebugDrawSphere(position, 0.02f, Color.Green, 1, false, false); // // VRageRender.MyRenderProxy.DebugDrawText3D(position, "RayCast hit", Color.Green, 1, false); // // } // // // shift the foot up for the ankle height according to the normal orientation // // //float dotProductAbs = Math.Abs( WorldMatrix.Forward.Dot(normal)); // // //{ // // // // get the difference between shape and ray cast and set the position // // // Vector3 difference = (position - cp.HitPosition) * (dotProductAbs); // // // cp.HitPosition = position - difference; // prefer shapecast when the ground is on ankle // // //} // // cp.HitPosition.Interpolate3(cp.HitPosition, position, Vector3.Dot(WorldMatrix.Up, normal)); // // //cp.Normal = normal; // //} // // where will be final foot if not ankle's shifted // if (MyDebugDrawSettings.ENABLE_DEBUG_DRAW && MyDebugDrawSettings.DEBUG_DRAW_CHARACTER_IK_RAYCASTHITS) // { // matrix.Translation = cp.HitPosition; // VRageRender.MyRenderProxy.DebugDrawSphere(cp.HitPosition, 0.02f, Color.Red, 1, false, false); // VRageRender.MyRenderProxy.DebugDrawText3D(cp.HitPosition, "Final hit", Color.Red, 1, false); // VRageRender.MyRenderProxy.DebugDrawLine3D(cp.HitPosition, cp.HitPosition + cp.Normal, Color.YellowGreen, Color.YellowGreen, false); // VRageRender.MyRenderProxy.DebugDrawOBB(Matrix.CreateScale(footDimension) * matrix, Color.Cyan, 1, false, false); // } //} return(gotHit ? new CastHit?(hit) : null); }
private void ThrustDamage() { if (m_flames.Count > 0 && MySession.Static.ThrusterDamage && Sync.IsServer && IsWorking && CubeGrid.InScene && CubeGrid.Physics != null && CubeGrid.Physics.Enabled) { if (CurrentStrength == 0 && !MyFakes.INACTIVE_THRUSTER_DMG) { return; } UpdateThrustFlame(); foreach (var flameInfo in m_flames) { var l = GetDamageCapsuleLine(flameInfo); HkShape shape; if (l.Length != 0) { shape = new HkCapsuleShape(Vector3.Zero, l.To - l.From, flameInfo.Radius * BlockDefinition.FlameDamageLengthScale); } else { shape = new HkSphereShape(flameInfo.Radius * BlockDefinition.FlameDamageLengthScale); } MyPhysics.GetPenetrationsShape(shape, ref l.From, ref Quaternion.Identity, m_flameCollisionsList, MyPhysics.CollisionLayers.DefaultCollisionLayer); shape.RemoveReference(); foreach (var obj in m_flameCollisionsList) { var ent = obj.GetCollisionEntity(); if (ent == null || ent.Equals(this)) { continue; } if (!(ent is MyCharacter)) { ent = ent.GetTopMostParent(); } if (m_damagedEntities.Contains(ent)) { continue; } else { m_damagedEntities.Add(ent); } if (ent is IMyDestroyableObject) { (ent as IMyDestroyableObject).DoDamage(flameInfo.Radius * BlockDefinition.FlameDamage * 10, MyDamageType.Environment, true, attackerId: EntityId); } else if (ent is MyCubeGrid) { var grid = ent as MyCubeGrid; if (grid.BlocksDestructionEnabled) { DamageGrid(flameInfo, l, grid); } } } m_damagedEntities.Clear(); m_flameCollisionsList.Clear(); } } }
private MyStringHash RayCastGround() { MyStringHash walkSurfaceMaterial = new MyStringHash(); float maxDistValue = MyConstants.DEFAULT_GROUND_SEARCH_DISTANCE; var from = m_character.PositionComp.GetPosition() + m_character.PositionComp.WorldMatrix.Up * 0.5; //(needs some small distance from the bottom or the following call to HavokWorld.CastRay will find no hits) var to = from + m_character.PositionComp.WorldMatrix.Down * maxDistValue; MyPhysics.CastRay(from, to, m_hits, MyPhysics.CollisionLayers.CharacterCollisionLayer); // Skips invalid hits (null body, self character) int index = 0; while ((index < m_hits.Count) && ((m_hits[index].HkHitInfo.Body == null) || (m_hits[index].HkHitInfo.GetHitEntity() == Entity.Components))) { index++; } if (m_hits.Count == 0) { if ((m_standingOnGrid != null || m_standingOnVoxel != null) && ShouldUpdateSoundEmitters) { m_standingOnGrid = null; m_standingOnVoxel = null; MyEntity3DSoundEmitter.UpdateEntityEmitters(true, true, false); } else { m_standingOnGrid = null; m_standingOnVoxel = null; } } if (index < m_hits.Count) { // We must take only closest hit (others are hidden behind) var h = m_hits[index]; var entity = h.HkHitInfo.GetHitEntity(); var sqDist = Vector3D.DistanceSquared((Vector3D)h.Position, from); if (sqDist < maxDistValue * maxDistValue) { var cubeGrid = entity as MyCubeGrid; var voxelBase = entity as MyVoxelBase; if (((cubeGrid != null && m_standingOnGrid != cubeGrid) || (voxelBase != null && m_standingOnVoxel != voxelBase)) && ShouldUpdateSoundEmitters) { m_standingOnGrid = cubeGrid; m_standingOnVoxel = voxelBase; MyEntity3DSoundEmitter.UpdateEntityEmitters(true, true, true); } else { m_standingOnGrid = cubeGrid; m_standingOnVoxel = voxelBase; } if (cubeGrid != null || voxelBase != null) { m_jumpReady = true; } if (cubeGrid != null) { walkSurfaceMaterial = cubeGrid.Physics.GetMaterialAt(h.Position + m_character.PositionComp.WorldMatrix.Down * 0.1f); } else if (voxelBase != null && voxelBase.Storage != null && voxelBase.Storage.DataProvider != null) { var materialDefinition = voxelBase.GetMaterialAt(ref h.Position); if (materialDefinition != null) { walkSurfaceMaterial = MyStringHash.GetOrCompute(materialDefinition.MaterialTypeName); } } if (walkSurfaceMaterial.ToString().Length == 0) { walkSurfaceMaterial = MyMaterialType.ROCK; } } } m_hits.Clear(); return(walkSurfaceMaterial); }
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; } } } while (entity == null && ++raycastListIndex < m_entityRaycastResult.Count); }
/// <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; } } 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); } }
public override bool Update(bool hasFocus) { m_ticks = MyPerformanceCounter.ElapsedTicks; m_frameCounter++; double secondsFromStart = MyPerformanceCounter.TicksToMs(m_ticks - m_startTime) / 1000; if (secondsFromStart > 1) { double updateLagOverMeasureTime = (secondsFromStart - m_frameCounter * VRage.Game.MyEngineConstants.UPDATE_STEP_SIZE_IN_SECONDS); m_updateLag = updateLagOverMeasureTime / secondsFromStart * 1000; m_startTime = m_ticks; m_frameCounter = 0; if (Sync.Layer != null) { m_sentLastSec = (Sync.Layer.TransportLayer.ByteCountSent - m_lastSent) / secondsFromStart; m_receivedLastSec = (Sync.Layer.TransportLayer.ByteCountReceived - m_lastReceived) / secondsFromStart; m_lastReceived = Sync.Layer.TransportLayer.ByteCountReceived; m_lastSent = Sync.Layer.TransportLayer.ByteCountSent; } } Stats.Timing.Write("FPS", MyFpsManager.GetFps(), VRage.Stats.MyStatTypeEnum.CurrentValue, 0, 0); Stats.Timing.Increment("UPS", 1000); Stats.Timing.Write("Simulation speed", Sandbox.Engine.Physics.MyPhysics.SimulationRatio, VRage.Stats.MyStatTypeEnum.CurrentValue, 100, 2); Stats.Timing.Write("Server simulation speed", Sync.ServerSimulationRatio, VRage.Stats.MyStatTypeEnum.CurrentValue, 100, 2); Stats.Timing.WriteFormat("Frame time: {0} ms", MyFpsManager.FrameTime, VRage.Stats.MyStatTypeEnum.CurrentValue, 0, 1); Stats.Timing.WriteFormat("Frame avg time: {0} ms", MyFpsManager.FrameTimeAvg, VRage.Stats.MyStatTypeEnum.CurrentValue, 0, 1); Stats.Timing.WriteFormat("Frame min time: {0} ms", MyFpsManager.FrameTimeMin, VRage.Stats.MyStatTypeEnum.CurrentValue, 0, 1); Stats.Timing.WriteFormat("Frame max time: {0} ms", MyFpsManager.FrameTimeMax, VRage.Stats.MyStatTypeEnum.CurrentValue, 0, 1); Stats.Timing.Write("Update lag (per s)", (float)m_updateLag, VRage.Stats.MyStatTypeEnum.CurrentValue, 0, 4); Stats.Timing.Write("GC Memory", GC.GetTotalMemory(false), VRage.Stats.MyStatTypeEnum.CurrentValue, 0, 0); #if !XB1 Stats.Timing.Write("Process memory", WinApi.WorkingSet, VRage.Stats.MyStatTypeEnum.CurrentValue, 0, 0); #endif // !XB1 Stats.Timing.Write("Active parcticle effects", MyParticlesManager.ParticleEffectsForUpdate.Count, VRage.Stats.MyStatTypeEnum.CurrentValue, 0, 0); //Stats.Timing.Write("Billboards total", VRageRender.MyPerformanceCounter.PerCameraDraw11Read.BillboardsDrawn, VRage.Stats.MyStatTypeEnum.CurrentValue, 0, 0); if (MyPhysics.GetClusterList() != null) { double i = 0.0; double sum = 0.0; double max = 0.0; foreach (Havok.HkWorld havokWorld in MyPhysics.GetClusterList()) { i += 1.0; var value = havokWorld.StepDuration.TotalMilliseconds; sum += value; if (value > max) { max = value; } } Stats.Timing.WriteFormat("Physics worlds count: {0}", (float)i, VRage.Stats.MyStatTypeEnum.CurrentValue, 0, 0); Stats.Timing.WriteFormat("Physics step time (sum): {0} ms", (float)sum, VRage.Stats.MyStatTypeEnum.CurrentValue, 0, 1); Stats.Timing.WriteFormat("Physics step time (avg): {0} ms", (float)(sum / i), VRage.Stats.MyStatTypeEnum.CurrentValue, 0, 1); Stats.Timing.WriteFormat("Physics step time (max): {0} ms", (float)max, VRage.Stats.MyStatTypeEnum.CurrentValue, 0, 1); } if (Sync.Layer != null) { Stats.Timing.Write("Received KB/s", (float)m_receivedLastSec / 1024, VRage.Stats.MyStatTypeEnum.CurrentValue, 0, 2); Stats.Timing.Write("Sent KB/s", (float)m_sentLastSec / 1024, VRage.Stats.MyStatTypeEnum.CurrentValue, 0, 2); } return(base.Update(hasFocus)); }
/// <summary> /// Returns true if the given small block connects to large one. One of the given AABB's is inflated with 0.05 to reduce inaccuracies. /// </summary> /// <param name="smallBlock">small block</param> /// <param name="smallBlockWorldAabb">small block world AABB</param> /// <param name="largeBlock">large block</param> /// <param name="largeBlockWorldAabb">large block wotld AABB</param> /// <returns>true when connected</returns> private bool SmallBlockConnectsToLarge(MySlimBlock smallBlock, ref BoundingBoxD smallBlockWorldAabb, MySlimBlock largeBlock, ref BoundingBoxD largeBlockWorldAabb) { Debug.Assert(GetCubeSize(smallBlock) == MyCubeSize.Small); Debug.Assert(GetCubeSize(largeBlock) == MyCubeSize.Large); Debug.Assert(!(smallBlock.FatBlock is MyCompoundCubeBlock)); Debug.Assert(!(largeBlock.FatBlock is MyCompoundCubeBlock)); BoundingBoxD smallBlockWorldAabbReduced = smallBlockWorldAabb; smallBlockWorldAabbReduced.Inflate(-smallBlock.CubeGrid.GridSize / 4); // Small block aabb penetrates large block aabb (large timbers). bool penetratesAabbs = largeBlockWorldAabb.Intersects(smallBlockWorldAabbReduced); if (!penetratesAabbs) { Vector3I addDir = GetSmallBlockAddDirection(ref smallBlockWorldAabb, ref smallBlockWorldAabbReduced, ref largeBlockWorldAabb); // Check small grid mount points Quaternion smallBlockRotation; smallBlock.Orientation.GetQuaternion(out smallBlockRotation); smallBlockRotation = Quaternion.CreateFromRotationMatrix(smallBlock.CubeGrid.WorldMatrix) * smallBlockRotation; if (!MyCubeGrid.CheckConnectivitySmallBlockToLargeGrid(largeBlock.CubeGrid, smallBlock.BlockDefinition, ref smallBlockRotation, ref addDir)) { return(false); } } BoundingBoxD smallBlockWorldAabbInflated = smallBlockWorldAabb; smallBlockWorldAabbInflated.Inflate(2 * smallBlock.CubeGrid.GridSize / 3); // Trim small block aabb with large block aabb. BoundingBoxD intersectedBox = smallBlockWorldAabbInflated.Intersect(largeBlockWorldAabb); Vector3D intersectedBoxCenter = intersectedBox.Center; HkShape shape = new HkBoxShape((Vector3)intersectedBox.HalfExtents); Quaternion largeRotation; largeBlock.Orientation.GetQuaternion(out largeRotation); largeRotation = Quaternion.CreateFromRotationMatrix(largeBlock.CubeGrid.WorldMatrix) * largeRotation; Vector3D largeTranslation; largeBlock.ComputeWorldCenter(out largeTranslation); bool result = false; try { if (largeBlock.FatBlock != null) { MyModel model = largeBlock.FatBlock.Model; if (model != null) { HkShape[] shapes = model.HavokCollisionShapes; if (shapes == null || shapes.Length == 0) { return(false); } for (int i = 0; i < shapes.Length; ++i) { result = MyPhysics.IsPenetratingShapeShape(shape, ref intersectedBoxCenter, ref Quaternion.Identity, shapes[i], ref largeTranslation, ref largeRotation); if (result) { break; } } } else { HkShape shapeLarge = new HkBoxShape(largeBlock.BlockDefinition.Size * largeBlock.CubeGrid.GridSize / 2); result = MyPhysics.IsPenetratingShapeShape(shape, ref intersectedBoxCenter, ref Quaternion.Identity, shapeLarge, ref largeTranslation, ref largeRotation); shapeLarge.RemoveReference(); } } else { HkShape shapeLarge = new HkBoxShape(largeBlock.BlockDefinition.Size * largeBlock.CubeGrid.GridSize / 2); result = MyPhysics.IsPenetratingShapeShape(shape, ref intersectedBoxCenter, ref Quaternion.Identity, shapeLarge, ref largeTranslation, ref largeRotation); shapeLarge.RemoveReference(); } } finally { shape.RemoveReference(); } return(result); }
protected MyMotorRotor FindMatchingRotor() { Debug.Assert(CubeGrid != null); Debug.Assert(m_penetrations != null); Debug.Assert(CubeGrid.Physics != null); if (CubeGrid == null) { MySandboxGame.Log.WriteLine("MyMotorStator.FindMatchingRotor(): Cube grid == null!"); return(null); } if (m_penetrations == null) { MySandboxGame.Log.WriteLine("MyMotorStator.FindMatchingRotor(): penetrations cache == null!"); return(null); } if (CubeGrid.Physics == null) { MySandboxGame.Log.WriteLine("MyMotorStator.FindMatchingRotor(): Cube grid physics == null!"); return(null); } Quaternion orientation; Vector3D pos; Vector3 halfExtents; ComputeRotorQueryBox(out pos, out halfExtents, out orientation); try { MyPhysics.GetPenetrationsBox(ref halfExtents, ref pos, ref orientation, m_penetrations, MyPhysics.DefaultCollisionLayer); foreach (var obj in m_penetrations) { if (obj == null) { continue; } if (obj == CubeGrid.Physics.RigidBody || obj == CubeGrid.Physics.RigidBody2) { continue; } var entity = obj.GetEntity(); if (entity == null) { continue; } var grid = entity as MyCubeGrid; if (grid == null) { continue; } // Rotor should always be on position [0,0,0]; var pos2 = Vector3.Transform(DummyPosition, CubeGrid.WorldMatrix); var blockPos = grid.RayCastBlocks(pos2, pos2 + WorldMatrix.Up); if (blockPos.HasValue) { var slimBlock = grid.GetCubeBlock(blockPos.Value); if (slimBlock == null || slimBlock.FatBlock == null) { continue; } var rotor = slimBlock.FatBlock as MyMotorRotor; if (rotor != null) { return(rotor); } } } } finally { m_penetrations.Clear(); } return(null); }
public override void UpdateBeforeSimulation() { int num = 0; if ((m_rayCastQueue.Count > 0) && ((this.m_rayCastCounter % 20) == 0)) { while ((num < 50) && (m_rayCastQueue.Count > 0)) { int randomInt = MyUtils.GetRandomInt(m_rayCastQueue.Count - 1); MyEntity entity = m_rayCastQueue[randomInt].Entity; MyEntityRayCastPair local1 = m_rayCastQueue[randomInt]; Vector3D position = m_rayCastQueue[randomInt].Position; MyParticleEffect particle = m_rayCastQueue[randomInt].Particle; if (entity is MyCubeGrid) { particle.Stop(true); MyCubeGrid grid = entity as MyCubeGrid; MatrixD worldMatrixNormalizedInv = grid.PositionComp.WorldMatrixNormalizedInv; if (grid.BlocksDestructionEnabled) { grid.Physics.ApplyDeformation(6f, 3f, 3f, (Vector3)Vector3.Transform((Vector3)position, worldMatrixNormalizedInv), Vector3.Normalize(Vector3.Transform((Vector3)m_directionFromSunNormalized, worldMatrixNormalizedInv)), MyDamageType.Environment, 0f, 0f, 0L); } m_rayCastQueue.RemoveAt(randomInt); this.m_hitLst.Clear(); break; } } } this.m_rayCastCounter++; if (IsActive) { float num2 = (MySandboxGame.TotalGamePlayTimeInMilliseconds - m_timeLastUpdate) / 1000f; m_timeLastUpdate = MySandboxGame.TotalGamePlayTimeInMilliseconds; if (!MySandboxGame.IsPaused) { m_deltaTime += num2; float num3 = m_speed * m_deltaTime; if (num3 >= 60000f) { IsActive = false; StopCue(); } else { Vector3D translation; if (MySession.Static.LocalCharacter != null) { translation = MySession.Static.LocalCharacter.Entity.WorldMatrix.Translation; } else { translation = Vector3D.Zero; } Vector3D point = translation; m_planeMiddle = new PlaneD(m_initialSunWindPosition + (m_directionFromSunNormalized * num3), m_directionFromSunNormalized); m_distanceToSunWind = m_planeMiddle.DistanceToPoint(ref point); m_positionOnCameraLine = -m_directionFromSunNormalized * m_distanceToSunWind; Vector3D position = m_positionOnCameraLine + (m_directionFromSunNormalized * 2000.0); Vector3D vectord3 = m_positionOnCameraLine + (m_directionFromSunNormalized * -2000.0); m_planeFront = new PlaneD(position, m_directionFromSunNormalized); m_planeBack = new PlaneD(vectord3, m_directionFromSunNormalized); m_planeFront.DistanceToPoint(ref point); m_planeBack.DistanceToPoint(ref point); int index = 0; while (index < m_sunwindEntities.Count) { if (m_sunwindEntities[index].MarkedForClose) { m_sunwindEntities.RemoveAtFast <IMyEntity>(index); continue; } index++; } Quaternion orientation = Quaternion.CreateFromRotationMatrix(Matrix.CreateFromDir((Vector3)m_directionFromSunNormalized, (Vector3)m_downVector)); Vector3 halfExtents = new Vector3(10000f, 10000f, 2000f); MyRenderProxy.DebugDrawOBB(new MyOrientedBoundingBoxD(position + (m_directionFromSunNormalized * 2500.0), halfExtents, orientation), Color.Red.ToVector3(), 1f, false, false, false); if (this.m_rayCastCounter == 120) { Vector3D translation = position + (m_directionFromSunNormalized * 2500.0); MyPhysics.GetPenetrationsBox(ref halfExtents, ref translation, ref orientation, m_intersectionLst, 15); using (List <HkBodyCollision> .Enumerator enumerator = m_intersectionLst.GetEnumerator()) { while (enumerator.MoveNext()) { IMyEntity collisionEntity = enumerator.Current.GetCollisionEntity(); if (!(collisionEntity is MyVoxelMap) && !m_sunwindEntities.Contains(collisionEntity)) { m_sunwindEntities.Add(collisionEntity); } } } m_intersectionLst.Clear(); int num6 = 0; while (true) { if (num6 >= m_sunwindEntities.Count) { this.m_rayCastCounter = 0; break; } IMyEntity item = m_sunwindEntities[num6]; if (item is MyCubeGrid) { MyCubeGrid grid2 = item as MyCubeGrid; BoundingBoxD worldAABB = grid2.PositionComp.WorldAABB; double num7 = (worldAABB.Center - worldAABB.Min).Length(); double num8 = ((worldAABB.Center - worldAABB.Min) / m_rightVector).AbsMin(); double num9 = ((worldAABB.Center - worldAABB.Min) / m_downVector).AbsMin(); Vector3I vectori = grid2.Max - grid2.Min; Math.Max(vectori.X, Math.Max(vectori.Y, vectori.Z)); MatrixD worldMatrixNormalizedInv = grid2.PositionComp.WorldMatrixNormalizedInv; Vector3D vectord6 = (worldAABB.Center - (num8 * m_rightVector)) - (num9 * m_downVector); int num10 = 0; while (true) { if (num10 >= (num8 * 2.0)) { m_sunwindEntities.Remove(grid2); num6--; break; } int num11 = 0; while (true) { if (num11 >= (num9 * 2.0)) { num10 += (grid2.GridSizeEnum == MyCubeSize.Large) ? 0x19 : 10; break; } Vector3D to = ((vectord6 + (num10 * m_rightVector)) + (num11 * m_downVector)) + (((float)num7) * m_directionFromSunNormalized); Vector3 vector2 = MyUtils.GetRandomVector3CircleNormalized(); float randomFloat = MyUtils.GetRandomFloat(0f, (grid2.GridSizeEnum == MyCubeSize.Large) ? ((float)10) : ((float)5)); to += ((m_rightVector * vector2.X) * randomFloat) + ((m_downVector * vector2.Z) * randomFloat); LineD ed = new LineD(to - (m_directionFromSunNormalized * ((float)num7)), to); if (grid2.RayCastBlocks(ed.From, ed.To) != null) { ed.From = to - (m_directionFromSunNormalized * 1000.0); MyPhysics.CastRay(ed.From, ed.To, this.m_hitLst, 0); this.m_rayCastCounter++; if ((this.m_hitLst.Count == 0) || !ReferenceEquals(this.m_hitLst[0].HkHitInfo.GetHitEntity(), grid2.Components)) { this.m_hitLst.Clear(); } else { MyParticleEffect effect2; MyParticlesManager.TryCreateParticleEffect("Dummy", MatrixD.CreateWorld(this.m_hitLst[0].Position, Vector3D.Forward, Vector3D.Up), out effect2); MyEntityRayCastPair pair = new MyEntityRayCastPair { Entity = grid2, _Ray = ed, Position = this.m_hitLst[0].Position, Particle = effect2 }; m_rayCastQueue.Add(pair); } } num11 += (grid2.GridSizeEnum == MyCubeSize.Large) ? 0x19 : 10; } } } else { m_sunwindEntities.Remove(item); num6--; } num6++; } } if (m_distanceToSunWind <= 10000.0) { m_smallBillboardsStarted = true; } ComputeMaxDistances(); base.UpdateBeforeSimulation(); } } } }
void Start() { physics = FindObjectOfType <MyPhysics> (); }
public override void UpdateBeforeSimulation100() { base.UpdateBeforeSimulation100(); Debug.Assert(m_initialized, "SolarGameLogic was not initialized before use!"); if (m_solarBlock.CubeGrid.Physics == null) { return; } float angleToSun = Vector3.Dot(Vector3.Transform(m_panelOrientation, m_solarBlock.WorldMatrix.GetOrientation()), MySector.DirectionToSunNormalized); if ((angleToSun < 0 && !m_isTwoSided) || !m_solarBlock.IsFunctional) { m_maxOutput = 0; return; } m_currentPivot %= 8; MatrixD rot = m_solarBlock.WorldMatrix.GetOrientation(); float scale = (float)m_solarBlock.WorldMatrix.Forward.Dot(Vector3.Transform(m_panelOrientation, rot)); float unit = m_solarBlock.BlockDefinition.CubeSize == MyCubeSize.Large ? 2.5f : 0.5f; Vector3D pivot = m_solarBlock.WorldMatrix.Translation; pivot += ((m_currentPivot % 4 - 1.5f) * unit * scale * (m_solarBlock.BlockDefinition.Size.X / 4f)) * m_solarBlock.WorldMatrix.Left; pivot += ((m_currentPivot / 4 - 0.5f) * unit * scale * (m_solarBlock.BlockDefinition.Size.Y / 2f)) * m_solarBlock.WorldMatrix.Up; pivot += unit * scale * (m_solarBlock.BlockDefinition.Size.Z / 2f) * Vector3.Transform(m_panelOrientation, rot) * m_panelOffset; LineD l = new LineD(pivot + MySector.DirectionToSunNormalized * 1000, pivot + MySector.DirectionToSunNormalized * m_solarBlock.CubeGrid.GridSize / 4); //shadows are drawn only 1000m MyPhysics.CastRay(l.From, l.To, m_hitList); m_pivotInSun[m_currentPivot] = true; foreach (var hit in m_hitList) { var ent = hit.HkHitInfo.GetHitEntity(); if (ent != m_solarBlock.CubeGrid) { m_pivotInSun[m_currentPivot] = false; break; } else { var grid = ent as MyCubeGrid; var pos = grid.RayCastBlocks(l.From, l.To); if (pos.HasValue && grid.GetCubeBlock(pos.Value) != m_solarBlock.SlimBlock) { m_pivotInSun[m_currentPivot] = false; break; } } } int pivotsInSun = 0; foreach (bool p in m_pivotInSun) { if (p) { pivotsInSun++; } } m_maxOutput = angleToSun; if (m_maxOutput < 0) { if (m_isTwoSided) { m_maxOutput = Math.Abs(m_maxOutput); } else { m_maxOutput = 0; } } m_maxOutput *= pivotsInSun / 8f; m_currentPivot++; }
public static List <CollectibleInfo> FindCollectiblesInRadius(Vector3D fromPosition, double radius, bool doRaycast = false) { Debug.Assert(m_retvalCollectibleInfos.Count == 0, "The result of the last call of FindComponentsInRadius was not cleared!"); List <MyPhysics.HitInfo> hits = new List <MyPhysics.HitInfo>(); BoundingSphereD sphere = new BoundingSphereD(fromPosition, radius); var entities = MyEntities.GetEntitiesInSphere(ref sphere); foreach (var entity in entities) { bool addCollectibleInfo = false; CollectibleInfo info = new CollectibleInfo(); MyCubeBlock block = null; MyCubeGrid grid = TryGetAsComponent(entity, out block); if (grid != null) { info.EntityId = grid.EntityId; info.DefinitionId = GetComponentId(block.SlimBlock); if (block.BlockDefinition.Components != null) { info.Amount = block.BlockDefinition.Components[0].Count; } else { Debug.Assert(false, "Block definition does not have any components!"); info.Amount = 0; } addCollectibleInfo = true; } else if (entity is MyFloatingObject) { var floatingObj = entity as MyFloatingObject; var defId = floatingObj.Item.Content.GetObjectId(); if (MyDefinitionManager.Static.GetPhysicalItemDefinition(defId).Public) { info.EntityId = floatingObj.EntityId; info.DefinitionId = defId; info.Amount = floatingObj.Item.Amount; addCollectibleInfo = true; } } if (addCollectibleInfo) { bool hitSomething = false; MyPhysics.CastRay(fromPosition, entity.WorldMatrix.Translation, hits, MyPhysics.CollisionLayers.DefaultCollisionLayer); foreach (var hit in hits) { var hitEntity = hit.HkHitInfo.GetHitEntity(); if (hitEntity == entity) { continue; } if (hitEntity is MyCharacter) { continue; } if (hitEntity is MyFracturedPiece) { continue; } if (hitEntity is MyFloatingObject) { continue; } MyCubeBlock dummy = null; if (TryGetAsComponent(hitEntity as MyEntity, out dummy) != null) { continue; } hitSomething = true; break; } if (!hitSomething) { m_retvalCollectibleInfos.Add(info); } } } entities.Clear(); return(m_retvalCollectibleInfos); }
void Start () { physics = FindObjectOfType<MyPhysics> (); }
/// <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); float closestFraction = 1.0f; 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; } if (rb.HkHitInfo.HitFraction < closestFraction) { outSafePosition = Vector3D.Lerp(raycastOrigin, raycastEnd - CAMERA_RADIUS * rayDirection, rb.HkHitInfo.HitFraction); closestDistanceSquared = Vector3D.DistanceSquared(raycastOrigin, outSafePosition); 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); }
public override bool HandleInput() { if (base.HandleInput()) { return(true); } bool handled = false; if (MyInput.Static.IsAnyCtrlKeyPressed() && MyInput.Static.IsNewLeftMouseReleased()) { Hammer(); } if (MyInput.Static.IsNewKeyPressed(MyKeys.NumPad1)) { ApplyMassMultiplier = !ApplyMassMultiplier; handled = true; } var mul = 1; if (MyInput.Static.IsKeyPress(MyKeys.N)) { mul = 10; } if (MyInput.Static.IsKeyPress(MyKeys.B)) { mul = 100; } if (MyInput.Static.IsNewKeyPressed(MyKeys.OemQuotes)) { if (MassMultiplier > 1) { MassMultiplier += mul; } else { MassMultiplier *= mul; } handled = true; } if (MyInput.Static.IsNewKeyPressed(MyKeys.OemSemicolon)) { if (MassMultiplier > 1) { MassMultiplier -= mul; } else { MassMultiplier /= mul; } handled = true; } if (MySector.MainCamera != null) { List <MyPhysics.HitInfo> lst = new List <MyPhysics.HitInfo>(); MyPhysics.CastRay(MySector.MainCamera.Position, MySector.MainCamera.Position + MySector.MainCamera.ForwardVector * 100, lst); foreach (var hit in lst) { VRageRender.MyRenderProxy.DebugDrawText2D(new Vector2(600, 10), hit.HkHitInfo.Body.GetEntity().ToString() + " " + MyDestructionHelper.MassFromHavok(hit.HkHitInfo.Body.Mass), Color.White, 0.8f); VRageRender.MyRenderProxy.DebugDrawText2D(new Vector2(600, 30), "Layer: " + hit.HkHitInfo.Body.Layer, Color.White, 0.8f); if (hit.HkHitInfo.Body.GetEntity() is MyCubeGrid) { var grid = hit.HkHitInfo.Body.GetEntity() as MyCubeGrid; var det = grid.GetBlocks().FirstElement().FatBlock.UseObjectsComponent.DetectorPhysics; //var layer = det.RigidBody.Layer; } break; } } if (MyInput.Static.IsNewKeyPressed(MyKeys.NumPad9)) { MyScriptManager.Static.LoadData(); } if (MyAudio.Static != null) { foreach (var em in MyAudio.Static.Get3DSounds()) { VRageRender.MyRenderProxy.DebugDrawSphere(em.SourcePosition, 0.1f, Color.Red, 1, false); } } return(handled); }
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; } }
private void Hammer() { var IntersectionStart = MySector.MainCamera.Position; var IntersectionDirection = MySector.MainCamera.ForwardVector; LineD line = new LineD(IntersectionStart, IntersectionStart + IntersectionDirection * 200); var m_tmpHitList = new List <MyPhysics.HitInfo>(); MyPhysics.CastRay(line.From, line.To, m_tmpHitList, MyPhysics.ObjectDetectionCollisionLayer); // Remove character hits. m_tmpHitList.RemoveAll(delegate(MyPhysics.HitInfo hit) { return(hit.HkHitInfo.Body.GetEntity() == MySession.ControlledEntity.Entity); }); if (m_tmpHitList.Count == 0) { return; } MyEntity closestEntity = null; MyPhysics.HitInfo closestHit = default(MyPhysics.HitInfo); foreach (var hit in m_tmpHitList) { if (hit.HkHitInfo.Body != null) { closestEntity = hit.HkHitInfo.Body.GetEntity() as MyEntity; closestHit = hit; break; } } if (closestEntity == null) { return; } HkdFractureImpactDetails details = HkdFractureImpactDetails.Create(); details.SetBreakingBody(closestEntity.Physics.RigidBody); details.SetContactPoint(closestEntity.Physics.WorldToCluster(closestHit.Position)); details.SetDestructionRadius(RADIUS); details.SetBreakingImpulse(Sandbox.MyDestructionConstants.STRENGTH * 10); if (HammerForce) { details.SetParticleVelocity(-line.Direction * 20); } details.SetParticlePosition(closestEntity.Physics.WorldToCluster(closestHit.Position)); details.SetParticleMass(1000000); //details.ZeroColidingParticleVelocity(); details.Flag = details.Flag | HkdFractureImpactDetails.Flags.FLAG_DONT_RECURSE; if (closestEntity.Physics.HavokWorld.DestructionWorld != null) { MyPhysics.FractureImpactDetails destruction = new MyPhysics.FractureImpactDetails(); destruction.Details = details; destruction.World = closestEntity.Physics.HavokWorld; destruction.Entity = closestEntity; MyPhysics.EnqueueDestruction(destruction); //closestGrid.Physics.HavokWorld.DestructionWorld.TriggerDestruction(ref details); } //details.RemoveReference(); }
/// <summary> /// Performes a physics raycast /// It can be recursive (it calls CastDDA when it hits a grid). /// </summary> /// <param name="fromWorldPos"></param> /// <returns>Returns starting damage for current stack</returns> private MyRaycastDamageInfo CastPhysicsRay(Vector3D fromWorldPos) { Vector3D pos = Vector3D.Zero; IMyEntity hitEntity = null; var hitInfo = MyPhysics.CastRay(fromWorldPos, m_explosion.Center, MyPhysics.ExplosionRaycastLayer); if (hitInfo.HasValue) { hitEntity = (hitInfo.Value.HkHitInfo.Body.UserObject != null) ? ((MyPhysicsBody)hitInfo.Value.HkHitInfo.Body.UserObject).Entity : null; pos = hitInfo.Value.Position; } Vector3D direction = (m_explosion.Center - fromWorldPos); float lengthToCenter = (float)direction.Length(); direction.Normalize(); var grid = (hitEntity as MyCubeGrid); if (grid == null) { MyCubeBlock hitBlock = hitEntity as MyCubeBlock; if (hitBlock != null) { grid = hitBlock.CubeGrid; } } if (grid != null) { //Try advancing the point to find the intersected block //If the block is a cube, this is necessary because the raycast will return a point somewhere outside the cube //If the block is not a full cube (slope, special block), the raycast can return inside the cube //It advances 4 times, each time one 8th the grid size for (int i = 0; i < 5; i++) { Vector3D localPos = Vector3D.Transform(pos, grid.PositionComp.WorldMatrixNormalizedInv) / grid.GridSize; Vector3I gridPos = Vector3I.Round(localPos); var cubeBlock = grid.GetCubeBlock(gridPos); if (cubeBlock != null) { if (m_castBlocks.Contains(cubeBlock)) { //This shouldn't happen //There is a corner case where the explosion position is inside the empty cell, but this should be handleded somewhere higher System.Diagnostics.Debug.Fail("Raycast failed!"); DrawRay(fromWorldPos, pos, Color.Red); return(new MyRaycastDamageInfo(0f, lengthToCenter)); } else { if (MyDebugDrawSettings.DEBUG_DRAW_EXPLOSION_HAVOK_RAYCASTS) { DrawRay(fromWorldPos, pos, Color.Blue); } return(CastDDA(cubeBlock)); } } pos += direction * grid.GridSize / 8f; } //We hit a grid but were unable to find the hit cube. Send another raycast //Ideally, we would want to get the cube in all cases, but it also has to be fast //We need to check if the explosion center is between the initial start position (fromWorldPos) and the new one (pos) Vector3D min = new Vector3D(Math.Min(fromWorldPos.X, pos.X), Math.Min(fromWorldPos.Y, pos.Y), Math.Min(fromWorldPos.Z, pos.Z)); Vector3D max = new Vector3D(Math.Max(fromWorldPos.X, pos.X), Math.Max(fromWorldPos.Y, pos.Y), Math.Max(fromWorldPos.Z, pos.Z)); BoundingBoxD boundingBox = new BoundingBoxD(min, max); if (boundingBox.Contains(m_explosion.Center) == ContainmentType.Contains) { return(new MyRaycastDamageInfo(m_explosionDamage, lengthToCenter)); } stackOverflowGuard++; if (stackOverflowGuard > MAX_PHYSICS_RECURSION_COUNT) { System.Diagnostics.Debug.Fail("Potential stack overflow!"); if (MyDebugDrawSettings.DEBUG_DRAW_EXPLOSION_HAVOK_RAYCASTS) { DrawRay(fromWorldPos, pos, Color.Red); } return(new MyRaycastDamageInfo(0f, lengthToCenter)); } else { if (MyDebugDrawSettings.DEBUG_DRAW_EXPLOSION_HAVOK_RAYCASTS) { DrawRay(fromWorldPos, pos, Color.White); } return(CastPhysicsRay(pos)); } } else if (hitInfo.HasValue) { //Something was hit, but it wasn't a grid. This needs to be handled somehow if (MyDebugDrawSettings.DEBUG_DRAW_EXPLOSION_HAVOK_RAYCASTS) { DrawRay(fromWorldPos, pos, Color.Violet); } return(new MyRaycastDamageInfo(0, lengthToCenter)); } //Nothing was hit, so we can assume the there was nothing blocking the explosion if (MyDebugDrawSettings.DEBUG_DRAW_EXPLOSION_HAVOK_RAYCASTS) { DrawRay(fromWorldPos, pos, Color.Salmon); } return(new MyRaycastDamageInfo(m_explosionDamage, lengthToCenter)); }
private void TrySpawnBot() { Vector3D cameraPos, cameraDir; if (MySession.Static.GetCameraControllerEnum() == MyCameraControllerEnum.ThirdPersonSpectator || MySession.Static.GetCameraControllerEnum() == MyCameraControllerEnum.Entity) { var headMatrix = MySession.Static.ControlledEntity.GetHeadMatrix(true, true); cameraPos = headMatrix.Translation; cameraDir = headMatrix.Forward; } else { cameraPos = MySector.MainCamera.Position; cameraDir = MySector.MainCamera.WorldMatrix.Forward; } List<MyPhysics.HitInfo> hitInfos = new List<MyPhysics.HitInfo>(); var line = new LineD(MySector.MainCamera.Position, MySector.MainCamera.Position + MySector.MainCamera.ForwardVector * 1000); MyPhysics.CastRay(line.From, line.To, hitInfos, MyPhysics.CollisionLayers.DefaultCollisionLayer); //MyPhysics.CastRay(cameraPos, cameraPos + cameraDir * 1000, hitInfos, MyPhysics.CollisionLayers.ObjectDetectionCollisionLayer); if (hitInfos.Count == 0) //return; { MyAIComponent.Static.SpawnNewBot(BotToSpawn, cameraPos); return; } MyPhysics.HitInfo? closestValidHit = null; foreach (var hitInfo in hitInfos) { var ent = hitInfo.HkHitInfo.GetHitEntity(); if (ent is MyCubeGrid) { closestValidHit = hitInfo; break; } else if (ent is MyVoxelBase) { closestValidHit = hitInfo; break; } else if (ent is MyVoxelPhysics) { closestValidHit = hitInfo; break; } } /* if (closestValidHit.HasValue) { Vector3D position = closestValidHit.Value.Position; MyAIComponent.Static.SpawnNewBot(BotToSpawn, position); } */ Vector3D position; if (closestValidHit.HasValue) position = closestValidHit.Value.Position; else position = MySector.MainCamera.Position; MyAIComponent.Static.SpawnNewBot(BotToSpawn, position); }
public override void Draw() { base.Draw(); if (!MyFakes.ENABLE_ARMOR_HAND) { return; } Vector3 forward = MySector.MainCamera.ForwardVector; Vector3D origin = MySector.MainCamera.Position; Vector3D end = origin + forward * 100f; m_lastCubeGrid = null; m_lastBone = null; var hitInfo = MyPhysics.CastRay(origin, end, MyPhysics.ExplosionRaycastLayer); var hitEntity = hitInfo.HasValue ? ((MyPhysicsBody)hitInfo.Value.HkHitInfo.Body.UserObject).Entity : null; var grid = (hitEntity as MyCubeGrid); if (grid != null) { m_lastCubeGrid = grid; double shortestDistance = double.MaxValue; LineD line = new LineD(origin, end); Vector3I hitCube = new Vector3I(); double distanceSquared = double.MaxValue; if (m_lastCubeGrid.GetLineIntersectionExactGrid(ref line, ref hitCube, ref distanceSquared)) { m_lastCube = hitCube; } else { m_lastCube = null; } foreach (var bone in grid.Skeleton.Bones) { var bonePos = (Vector3D)(bone.Key / (float)grid.Skeleton.BoneDensity) * grid.GridSize + bone.Value; bonePos -= new Vector3D(grid.GridSize / grid.Skeleton.BoneDensity); Vector3D pos = Vector3D.Transform(bonePos, grid.PositionComp.WorldMatrix); Color color = Color.Red; double distance = MyUtils.GetPointLineDistance(ref origin, ref end, ref pos); if (distance < 0.1f) { double distanceToCamera = (origin - pos).LengthSquared(); if (distanceToCamera < shortestDistance) { shortestDistance = distanceToCamera; color = Color.Blue; m_lastBone = bone.Key; } } MyRenderProxy.DebugDrawSphere(pos, 0.05f, color.ToVector3(), 0.5f, false, 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] != null) { sameGrid = m_rigidList[0].UserObject == ((MyEntity)MySession.ControlledEntity).Physics; } 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.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(); } }
public override void UpdateAfterSimulation() { base.UpdateAfterSimulation(); m_rootIslands.Clear(); m_rootEntityIslandIndex.Clear(); var clusterList = MyPhysics.GetClusterList(); if (clusterList != null) { foreach (Havok.HkWorld havokWorld in MyPhysics.GetClusterList()) { var islandCount = havokWorld.GetActiveSimulationIslandsCount(); for (int i = 0; i < islandCount; i++) { havokWorld.GetActiveSimulationIslandRigidBodies(i, m_rigidBodies); HashSet <IMyEntity> island = null; foreach (var rigidBody in m_rigidBodies) { var ents = rigidBody.GetAllEntities(); foreach (var entity in ents) { var topParent = entity.GetTopMostParent(); foreach (var rootIsland in m_rootIslands) { if (rootIsland.RootEntities.Contains(topParent)) { island = rootIsland.RootEntities; break; } } } ents.Clear(); } if (island == null) { IslandData islandData = new IslandData() { AABB = BoundingBoxD.CreateInvalid(), RootEntities = new HashSet <IMyEntity>(), ClientPriority = new Dictionary <ulong, float>() }; island = islandData.RootEntities; m_rootIslands.Add(islandData); } foreach (var rigidBody in m_rigidBodies) { var ents = rigidBody.GetAllEntities(); foreach (var entity in ents) { var topParent = entity.GetTopMostParent(); island.Add(topParent); } ents.Clear(); } m_rigidBodies.Clear(); } } for (int i = 0; i < m_rootIslands.Count; i++) { var islandData = m_rootIslands[i]; islandData.AABB = BoundingBoxD.CreateInvalid(); foreach (var entity in islandData.RootEntities) { islandData.AABB.Include(entity.PositionComp.WorldAABB); m_rootEntityIslandIndex[entity] = i; } m_rootIslands[i] = islandData; } } }
public override void Draw() { base.Draw(); if (MyTrashRemoval.PreviewEnabled && MySession.Static.HasCreativeRights) { DrawTrashAdminView(); } bool visible = false; for (int i = 0; i < RenderObjectIDs.Length; i++) { if (RenderObjectIDs[i] == MyRenderProxy.RENDER_ID_UNASSIGNED) { break; } if (MyRenderProxy.VisibleObjectsRead.Contains(this.RenderObjectIDs[i])) { visible = true; break; } } if (visible) { foreach (var block in m_grid.BlocksForDraw) { if (MyRenderProxy.VisibleObjectsRead.Contains(block.Render.RenderObjectIDs[0])) { block.Render.Draw(); } } } if (MyCubeGrid.ShowCenterOfMass && !IsStatic && Container.Entity.Physics != null && Container.Entity.Physics.HasRigidBody) { var matrix = Container.Entity.Physics.GetWorldMatrix(); var center = Container.Entity.Physics.CenterOfMassWorld; var cam = MySector.MainCamera.Position; var dist = Vector3.Distance(cam, center); bool draw = false; if (dist < 30) { draw = true; } else if (dist < 200) { draw = true; MyPhysics.CastRay(cam, center, m_tmpHitList, MyPhysics.CollisionLayers.DynamicDoubledCollisionLayer); foreach (var hit in m_tmpHitList) { if (hit.HkHitInfo.GetHitEntity() != this) { draw = false; break; } } m_tmpHitList.Clear(); } if (draw) { float size = MathHelper.Lerp(1, 9, dist / 200); var mat = "WeaponLaserIgnoreDepth"; var color = Color.Yellow.ToVector4(); var thickness = 0.02f * size; MySimpleObjectDraw.DrawLine(center - matrix.Up * 0.5f * size, center + matrix.Up * 0.5f * size, mat, ref color, thickness); MySimpleObjectDraw.DrawLine(center - matrix.Forward * 0.5f * size, center + matrix.Forward * 0.5f * size, mat, ref color, thickness); MySimpleObjectDraw.DrawLine(center - matrix.Right * 0.5f * size, center + matrix.Right * 0.5f * size, mat, ref color, thickness); MyTransparentGeometry.AddBillboardOriented("RedDotIgnoreDepth", Color.White.ToVector4(), center, MySector.MainCamera.LeftVector, MySector.MainCamera.UpVector, 0.1f * size); } } if (MyCubeGrid.ShowGridPivot) { var matrix = Container.Entity.WorldMatrix; var pos = matrix.Translation; var cam = MySector.MainCamera.Position; var dist = Vector3.Distance(cam, pos); bool draw = false; if (dist < 30) { draw = true; } else if (dist < 200) { draw = true; MyPhysics.CastRay(cam, pos, m_tmpHitList, MyPhysics.CollisionLayers.DynamicDoubledCollisionLayer); foreach (var hit in m_tmpHitList) { if (hit.HkHitInfo.GetHitEntity() != this) { draw = false; break; } } m_tmpHitList.Clear(); } if (draw) { float size = MathHelper.Lerp(1, 9, dist / 200); var mat = "WeaponLaserIgnoreDepth"; var thickness = 0.02f * size; var color = Color.Green.ToVector4(); MySimpleObjectDraw.DrawLine(pos, pos + matrix.Up * 0.5f * size, mat, ref color, thickness); color = Color.Blue.ToVector4(); MySimpleObjectDraw.DrawLine(pos, pos + matrix.Forward * 0.5f * size, mat, ref color, thickness); color = Color.Red.ToVector4(); MySimpleObjectDraw.DrawLine(pos, pos + matrix.Right * 0.5f * size, mat, ref color, thickness); MyTransparentGeometry.AddBillboardOriented("RedDotIgnoreDepth", Color.White.ToVector4(), pos, MySector.MainCamera.LeftVector, MySector.MainCamera.UpVector, 0.1f * size); MyRenderProxy.DebugDrawAxis(matrix, 0.5f, false);//DX 11 desnt support depthRead false } } if (MyCubeGrid.ShowStructuralIntegrity) { if (m_grid.StructuralIntegrity == null) { if (MyFakes.ENABLE_STRUCTURAL_INTEGRITY) { m_grid.CreateStructuralIntegrity(); if (m_grid.StructuralIntegrity != null) { m_grid.StructuralIntegrity.EnabledOnlyForDraw = true; } } } else { m_grid.StructuralIntegrity.Draw(); } } else if (m_grid.StructuralIntegrity != null && m_grid.StructuralIntegrity.EnabledOnlyForDraw) { m_grid.CloseStructuralIntegrity(); } if (MyFakes.ENABLE_ATMOSPHERIC_ENTRYEFFECT) { ProfilerShort.Begin("DrawAtmosphericEntryEffect"); DrawAtmosphericEntryEffect(); ProfilerShort.End(); } }
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(); }
public static void OnGlobalSpawnEvent(object senderEvent) { // Select a spawn group to spawn MySpawnGroupDefinition spawnGroup = PickRandomSpawnGroup(); if (spawnGroup == null) { return; } spawnGroup.ReloadPrefabs(); ProfilerShort.Begin("Generate position and direction"); double spawnDistance = NEUTRAL_SHIP_SPAWN_DISTANCE; Vector3D playerPosition = Vector3D.Zero; bool isWorldLimited = MyEntities.IsWorldLimited(); int numPlayers = 0; if (isWorldLimited) { spawnDistance = Math.Min(spawnDistance, MyEntities.WorldSafeHalfExtent() - spawnGroup.SpawnRadius); } else { // In infinite worlds players can be thousands of kilometers away, so spawn ship around random player // so cargo ships will be spawned around every player at some time var players = MySession.Static.Players.GetOnlinePlayers(); // In DS there can be no players connected numPlayers = Math.Max(0, players.Count - 1); int randomPlayerPosition = MyUtils.GetRandomInt(0, numPlayers); int i = 0; foreach (var player in players) { if (i == randomPlayerPosition) { if (player.Character != null) { playerPosition = player.GetPosition(); } break; } i++; } } if (spawnDistance < 0.0f) { MySandboxGame.Log.WriteLine("Not enough space in the world to spawn such a huge spawn group!"); return; } double forbiddenRadius = NEUTRAL_SHIP_FORBIDDEN_RADIUS; BoundingBoxD spawnBox; if (isWorldLimited) { spawnBox = new BoundingBoxD(new Vector3D(playerPosition - spawnDistance), new Vector3D(playerPosition + spawnDistance)); } else { // We need to extend bouding box so cargo ships aren't spawned near other players GetSafeBoundingBoxForPlayers(playerPosition, spawnDistance, out spawnBox); // Forbidden radius is sphere around all players in box. // Bounding box is generated from players positions so their distance to center shall be same for all players forbiddenRadius += spawnBox.HalfExtents.Max() - NEUTRAL_SHIP_FORBIDDEN_RADIUS; } // Get the direction to the center and deviate it randomly Vector3D?origin = MyUtils.GetRandomBorderPosition(ref spawnBox); origin = MyEntities.FindFreePlace(origin.Value, spawnGroup.SpawnRadius); if (!origin.HasValue) { MySandboxGame.Log.WriteLine("Could not spawn neutral ships - no free place found"); MyGlobalEvents.RescheduleEvent(senderEvent as MyGlobalEventBase, NEUTRAL_SHIP_RESCHEDULE_TIME); ProfilerShort.End(); return; } // Radius in arc units of the forbidden sphere in the center, when viewed from origin float centerArcRadius = (float)Math.Atan(forbiddenRadius / (origin.Value - spawnBox.Center).Length()); // Generate direction with elevation from centerArcRadius radians to (cAR + N_S_D_S) radians Vector3D direction = -Vector3D.Normalize(origin.Value); float theta = MyUtils.GetRandomFloat(centerArcRadius, centerArcRadius + NEUTRAL_SHIP_DIRECTION_SPREAD); float phi = MyUtils.GetRandomRadian(); Vector3D cosVec = Vector3D.CalculatePerpendicularVector(direction); Vector3D sinVec = Vector3D.Cross(direction, cosVec); cosVec *= (Math.Sin(theta) * Math.Cos(phi)); sinVec *= (Math.Sin(theta) * Math.Sin(phi)); direction = direction * Math.Cos(theta) + cosVec + sinVec; Vector3D destination = Vector3D.Zero; RayD ray = new RayD(origin.Value, direction); double? intersection = ray.Intersects(spawnBox); Vector3D directionMult; if (!intersection.HasValue || intersection.Value < NEUTRAL_SHIP_MINIMAL_ROUTE_LENGTH) { directionMult = direction * NEUTRAL_SHIP_MINIMAL_ROUTE_LENGTH; } else { directionMult = direction * intersection.Value; } destination = origin.Value + directionMult; Vector3D upVector = Vector3D.CalculatePerpendicularVector(direction); Vector3D rightVector = Vector3D.Cross(direction, upVector); MatrixD originMatrix = MatrixD.CreateWorld(origin.Value, direction, upVector); ProfilerShort.End(); ProfilerShort.Begin("Check free space"); // CH:TODO: Convex cast to detect collision // Check ships' path to avoid possible collisions. (TODO: But only if it is said in the definitions) m_raycastHits.Clear(); foreach (var shipPrefab in spawnGroup.Prefabs) { var prefabDef = MyDefinitionManager.Static.GetPrefabDefinition(shipPrefab.SubtypeId); Debug.Assert(prefabDef != null); Vector3D shipPosition = Vector3.Transform(shipPrefab.Position, originMatrix); Vector3D shipDestination = shipPosition + directionMult; float radius = prefabDef == null ? 10.0f : prefabDef.BoundingSphere.Radius; MyPhysics.CastRay(shipPosition, shipDestination, m_raycastHits, MyPhysics.ObjectDetectionCollisionLayer); if (m_raycastHits.Count() > 0) { MySandboxGame.Log.WriteLine("Could not spawn neutral ships due to collision"); MyGlobalEvents.RescheduleEvent(senderEvent as MyGlobalEventBase, NEUTRAL_SHIP_RESCHEDULE_TIME); ProfilerShort.End(); return; } for (int i = 0; i < 4; ++i) { Vector3D shiftVector = upVector * m_upVecMultipliers[i] * radius + rightVector * m_rightVecMultipliers[i] * radius; MyPhysics.CastRay(shipPosition + shiftVector, shipDestination + shiftVector, m_raycastHits, MyPhysics.ObjectDetectionCollisionLayer); if (m_raycastHits.Count() > 0) { MySandboxGame.Log.WriteLine("Could not spawn neutral ships due to collision"); MyGlobalEvents.RescheduleEvent(senderEvent as MyGlobalEventBase, NEUTRAL_SHIP_RESCHEDULE_TIME); ProfilerShort.End(); return; } } } ProfilerShort.End(); ProfilerShort.Begin("Spawn ships"); long spawnGroupId = MyPirateAntennas.GetPiratesId(); // The ships were collision-free. Now spawn them foreach (var shipPrefab in spawnGroup.Prefabs) { ProfilerShort.Begin(shipPrefab.BeaconText); // Yes, this could have been saved in the previous loop, but compared to (e.g.) raycasts, this does not take too much time to recalculate Vector3D shipPosition = Vector3D.Transform((Vector3D)shipPrefab.Position, originMatrix); Vector3D shipDestination = shipPosition + directionMult; Vector3D up = Vector3D.CalculatePerpendicularVector(-direction); m_tmpGridList.Clear(); // CH: We don't want a new identity for each ship anymore. We should handle that in a better way... /*if (shipPrefab.ResetOwnership) * { * if (spawnGroupId == 0) * { * //This is not an NPC so that it doesn't show up in assign ownership drop down menu * MyIdentity spawnGroupIdentity = Sync.Players.CreateNewIdentity("Neutral NPC"); * spawnGroupId = spawnGroupIdentity.IdentityId; * } * }*/ // Deploy ship ProfilerShort.Begin("Spawn cargo ship"); MyPrefabManager.Static.SpawnPrefab( resultList: m_tmpGridList, prefabName: shipPrefab.SubtypeId, position: shipPosition, forward: direction, up: up, initialLinearVelocity: shipPrefab.Speed * direction, beaconName: shipPrefab.BeaconText, spawningOptions: Sandbox.ModAPI.SpawningOptions.RotateFirstCockpitTowardsDirection | Sandbox.ModAPI.SpawningOptions.SpawnRandomCargo | Sandbox.ModAPI.SpawningOptions.DisableDampeners, ownerId: shipPrefab.ResetOwnership ? spawnGroupId : 0, updateSync: true); ProfilerShort.End(); foreach (var grid in m_tmpGridList) { var cockpit = grid.GetFirstBlockOfType <MyCockpit>(); if (cockpit != null) { MySimpleAutopilot ai = new MySimpleAutopilot(shipDestination, (Vector3)direction); cockpit.AttachAutopilot(ai); break; } } m_tmpGridList.Clear(); ProfilerShort.End(); } ProfilerShort.End(); }
/// <summary> /// Casts preview grids aabbs and get shortest distance. Returns shortest intersection or null. /// </summary> protected Vector3D?GetFreeSpacePlacementPositionGridAabbs(bool copyPaste, out bool buildAllowed) { Vector3D?freePlacementIntersectionPoint = null; buildAllowed = true; float gridSize = PreviewGrids[0].GridSize; double shortestDistance = double.MaxValue; double?currentRayInts = MyCubeBuilder.GetCurrentRayIntersection(); if (currentRayInts.HasValue) { shortestDistance = currentRayInts.Value; } Vector3D worldRefPointOffset = Vector3D.Zero; if (copyPaste) { Matrix firstGridOrientation = GetFirstGridOrientationMatrix(); worldRefPointOffset = Vector3.TransformNormal(m_dragPointToPositionLocal, firstGridOrientation); } Vector3D worldRefPoint = PreviewGrids[0].GridIntegerToWorld(Vector3I.Zero); foreach (var grid in PreviewGrids) { Vector3 halfExt = grid.PositionComp.LocalAABB.HalfExtents; Vector3 minLocal = grid.Min * grid.GridSize - Vector3.Half * grid.GridSize; Vector3 maxLocal = grid.Max * grid.GridSize + Vector3.Half * grid.GridSize; MatrixD gridWorlTransform = MatrixD.Identity; gridWorlTransform.Translation = 0.5f * (minLocal + maxLocal); gridWorlTransform = gridWorlTransform * grid.WorldMatrix; Vector3I size = grid.Max - grid.Min + Vector3I.One; Vector3 sizeOffset = Vector3I.Abs((size % 2) - Vector3I.One) * 0.5 * grid.GridSize; sizeOffset = Vector3.TransformNormal(sizeOffset, grid.WorldMatrix); Vector3D offset = gridWorlTransform.Translation + worldRefPointOffset - worldRefPoint /*- sizeOffset*/;// Vector3.Zero;// gridWorlTransform.Translation + worldRefPointOffset - worldRefPoint; HkShape shape = new HkBoxShape(halfExt); Vector3D rayStart = MyCubeBuilder.IntersectionStart + offset; double castPlaneDistanceToRayStart = DistanceFromCharacterPlane(ref rayStart); rayStart -= castPlaneDistanceToRayStart * MyCubeBuilder.IntersectionDirection; Vector3D rayEnd = MyCubeBuilder.IntersectionStart + (m_dragDistance - castPlaneDistanceToRayStart) * MyCubeBuilder.IntersectionDirection + offset; MatrixD matrix = gridWorlTransform; matrix.Translation = rayStart; try { float?dist = MyPhysics.CastShape(rayEnd, shape, ref matrix, MyPhysics.CollisionLayers.CollisionLayerWithoutCharacter); if (dist.HasValue && dist.Value != 0f) { Vector3D intersectionPoint = rayStart + dist.Value * (rayEnd - rayStart); const bool debugDraw = true; if (debugDraw) { Color green = Color.Green; BoundingBoxD localAABB = new BoundingBoxD(-halfExt, halfExt); localAABB.Inflate(0.03f); MatrixD drawMatrix = matrix; drawMatrix.Translation = intersectionPoint; MySimpleObjectDraw.DrawTransparentBox(ref drawMatrix, ref localAABB, ref green, MySimpleObjectRasterizer.Wireframe, 1, 0.04f); } double fixedDistance = DistanceFromCharacterPlane(ref intersectionPoint) - castPlaneDistanceToRayStart; if (fixedDistance <= 0) { fixedDistance = 0; shortestDistance = 0; buildAllowed = false; break; } if (fixedDistance < shortestDistance) { shortestDistance = fixedDistance; } } else { buildAllowed = false; } } finally { shape.RemoveReference(); } } if (shortestDistance != 0 && shortestDistance < m_dragDistance) { freePlacementIntersectionPoint = MyCubeBuilder.IntersectionStart + shortestDistance * MyCubeBuilder.IntersectionDirection; } else { buildAllowed = false; } return(freePlacementIntersectionPoint); }
private MyAttachableTopBlockBase FindMatchingTop() { Debug.Assert(CubeGrid != null); Debug.Assert(m_penetrations != null); Debug.Assert(CubeGrid.Physics != null); if (CubeGrid == null) { MySandboxGame.Log.WriteLine("MyPistonBase.FindMatchingTop(): Cube grid == null!"); return(null); } if (m_penetrations == null) { MySandboxGame.Log.WriteLine("MyPistonBase.FindMatchingTop(): penetrations cache == null!"); return(null); } if (CubeGrid.Physics == null) { MySandboxGame.Log.WriteLine("MyPistonBase.FindMatchingTop(): Cube grid physics == null!"); return(null); } Quaternion orientation; Vector3D pos; Vector3 halfExtents; ComputeTopQueryBox(out pos, out halfExtents, out orientation); try { MyPhysics.GetPenetrationsBox(ref halfExtents, ref pos, ref orientation, m_penetrations, MyPhysics.CollisionLayers.DefaultCollisionLayer); foreach (var obj in m_penetrations) { var entity = obj.GetCollisionEntity(); if (entity == null || entity == CubeGrid) { continue; } MyAttachableTopBlockBase top = FindTopInGrid(entity, pos); if (top != null) { return(top); } MyPhysicsBody body = entity.Physics as MyPhysicsBody; if (body != null) { foreach (var child in body.WeldInfo.Children) { top = FindTopInGrid(child.Entity, pos); if (top != null) { return(top); } } } } } catch (Exception ex) { } finally { m_penetrations.Clear(); } return(null); }
private void PlaceAreaMarker() { Vector3D cameraPos, cameraDir; if (MySession.GetCameraControllerEnum() == Common.ObjectBuilders.MyCameraControllerEnum.ThirdPersonSpectator || MySession.GetCameraControllerEnum() == Common.ObjectBuilders.MyCameraControllerEnum.Entity) { var headMatrix = MySession.ControlledEntity.GetHeadMatrix(true, true); cameraPos = headMatrix.Translation; cameraDir = headMatrix.Forward; } else { cameraPos = MySector.MainCamera.Position; cameraDir = MySector.MainCamera.WorldMatrix.Forward; } List <MyPhysics.HitInfo> hitInfos = new List <MyPhysics.HitInfo>(); MyPhysics.CastRay(cameraPos, cameraPos + cameraDir * 100, hitInfos, MyPhysics.ObjectDetectionCollisionLayer); if (hitInfos.Count == 0) { return; } MyPhysics.HitInfo?closestValidHit = null; foreach (var hitInfo in hitInfos) { var ent = hitInfo.HkHitInfo.Body.GetEntity(); if (ent is MyCubeGrid) { closestValidHit = hitInfo; break; } else if (ent is MyVoxelMap) { closestValidHit = hitInfo; break; } } if (closestValidHit.HasValue) { MyAreaMarkerDefinition definition = AreaMarkerDefinition; Debug.Assert(definition != null, "Area marker definition cannot be null!"); if (definition == null) { return; } Vector3D position = closestValidHit.Value.Position; var forward = Vector3D.Reject(cameraDir, Vector3D.Up); if (Vector3D.IsZero(forward)) { forward = Vector3D.Forward; } var positionAndOrientation = new MyPositionAndOrientation(position, Vector3D.Normalize(forward), Vector3D.Up); MyObjectBuilder_AreaMarker objectBuilder = (MyObjectBuilder_AreaMarker)MyObjectBuilderSerializer.CreateNewObject(definition.Id); objectBuilder.PersistentFlags = MyPersistentEntityFlags2.Enabled | MyPersistentEntityFlags2.InScene; objectBuilder.PositionAndOrientation = positionAndOrientation; if (objectBuilder.IsSynced) { MySyncCreate.RequestEntityCreate(objectBuilder); } else { MyAreaMarker flag = MyEntityFactory.CreateEntity <MyAreaMarker>(objectBuilder); flag.Init(objectBuilder); MyEntities.Add(flag); } } }
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; } }