/// <summary> /// Finds a random block facing the sky. Raycast is slightly randomized to simulate wind blowing rain /// </summary> /// <param name="grid"></param> /// <param name="blocks"></param> /// <param name="gravityDirection"></param> /// <param name="physicsCast"></param> /// <returns></returns> public static IMySlimBlock GetRandomSkyFacingBlock(IMyCubeGrid grid, List <IMySlimBlock> blocks, Vector3D gravityDirection, out LineD line, bool physicsCast = false) { Vector3D posInt = grid.GridIntegerToWorld(blocks.GetRandomItemFromList().Position) + -gravityDirection * 2; Vector3D posExt = posInt + gravityDirection * Math.Max(25, grid.WorldVolume.Radius * 2); posExt = RandomPositionFromPoint(ref posExt, grid.WorldVolume.Radius); line = new LineD(); Vector3I?blockPos = grid.RayCastBlocks(posExt, posInt); if (!blockPos.HasValue) { return(null); } IMySlimBlock block = grid.GetCubeBlock(blockPos.Value); if (block == null) { return(null); } if (physicsCast) { var hits = new List <IHitInfo>(); MyAPIGateway.Physics.CastRay(posExt, grid.GridIntegerToWorld(blockPos.Value), hits); foreach (IHitInfo hit in hits) { if (hit?.HitEntity?.GetTopMostParent() == null) { continue; } if (hit.HitEntity.GetTopMostParent().EntityId != grid.EntityId) { return(null); } } } if (Debug) { Lines.Add(new LineD { From = posExt, To = grid.GridIntegerToWorld(blockPos.Value) }); } line = new LineD { From = posExt, To = grid.GridIntegerToWorld(blockPos.Value) }; return(block); }
/// <summary> /// Gets a block on the exterior hull of a ship /// </summary> /// <param name="grid"></param> /// <param name="blocks"></param> /// <returns></returns> public static IMySlimBlock GetRandomExteriorBlock(IMyCubeGrid grid, List <IMySlimBlock> blocks) { Vector3D posInt = grid.GridIntegerToWorld(blocks.GetRandomItemFromList().Position); Vector3D posExt = RandomPositionFromPoint(ref posInt, grid.WorldAABB.HalfExtents.Length()); if (Debug) { Lines.Add(new LineD { From = posExt, To = posInt }); } Vector3I?blockPos = grid.RayCastBlocks(posExt, posInt); return(blockPos.HasValue ? grid.GetCubeBlock(blockPos.Value) : null); }
public static double?GridHitCheck(IMyCubeGrid cubeGrid, LineD lineCheck, Vector3D lineStartPoint, Vector3D lineEndPoint) { // Hit a grid, do a raycast to it for block hit. Vector3I?gridBlockHit = cubeGrid.RayCastBlocks(lineStartPoint, lineEndPoint); if (gridBlockHit.HasValue) { // Get the block on hit grid IMySlimBlock blk = cubeGrid.GetCubeBlock(gridBlockHit.Value); if (blk.FatBlock != null) { var blockBBox = blk.FatBlock.LocalAABB; MyOrientedBoundingBoxD blockOBB = new MyOrientedBoundingBoxD(blockBBox, blk.FatBlock.WorldMatrix); double?blockIntersect = blockOBB.Intersects(ref lineCheck); if (blockIntersect != null) { var hitDist = blockOBB.Intersects(ref lineCheck); return(hitDist); } //DrawOBB(blockOBB, Color.Red, MySimpleObjectRasterizer.Wireframe, 0.01f); } else { var center = blk.GetPosition(); Vector3 halfExt; blk.ComputeScaledHalfExtents(out halfExt); BoundingBoxD blockBBox = new BoundingBoxD(-halfExt, halfExt); Quaternion rotMatrix = Quaternion.CreateFromRotationMatrix(blk.CubeGrid.WorldMatrix); MyOrientedBoundingBoxD blockOBB = new MyOrientedBoundingBoxD(center, blockBBox.HalfExtents, rotMatrix); var hitDist = blockOBB.Intersects(ref lineCheck); return(hitDist); //DrawOBB(blockOBB, Color.Green, MySimpleObjectRasterizer.Wireframe, 0.01f); } } return(double.MaxValue); }
private void Check() { Vector3D End = Position + Velocity * Tools.Tick; IHitInfo hit; MyAPIGateway.Physics.CastRay(Position, End, out hit); if (hit != null) { Expired = true; //apply recoil if (Ammo.ProjectileHitImpulse > 0) { Vector3 forceVector = -hit.Normal * Ammo.ProjectileHitImpulse; hit.HitEntity.Physics.AddForce(MyPhysicsForceType.APPLY_WORLD_IMPULSE_AND_WORLD_ANGULAR_IMPULSE, forceVector, hit.Position, Vector3.Zero); } if (!MyAPIGateway.Session.IsServer) { return; } if (hit.HitEntity is IMyDestroyableObject) { (hit.HitEntity as IMyDestroyableObject).DoDamage(Ammo.ProjectileMassDamage, MyStringHash.GetOrCompute(Ammo.SubtypeId), false, null, ShooterId); } else if (hit.HitEntity is IMyCubeGrid) { IMyCubeGrid grid = hit.HitEntity as IMyCubeGrid; Vector3I? hitPos = grid.RayCastBlocks(hit.Position, hit.Position + Direction); if (hitPos.HasValue) { IMySlimBlock block = grid.GetCubeBlock(hitPos.Value); block.DoDamage(Ammo.ProjectileMassDamage, MyStringHash.GetOrCompute(Ammo.SubtypeId), false, null, ShooterId); } } } }
public static ConcurrentBag <MyGroups <MyCubeGrid, MyGridPhysicalGroupData> .Group> FindLookAtGridGroup(IMyCharacter controlledEntity) { const float range = 5000; Matrix worldMatrix; Vector3D startPosition; Vector3D endPosition; worldMatrix = controlledEntity.GetHeadMatrix(true, true, false); // dead center of player cross hairs, or the direction the player is looking with ALT. startPosition = worldMatrix.Translation + worldMatrix.Forward * 0.5f; endPosition = worldMatrix.Translation + worldMatrix.Forward * (range + 0.5f); var list = new Dictionary <MyGroups <MyCubeGrid, MyGridPhysicalGroupData> .Group, double>(); var ray = new RayD(startPosition, worldMatrix.Forward); foreach (var group in MyCubeGridGroups.Static.Physical.Groups) { foreach (MyGroups <MyCubeGrid, MyGridPhysicalGroupData> .Node groupNodes in group.Nodes) { IMyCubeGrid cubeGrid = groupNodes.NodeData; if (cubeGrid == null) { continue; } if (cubeGrid.Physics == null) { continue; } // check if the ray comes anywhere near the Grid before continuing. if (!ray.Intersects(cubeGrid.WorldAABB).HasValue) { continue; } Vector3I?hit = cubeGrid.RayCastBlocks(startPosition, endPosition); if (!hit.HasValue) { continue; } double distance = (startPosition - cubeGrid.GridIntegerToWorld(hit.Value)).Length(); if (list.TryGetValue(group, out double oldDistance)) { if (distance < oldDistance) { list.Remove(group); list.Add(group, distance); } } else { list.Add(group, distance); } } } var bag = new ConcurrentBag <MyGroups <MyCubeGrid, MyGridPhysicalGroupData> .Group>(); if (list.Count == 0) { return(bag); } // find the closest Entity. var item = list.OrderBy(f => f.Value).First(); bag.Add(item.Key); return(bag); }
void GetTarget(IMyCharacter character, out IMyCubeGrid targetGrid, out IMySlimBlock targetBlock, out IMyPlayer targetPlayer, out Vector3D aimPoint) { targetGrid = null; targetBlock = null; targetPlayer = null; bool aiming = Utils.IsAimingDownSights(character); MatrixD head = character.GetHeadMatrix(false, true); Vector3D rayDir = head.Forward; Vector3D rayFrom = head.Translation; if (aiming) { rayFrom += rayDir * PAINT_AIM_START_OFFSET; } Vector3D rayTo = head.Translation + rayDir * PAINT_DISTANCE; aimPoint = rayTo; targetGrid = MyAPIGateway.CubeBuilder.FindClosestGrid(); if (targetGrid == null || targetGrid.Physics == null || !targetGrid.Physics.Enabled) { targetGrid = null; return; } // older selection behavior when aiming down sights if (aiming) { Vector3I?blockPos = targetGrid.RayCastBlocks(rayFrom, rayTo); if (blockPos.HasValue) { targetBlock = targetGrid.GetCubeBlock(blockPos.Value); } return; } // HACK copied and converted from MyDrillSensorRayCast.ReadEntitiesInRange() + MyCasterComponent.OnWorldPosChanged() // last cloned in SE v201 #region Welder-like block selection hits.Clear(); detections.Clear(); rayOverlapResults.Clear(); MyAPIGateway.Physics.CastRay(rayFrom, rayTo, hits, 24); foreach (IHitInfo hit in hits) { IMyEntity parent = hit.HitEntity?.GetTopMostParent(); if (parent == null || parent.Physics == null || !parent.Physics.Enabled) { continue; } Vector3D hitPos = hit.Position; IMyCubeGrid grid = parent as IMyCubeGrid; if (grid != null) { // just how it's set in game code /shrug hitPos += hit.Normal * -0.005f; } DetectionInfo detected; if (detections.TryGetValue(parent.EntityId, out detected)) { double dist1 = Vector3D.DistanceSquared(rayFrom, detected.DetectionPoint); double dist2 = Vector3D.DistanceSquared(rayFrom, hitPos); if (dist1 > dist2) { detections[parent.EntityId] = new DetectionInfo(parent, hitPos); } } else { detections[parent.EntityId] = new DetectionInfo(parent, hitPos); } } hits.Clear(); LineD line = new LineD(rayFrom, rayTo); MyGamePruningStructure.GetAllEntitiesInRay(ref line, rayOverlapResults); foreach (MyLineSegmentOverlapResult <MyEntity> result in rayOverlapResults) { if (result.Element == null) { continue; } IMyCubeBlock block = result.Element as IMyCubeBlock; if (block == null) { continue; } MyCubeBlockDefinition def = (MyCubeBlockDefinition)block.SlimBlock.BlockDefinition; if (def.HasPhysics) { continue; // this section is only for things that are not caught by the raycast } MyEntity parent = result.Element.GetTopMostParent(); if (parent.Physics == null || !parent.Physics.Enabled) { continue; } MatrixD invMatrix = block.PositionComp.WorldMatrixNormalizedInv; Vector3 localFrom = Vector3D.Transform(rayFrom, ref invMatrix); Vector3 localTo = Vector3D.Transform(rayTo, ref invMatrix); float?intersectDistance = new Ray(localFrom, Vector3.Normalize(localTo - localFrom)).Intersects(block.PositionComp.LocalAABB) + 0.01f; if (intersectDistance.HasValue && intersectDistance <= PAINT_DISTANCE) { Vector3D hitPos = rayFrom + rayDir * intersectDistance.Value; DetectionInfo detected; if (detections.TryGetValue(parent.EntityId, out detected)) { double dist1 = Vector3D.DistanceSquared(rayFrom, detected.DetectionPoint); double dist2 = Vector3D.DistanceSquared(rayFrom, hitPos); if (dist1 > dist2) { detections[parent.EntityId] = new DetectionInfo(parent, hitPos); } } else { detections[parent.EntityId] = new DetectionInfo(parent, hitPos); } } } rayOverlapResults.Clear(); if (detections.Count == 0) { return; } double closetDist = double.MaxValue; DetectionInfo closestObj = new DetectionInfo(null, Vector3D.Zero); foreach (DetectionInfo detected in detections.Values) { double dist = Vector3D.DistanceSquared(detected.DetectionPoint, rayFrom); if (dist < closetDist) { closestObj = detected; closetDist = dist; } } detections.Clear(); targetGrid = closestObj.Entity as IMyCubeGrid; if (targetGrid == null) { return; } Vector3D localPos = Vector3D.Transform(closestObj.DetectionPoint, targetGrid.WorldMatrixNormalizedInv); Vector3I cube; targetGrid.FixTargetCube(out cube, localPos / targetGrid.GridSize); targetBlock = targetGrid.GetCubeBlock(cube); #endregion Welder-like block selection }
public void TargetIntersectionCheck() { _entityScanList.Clear(); _voxelScanList.Clear(); _entityScanList = new List <MyLineSegmentOverlapResult <MyEntity> >(); MyGamePruningStructure.GetTopmostEntitiesOverlappingRay(ref Line, _entityScanList); IMyCubeGrid closestGrid = null; double closestGridDistance = -1; MySafeZone closestZone = null; double closestZoneDistance = -1; IMyCharacter closestCharacter = null; double closestCharacterDistance = -1; foreach (var item in _entityScanList) { var targetGrid = item.Element as IMyCubeGrid; var targetZone = item.Element as MySafeZone; var targetVoxel = item.Element as MyVoxelBase; var targetPlayer = item.Element as IMyCharacter; if (targetGrid != null) { if (targetGrid == _collisionSystem.RemoteControl.SlimBlock.CubeGrid || _collisionSystem.RemoteControl.SlimBlock.CubeGrid.IsSameConstructAs(targetGrid)) { continue; } if (closestGrid == null || (closestGrid != null && item.Distance < closestGridDistance)) { closestGrid = targetGrid; closestGridDistance = item.Distance; } } if (targetZone != null) { if (closestZone == null || (closestZone != null && item.Distance < closestZoneDistance)) { closestZone = targetZone; closestZoneDistance = item.Distance; } } if (targetVoxel != null) { _voxelScanList.Add(targetVoxel); } if (targetPlayer != null) { if (closestCharacter == null || (closestCharacter != null && item.Distance < closestCharacterDistance)) { closestCharacter = targetPlayer; closestCharacterDistance = item.Distance; } } } if (closestGrid != null) { double minDist = 0; double maxDist = 0; bool boxCheckResult = closestGrid.PositionComp.WorldAABB.Intersect(ref Ray, out minDist, out maxDist); Vector3D startBox = boxCheckResult ? (minDist - 5) * DirectionVector + StartPosition : StartPosition; Vector3D endBox = boxCheckResult ? (maxDist + 5) * DirectionVector + StartPosition : EndPosition; var blockPos = closestGrid.RayCastBlocks(startBox, endBox); if (!blockPos.HasValue) { return; } IMySlimBlock slimBlock = closestGrid.GetCubeBlock(blockPos.Value); if (slimBlock == null) { return; } Vector3D blockPosition = Vector3D.Zero; slimBlock.ComputeWorldCenter(out blockPosition); GridCoords = blockPosition; GridDistance = Vector3D.Distance(blockPosition, StartPosition); GridEntity = closestGrid; GridOwner = OwnershipHelper.GetOwnershipTypes(closestGrid, false); GridRelation = OwnershipHelper.GetTargetReputation(_collisionSystem.Owner, closestGrid, false); } if (closestZone != null) { SafezoneEntity = closestZone; SafezoneCoords = closestZoneDistance * DirectionVector + StartPosition; SafezoneDistance = closestZoneDistance; } if (closestCharacter != null) { PlayerEntity = closestCharacter; PlayerCoords = PlayerEntity.PositionComp.WorldAABB.Center; PlayerDistance = closestCharacterDistance; } }
public void Check(Projectile p) { Vector3D End = p.Position + p.Velocity * Tools.Tick; IHitInfo hit; MyAPIGateway.Physics.CastRay(p.Position, End, out hit); if (hit != null) { Tools.Debug($"----- ricochet check start -----"); if (hit.HitEntity is IMyDestroyableObject) { p.Expired = true; (hit.HitEntity as IMyDestroyableObject).DoDamage(p.Ammo.ProjectileMassDamage, MyStringHash.GetOrCompute(p.Ammo.SubtypeId), false, null, p.ShooterId); } else if (hit.HitEntity is IMyCubeGrid) { Tools.Debug($"hit cube grid"); IMyCubeGrid grid = hit.HitEntity as IMyCubeGrid; Vector3I?hitPos = grid.RayCastBlocks(hit.Position, hit.Position + Vector3D.Normalize(p.Velocity)); // p.Direction if (hitPos.HasValue) { Tools.Debug($"hit block"); IMySlimBlock block = grid.GetCubeBlock(hitPos.Value); Vector3 hitObjectVelocity = Vector3.Zero; if (hit.HitEntity.Physics != null) { hitObjectVelocity = hit.HitEntity.Physics.LinearVelocity; } Vector3D relativeV = p.Velocity - hitObjectVelocity; float NotHitAngle = (float)Tools.AngleBetween(-Vector3D.Normalize(relativeV), hit.Normal); float HitAngle = (90f - NotHitAngle); float NotHitFraction = NotHitAngle / 90f; float random = (float)Tools.Random.NextDouble(); if (HitAngle < DeflectionAngle && RicochetChance > random) { Tools.Debug($"angle {HitAngle} < {DeflectionAngle}"); // Apply impulse float impulse = p.Ammo.ProjectileHitImpulse * NotHitFraction * MaxVelocityTransfer; if (hit.HitEntity.Physics != null) { hit.HitEntity.Physics.AddForce(MyPhysicsForceType.APPLY_WORLD_IMPULSE_AND_WORLD_ANGULAR_IMPULSE, p.Velocity * impulse * -hit.Normal, hit.Position, null); } // apply partial damage float damage = p.Ammo.ProjectileMassDamage * NotHitFraction * MaxDamageTransfer; if (block != null && MyAPIGateway.Session.IsServer) { Tools.Debug($"damage {damage}"); block.DoDamage(damage, MyStringHash.GetOrCompute(p.Ammo.SubtypeId), false, null, p.ShooterId); } // reduce velocity p.Velocity -= p.Velocity * NotHitFraction * MaxVelocityTransfer; // reflect p.Velocity = Vector3.Reflect(p.Velocity, hit.Normal); // calculate new direction p.Direction = Vector3D.Normalize(p.Velocity); p.Position = hit.Position + (p.Direction * 0.5f); p.Origin = p.Position; p.DrawFullTracer = false; //if (!MyAPIGateway.Utilities.IsDedicated) //{ // MatrixD world = MatrixD.CreateFromDir(hit.Normal); // world.Translation = hit.Position; // MyParticleEffect effect; // MyParticlesManager.TryCreateParticleEffect("Collision_Sparks_Directional", world, out effect); // effect.Loop = false; // effect.UserScale = 0.5f; // effect.UserEmitterScale = 16f; // effect.UserRadiusMultiplier = 0.1f; // effect.UserBirthMultiplier = 20f; // effect.DurationMin = 0.015f; // effect.DurationMax = 0.025f; // effect.SetRandomDuration(); //} } else { Tools.Debug($"obsorb damage"); if (block != null && MyAPIGateway.Session.IsServer) { block.DoDamage(p.Ammo.ProjectileMassDamage, MyStringHash.GetOrCompute(p.Ammo.SubtypeId), true); } p.Expired = true; } } } Tools.Debug($"----- ricochet check end -----"); } }