public static IntRect Round(this FloatRect rect) { var top = (int)Math.Round(rect.Top); var left = (int)Math.Round(rect.Left); var right = (int)Math.Round(rect.Right()); var bottom = (int)Math.Round(rect.Bottom()); return(new IntRect(left, top, right - left, bottom - top)); }
/// <summary> /// returns true if collider intersects a collidable under management. Does not trigger Bump. /// </summary> /// <param name="collider">Rectangle to check for collision</param> /// <returns></returns> public bool IsColliding(FloatRect collider) { Vector2f[] points = { new Vector2f(collider.Left, collider.Top), new Vector2f(collider.Right(), collider.Top), new Vector2f(collider.Right(), collider.Bottom()), new Vector2f(collider.Left, collider.Bottom()) }; //Get the buckets that correspond to the collider's points. List <CollidableBucket> buckets = points.Select(GetBucket).Distinct().ToList(); //Get all of the points var cpoints = new List <CollidablePoint>(); foreach (CollidableBucket bucket in buckets) { cpoints.AddRange(bucket.GetPoints()); } //Expand points to distinct AABBs List <CollidableAABB> aabBs = (cpoints.Select(cp => cp.ParentAABB)).Distinct().ToList(); //try all of the AABBs against the target rect. bool collided = false; foreach (CollidableAABB aabb in aabBs.Where(aabb => aabb.Collidable.AABB.Intersects(collider))) { if (aabb.IsHardCollider) //If the collider is supposed to prevent movement { collided = true; } } return(collided || IoCManager.Resolve <IMapManager>().GetTilesIntersecting(collider, true).Any(t => t.Tile.TileDef.IsCollidable)); }
// If `ignoreSpace` is false, this will return tiles in chunks that don't even exist. // This is to make the tile count predictable. Is this appropriate behavior? public IEnumerable <TileRef> GetTilesIntersecting(FloatRect area, bool ignoreSpace) { int chunkLeft = (int)Math.Floor(area.Left / ChunkSize); int chunkTop = (int)Math.Floor(area.Top / ChunkSize); int chunkRight = (int)Math.Floor(area.Right() / ChunkSize); int chunkBottom = (int)Math.Floor(area.Bottom() / ChunkSize); for (int chunkY = chunkTop; chunkY <= chunkBottom; ++chunkY) { for (int chunkX = chunkLeft; chunkX <= chunkRight; ++chunkX) { int xMin = 0; int yMin = 0; int xMax = 15; int yMax = 15; if (chunkX == chunkLeft) { xMin = Mod(Math.Floor(area.Left), ChunkSize); } if (chunkY == chunkTop) { yMin = Mod(Math.Floor(area.Top), ChunkSize); } if (chunkX == chunkRight) { xMax = Mod(Math.Floor(area.Right()), ChunkSize); } if (chunkY == chunkBottom) { yMax = Mod(Math.Floor(area.Bottom()), ChunkSize); } Chunk chunk; if (!chunks.TryGetValue(new Vector2i(chunkX, chunkY), out chunk)) { if (ignoreSpace) { continue; } else { for (int y = yMin; y <= yMax; ++y) { for (int x = xMin; x <= xMax; ++x) { yield return(new TileRef(this, chunkX * ChunkSize + x, chunkY * ChunkSize + y)); } } } } else { for (int y = yMin; y <= yMax; ++y) { int i = y * ChunkSize + xMin; for (int x = xMin; x <= xMax; ++x, ++i) { if (!ignoreSpace || chunk.Tiles[i].TileId != 0) { yield return(new TileRef(this, chunkX * ChunkSize + x, chunkY * ChunkSize + y, chunk, i)); } } } } } } }
public static bool Encloses(this FloatRect outer, FloatRect inner) => (outer.Left <= inner.Left) && (inner.Right() <= outer.Right()) && (outer.Top <= inner.Top) && (inner.Bottom() <= outer.Bottom());
public override bool Update(Vector2i mouseS, IMapManager currentMap) { if (currentMap == null) return false; spriteToDraw = GetDirectionalSprite(pManager.CurrentBaseSpriteKey); var spriteBounds = spriteToDraw.GetLocalBounds(); mouseScreen = mouseS; mouseWorld = CluwneLib.ScreenToWorld(mouseScreen); var spriteSize = CluwneLib.PixelToTile(new Vector2f(spriteBounds.Width, spriteBounds.Height)); // TODO: Doublecheck this. Use SizeF? var spriteRectWorld = new FloatRect(mouseWorld.X - (spriteSize.X / 2f), mouseWorld.Y - (spriteSize.Y / 2f), spriteSize.X, spriteSize.Y); if (pManager.CurrentPermission.IsTile) return false; currentTile = currentMap.GetTileRef(mouseWorld); //Align to similar if nearby found else free if (currentTile.Tile.TileDef.IsWall) return false; //HANDLE CURSOR OUTSIDE MAP var rangeSquared = pManager.CurrentPermission.Range * pManager.CurrentPermission.Range; if (rangeSquared > 0) if ( (pManager.PlayerManager.ControlledEntity.GetComponent<TransformComponent>(ComponentFamily.Transform) .Position - mouseWorld).LengthSquared() > rangeSquared) return false; Entity[] nearbyEntities = ((EntityManager) IoCManager.Resolve<IEntityManagerContainer>().EntityManager).GetEntitiesInRange( mouseWorld, snapToRange); IOrderedEnumerable<Entity> snapToEntities = from Entity entity in nearbyEntities where entity.Template == pManager.CurrentTemplate orderby (entity.GetComponent<TransformComponent>( ComponentFamily.Transform).Position - mouseWorld).LengthSquared() ascending select entity; if (snapToEntities.Any()) { Entity closestEntity = snapToEntities.First(); ComponentReplyMessage reply = closestEntity.SendMessage(this, ComponentFamily.Renderable, ComponentMessageType.GetSprite); //if(replies.Any(x => x.messageType == SS13_Shared.GO.ComponentMessageType.CurrentSprite)) //{ // Sprite closestSprite = (Sprite)replies.Find(x => x.messageType == SS13_Shared.GO.ComponentMessageType.CurrentSprite).paramsList[0]; //This is safer but slower. if (reply.MessageType == ComponentMessageType.CurrentSprite) { var closestSprite = (Sprite) reply.ParamsList[0]; //This is faster but kinda unsafe. var closestBounds = closestSprite.GetLocalBounds(); var closestRect = new FloatRect( closestEntity.GetComponent<TransformComponent>(ComponentFamily.Transform).Position.X - closestBounds.Width / 2f, closestEntity.GetComponent<TransformComponent>(ComponentFamily.Transform).Position.Y - closestBounds.Height / 2f, closestBounds.Width, closestBounds.Height); var sides = new List<Vector2f> { new Vector2f(closestRect.Left + (closestRect.Width / 2f), closestRect.Top - closestBounds.Height / 2f), new Vector2f(closestRect.Left + (closestRect.Width / 2f), closestRect.Bottom() + closestBounds.Height / 2f), new Vector2f(closestRect.Left - closestBounds.Width / 2f, closestRect.Top + (closestRect.Height / 2f)), new Vector2f(closestRect.Right() + closestBounds.Width / 2f, closestRect.Top + (closestRect.Height / 2f)) }; Vector2f closestSide = (from Vector2f side in sides orderby (side - mouseWorld).LengthSquared() ascending select side).First(); mouseWorld = closestSide; mouseScreen = CluwneLib.WorldToScreen(mouseWorld).Round(); } } spriteRectWorld = new FloatRect(mouseWorld.X - (spriteBounds.Width/2f), mouseWorld.Y - (spriteBounds.Height/2f), spriteBounds.Width, spriteBounds.Height); if (pManager.CollisionManager.IsColliding(spriteRectWorld)) return false; return true; }
public override bool Update(Vector2i mouseS, IMapManager currentMap) { if (currentMap == null) { return(false); } spriteToDraw = GetDirectionalSprite(pManager.CurrentBaseSpriteKey); var spriteBounds = spriteToDraw.GetLocalBounds(); mouseScreen = mouseS; mouseWorld = CluwneLib.ScreenToWorld(mouseScreen); if (pManager.CurrentPermission.IsTile) { return(false); } currentTile = currentMap.GetTileRef(mouseWorld); //Align to similar if nearby found else free if (currentTile.Tile.TileDef.IsWall) { return(false); //HANDLE CURSOR OUTSIDE MAP } var rangeSquared = pManager.CurrentPermission.Range * pManager.CurrentPermission.Range; if (rangeSquared > 0) { if ( (pManager.PlayerManager.ControlledEntity.GetComponent <TransformComponent>(ComponentFamily.Transform) .Position - mouseWorld).LengthSquared() > rangeSquared) { return(false); } } var manager = IoCManager.Resolve <IClientEntityManager>(); IOrderedEnumerable <IEntity> snapToEntities = from IEntity entity in manager.GetEntitiesInRange(mouseWorld, snapToRange) where entity.Prototype == pManager.CurrentPrototype orderby (entity.GetComponent <TransformComponent>( ComponentFamily.Transform).Position - mouseWorld).LengthSquared() ascending select entity; if (snapToEntities.Any()) { IEntity closestEntity = snapToEntities.First(); ComponentReplyMessage reply = closestEntity.SendMessage(this, ComponentFamily.Renderable, ComponentMessageType.GetSprite); //if(replies.Any(x => x.messageType == SS13_Shared.GO.ComponentMessageType.CurrentSprite)) //{ // Sprite closestSprite = (Sprite)replies.Find(x => x.messageType == SS13_Shared.GO.ComponentMessageType.CurrentSprite).paramsList[0]; //This is safer but slower. if (reply.MessageType == ComponentMessageType.CurrentSprite) { var closestSprite = (Sprite)reply.ParamsList[0]; //This is faster but kinda unsafe. var closestBounds = closestSprite.GetLocalBounds(); var closestRect = new FloatRect( closestEntity.GetComponent <TransformComponent>(ComponentFamily.Transform).Position.X - closestBounds.Width / 2f, closestEntity.GetComponent <TransformComponent>(ComponentFamily.Transform).Position.Y - closestBounds.Height / 2f, closestBounds.Width, closestBounds.Height); var sides = new List <Vector2f> { new Vector2f(closestRect.Left + (closestRect.Width / 2f), closestRect.Top - closestBounds.Height / 2f), new Vector2f(closestRect.Left + (closestRect.Width / 2f), closestRect.Bottom() + closestBounds.Height / 2f), new Vector2f(closestRect.Left - closestBounds.Width / 2f, closestRect.Top + (closestRect.Height / 2f)), new Vector2f(closestRect.Right() + closestBounds.Width / 2f, closestRect.Top + (closestRect.Height / 2f)) }; Vector2f closestSide = (from Vector2f side in sides orderby(side - mouseWorld).LengthSquared() ascending select side).First(); mouseWorld = closestSide; mouseScreen = CluwneLib.WorldToScreen(mouseWorld).Round(); } } FloatRect spriteRectWorld = new FloatRect(mouseWorld.X - (spriteBounds.Width / 2f), mouseWorld.Y - (spriteBounds.Height / 2f), spriteBounds.Width, spriteBounds.Height); if (pManager.CollisionManager.IsColliding(spriteRectWorld)) { return(false); } return(true); }
/// <summary> /// Converts a SFML FloatRect to a OpenTK Box2. /// </summary> /// <param name="rect">SFML FloatRect.</param> /// <returns>OpenTK Box2.</returns> public static Box2 Convert(this FloatRect rect) { return(new Box2(rect.Left, rect.Top, rect.Right(), rect.Bottom())); }
/// <summary> /// Returns the positions of the BottomRight corner of the given FloatRect /// </summary> public static Vector2f BottomRight(this FloatRect rect) { return(new Vector2f(rect.Right(), rect.Bottom())); }
/// <summary> /// Returns the positions of the BottomLeft corner of the given FloatRect /// </summary> public static Vector2f BottomLeft(this FloatRect rect) { return(new Vector2f(rect.Left, rect.Bottom())); }
/// <summary> /// Render the renderables /// </summary> /// <param name="frametime">time since the last frame was rendered.</param> private void RenderComponents(float frameTime, FloatRect viewPort) { IEnumerable<Component> components = _entityManager.ComponentManager.GetComponents(ComponentFamily.Renderable) .Union(_entityManager.ComponentManager.GetComponents(ComponentFamily.Particles)); IEnumerable<IRenderableComponent> floorRenderables = from IRenderableComponent c in components orderby c.Bottom ascending, c.DrawDepth ascending where c.DrawDepth < DrawDepth.MobBase select c; RenderList(new Vector2f(viewPort.Left, viewPort.Top), new Vector2f(viewPort.Right(), viewPort.Bottom()), floorRenderables); IEnumerable<IRenderableComponent> largeRenderables = from IRenderableComponent c in components orderby c.Bottom ascending where c.DrawDepth >= DrawDepth.MobBase && c.DrawDepth < DrawDepth.WallTops select c; RenderList(new Vector2f(viewPort.Left, viewPort.Top), new Vector2f(viewPort.Right(), viewPort.Bottom()), largeRenderables); IEnumerable<IRenderableComponent> ceilingRenderables = from IRenderableComponent c in components orderby c.Bottom ascending, c.DrawDepth ascending where c.DrawDepth >= DrawDepth.WallTops select c; RenderList(new Vector2f(viewPort.Left, viewPort.Top), new Vector2f(viewPort.Right(), viewPort.Bottom()), ceilingRenderables); }
// If `ignoreSpace` is false, this will return tiles in chunks that don't even exist. // This is to make the tile count predictable. Is this appropriate behavior? public IEnumerable<TileRef> GetTilesIntersecting(FloatRect area, bool ignoreSpace) { int chunkLeft = (int)Math.Floor(area.Left / ChunkSize); int chunkTop = (int)Math.Floor(area.Top / ChunkSize); int chunkRight = (int)Math.Floor(area.Right() / ChunkSize); int chunkBottom = (int)Math.Floor(area.Bottom() / ChunkSize); for (int chunkY = chunkTop; chunkY <= chunkBottom; ++chunkY) { for (int chunkX = chunkLeft; chunkX <= chunkRight; ++chunkX) { int xMin = 0; int yMin = 0; int xMax = 15; int yMax = 15; if (chunkX == chunkLeft) xMin = Mod(Math.Floor(area.Left), ChunkSize); if (chunkY == chunkTop) yMin = Mod(Math.Floor(area.Top), ChunkSize); if (chunkX == chunkRight) xMax = Mod(Math.Floor(area.Right()), ChunkSize); if (chunkY == chunkBottom) yMax = Mod(Math.Floor(area.Bottom()), ChunkSize); Chunk chunk; if (!chunks.TryGetValue(new Vector2i(chunkX, chunkY), out chunk)) { if (ignoreSpace) continue; else for (int y = yMin; y <= yMax; ++y) for (int x = xMin; x <= xMax; ++x) yield return new TileRef(this, chunkX * ChunkSize + x, chunkY * ChunkSize + y); } else { for (int y = yMin; y <= yMax; ++y) { int i = y * ChunkSize + xMin; for (int x = xMin; x <= xMax; ++x, ++i) { if (!ignoreSpace || chunk.Tiles[i].TileId != 0) yield return new TileRef(this, chunkX * ChunkSize + x, chunkY * ChunkSize + y, chunk, i); } } } } } }
/// <summary> /// returns true if collider intersects a collidable under management. Does not trigger Bump. /// </summary> /// <param name="collider">Rectangle to check for collision</param> /// <returns></returns> public bool IsColliding(FloatRect collider) { Vector2f[] points = { new Vector2f(collider.Left, collider.Top), new Vector2f(collider.Right(), collider.Top), new Vector2f(collider.Right(), collider.Bottom()), new Vector2f(collider.Left, collider.Bottom()) }; //Get the buckets that correspond to the collider's points. List<CollidableBucket> buckets = points.Select(GetBucket).Distinct().ToList(); //Get all of the points var cpoints = new List<CollidablePoint>(); foreach (CollidableBucket bucket in buckets) { cpoints.AddRange(bucket.GetPoints()); } //Expand points to distinct AABBs List<CollidableAABB> aabBs = (cpoints.Select(cp => cp.ParentAABB)).Distinct().ToList(); //try all of the AABBs against the target rect. bool collided = false; foreach (CollidableAABB aabb in aabBs.Where(aabb => aabb.Collidable.AABB.Intersects(collider))) { if (aabb.IsHardCollider) //If the collider is supposed to prevent movement { collided = true; } } return collided || IoCManager.Resolve<IMapManager>().GetTilesIntersecting(collider, true).Any(t => t.Tile.TileDef.IsCollidable); }
/// <summary> /// Converts a SFML FloatRect to a SS14 Box2. /// </summary> public static Shared.Maths.Box2 ToBox(this FloatRect rect) { return(new Shared.Maths.Box2(rect.Left, rect.Top, rect.Right(), rect.Bottom())); }