/// <summary> /// <para>List of rectangles we collide with.</para> /// <para>This function checks a specified area for collidable tiles to detect the exact position of the obstacle, /// because the gridcollider does not provide such information, and then calls <c>ExtendCollisionTile</c> to detect /// the complete obstacle (as opposed to only the tile we collide with)</para> /// </summary> /// <param name="collider">Collider to use</param> /// <param name="collidingEntity">Entity colliding with the Grid, for example a Tank</param> /// <param name="leftStart">left tile to start check at</param> /// <param name="topStart">top tile to start check at</param> /// <param name="checkWidth">how many tiles to check in x</param> /// <param name="checkHeight">how many tiles to check in y</param> /// <returns>List of rectangles we collide with</returns> public static List <Rectangle> GetCollidingRectangles(GridCollider collider, Entity collidingEntity, int leftStart, int topStart, int checkWidth = 3, int checkHeight = 3) { //create the test entity if it does not exist yet if (_testingEntity == null) { _testingEntity = new Entity(0, 0, null, new BoxCollider(0, 0, CollidableTags.Tester)); } //create list for collisions List <Rectangle> collisionList = new List <Rectangle>(); //check each tile underneath the tank for collision for (int x = leftStart; x < checkWidth + leftStart; x++) { for (int y = topStart; y < checkHeight + topStart; y++) { //if we found a tile that actually collides, save it to the list if (collider.GetTile(x, y)) { _testingEntity.Collider.SetPosition(x * collider.TileWidth, y * collider.TileHeight); _testingEntity.Collider.Width = collider.TileWidth; _testingEntity.Collider.Height = collider.TileHeight; if (collidingEntity.Collider.Collide(collidingEntity.X, collidingEntity.Y, _testingEntity) != null) { collisionList.Add(ExtendCollisionTile(collider, x, y)); } } } } //return return(collisionList); }
/// <summary> /// This code tries to extend the collision tile to the largest possible rectangle (eg find the complete obstacle), /// so that following algorithm parts /// can work with these rectangles to easily decide whether to move the offending entity on the x or the y axis. /// </summary> /// <param name="collider">The collider to work with, probably the grid collision collider.</param> /// <param name="startX">int x position of the tile in the grid (!= pixel position)</param> /// <param name="startY">int y position of the tile in the grid (!= pixel position)</param> /// <returns></returns> public static Rectangle ExtendCollisionTile(GridCollider collider, int startX, int startY) { //copy the positions into variables that will be changed to calculate the resulting rectangle int left = startX, right = startX + 1, top = startY, bottom = startY + 1; //go as far in all directions as the tile is collidable while (collider.GetTile(left - 1, startY) && left > 1) { left--; } while (collider.GetTile(right, startY) && right < collider.TileColumns) { right++; } while (collider.GetTile(startX, top - 1) && top > 1) { top--; } while (collider.GetTile(startX, bottom) && bottom < collider.TileRows) { bottom++; } //create the rectangle the tank collides with return(new Rectangle(left * collider.TileWidth, top * collider.TileHeight, (right - left) * collider.TileWidth, (bottom - top) * collider.TileHeight)); }
private void Cleanup() { if (movementState == MovementState.Stopped) { gridColliderUnderSlidable = null; slidable = null; } }
public void MakeTiles(XmlDocument doc) { XmlNode graphicsData = doc.SelectSingleNode("map/layer[@name='Graphics']/data"); XmlNode gridData = doc.SelectSingleNode("map/layer[@name='Grid']/data"); var tileset = AddGraphic(new Tilemap(Global.imagePath + "Rooms/tiles.png", 640, 32)); grid = AddCollider(new GridCollider(Global.screenWidth, Global.screenHeight, 32, 32, Global.Tags.Wall)); grid.LoadCSV(gridData.InnerXml.Replace("\r", ""), "0", "66"); tileset.LoadCSV(graphicsData.InnerXml.Replace("\r", ""), ',', '\n', "", 1); }
/// <summary> /// Load tiles in from a GridCollider. /// </summary> /// <param name="grid">The GridCollider to reference.</param> /// <param name="color">The color to set tiles that are collidable on the grid.</param> /// <param name="layer">The layer to place the tiles on.</param> public void LoadGrid(GridCollider grid, Color color, string layer = "") { for (var i = 0; i < grid.TileColumns; i++) { for (var j = 0; j < grid.TileRows; j++) { if (grid.GetTile(i, j)) { SetTile(i, j, color, layer); } } } }
protected override void OnAdded() { base.OnAdded(); var triggerGrid = new GridCollider(Data.WidthTiles, Data.HeightTiles, Global.TileSize, Global.TileSize, "tileset"); Data.IterateTiles((tile) => { if (tile.Trigger != null) { if (tile.SolidType == TileSolidType.PixelMask) { triggerGrid.SetPixelMaskAt(tile.X, tile.Y, tile.DisplayTid, tile.Properties); } else { triggerGrid.SetTileAt(tile.X, tile.Y, tile.SolidType, tile.Properties); } } }); var triggerEntity = new Entity(); triggerEntity.Type = Global.TypeTrigger; triggerEntity.Collider = triggerGrid; Scene.Add(triggerEntity); Data.IterateObjects((obj) => Scene.Add(new Object(obj))); Log.Debug("Loading groups..."); Data.IterateEntities((args) => { var entity = GameEntity.Create(args); if (args.GroupId != -1) { EntityGroup group; if (!groups.TryGetValue(args.GroupId, out group)) { group = new EntityGroup(args.GroupId, Data.GetGroupReward(args.GroupId)); groups[args.GroupId] = group; Log.Debug("Created group " + args.GroupId); } group.Add(entity); entity.Group = group; } Scene.Add(entity); }); }
public override void Added() { base.Added(); // Create the grid collider based off of the scene's dimensions. GridCollider = new GridCollider(Scene.Width, Scene.Height, GridSize, GridSize); // Create the tilemap based off of the scene's dimensions. Tilemap = new Tilemap("tiles.png", Scene.Width, Scene.Height, GridSize, GridSize); // Add the tilemap graphic. AddGraphic(Tilemap); // Add the grid collider. AddCollider(GridCollider); }
private void UpdateMoveState() { //We check if we have more than one touch happening. //We also check if the first touches phase is Ended (that the finger was lifted) if (inputHandler.IsInputDown()) { //We transform the touch position into word space from screen space and store it. Vector3 touchPosWorld = Camera.main.ScreenToWorldPoint(inputHandler.GetInputScreenPosition()); RaycastHit slidableHit; // Does the ray intersect with any grid colliders? // Bit shift the index of the layer to get a bit mask int slidableLayerMask = 1 << Constants.SLIDABLE_LAYER; Physics.Raycast(touchPosWorld, raycastDirection, out slidableHit, float.MaxValue, slidableLayerMask); if (slidableHit.collider != null) { Slidable touchedSlidable = slidableHit.collider.GetComponent <Slidable>(); // Early exit if THIS grid movement controller is not relevant. if (!touchedSlidable.BelongsTo(grid)) { return; } slidable = touchedSlidable; movementState = MovementState.Moving; } if (slidable != null) { // check if we should update our tracked grid collider int gridColliderLayerMask = 1 << Constants.GRID_COLLIDER_LAYER; RaycastHit gridColliderHit; Physics.Raycast(slidable.transform.position, raycastDirection, out gridColliderHit, float.MaxValue, gridColliderLayerMask); if (gridColliderHit.collider != null) { gridColliderUnderSlidable = gridColliderHit.collider.GetComponent <GridCollider>(); } } } if (inputHandler.HasInputEnded()) { movementState = MovementState.Stopped; Debug.Log("input ended"); } }
private void InitGrid() { grid = new GridCell[rows][]; for (int r = 0; r < rows; r++) { grid[r] = new GridCell[columns]; for (int c = 0; c < columns; c++) { Vector3 gridColliderPos = GetGridColliderWorldPos(r, c); GridCollider gridCollider = Instantiate(gridColliderPrefab, gridColliderPos, Quaternion.identity).GetComponent <GridCollider>(); gridCollider.transform.parent = gameObject.transform; gridCollider.SetPosition(r, c); // Raycast to hit GridObject GridObject gridObject = GetGridObject(gridColliderPos); grid[r][c] = new GridCell(gridCollider, gridObject); } } }
// Our new constructor takes in the new J,I coordinates, and a Player object public GameScene(int nextJ = 0, int nextI = 0, Player player = null, HaguruClock clock = null) : base() { screenJ = nextJ; screenI = nextI; // If a Player object isn't passed in, start at the default x,y position of 100,100 if (player == null) { Global.player = new Player(100, 100); } else { Global.player = player; } //if no Clock is passed in start a new clock at the default pos if (clock == null) { Global.clock = new HaguruClock(); } else { Global.clock = clock; } // Create and load our Tilemap and GridCollider tilemap = new Tilemap(Assets.TILESET, WIDTH, HEIGHT, Global.GRID_WIDTH, Global.GRID_HEIGHT); grid = new GridCollider(WIDTH, HEIGHT, Global.GRID_WIDTH, Global.GRID_HEIGHT); string mapToLoad = Assets.MAP_WORLD; string solidsToLoad = Assets.MAP_SOLID; LoadWorld(mapToLoad, solidsToLoad); // Since we are constantly switching Scenes we need to do some checking, // ensuring that the music doesn't get restarted. // We should probably add an isPlaying boolean to the Music class. I will do this soon. if (Global.gameMusic == null) { Global.gameMusic = new Music(Assets.MUSIC_GAME); Global.gameMusic.Play(); Global.gameMusic.Volume = 0.40f; } }
public PixelMaskTest() { player = new Entity(80, 80); player.Collider = new PixelMask("gfx/mask2"); player.OriginX = player.Width / 2; player.OriginY = player.Height / 2; var playerSprite = new Sprite("gfx/mask2"); playerSprite.CenterOrigin(); player.Add(playerSprite); Add(player); var entity1 = new Entity(40, 30); entity1.Type = TypeSolid; entity1.Collider = new PixelMask("gfx/mask1"); entity1.Add(new Sprite("gfx/mask1")); Add(entity1); var tileset = new Tileset("gfx/mask_tiles", 16, 16); var tilemap = new Tilemap(tileset, 5, 5); var gridCollider = new GridCollider(8, 8, 16, 16, new PixelMaskSet(tileset)); SetTile(tilemap, gridCollider, 0, 0, 0); SetTile(tilemap, gridCollider, 1, 0, 4); SetTile(tilemap, gridCollider, 2, 0, 1); SetTile(tilemap, gridCollider, 0, 1, 4); SetTile(tilemap, gridCollider, 1, 1, 4); SetTile(tilemap, gridCollider, 2, 1, 4); SetTile(tilemap, gridCollider, 0, 2, 2); SetTile(tilemap, gridCollider, 1, 2, 4); SetTile(tilemap, gridCollider, 2, 2, 3); var mapEntity = new Entity(100, 100); mapEntity.Type = TypeSolid; mapEntity.Add(tilemap); mapEntity.Collider = gridCollider; Add(mapEntity); }
public override void Update() { base.Update(); //returns true if we collide witht the grid at any position if (Tank.Collider.Overlap(Tank.X, Tank.Y, CollidableTags.Wall)) { //notify the tank Tank.WallCollision = true; //extract the wallCollider from the list of colliders with the tag wallcollider GridCollider wallGridCollider = (GridCollider)Tank.Collider.CollideList(Tank.X, Tank.Y, CollidableTags.Wall)[0]; //calculate colliding tiles check start position, eg the top-left-most tile the tank could hit int leftmostTile = wallGridCollider.GridX(Tank.Collider.Left); int topmostTile = wallGridCollider.GridY(Tank.Collider.Top); //get the collision rectangles List <Rectangle> collidingRectangles = CollisionUtilites.GetCollidingRectangles(wallGridCollider, Tank, leftmostTile, topmostTile); //filter out identical rectangles created when the tile checker found multiple colliding candidates collidingRectangles = collidingRectangles.Distinct().ToList(); //reset out of all rectangles foreach (Rectangle obstacle in collidingRectangles) { Vector2 projection = CollisionUtilites.ShortestProjection(Tank, obstacle); //something smells fishy: the projection is larger than a complete tile? f**k that. if (Math.Abs(projection.X) < wallGridCollider.TileWidth && Math.Abs(projection.Y) < wallGridCollider.TileHeight) { Tank.AddPosition(projection); } } } else { Tank.WallCollision = false; } }
/// <summary> /// Load level data from a string into a Scene. /// </summary> /// <param name="data">The level data to load.</param> /// <param name="scene">The Scene to load into.</param> public void LoadLevel(string data, Scene scene) { Entities.Clear(); CurrentLevel = data; var xmlDoc = new XmlDocument(); xmlDoc.LoadXml(data); var xmlLevel = xmlDoc["level"]; scene.Width = int.Parse(xmlDoc["level"].Attributes["width"].Value); scene.Height = int.Parse(xmlDoc["level"].Attributes["height"].Value); int i = 0; foreach (var layer in Layers.Values) { if (layer.Type == "GridLayerDefinition") { var Entity = new Entity(); var grid = new GridCollider(scene.Width, scene.Height, layer.GridWidth, layer.GridHeight); grid.LoadString(xmlLevel[layer.Name].InnerText); if (ColliderTags.ContainsKey(layer.Name)) { grid.AddTag(ColliderTags[layer.Name]); } if (DisplayGrids) { var tilemap = new Tilemap(scene.Width, scene.Height, layer.GridWidth, layer.GridHeight); tilemap.LoadString(xmlLevel[layer.Name].InnerText, layer.Color); Entity.AddGraphic(tilemap); } Entity.AddCollider(grid); scene.Add(Entity); Entities.Add(layer.Name, Entity); } if (layer.Type == "TileLayerDefinition") { var Entity = new Entity(); var xmlTiles = xmlLevel[layer.Name]; var tileset = xmlTiles.Attributes["tileset"].Value; var tilepath = ImagePath + TileMaps[tileset]; foreach (var kv in assetMappings) { var find = kv.Key; var replace = kv.Value; if (tilepath.EndsWith(find)) { tilepath = replace; break; } } var tilemap = new Tilemap(tilepath, scene.Width, scene.Height, layer.GridWidth, layer.GridHeight); var exportMode = xmlTiles.Attributes["exportMode"].Value; switch (exportMode) { case "CSV": tilemap.LoadCSV(xmlTiles.InnerText); break; case "XMLCoords": foreach (XmlElement t in xmlTiles) { tilemap.SetTile(t); } break; } tilemap.Update(); Entity.AddGraphic(tilemap); Entity.Layer = BaseTileDepth - i * TileDepthIncrement; i++; scene.Add(Entity); Entities.Add(layer.Name, Entity); } if (layer.Type == "EntityLayerDefinition") { var xmlEntities = xmlLevel[layer.Name]; if (xmlEntities != null) { foreach (XmlElement e in xmlEntities) { CreateEntity(e, scene); } } } } if (UseCameraBounds) { scene.CameraBounds = new Rectangle(0, 0, scene.Width, scene.Height); scene.UseCameraBounds = true; } }
public GridCell(GridCollider gridCollider, GridObject gridObject) { this.gridCollider = gridCollider; this.gridObject = gridObject; }
/// <summary> /// Load tiles in from a GridCollider. /// </summary> /// <param name="grid">The GridCollider to reference.</param> /// <param name="color">The color to set tiles that are collidable on the grid.</param> /// <param name="layer">The layer to place the tiles on.</param> public void LoadGrid(GridCollider grid, Color color, Enum layer) { LoadGrid(grid, color, Util.EnumValueToString(layer)); }
/// <summary> /// Load tiles in from a GridCollider and choose tiles based on the shape of the grid. /// </summary> /// <param name="grid">The GridCollider to reference.</param> /// <param name="layer">The layer to place the tiles on.</param> public void LoadGridAutoTile(GridCollider grid, string layer = "") { if (autoTileTable == null) { SetAutoTileData(autoTileDefaultData); } for (var i = 0; i < grid.TileColumns; i++) { for (var j = 0; j < grid.TileRows; j++) { if (grid.GetTile(i, j)) { int tileValue = 0; /* * auto tiling grid * * 128 001 016 * 008 ___ 002 * 064 004 032 * */ if (grid.GetTile(i - 1, j - 1)) { tileValue += 128; } if (grid.GetTile(i, j - 1)) { tileValue += 1; } if (grid.GetTile(i + 1, j - 1)) { tileValue += 16; } if (grid.GetTile(i + 1, j)) { tileValue += 2; } if (grid.GetTile(i + 1, j + 1)) { tileValue += 32; } if (grid.GetTile(i, j + 1)) { tileValue += 4; } if (grid.GetTile(i - 1, j + 1)) { tileValue += 64; } if (grid.GetTile(i - 1, j)) { tileValue += 8; } if (autoTileTable.ContainsKey(tileValue)) { tileValue = Rand.ChooseElement <int>(autoTileTable[tileValue]); } SetTile(i, j, tileValue, layer); } } } }
private void SetTile(Tilemap tilemap, GridCollider gridCollider, int x, int y, int id) { tilemap.SetTileAt(x, y, id); gridCollider.SetPixelMaskAt(x, y, id); }
/// <summary> /// Creates a grid collider from any TiledTileLayer. Each tile that have an image set it will /// create a collider the size of the tile. /// </summary> /// <param name="tileLayer"> /// The tile layer with all the information needed to generate a grid collider. /// </param> /// <param name="tags"> /// The tags that will be applied to all of the colliders in the grid collider. /// </param> /// <returns> /// A grid collider with a collider at each position where a tile is set. /// </returns> public GridCollider CreateGridCollider(TiledTileLayer tileLayer, params int[] tags) { var grid = new GridCollider(PixelWidth, PixelHeight, TileWidth, TileHeight, tags); foreach(var tile in tileLayer.Tiles) { if(tile.Gid > 0) { grid.SetTile(tile.X, tile.Y); } } return grid; }
public DungeonMap(DungeonData data) { Data = data; Type = Global.TypeMap; Width = data.WidthTiles * Global.TileSize; Height = data.HeightTiles * Global.TileSize; var solidGrid = new GridCollider(data.WidthTiles, data.HeightTiles, Global.TileSize, Global.TileSize, "tileset"); Collider = solidGrid; var groundMap = new Tilemap(data.Tileset, data.WidthTiles, data.HeightTiles); groundMap.Layer = Global.LayerMapGround; Add(groundMap); var backMap = new Tilemap(data.Tileset, data.WidthTiles, data.HeightTiles); backMap.Layer = Global.LayerMapWall; Add(backMap); var frontMap = new Tilemap(data.Tileset, data.WidthTiles, data.HeightTiles); frontMap.Layer = Global.LayerMapRoof; Add(frontMap); Data.IterateTiles((tile) => { if (tile.Trigger == null) { if (tile.SolidType == TileSolidType.PixelMask) { solidGrid.SetPixelMaskAt(tile.X, tile.Y, tile.DisplayTid, tile.Properties); } else { solidGrid.SetTileAt(tile.X, tile.Y, tile.SolidType, tile.Properties); } } switch (tile.Type) { case DungeonTileType.Ground: RenderFlatTile(groundMap, tile, TileGround); break; case DungeonTileType.Wall: RenderWallTile(solidGrid, backMap, tile, TileWall); break; case DungeonTileType.Roof: RenderFlatTile(frontMap, tile, TileRoof); break; } if (tile.Trigger != null) { backMap.SetTileAt(tile.X, tile.Y, tile.DisplayTid); } }); tireLayer = new DrawLayer(data.WidthTiles * Global.TileSize, data.HeightTiles * Global.TileSize); tireLayer.Layer = Global.LayerTireEffect; Add(tireLayer); }
private void RenderWallTile(GridCollider solidGrid, Tilemap tilemap, DungeonTile tile, int tid) { var neighbors = GetNeighbors(tile); // vertical if (GetTileTypeAt(tile.X - 1, tile.Y) == DungeonTileType.Roof && GetTileTypeAt(tile.X + 1, tile.Y) == DungeonTileType.Ground) { SetTile(tilemap, tile, tid + 16, Direction.Left); } else if (GetTileTypeAt(tile.X + 1, tile.Y) == DungeonTileType.Roof && GetTileTypeAt(tile.X - 1, tile.Y) == DungeonTileType.Ground) { SetTile(tilemap, tile, tid + 18, Direction.Right); } // horizontal else if (GetTileTypeAt(tile.X, tile.Y - 1) == DungeonTileType.Roof && GetTileTypeAt(tile.X, tile.Y + 1) == DungeonTileType.Ground) { SetTile(tilemap, tile, tid + 1, Direction.Up); } else if (GetTileTypeAt(tile.X, tile.Y + 1) == DungeonTileType.Roof && GetTileTypeAt(tile.X, tile.Y - 1) == DungeonTileType.Ground) { SetTile(tilemap, tile, tid + 33, Direction.Down); } // corner outer else if (GetTileTypeAt(tile.X + 1, tile.Y + 1) == DungeonTileType.Ground && GetTileTypeAt(tile.X + 1, tile.Y) == DungeonTileType.Wall && GetTileTypeAt(tile.X, tile.Y + 1) == DungeonTileType.Wall) { SetTile(tilemap, tile, tid + 0); } else if (GetTileTypeAt(tile.X - 1, tile.Y + 1) == DungeonTileType.Ground && GetTileTypeAt(tile.X - 1, tile.Y) == DungeonTileType.Wall && GetTileTypeAt(tile.X, tile.Y + 1) == DungeonTileType.Wall) { SetTile(tilemap, tile, tid + 2); } else if (GetTileTypeAt(tile.X + 1, tile.Y - 1) == DungeonTileType.Ground && GetTileTypeAt(tile.X + 1, tile.Y) == DungeonTileType.Wall && GetTileTypeAt(tile.X, tile.Y - 1) == DungeonTileType.Wall) { SetTile(tilemap, tile, tid + 32); } else if (GetTileTypeAt(tile.X - 1, tile.Y - 1) == DungeonTileType.Ground && GetTileTypeAt(tile.X - 1, tile.Y) == DungeonTileType.Wall && GetTileTypeAt(tile.X, tile.Y - 1) == DungeonTileType.Wall) { SetTile(tilemap, tile, tid + 34); } // corner inner else if (GetTileTypeAt(tile.X - 1, tile.Y - 1) == DungeonTileType.Ground && GetTileTypeAt(tile.X + 1, tile.Y) == DungeonTileType.Wall && GetTileTypeAt(tile.X, tile.Y + 1) == DungeonTileType.Wall) { SetTile(tilemap, tile, tid + 3); solidGrid.SetPixelMaskAt(tile.X, tile.Y, tid + 3); } else if (GetTileTypeAt(tile.X + 1, tile.Y - 1) == DungeonTileType.Ground && GetTileTypeAt(tile.X - 1, tile.Y) == DungeonTileType.Wall && GetTileTypeAt(tile.X, tile.Y + 1) == DungeonTileType.Wall) { SetTile(tilemap, tile, tid + 4); solidGrid.SetPixelMaskAt(tile.X, tile.Y, tid + 4); } else if (GetTileTypeAt(tile.X - 1, tile.Y + 1) == DungeonTileType.Ground && GetTileTypeAt(tile.X + 1, tile.Y) == DungeonTileType.Wall && GetTileTypeAt(tile.X, tile.Y - 1) == DungeonTileType.Wall) { SetTile(tilemap, tile, tid + 19); solidGrid.SetPixelMaskAt(tile.X, tile.Y, tid + 19); } else if (GetTileTypeAt(tile.X + 1, tile.Y + 1) == DungeonTileType.Ground && GetTileTypeAt(tile.X - 1, tile.Y) == DungeonTileType.Wall && GetTileTypeAt(tile.X, tile.Y - 1) == DungeonTileType.Wall) { SetTile(tilemap, tile, tid + 20); solidGrid.SetPixelMaskAt(tile.X, tile.Y, tid + 20); } // error else { Log.Error("Unkown wall tile at " + tile); } }