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; }
/// <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); }
/// <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)); }
private HashSet <IEntity> ArcRayCast(Vector2 position, Angle angle, IEntity ignore) { var widthRad = Angle.FromDegrees(ArcWidth); var increments = 1 + 35 * (int)Math.Ceiling(widthRad / (2 * Math.PI)); var increment = widthRad / increments; var baseAngle = angle - widthRad / 2; var resSet = new HashSet <IEntity>(); var mapId = Owner.Transform.MapID; for (var i = 0; i < increments; i++) { var castAngle = new Angle(baseAngle + increment * i); var res = _physicsManager.IntersectRay(mapId, new CollisionRay(position, castAngle.ToVec(), (int)(CollisionGroup.Impassable | CollisionGroup.MobImpassable)), Range, ignore).FirstOrDefault(); if (res.HitEntity != null) { resSet.Add(res.HitEntity); } } return(resSet); }
private IEntity FindBestTarget() { // "best" target is the closest one with LOS var ents = _entMan.GetEntitiesInRange(SelfEntity, VisionRadius); var myTransform = SelfEntity.GetComponent <ITransformComponent>(); var maxRayLen = VisionRadius * 2.5f; // circle inscribed in square, square diagonal = 2*r*sqrt(2) _workList.Clear(); foreach (var entity in ents) { // filter to "people" entities (entities with controllers) if (!entity.HasComponent <IMoverComponent>()) { continue; } // build the ray var dir = entity.GetComponent <ITransformComponent>().WorldPosition - myTransform.WorldPosition; var ray = new Ray(myTransform.WorldPosition, dir.Normalized, (int)(CollisionGroup.MobImpassable | CollisionGroup.Impassable)); // cast the ray var result = _physMan.IntersectRay(myTransform.MapID, ray, maxRayLen, SelfEntity); // add to visible list if (result.HitEntity == entity) { _workList.Add(entity); } } // get closest entity in list var closestEnt = GetClosest(myTransform.WorldPosition, _workList); // return closest return(closestEnt); }