2019-09-18 15:54:20 +02:00
|
|
|
using System;
|
|
|
|
using System.Collections.Generic;
|
|
|
|
using System.Collections.ObjectModel;
|
|
|
|
using System.Linq;
|
|
|
|
using Microsoft.Xna.Framework;
|
|
|
|
using MLEM.Extensions;
|
2020-03-21 00:49:43 +01:00
|
|
|
using MLEM.Misc;
|
2019-09-18 15:54:20 +02:00
|
|
|
using MonoGame.Extended.Tiled;
|
2020-03-21 00:49:43 +01:00
|
|
|
using RectangleF = MonoGame.Extended.RectangleF;
|
2019-09-18 15:54:20 +02:00
|
|
|
|
|
|
|
namespace MLEM.Extended.Tiled {
|
|
|
|
public class TiledMapCollisions {
|
|
|
|
|
|
|
|
private TiledMap map;
|
|
|
|
private TileCollisionInfo[,,] collisionInfos;
|
2020-01-01 12:41:48 +01:00
|
|
|
private CollectCollisions collisionFunction;
|
2019-09-18 15:54:20 +02:00
|
|
|
|
|
|
|
public TiledMapCollisions(TiledMap map = null) {
|
|
|
|
if (map != null)
|
|
|
|
this.SetMap(map);
|
|
|
|
}
|
|
|
|
|
2020-01-01 12:41:48 +01:00
|
|
|
public void SetMap(TiledMap map, CollectCollisions collisionFunction = null) {
|
2019-09-18 15:54:20 +02:00
|
|
|
this.map = map;
|
2020-01-01 12:41:48 +01:00
|
|
|
this.collisionFunction = collisionFunction ?? ((collisions, tile) => {
|
|
|
|
foreach (var obj in tile.TilesetTile.Objects) {
|
|
|
|
var area = obj.GetArea(tile.Map);
|
|
|
|
if (tile.Tile.IsFlippedHorizontally)
|
|
|
|
area.X = 1 - area.X - area.Width;
|
|
|
|
if (tile.Tile.IsFlippedVertically)
|
|
|
|
area.Y = 1 - area.Y - area.Height;
|
|
|
|
area.Offset(tile.Position);
|
|
|
|
collisions.Add(area);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2019-09-18 15:54:20 +02:00
|
|
|
this.collisionInfos = new TileCollisionInfo[map.Layers.Count, map.Width, map.Height];
|
|
|
|
for (var i = 0; i < map.TileLayers.Count; i++) {
|
|
|
|
for (var x = 0; x < map.Width; x++) {
|
|
|
|
for (var y = 0; y < map.Height; y++) {
|
2019-09-19 11:11:47 +02:00
|
|
|
this.UpdateCollisionInfo(i, x, y);
|
2019-09-18 15:54:20 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-19 11:11:47 +02:00
|
|
|
public void UpdateCollisionInfo(int layerIndex, int x, int y) {
|
|
|
|
var layer = this.map.TileLayers[layerIndex];
|
2019-09-24 12:26:38 +02:00
|
|
|
var tile = layer.GetTile(x, y);
|
2019-12-07 02:08:21 +01:00
|
|
|
if (tile.IsBlank) {
|
|
|
|
this.collisionInfos[layerIndex, x, y] = null;
|
2019-09-19 11:11:47 +02:00
|
|
|
return;
|
2019-12-07 02:08:21 +01:00
|
|
|
}
|
2019-09-19 11:11:47 +02:00
|
|
|
var tilesetTile = tile.GetTilesetTile(this.map);
|
2020-01-01 12:41:48 +01:00
|
|
|
this.collisionInfos[layerIndex, x, y] = new TileCollisionInfo(this.map, new Vector2(x, y), tile, layer, tilesetTile, this.collisionFunction);
|
2019-09-19 11:11:47 +02:00
|
|
|
}
|
|
|
|
|
2019-09-18 15:54:20 +02:00
|
|
|
public IEnumerable<TileCollisionInfo> GetCollidingTiles(RectangleF area, Func<TileCollisionInfo, bool> included = null) {
|
|
|
|
var inclusionFunc = included ?? (tile => tile.Collisions.Any(c => c.Intersects(area)));
|
2019-09-25 21:06:56 +02:00
|
|
|
var minX = Math.Max(0, area.Left.Floor());
|
|
|
|
var maxX = Math.Min(this.map.Width - 1, area.Right);
|
|
|
|
var minY = Math.Max(0, area.Top.Floor());
|
|
|
|
var maxY = Math.Min(this.map.Height - 1, area.Bottom);
|
2019-09-18 15:54:20 +02:00
|
|
|
for (var i = 0; i < this.map.TileLayers.Count; i++) {
|
2019-09-25 21:06:56 +02:00
|
|
|
for (var x = minX; x <= maxX; x++) {
|
|
|
|
for (var y = minY; y <= maxY; y++) {
|
2019-09-18 15:54:20 +02:00
|
|
|
var tile = this.collisionInfos[i, x, y];
|
|
|
|
if (tile == null)
|
|
|
|
continue;
|
|
|
|
if (inclusionFunc(tile))
|
|
|
|
yield return tile;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public bool IsColliding(RectangleF area, Func<TileCollisionInfo, bool> included = null) {
|
|
|
|
return this.GetCollidingTiles(area, included).Any();
|
|
|
|
}
|
|
|
|
|
2020-01-01 12:41:48 +01:00
|
|
|
public delegate void CollectCollisions(List<RectangleF> collisions, TileCollisionInfo tile);
|
|
|
|
|
2020-03-21 00:49:43 +01:00
|
|
|
public class TileCollisionInfo : GenericDataHolder {
|
2019-09-18 15:54:20 +02:00
|
|
|
|
2020-01-01 12:41:48 +01:00
|
|
|
public readonly TiledMap Map;
|
|
|
|
public readonly Vector2 Position;
|
2019-09-18 15:54:20 +02:00
|
|
|
public readonly TiledMapTile Tile;
|
2019-12-30 19:19:40 +01:00
|
|
|
public readonly TiledMapTileLayer Layer;
|
2019-09-18 15:54:20 +02:00
|
|
|
public readonly TiledMapTilesetTile TilesetTile;
|
2020-01-01 12:41:48 +01:00
|
|
|
public readonly List<RectangleF> Collisions;
|
2019-09-18 15:54:20 +02:00
|
|
|
|
2020-01-01 12:41:48 +01:00
|
|
|
public TileCollisionInfo(TiledMap map, Vector2 position, TiledMapTile tile, TiledMapTileLayer layer, TiledMapTilesetTile tilesetTile, CollectCollisions collisionFunction) {
|
2019-09-18 15:54:20 +02:00
|
|
|
this.TilesetTile = tilesetTile;
|
2019-12-30 19:19:40 +01:00
|
|
|
this.Layer = layer;
|
2019-09-18 15:54:20 +02:00
|
|
|
this.Tile = tile;
|
2020-01-01 12:41:48 +01:00
|
|
|
this.Map = map;
|
|
|
|
this.Position = position;
|
2019-09-18 15:54:20 +02:00
|
|
|
|
2020-01-01 12:41:48 +01:00
|
|
|
this.Collisions = new List<RectangleF>();
|
|
|
|
collisionFunction(this.Collisions, this);
|
2019-09-18 15:54:20 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|