コード例 #1
0
        /// <summary>
        ///     Checks that these coordinates are within a certain distance without any
        ///     entity that matches the collision mask obstructing them.
        ///     If the <paramref name="range"/> is zero or negative,
        ///     this method will only check if nothing obstructs the two sets of coordinates..
        /// </summary>
        /// <param name="coords">Set of coordinates to use.</param>
        /// <param name="otherCoords">Other set of coordinates to use.</param>
        /// <param name="range">maximum distance between the two sets of coordinates.</param>
        /// <param name="collisionMask">the mask to check for collisions</param>
        /// <param name="predicate">.</param>
        /// <param name="mapManager">Map manager containing the two GridIds.</param>
        /// <param name="insideBlockerValid">if coordinates inside obstructions count as obstructed or not</param>
        /// <returns>True if the two points are within a given range without being obstructed.</returns>
        public bool InRangeUnobstructed(MapCoordinates coords, Vector2 otherCoords, float range = InteractionRange,
                                        int collisionMask = (int)CollisionGroup.Impassable, Func <IEntity, bool> predicate = null, bool insideBlockerValid = false)
        {
            var dir = otherCoords - coords.Position;

            if (dir.LengthSquared.Equals(0f))
            {
                return(true);
            }
            if (range > 0f && !(dir.LengthSquared <= range * range))
            {
                return(false);
            }

            var ray        = new CollisionRay(coords.Position, dir.Normalized, collisionMask);
            var rayResults = _physicsManager.IntersectRayWithPredicate(coords.MapId, ray, dir.Length, predicate, true);

            if (!rayResults.DidHitObject || (insideBlockerValid && rayResults.DidHitObject && (rayResults.HitPos - otherCoords).Length < 1f))
            {
                if (_mapManager.TryFindGridAt(coords, out var mapGrid) && mapGrid != null)
                {
                    var srcPos  = mapGrid.MapToGrid(coords);
                    var destPos = new GridCoordinates(otherCoords, mapGrid);
                    if (srcPos.InRange(_mapManager, destPos, range))
                    {
                        return(true);
                    }
                }
            }
            return(false);
        }
コード例 #2
0
        // Just do a simple range check, then chuck the ray out. If we get bigger than 1 tile mobs may need to adjust this
        public static bool InLineOfSight(IEntity owner, IEntity target)
        {
            var range = 50.0f;

            if (owner.Transform.GridID != target.Transform.GridID)
            {
                return(false);
            }

            if (owner.TryGetComponent(out AiControllerComponent controller))
            {
                var targetRange = (target.Transform.GridPosition.Position - owner.Transform.GridPosition.Position).Length;
                if (targetRange > controller.VisionRadius)
                {
                    return(false);
                }

                range = controller.VisionRadius;
            }

            var angle = new Angle(target.Transform.GridPosition.Position - owner.Transform.GridPosition.Position);
            var ray   = new CollisionRay(
                owner.Transform.GridPosition.Position,
                angle.ToVec(),
                (int)(CollisionGroup.Opaque | CollisionGroup.Impassable | CollisionGroup.MobImpassable));

            var rayCastResults = IoCManager.Resolve <IPhysicsManager>().IntersectRay(owner.Transform.MapID, ray, range, owner).ToList();

            return(rayCastResults.Count > 0 && rayCastResults[0].HitEntity == target);
        }
コード例 #3
0
        public void RayCast()
        {
            // Arrange
            var box     = new Box2(5, -5, 10, 6);
            var ray     = new CollisionRay(new Vector2(0, 1), Vector2.UnitX, 1);
            var manager = new PhysicsManager();

            var mock = new Mock <IPhysBody>();

            mock.Setup(foo => foo.WorldAABB).Returns(box);
            mock.Setup(foo => foo.Entity).Returns(new Entity(new ServerEntityManager(), EntityUid.FirstUid)); // requires IPhysBody not have null owner
            mock.Setup(foo => foo.CanCollide).Returns(true);
            mock.Setup(foo => foo.CollisionLayer).Returns(1);
            mock.Setup(foo => foo.CollisionMask).Returns(1);
            manager.AddBody(mock.Object);

            // Act
            var results = manager.IntersectRay(new MapId(0), ray).ToList();

            Assert.That(results.Count, Is.EqualTo(1));

            var result = results.First();

            // Assert
            Assert.That(result.Distance, Is.EqualTo(5));
            Assert.That(result.HitPos.X, Is.EqualTo(5));
            Assert.That(result.HitPos.Y, Is.EqualTo(1));
        }
コード例 #4
0
ファイル: JumpController.cs プロジェクト: SWE3T/Bright
 private void Start()
 {
     rb         = GetComponent <Rigidbody2D>();
     ray        = GetComponent <CollisionRay>();
     staminaBar = GetComponent <StaminaBar>();
     physics    = GetComponent <ModifyPhysics>();
 }
コード例 #5
0
        public void RayCast()
        {
            // Arrange
            var box     = new Box2(5, -5, 10, 6);
            var ray     = new CollisionRay(new Vector2(0, 1), Vector2.UnitX, 1);
            var manager = new PhysicsManager();

            var mock = new Mock <IPhysBody>();

            mock.Setup(foo => foo.WorldAABB).Returns(box);
            mock.Setup(foo => foo.Owner).Returns(new Entity()); // requires IPhysBody not have null owner
            mock.Setup(foo => foo.CollisionEnabled).Returns(true);
            mock.Setup(foo => foo.CollisionLayer).Returns(1);
            mock.Setup(foo => foo.CollisionMask).Returns(1);
            mock.Setup(foo => foo.IsHardCollidable).Returns(true);
            manager.AddBody(mock.Object);

            // Act
            var result = manager.IntersectRay(new MapId(0), ray);

            // Assert
            Assert.That(result.DidHitObject, Is.True);
            Assert.That(result.Distance, Is.EqualTo(5));
            Assert.That(result.HitPos.X, Is.EqualTo(5));
            Assert.That(result.HitPos.Y, Is.EqualTo(1));
        }
コード例 #6
0
 private void Start()
 {
     movement = GetComponent <MovementController>();
     ray      = GetComponent <CollisionRay>();
     rb       = GetComponent <Rigidbody2D>();
     anim     = GetComponent <Animator>();
 }
コード例 #7
0
        /// <summary>
        /// Fires hitscan entities and then displays their effects
        /// </summary>
        private void FireHitscan(IEntity shooter, HitscanComponent hitscan, Angle angle)
        {
            var ray            = new CollisionRay(Owner.Transform.Coordinates.ToMapPos(Owner.EntityManager), angle.ToVec(), (int)hitscan.CollisionMask);
            var physicsManager = EntitySystem.Get <SharedBroadPhaseSystem>();
            var rayCastResults = physicsManager.IntersectRay(Owner.Transform.MapID, ray, hitscan.MaxLength, shooter, false).ToList();

            if (rayCastResults.Count >= 1)
            {
                var result   = rayCastResults[0];
                var distance = result.Distance;
                hitscan.FireEffects(shooter, distance, angle, result.HitEntity);

                if (!result.HitEntity.TryGetComponent(out IDamageableComponent? damageable))
                {
                    return;
                }

                damageable.ChangeDamage(hitscan.DamageType, (int)Math.Round(hitscan.Damage, MidpointRounding.AwayFromZero), false, Owner);
                //I used Math.Round over Convert.toInt32, as toInt32 always rounds to
                //even numbers if halfway between two numbers, rather than rounding to nearest
            }
            else
            {
                hitscan.FireEffects(shooter, hitscan.MaxLength, angle);
            }
        }
コード例 #8
0
 private void Start()
 {
     staminaBar = GetComponent <StaminaBar>();
     rb         = GetComponent <Rigidbody2D>();
     ray        = GetComponent <CollisionRay>();
     fsm        = GetComponent <FiniteStateMachine>();
 }
コード例 #9
0
        /// <summary>
        ///     Checks that these coordinates are within a certain distance without any
        ///     entity that matches the collision mask obstructing them.
        ///     If the <paramref name="range"/> is zero or negative,
        ///     this method will only check if nothing obstructs the two sets
        ///     of coordinates.
        /// </summary>
        /// <param name="origin">Set of coordinates to use.</param>
        /// <param name="other">Other set of coordinates to use.</param>
        /// <param name="range">
        ///     Maximum distance between the two sets of coordinates.
        /// </param>
        /// <param name="collisionMask">The mask to check for collisions.</param>
        /// <param name="predicate">
        ///     A predicate to check whether to ignore an entity or not.
        ///     If it returns true, it will be ignored.
        /// </param>
        /// <param name="ignoreInsideBlocker">
        ///     If true and <see cref="origin"/> or <see cref="other"/> are inside
        ///     the obstruction, ignores the obstruction and considers the interaction
        ///     unobstructed.
        ///     Therefore, setting this to true makes this check more permissive,
        ///     such as allowing an interaction to occur inside something impassable
        ///     (like a wall). The default, false, makes the check more restrictive.
        /// </param>
        /// <returns>
        ///     True if the two points are within a given range without being obstructed.
        /// </returns>
        public bool InRangeUnobstructed(
            MapCoordinates origin,
            MapCoordinates other,
            float range = InteractionRange,
            CollisionGroup collisionMask = CollisionGroup.Impassable,
            Ignored?predicate            = null,
            bool ignoreInsideBlocker     = false)
        {
            if (!origin.InRange(other, range))
            {
                return(false);
            }

            var dir = other.Position - origin.Position;

            if (dir.LengthSquared.Equals(0f))
            {
                return(true);
            }
            if (range > 0f && !(dir.LengthSquared <= range * range))
            {
                return(false);
            }

            predicate ??= _ => false;

            var ray        = new CollisionRay(origin.Position, dir.Normalized, (int)collisionMask);
            var rayResults = _sharedBroadphaseSystem.IntersectRayWithPredicate(origin.MapId, ray, dir.Length, predicate.Invoke, false).ToList();

            if (rayResults.Count == 0)
            {
                return(true);
            }

            // TODO: Wot? This should just be in the predicate.
            if (!ignoreInsideBlocker)
            {
                return(false);
            }

            foreach (var result in rayResults)
            {
                if (!result.HitEntity.TryGetComponent(out IPhysBody? p))
                {
                    continue;
                }

                var bBox = p.GetWorldAABB();

                if (bBox.Contains(origin.Position) || bBox.Contains(other.Position))
                {
                    continue;
                }

                return(false);
            }

            return(true);
        }
コード例 #10
0
        private void IdleState()
        {
            if (!ActionBlockerSystem.CanMove(SelfEntity))
            {
                DisabledPositiveEdge();
                return;
            }

            if (_timeMan.CurTime < _startStateTime + IdleTimeSpan)
            {
                return;
            }

            var entWorldPos = SelfEntity.Transform.WorldPosition;

            if (SelfEntity.TryGetComponent <CollidableComponent>(out var bounds))
            {
                entWorldPos = ((IPhysBody)bounds).WorldAABB.Center;
            }

            var rngState = GenSeed();

            for (var i = 0; i < 3; i++) // you get 3 chances to find a place to walk
            {
                var dir        = new Vector2(Random01(ref rngState) * 2 - 1, Random01(ref rngState) * 2 - 1).Normalized;
                var ray        = new CollisionRay(entWorldPos, dir, (int)CollisionGroup.Impassable);
                var rayResults = _physMan.IntersectRay(SelfEntity.Transform.MapID, ray, MaxWalkDistance, SelfEntity).ToList();

                if (rayResults.Count == 1)
                {
                    var rayResult = rayResults[0];
                    if (rayResult.Distance > 1) // hit an impassable object
                    {
                        // set the new position back from the wall a bit
                        _walkTargetPos = entWorldPos + dir * (rayResult.Distance - 0.5f);
                        WalkingPositiveEdge();
                        return;
                    }
                }
                else // hit nothing (path clear)
                {
                    _walkTargetPos = dir * MaxWalkDistance;
                    WalkingPositiveEdge();
                    return;
                }
            }

            // can't find clear spot, do nothing, sleep longer
            _startStateTime = _timeMan.CurTime;
        }
コード例 #11
0
 public override void Update(Entity entity)
 {
     if (CollisionRay.IsEntityInSight(entity as Enemy, GameWorld.GetPlayers()[0]))
     {
         _jumpTimer.ChangeWaitTime(TimeBetweenJumps_ACTIVE);
         _canSeePlayer = true;
     }
     else
     {
         _jumpTimer.ChangeWaitTime(TimeBetweenJumps_IDLE);
         _canSeePlayer = false;
     }
     base.Update(entity);
 }
コード例 #12
0
        private void Fire(IEntity user, GridCoordinates clickLocation)
        {
            if (capacitorComponent.Charge < _lowerChargeLimit)
            {//If capacitor has less energy than the lower limit, do nothing
                return;
            }
            float energyModifier = capacitorComponent.GetChargeFrom(_baseFireCost) / _baseFireCost;
            var   userPosition   = user.Transform.WorldPosition; //Remember world positions are ephemeral and can only be used instantaneously
            var   angle          = new Angle(clickLocation.Position - userPosition);

            var ray            = new CollisionRay(userPosition, angle.ToVec(), (int)(CollisionGroup.Impassable | CollisionGroup.MobImpassable));
            var rayCastResults = IoCManager.Resolve <IPhysicsManager>().IntersectRay(user.Transform.MapID, ray, MaxLength, user);

            Hit(rayCastResults, energyModifier);
            AfterEffects(user, rayCastResults, angle, energyModifier);
        }
コード例 #13
0
        public bool Condition(EntityUid user, EntityCoordinates location, Direction direction)
        {
            var entManager = IoCManager.Resolve <IEntityManager>();

            // get blueprint and user position
            var userWorldPosition = entManager.GetComponent <TransformComponent>(user).WorldPosition;
            var objWorldPosition  = location.ToMap(entManager).Position;

            // find direction from user to blueprint
            var userToObject = (objWorldPosition - userWorldPosition);
            // get direction of the grid being placed on as an offset.
            var gridRotation        = entManager.GetComponent <TransformComponent>(location.EntityId).WorldRotation;
            var directionWithOffset = gridRotation.RotateVec(direction.ToVec());

            // dot product will be positive if user direction and blueprint are co-directed
            var dotProd = Vector2.Dot(directionWithOffset.Normalized, userToObject.Normalized);

            if (dotProd > 0)
            {
                return(false);
            }

            // now we need to check that user actually tries to build wallmount on a wall
            var physics    = EntitySystem.Get <SharedPhysicsSystem>();
            var rUserToObj = new CollisionRay(userWorldPosition, userToObject.Normalized, (int)CollisionGroup.Impassable);
            var length     = userToObject.Length;

            var tagSystem = EntitySystem.Get <TagSystem>();

            var userToObjRaycastResults = physics.IntersectRayWithPredicate(entManager.GetComponent <TransformComponent>(user).MapID, rUserToObj, maxLength: length,
                                                                            predicate: (e) => !tagSystem.HasTag(e, "Wall"));

            var targetWall = userToObjRaycastResults.FirstOrNull();

            if (targetWall == null)
            {
                return(false);
            }

            // get this wall entity
            // check that we didn't try to build wallmount that facing another adjacent wall
            var rAdjWall = new CollisionRay(objWorldPosition, directionWithOffset.Normalized, (int)CollisionGroup.Impassable);
            var adjWallRaycastResults = physics.IntersectRayWithPredicate(entManager.GetComponent <TransformComponent>(user).MapID, rAdjWall, maxLength: 0.5f,
                                                                          predicate: (e) => e == targetWall.Value.HitEntity || !tagSystem.HasTag(e, "Wall"));

            return(!adjWallRaycastResults.Any());
        }
コード例 #14
0
        private void UpdatePanelCoverage(SolarPanelComponent panel)
        {
            IEntity entity = panel.Owner;

            // So apparently, and yes, I *did* only find this out later,
            // this is just a really fancy way of saying "Lambert's law of cosines".
            // ...I still think this explaination makes more sense.

            // In the 'sunRelative' coordinate system:
            // the sun is considered to be an infinite distance directly up.
            // this is the rotation of the panel relative to that.
            // directly upwards (theta = 0) = coverage 1
            // left/right 90 degrees (abs(theta) = (pi / 2)) = coverage 0
            // directly downwards (abs(theta) = pi) = coverage -1
            // as TowardsSun + = CCW,
            // panelRelativeToSun should - = CW
            var panelRelativeToSun = entity.Transform.WorldRotation - TowardsSun;
            // essentially, given cos = X & sin = Y & Y is 'downwards',
            // then for the first 90 degrees of rotation in either direction,
            // this plots the lower-right quadrant of a circle.
            // now basically assume a line going from the negated X/Y to there,
            // and that's the hypothetical solar panel.
            //
            // since, again, the sun is considered to be an infinite distance upwards,
            // this essentially means Cos(panelRelativeToSun) is half of the cross-section,
            // and since the full cross-section has a max of 2, effectively-halving it is fine.
            //
            // as for when it goes negative, it only does that when (abs(theta) > pi)
            // and that's expected behavior.
            float coverage = (float)Math.Max(0, Math.Cos(panelRelativeToSun));

            if (coverage > 0)
            {
                // Determine if the solar panel is occluded, and zero out coverage if so.
                // FIXME: The "Opaque" collision group doesn't seem to work right now.
                var ray            = new CollisionRay(entity.Transform.WorldPosition, TowardsSun.ToVec(), (int)CollisionGroup.Opaque);
                var rayCastResults = EntitySystem.Get <SharedBroadPhaseSystem>().IntersectRay(entity.Transform.MapID, ray, SunOcclusionCheckDistance, entity);
                if (rayCastResults.Any())
                {
                    coverage = 0;
                }
            }

            // Total coverage calculated; apply it to the panel.
            panel.Coverage = coverage;
        }
コード例 #15
0
        /// <summary>
        ///     Checks that these coordinates are within a certain distance without any
        ///     entity that matches the collision mask obstructing them.
        ///     If the <paramref name="range"/> is zero or negative,
        ///     this method will only check if nothing obstructs the two sets
        ///     of coordinates.
        /// </summary>
        /// <param name="origin">Set of coordinates to use.</param>
        /// <param name="other">Other set of coordinates to use.</param>
        /// <param name="range">
        ///     Maximum distance between the two sets of coordinates.
        /// </param>
        /// <param name="collisionMask">The mask to check for collisions.</param>
        /// <param name="predicate">
        ///     A predicate to check whether to ignore an entity or not.
        ///     If it returns true, it will be ignored.
        /// </param>
        /// <param name="ignoreInsideBlocker">
        ///     If true and <see cref="origin"/> or <see cref="other"/> are inside
        ///     the obstruction, ignores the obstruction and considers the interaction
        ///     unobstructed.
        ///     Therefore, setting this to true makes this check more permissive,
        ///     such as allowing an interaction to occur inside something impassable
        ///     (like a wall). The default, false, makes the check more restrictive.
        /// </param>
        /// <returns>
        ///     True if the two points are within a given range without being obstructed.
        /// </returns>
        public bool InRangeUnobstructed(
            MapCoordinates origin,
            MapCoordinates other,
            float range = InteractionRange,
            CollisionGroup collisionMask = CollisionGroup.Impassable,
            Ignored predicate            = null,
            bool ignoreInsideBlocker     = false)
        {
            if (!origin.InRange(other, range))
            {
                return(false);
            }

            var dir = other.Position - origin.Position;

            if (dir.LengthSquared.Equals(0f))
            {
                return(true);
            }
            if (range > 0f && !(dir.LengthSquared <= range * range))
            {
                return(false);
            }

            predicate ??= _ => false;

            var ray        = new CollisionRay(origin.Position, dir.Normalized, (int)collisionMask);
            var rayResults = _physicsManager.IntersectRayWithPredicate(origin.MapId, ray, dir.Length, predicate.Invoke, false).ToList();

            if (rayResults.Count == 0)
            {
                return(true);
            }

            if (!ignoreInsideBlocker)
            {
                return(false);
            }

            if (rayResults.Count <= 0)
            {
                return(false);
            }

            return((rayResults[0].HitPos - other.Position).Length < 1f);
        }
コード例 #16
0
        private bool HandleDrop(ICommonSession session, GridCoordinates coords, EntityUid uid)
        {
            var ent = ((IPlayerSession)session).AttachedEntity;

            if (ent == null || !ent.IsValid())
            {
                return(false);
            }

            if (!ent.TryGetComponent(out HandsComponent handsComp))
            {
                return(false);
            }

            if (handsComp.GetActiveHand == null)
            {
                return(false);
            }

            var dir        = (coords.Position - ent.Transform.GridPosition.Position);
            var ray        = new CollisionRay(ent.Transform.GridPosition.Position, dir.Normalized, (int)CollisionGroup.Impassable);
            var rayResults = IoCManager.Resolve <IPhysicsManager>().IntersectRay(ent.Transform.MapID, ray, dir.Length, ent);

            if (!rayResults.DidHitObject)
            {
                if (coords.InRange(_mapManager, ent.Transform.GridPosition, InteractionSystem.InteractionRange))
                {
                    handsComp.Drop(handsComp.ActiveIndex, coords);
                }
                else
                {
                    var entCoords = ent.Transform.GridPosition.Position;
                    var entToDesiredDropCoords = coords.Position - entCoords;
                    var clampedDropCoords      = ((entToDesiredDropCoords.Normalized * InteractionSystem.InteractionRange) + entCoords);

                    handsComp.Drop(handsComp.ActiveIndex, new GridCoordinates(clampedDropCoords, coords.GridID));
                }
            }
            else
            {
                handsComp.Drop(handsComp.ActiveIndex, ent.Transform.GridPosition);
            }

            return(true);
        }
コード例 #17
0
        /// <summary>
        ///     Checks that these coordinates are within a certain distance without any
        ///     entity that matches the collision mask obstructing them.
        ///     If the <paramref name="range"/> is zero or negative,
        ///     this method will only check if nothing obstructs the two sets of coordinates..
        /// </summary>
        /// <param name="mapManager">Map manager containing the two GridIds.</param>
        /// <param name="coords">Set of coordinates to use.</param>
        /// <param name="otherCoords">Other set of coordinates to use.</param>
        /// <param name="range">maximum distance between the two sets of coordinates.</param>
        /// <param name="collisionMask">the mask to check for collisions</param>
        /// <param name="ignoredEnt">the entity to be ignored when checking for collisions.</param>
        /// <returns>True if the two points are within a given range without being obstructed.</returns>
        public bool InRangeUnobstructed(GridCoordinates coords, GridCoordinates otherCoords, float range = InteractionRange, int collisionMask = (int)CollisionGroup.Impassable, IEntity ignoredEnt = null)
        {
            if (range > 0f && !coords.InRange(_mapManager, otherCoords, range))
            {
                return(false);
            }

            var dir = (otherCoords.Position - coords.Position);

            if (!(dir.Length > 0f))
            {
                return(true);
            }
            var ray        = new CollisionRay(coords.Position, dir.Normalized, collisionMask);
            var rayResults = _physicsManager.IntersectRay(_mapManager.GetGrid(coords.GridID).ParentMapId, ray, dir.Length, ignoredEnt);

            return(!rayResults.DidHitObject);
        }
コード例 #18
0
        /// <summary>
        /// Fires hitscan entities and then displays their effects
        /// </summary>
        private void FireHitscan(IEntity shooter, HitscanComponent hitscan, Angle angle)
        {
            var ray            = new CollisionRay(Owner.Transform.Coordinates.ToMapPos(Owner.EntityManager), angle.ToVec(), (int)hitscan.CollisionMask);
            var physicsManager = EntitySystem.Get <SharedPhysicsSystem>();
            var rayCastResults = physicsManager.IntersectRay(Owner.Transform.MapID, ray, hitscan.MaxLength, shooter, false).ToList();

            if (rayCastResults.Count >= 1)
            {
                var result   = rayCastResults[0];
                var distance = result.Distance;
                hitscan.FireEffects(shooter, distance, angle, result.HitEntity);
                EntitySystem.Get <DamageableSystem>().TryChangeDamage(result.HitEntity.Uid, hitscan.Damage);
            }
            else
            {
                hitscan.FireEffects(shooter, hitscan.MaxLength, angle);
            }
        }
コード例 #19
0
        public override void Update(Entity entity)
        {
            if (CollisionRay.IsEntityInSight(entity, GameWorld.GetPlayers()[0]) && !isAngry)
            {
                isAngry = true;
                chargeUpTimer.ResetAndWaitFor(1000);
                entity.IsFacingRight = !entity.IsPlayerToTheRight();
            }

            if (isAngry)
            {
                if (!firingUp)
                {
                    firingUp = true;
                    entity.AddAnimationToQueue("angry");
                    entity.Sounds.GetSoundRef("scream").PlayIfStopped();
                    entity.Sounds.GetSoundRef("fire").PlayIfStopped();
                }
            }
            if (firingUp)
            {
                chargeUpTimer.Increment();
                entity.Sounds.GetSoundRef("fire").PlayIfStopped();
            }

            if (isRunningToPlayer)
            {
                chargeUpTimer.Reset();
                entity.AddAnimationToQueue("charge");
                entity.Sounds.GetSoundRef("fire").PlayIfStopped();
                if (playerToRightWhenAngry)
                {
                    entity.SetVelX(5);
                }
                else
                {
                    entity.SetVelX(-5);
                }
                entity.IsFacingRight = !playerToRightWhenAngry;
            }


            base.Update(entity);
        }
コード例 #20
0
        public static void FlashAreaHelper(IEntity source, double range, double duration, string sound = null)
        {
            var physicsManager = IoCManager.Resolve <IPhysicsManager>();
            var entityManager  = IoCManager.Resolve <IEntityManager>();

            foreach (var entity in entityManager.GetEntities(new TypeEntityQuery(typeof(ServerFlashableComponent))))
            {
                if (source.Transform.MapID != entity.Transform.MapID ||
                    entity == source)
                {
                    continue;
                }

                var direction = entity.Transform.WorldPosition - source.Transform.WorldPosition;

                if (direction.Length > range)
                {
                    continue;
                }

                // Direction will be zero if they're hit with the source only I think
                if (direction == Vector2.Zero)
                {
                    continue;
                }

                var ray            = new CollisionRay(source.Transform.WorldPosition, direction.Normalized, (int)CollisionGroup.Opaque);
                var rayCastResults = physicsManager.IntersectRay(source.Transform.MapID, ray, direction.Length, source, false).ToList();
                if (rayCastResults.Count == 0 ||
                    rayCastResults[0].HitEntity != entity)
                {
                    continue;
                }

                var flashable = entity.GetComponent <ServerFlashableComponent>();
                flashable.Flash(duration);
            }

            if (sound != null)
            {
                IoCManager.Resolve <IEntitySystemManager>().GetEntitySystem <AudioSystem>().PlayAtCoords(sound, source.Transform.GridPosition);
            }
        }
コード例 #21
0
        /// <summary>
        ///     Traces a ray from coords to otherCoords and returns the length
        ///     of the vector between coords and the ray's first hit.
        /// </summary>
        /// <param name="coords">Set of coordinates to use.</param>
        /// <param name="otherCoords">Other set of coordinates to use.</param>
        /// <param name="collisionMask">the mask to check for collisions</param>
        /// <param name="predicate">A predicate to check whether to ignore an entity or not. If it returns true, it will be ignored.</param>
        /// <returns>Length of resulting ray.</returns>
        public float UnobstructedRayLength(MapCoordinates coords, MapCoordinates otherCoords,
                                           int collisionMask = (int)CollisionGroup.Impassable, Func <IEntity, bool> predicate = null)
        {
            var dir = otherCoords.Position - coords.Position;

            if (dir.LengthSquared.Equals(0f))
            {
                return(0f);
            }

            var ray        = new CollisionRay(coords.Position, dir.Normalized, collisionMask);
            var rayResults = _physicsManager.IntersectRayWithPredicate(coords.MapId, ray, dir.Length, predicate, returnOnFirstHit: false).ToList();

            if (rayResults.Count == 0)
            {
                return(dir.Length);
            }
            return((rayResults[0].HitPos - coords.Position).Length);
        }
コード例 #22
0
        private void Fire(IEntity user, GridCoordinates clickLocation)
        {
            if (capacitorComponent.Charge < _lowerChargeLimit)
            {//If capacitor has less energy than the lower limit, do nothing
                return;
            }
            float energyModifier = capacitorComponent.GetChargeFrom(_baseFireCost) / _baseFireCost;
            var   userPosition   = user.Transform.WorldPosition; //Remember world positions are ephemeral and can only be used instantaneously
            var   angle          = new Angle(clickLocation.Position - userPosition);

            var ray            = new CollisionRay(userPosition, angle.ToVec(), (int)(CollisionGroup.Opaque));
            var rayCastResults = IoCManager.Resolve <IPhysicsManager>().IntersectRay(user.Transform.MapID, ray, MaxLength, user, returnOnFirstHit: false).ToList();

            //The first result is guaranteed to be the closest one
            if (rayCastResults.Count >= 1)
            {
                Hit(rayCastResults[0], energyModifier, user);
                AfterEffects(user, rayCastResults[0], angle, energyModifier);
            }
        }
コード例 #23
0
        public bool Condition(IEntity user, EntityCoordinates location, Direction direction)
        {
            var entManager = IoCManager.Resolve <IEntityManager>();

            // get blueprint and user position
            var userWorldPosition = user.Transform.WorldPosition;
            var objWorldPosition  = location.ToMap(entManager).Position;

            // find direction from user to blueprint
            var userToObject = (objWorldPosition - userWorldPosition);

            // dot product will be positive if user direction and blueprint are co-directed
            var dotProd = Vector2.Dot(direction.ToVec(), userToObject);

            if (dotProd > 0)
            {
                return(false);
            }

            // now we need to check that user actually tries to build wallmount on a wall
            var physics    = EntitySystem.Get <SharedBroadphaseSystem>();
            var rUserToObj = new CollisionRay(userWorldPosition, userToObject.Normalized, (int)CollisionGroup.Impassable);
            var length     = userToObject.Length;
            var userToObjRaycastResults = physics.IntersectRayWithPredicate(user.Transform.MapID, rUserToObj, maxLength: length,
                                                                            predicate: (e) => !e.HasTag("Wall"));

            if (!userToObjRaycastResults.Any())
            {
                return(false);
            }

            // get this wall entity
            var targetWall = userToObjRaycastResults.First().HitEntity;

            // check that we didn't try to build wallmount that facing another adjacent wall
            var rAdjWall = new CollisionRay(objWorldPosition, direction.ToVec(), (int)CollisionGroup.Impassable);
            var adjWallRaycastResults = physics.IntersectRayWithPredicate(user.Transform.MapID, rAdjWall, maxLength: 0.5f,
                                                                          predicate: (e) => e == targetWall || !e.HasTag("Wall"));

            return(!adjWallRaycastResults.Any());
        }
コード例 #24
0
        public void MultiHitRayCast()
        {
            // Arrange
            var b1      = new Box2(5, -5, 10, 6);
            var b2      = new Box2(6, -10, 7, 10);
            var ray     = new CollisionRay(Vector2.UnitY, Vector2.UnitX, 1);
            var manager = new PhysicsManager();

            var e1 = new Entity(new ServerEntityManager(), EntityUid.FirstUid);
            var e2 = new Entity(new ServerEntityManager(), EntityUid.FirstUid);

            var m1 = new Mock <IPhysBody>();

            m1.Setup(foo => foo.WorldAABB).Returns(b1);
            m1.Setup(foo => foo.Entity).Returns(e1);
            m1.Setup(foo => foo.CanCollide).Returns(true);
            m1.Setup(foo => foo.CollisionLayer).Returns(1);
            m1.Setup(foo => foo.CollisionMask).Returns(1);
            manager.AddBody(m1.Object);

            var m2 = new Mock <IPhysBody>();

            m2.Setup(foo => foo.WorldAABB).Returns(b2);
            m2.Setup(foo => foo.Entity).Returns(e2);
            m2.Setup(foo => foo.CanCollide).Returns(true);
            m2.Setup(foo => foo.CollisionLayer).Returns(1);
            m2.Setup(foo => foo.CollisionMask).Returns(1);
            manager.AddBody(m2.Object);

            var results = manager.IntersectRay(new MapId(0), ray, returnOnFirstHit: false).ToList();

            Assert.That(results.Count, Is.EqualTo(2));
            Assert.That(results[0].HitEntity.Uid, Is.EqualTo(e1.Uid));
            Assert.That(results[1].HitEntity.Uid, Is.EqualTo(e2.Uid));
            Assert.That(results[0].Distance, Is.EqualTo(5));
            Assert.That(results[0].HitPos.X, Is.EqualTo(5));
            Assert.That(results[0].HitPos.Y, Is.EqualTo(1));
            Assert.That(results[1].Distance, Is.EqualTo(6));
            Assert.That(results[1].HitPos.X, Is.EqualTo(6));
            Assert.That(results[1].HitPos.Y, Is.EqualTo(1));
        }
コード例 #25
0
        /// <summary>
        ///     Checks that these coordinates are within a certain distance without any
        ///     entity that matches the collision mask obstructing them.
        ///     If the <paramref name="range"/> is zero or negative,
        ///     this method will only check if nothing obstructs the two sets
        ///     of coordinates.
        /// </summary>
        /// <param name="origin">Set of coordinates to use.</param>
        /// <param name="other">Other set of coordinates to use.</param>
        /// <param name="range">
        ///     Maximum distance between the two sets of coordinates.
        /// </param>
        /// <param name="collisionMask">The mask to check for collisions.</param>
        /// <param name="predicate">
        ///     A predicate to check whether to ignore an entity or not.
        ///     If it returns true, it will be ignored.
        /// </param>
        /// <returns>
        ///     True if the two points are within a given range without being obstructed.
        /// </returns>
        public bool InRangeUnobstructed(
            MapCoordinates origin,
            MapCoordinates other,
            float range = InteractionRange,
            CollisionGroup collisionMask = CollisionGroup.Impassable,
            Ignored?predicate            = null)
        {
            // Have to be on same map regardless.
            if (other.MapId != origin.MapId)
            {
                return(false);
            }

            var dir    = other.Position - origin.Position;
            var length = dir.Length;

            // If range specified also check it
            if (range > 0f && length > range)
            {
                return(false);
            }

            if (MathHelper.CloseTo(length, 0))
            {
                return(true);
            }

            predicate ??= _ => false;

            if (length > MaxRaycastRange)
            {
                Logger.Warning("InRangeUnobstructed check performed over extreme range. Limiting CollisionRay size.");
                length = MaxRaycastRange;
            }

            var ray        = new CollisionRay(origin.Position, dir.Normalized, (int)collisionMask);
            var rayResults = _sharedBroadphaseSystem.IntersectRayWithPredicate(origin.MapId, ray, length, predicate.Invoke, false).ToList();

            return(rayResults.Count == 0);
        }
コード例 #26
0
    /// <summary>
    /// Fires hitscan entities and then displays their effects
    /// </summary>
    private void FireHitscan(EntityUid shooter, HitscanComponent hitscan, ServerRangedBarrelComponent component, Angle angle)
    {
        var ray            = new CollisionRay(Transform(component.Owner).WorldPosition, angle.ToVec(), (int)hitscan.CollisionMask);
        var rayCastResults = _physics.IntersectRay(Transform(component.Owner).MapID, ray, hitscan.MaxLength, shooter, false).ToList();

        if (rayCastResults.Count >= 1)
        {
            var result   = rayCastResults[0];
            var distance = result.Distance;
            hitscan.FireEffects(shooter, distance, angle, result.HitEntity);
            var dmg = _damageable.TryChangeDamage(result.HitEntity, hitscan.Damage);
            if (dmg != null)
            {
                _logs.Add(LogType.HitScanHit,
                          $"{EntityManager.ToPrettyString(shooter):user} hit {EntityManager.ToPrettyString(result.HitEntity):target} using {EntityManager.ToPrettyString(hitscan.Owner):used} and dealt {dmg.Total:damage} damage");
            }
        }
        else
        {
            hitscan.FireEffects(shooter, hitscan.MaxLength, angle);
        }
    }
コード例 #27
0
        /// <summary>
        ///     Checks that these coordinates are within a certain distance without any
        ///     entity that matches the collision mask obstructing them.
        ///     If the <paramref name="range"/> is zero or negative,
        ///     this method will only check if nothing obstructs the two sets of coordinates..
        /// </summary>
        /// <param name="coords">Set of coordinates to use.</param>
        /// <param name="otherCoords">Other set of coordinates to use.</param>
        /// <param name="range">maximum distance between the two sets of coordinates.</param>
        /// <param name="collisionMask">the mask to check for collisions</param>
        /// <param name="ignoredEnt">the entity to be ignored when checking for collisions.</param>
        /// <param name="mapManager">Map manager containing the two GridIds.</param>
        /// <param name="insideBlockerValid">if coordinates inside obstructions count as obstructed or not</param>
        /// <returns>True if the two points are within a given range without being obstructed.</returns>
        public bool InRangeUnobstructed(MapCoordinates coords, Vector2 otherCoords, float range = InteractionRange,
                                        int collisionMask = (int)CollisionGroup.Impassable, IEntity ignoredEnt = null, bool insideBlockerValid = false)
        {
            var dir = otherCoords - coords.Position;

            if (dir.LengthSquared.Equals(0f))
            {
                return(true);
            }

            if (range > 0f && !(dir.LengthSquared <= range * range))
            {
                return(false);
            }

            var ray        = new CollisionRay(coords.Position, dir.Normalized, collisionMask);
            var rayResults = _physicsManager.IntersectRay(coords.MapId, ray, dir.Length, ignoredEnt, true);



            return(!rayResults.DidHitObject || (insideBlockerValid && rayResults.DidHitObject && rayResults.Distance < 1f));
        }
コード例 #28
0
        public override void Update(Entity entity)
        {
            StoneGolem golem = entity as StoneGolem;

            if (CollisionRay.IsEntityInSight(entity, GameWorld.GetPlayers()[0]))
            {
                float velX = 1.0f;
                golem.IsFacingRight = false;
                if (!golem.IsPlayerToTheRight())
                {
                    velX *= -1;
                    golem.IsFacingRight = true;
                }
                golem.SetVelX(velX);
                entity.AddAnimationToQueue("walk");
            }
            else
            {
                entity.RemoveAnimationFromQueue("walk");
            }
            base.Update(entity);
        }
コード例 #29
0
        public void RayCastMissUp()
        {
            // Arrange
            var box     = new Box2(5, -5, 10, 6);
            var ray     = new CollisionRay(new Vector2(4.99999f, 1), Vector2.UnitY, 1);
            var manager = new PhysicsManager();

            var mock = new Mock <IPhysBody>();

            mock.Setup(foo => foo.WorldAABB).Returns(box);
            mock.Setup(foo => foo.Entity).Returns(new Entity()); // requires IPhysBody not have null owner
            mock.Setup(foo => foo.CanCollide).Returns(true);
            mock.Setup(foo => foo.CollisionLayer).Returns(1);
            mock.Setup(foo => foo.CollisionMask).Returns(1);
            manager.AddBody(mock.Object);

            // Act
            var results = manager.IntersectRay(new MapId(0), ray);

            // Assert
            Assert.That(results.Count(), Is.EqualTo(0));
        }
コード例 #30
0
        /// <summary>
        ///     Traces a ray from coords to otherCoords and returns the length
        ///     of the vector between coords and the ray's first hit.
        /// </summary>
        /// <param name="origin">Set of coordinates to use.</param>
        /// <param name="other">Other set of coordinates to use.</param>
        /// <param name="collisionMask">the mask to check for collisions</param>
        /// <param name="predicate">
        ///     A predicate to check whether to ignore an entity or not.
        ///     If it returns true, it will be ignored.
        /// </param>
        /// <returns>Length of resulting ray.</returns>
        public float UnobstructedDistance(
            MapCoordinates origin,
            MapCoordinates other,
            int collisionMask = (int)CollisionGroup.Impassable,
            Ignored?predicate = null)
        {
            var dir = other.Position - origin.Position;

            if (dir.LengthSquared.Equals(0f))
            {
                return(0f);
            }

            predicate ??= _ => false;
            var ray        = new CollisionRay(origin.Position, dir.Normalized, collisionMask);
            var rayResults = _sharedBroadphaseSystem.IntersectRayWithPredicate(origin.MapId, ray, dir.Length, predicate.Invoke, false).ToList();

            if (rayResults.Count == 0)
            {
                return(dir.Length);
            }
            return((rayResults[0].HitPos - origin.Position).Length);
        }