/// <summary> /// Throw an entity at the position of <paramref name="targetLoc"/> from <paramref name="sourceLoc"/>, /// without overshooting. /// </summary> /// <param name="thrownEnt">The entity to throw.</param> /// <param name="throwForceMax"> /// The MAXIMUM force to throw the entity with. /// Throw force increases with distance to target, this is the maximum force allowed. /// </param> /// <param name="targetLoc"> /// The target location to throw at. /// This function will try to land at this exact spot, /// if <paramref name="throwForceMax"/> is large enough to allow for it to be reached. /// </param> /// <param name="sourceLoc"> /// The position to start the throw from. /// </param> /// <param name="spread"> /// If true, slightly spread the actual throw angle. /// </param> /// <param name="throwSourceEnt"> /// The entity that did the throwing. An opposite impulse will be applied to this entity if passed in. /// </param> public static void ThrowTo(this IEntity thrownEnt, float throwForceMax, EntityCoordinates targetLoc, EntityCoordinates sourceLoc, bool spread = false, IEntity throwSourceEnt = null) { var entityManager = IoCManager.Resolve <IEntityManager>(); var timing = IoCManager.Resolve <IGameTiming>(); // Calculate the force necessary to land a throw based on throw duration, mass and distance. if (!targetLoc.TryDistance(entityManager, sourceLoc, out var distance)) { return; } var throwDuration = ThrownItemComponent.DefaultThrowTime; var mass = 1f; if (thrownEnt.TryGetComponent(out IPhysicsComponent physics)) { mass = physics.Mass; } var velocityNecessary = distance / throwDuration; var impulseNecessary = velocityNecessary * mass; var forceNecessary = impulseNecessary * (1f / timing.TickRate); // Then clamp it to the max force allowed and call Throw(). thrownEnt.Throw(MathF.Min(forceNecessary, throwForceMax), targetLoc, sourceLoc, spread, throwSourceEnt); }
public void PingListeners(IEntity source, EntityCoordinates sourcePos, string message) { foreach (var listener in ComponentManager.EntityQuery <ListeningComponent>()) { if (!sourcePos.TryDistance(EntityManager, listener.Owner.Transform.Coordinates, out var distance)) { return; } listener.PassSpeechData(message, source, distance); } }
public void Update(float frameTime) { if (!Owner.TryGetComponent(out SolutionContainerComponent contents)) { return; } if (!_running) { return; } _timer += frameTime; _reactTimer += frameTime; if (_reactTimer >= ReactTime && Owner.TryGetComponent(out IPhysicsComponent physics)) { _reactTimer = 0; var mapGrid = _mapManager.GetGrid(Owner.Transform.GridID); var tile = mapGrid.GetTileRef(Owner.Transform.Coordinates.ToVector2i(Owner.EntityManager, _mapManager)); foreach (var reagentQuantity in contents.ReagentList.ToArray()) { if (reagentQuantity.Quantity == ReagentUnit.Zero) { continue; } var reagent = _prototypeManager.Index <ReagentPrototype>(reagentQuantity.ReagentId); contents.TryRemoveReagent(reagentQuantity.ReagentId, reagent.ReactionTile(tile, (reagentQuantity.Quantity / _transferAmount) * 0.25f)); } } // Check if we've reached our target. if (!_reached && _target.TryDistance(Owner.EntityManager, Owner.Transform.Coordinates, out var distance) && distance <= 0.5f) { _reached = true; if (Owner.TryGetComponent(out IPhysicsComponent coll)) { var controller = coll.EnsureController <VaporController>(); controller.Stop(); } } if (contents.CurrentVolume == 0 || _timer > _aliveTime) { // Delete this Owner.Delete(); } }
/// <summary> /// Throw an entity at the position of <paramref name="targetLoc"/> from <paramref name="sourceLoc"/>, /// without overshooting. /// </summary> /// <param name="thrownEnt">The entity to throw.</param> /// <param name="throwForceMax"> /// The MAXIMUM force to throw the entity with. /// Throw force increases with distance to target, this is the maximum force allowed. /// </param> /// <param name="targetLoc"> /// The target location to throw at. /// This function will try to land at this exact spot, /// if <paramref name="throwForceMax"/> is large enough to allow for it to be reached. /// </param> /// <param name="sourceLoc"> /// The position to start the throw from. /// </param> /// <param name="spread"> /// If true, slightly spread the actual throw angle. /// </param> /// <param name="throwSourceEnt"> /// The entity that did the throwing. An opposite impulse will be applied to this entity if passed in. /// </param> public static void ThrowTo(this IEntity thrownEnt, float throwForceMax, EntityCoordinates targetLoc, EntityCoordinates sourceLoc, bool spread = false, IEntity throwSourceEnt = null) { var entityManager = IoCManager.Resolve <IEntityManager>(); var timing = IoCManager.Resolve <IGameTiming>(); // Calculate the force necessary to land a throw based on throw duration, mass and distance. if (!targetLoc.TryDistance(entityManager, sourceLoc, out var distance)) { return; } var throwDuration = ThrownItemComponent.DefaultThrowTime; // TODO: Mass isn't even used on the system side yet for controllers so do that someday var velocityNecessary = distance / throwDuration; var forceNecessary = velocityNecessary / timing.TickRate; // Then clamp it to the max force allowed and call Throw(). thrownEnt.Throw(MathF.Min(forceNecessary, throwForceMax), targetLoc, sourceLoc, spread, throwSourceEnt); }