/// <summary> /// Given an input of perimeters that describe a single tile group, returns a list of ConvexPolygonShape2Ds that /// represent the tile group but decomposed into rectangles. /// </summary> /// <param name="allPerims">Array of lists describing single tile group. Every list in the array represents a /// different perimeter.</param> /// <returns>A list of ConvexPolygonShape2Ds, with each one being a rectangle that the original irregular polygon /// was decomposed into.</returns> private static List <ConvexPolygonShape2D> _PartitionPolygonToRectangles( IReadOnlyList <List <Vector2> > allPerims) { var partitionedRectangles = new List <ConvexPolygonShape2D>(); var allIsoPerims = new List <Vector2> [allPerims.Count]; for (int i = 0; i < allPerims.Count; i++) { //convert to iso axis so all the shapes 'look' rectangular allIsoPerims[i] = AxisFuncs.CoordArrayToIsoAxis(allPerims[i]); } (List <Chord> chords, List <ChordlessPolygon> chordlessPolygons) = allIsoPerims.DecomposeComplexPolygonToRectangles(); List <List <Vector2> > allRectangles = chordlessPolygons.DecomposeChordlessPolygonToRectangles(chords); foreach (List <Vector2> rectangle in allRectangles) { List <Vector2> carteRectangle = AxisFuncs.CoordArrayToCarteAxis(rectangle); var cps2d = new ConvexPolygonShape2D() { Points = carteRectangle.ToArray() }; partitionedRectangles.Add(cps2d); } return(partitionedRectangles); }
/// <summary> /// Create a default polygon. /// </summary> public SimplePolygon() { polygonShape2D = new ConvexPolygonShape2D(); collisionShape2D = new CollisionShape2D() { Shape = polygonShape2D }; }
public static TileSet makeTileset(Texture texture, bool collisions) { var ts = new TileSet(); int i = 0; for (int y = 0; y < TILESET_HEIGHT; y++) { for (int x = 0; x < TILESET_WIDTH; x++) { ts.CreateTile(i); ts.TileSetTexture(i, texture); var region = new Rect2(x * TILE_WIDTH, y * TILE_HEIGHT, TILE_WIDTH, TILE_HEIGHT); ts.TileSetRegion(i, region); if (collisions) { var image = texture.GetData(); var bitmap = new BitMap(); bitmap.CreateFromImageAlpha(image, .01f); var polygons = bitmap.OpaqueToPolygons(region, 2); List <Vector2> plist = new List <Vector2>(); for (int j = 0; j < polygons.Count; j++) { Vector2[] v = (Vector2[])polygons[j]; for (int k = 0; k < v.Length; k++) { // I have no idea why it's adding y*48 to y coordinates... Vector2 mv = new Vector2(v[k].x, v[k].y - (y * TILE_HEIGHT * 2)); plist.Add(mv); } } // Point cloud must be at least 3 if (plist.Count >= 3) { var collision = new ConvexPolygonShape2D(); collision.SetPointCloud(plist.ToArray()); ts.TileSetShape(i, 0, collision); } } i++; } } return(ts); }
public override void _Ready() { surface_1 = GetNode <Line2D>("Water_Surface_1"); surface_2 = GetNode <Line2D>("Water_Surface_2"); collider = (ConvexPolygonShape2D)GetNode <CollisionShape2D>("Collider/CollisionShape2D").Shape; Vector2[] polygon_body = new Vector2[length + 2]; segment_spread = Math.Abs(bounds[1].x - bounds[0].x) / (length - 1); for (int i = 0; i < length; i++) { water_surface[i] = new Water_Segment_Poly(new Vector2((i * segment_spread) + bounds[0].x, bounds[0].y)); polygon_body[i] = water_surface[i].position; surface_1.AddPoint(water_surface[i].position); surface_2.AddPoint(new Vector2(water_surface[i].position.x, water_surface[i].position.y + 1)); left_deltas[i] = 0; right_deltas[i] = 0; } polygon_body[length] = bounds[1]; polygon_body[length + 1] = new Vector2(bounds[0].x, bounds[1].y); Polygon = polygon_body; collider.Points = polygon_body; }
public void MakeDraggable() { dragArea = new Area2D(); AddChild(dragArea); dragArea.Connect("mouse_entered", this, nameof(OnMouseEntered)); dragArea.Connect("mouse_exited", this, nameof(OnMouseExited)); var shape = new ConvexPolygonShape2D(); shape.SetPoints(new Vector2[] { new Vector2(0, -1f), new Vector2(1f, -0.5f), new Vector2(1f, 0.5f), new Vector2(0, 1f), new Vector2(-1f, 0.5f), new Vector2(-1f, -5f), }); var ownerId = dragArea.CreateShapeOwner(dragArea); dragArea.ShapeOwnerAddShape(ownerId, shape); }
void MakeTileCollisionShapes(TileMap map) { TileSet tileSet = map.TileSet; foreach (int tileId in tileSet.GetTilesIds()) { // Load image and calculate collison polygon // https://github.com/godotengine/godot/blob/2abe996414b8b551e69e29461de3ff1bcaf5a28f/editor/plugins/sprite_2d_editor_plugin.cpp#L160 // https://github.com/godotengine/godot/blob/2abe996414b8b551e69e29461de3ff1bcaf5a28f/editor/plugins/sprite_2d_editor_plugin.cpp#L255 Image tileImage = tileSet.TileGetTexture(tileId).GetData(); Rect2 rect = new Rect2(); rect.Size = new Vector2(tileImage.GetWidth(), tileImage.GetHeight()); BitMap imageBitMap = new BitMap(); imageBitMap.CreateFromImageAlpha(tileImage); Array lines = imageBitMap.OpaqueToPolygons(rect); Array <Array <Vector2> > OutlineLines = new Array <Array <Vector2> >(); OutlineLines.Resize(lines.Count); Array <Array <Vector2> > computedOutlineLines = new Array <Array <Vector2> >(); computedOutlineLines.Resize(lines.Count); for (int pi = 0; pi < lines.Count; pi++) { Array <Vector2> ol = new Array <Vector2>(); Array <Vector2> col = new Array <Vector2>(); IList <Vector2> linesLines = (IList <Vector2>)lines[pi]; ol.Resize(linesLines.Count); col.Resize(linesLines.Count); for (int i = 0; i < linesLines.Count; i++) { Vector2 vtx = linesLines[i]; ol[i] = vtx; vtx -= rect.Position; // Flipping logic is not implemented since idk how that would // translate from a Sprite to an Image // Don't flip any sprites horizontally or vertically // this assumes the texture is centered in the image (which it is) vtx -= rect.Size / 2; col[i] = vtx; } OutlineLines[pi] = ol; computedOutlineLines[pi] = col; } // Now that we've calculated the collision polygon, we need to set it // https://github.com/godotengine/godot/blob/2abe996414b8b551e69e29461de3ff1bcaf5a28f/editor/plugins/sprite_2d_editor_plugin.cpp#L400 if (computedOutlineLines.Count == 0) { GD.PrintErr("Error, couldn't make some geometry - tileId is " + tileId.ToString()); continue; } ConvexPolygonShape2D newShape = new ConvexPolygonShape2D(); for (int i = 0; i < computedOutlineLines.Count; i++) { var outline = computedOutlineLines[i]; newShape.Points = outline.ToArray <Vector2>(); tileSet.TileSetShape(tileId, 0, newShape); tileSet.TileSetShapeOffset(tileId, 0, new Vector2(256, 256)); // needs to be offset by this amount for some reason } } }
public static TileSet makeTileset(Texture texture, bool collisions) { BitMap original_bitmap = null; BitMap bitmap = null; if (collisions) { var image = texture.GetData(); original_bitmap = new BitMap(); original_bitmap.CreateFromImageAlpha(image, .001f); // bitmap with borders is needed to shrink mask later bitmap = new BitMap(); bitmap.Create(new Vector2((TILE_WIDTH + 2) * TILESET_WIDTH, (TILE_HEIGHT + 2) * TILESET_HEIGHT)); bitmap.SetBitRect(new Rect2(new Vector2(0, 0), bitmap.GetSize()), true); } var ts = new TileSet(); int i = 0; for (int y = 0; y < TILESET_HEIGHT; y++) { for (int x = 0; x < TILESET_WIDTH; x++) { ts.CreateTile(i); ts.TileSetTexture(i, texture); var region = new Rect2(x * TILE_WIDTH, y * TILE_HEIGHT, TILE_WIDTH, TILE_HEIGHT); ts.TileSetRegion(i, region); if (collisions) { for (int m = 0; m < TILE_WIDTH; m++) { for (int n = 0; n < TILE_HEIGHT; n++) { bitmap.SetBit(new Vector2(x * (TILE_WIDTH + 2) + m + 1, y * (TILE_HEIGHT + 2) + n + 1), original_bitmap.GetBit(new Vector2(x * TILE_WIDTH + m, y * TILE_HEIGHT + n))); } } var bitmap_region = new Rect2(x * (TILE_WIDTH + 2) + 1, y * (TILE_HEIGHT + 2) + 1, TILE_WIDTH, TILE_HEIGHT); var polygons = tilePolygons(bitmap, bitmap_region); int c = 0; foreach (Vector2[] polygon in polygons) { if (isConvex(polygon)) { var collision = new ConvexPolygonShape2D(); collision.SetPointCloud(polygon); ts.TileSetShape(i, c++, collision); } else { int[] triangles = Geometry.TriangulatePolygon(polygon); for (int t = 0; t < triangles.Length; t += 3) { Vector2[] triangle = { polygon[triangles[t]], polygon[triangles[t + 1]], polygon[triangles[t + 2]] }; var collision = new ConvexPolygonShape2D(); collision.SetPointCloud(triangle); ts.TileSetShape(i, c++, collision); } } } } i++; } } return(ts); }
public void LoadTMX(string filename) { layers = new Dictionary <string, TileMap>(); File f = new File(); string mapPath = "res://map/"; string mapFilename = mapPath + filename; if (f.Open(mapFilename, File.ModeFlags.Read) == Error.Ok) { XmlDocument xmlDoc = new XmlDocument(); xmlDoc.LoadXml(f.GetAsText()); XmlElement root = xmlDoc.DocumentElement; tileWidth = int.Parse(root.Attributes["tilewidth"].Value); tileHeight = int.Parse(root.Attributes["tileheight"].Value); tileSize = new Vector2(tileWidth, tileHeight); width = int.Parse(root.Attributes["width"].Value); height = int.Parse(root.Attributes["height"].Value); XmlNode tilesetNode = root.SelectSingleNode("tileset"); string tilesetPath = tilesetNode["image"].Attributes["source"].Value; int firstgid = int.Parse(tilesetNode.Attributes["firstgid"].Value); int tilesetColumns = int.Parse(tilesetNode.Attributes["columns"].Value); int tilesetCount = int.Parse(tilesetNode.Attributes["tilecount"].Value); int tilesetWidth = int.Parse(tilesetNode["image"].Attributes["width"].Value); int tilesetHeight = int.Parse(tilesetNode["image"].Attributes["height"].Value); tilesetPath = System.IO.Path.Combine(mapPath, tilesetPath); GD.Print(tilesetPath); tilesetPath = ResolvePath(tilesetPath); GD.Print(tilesetPath); Texture tilesetTexture = GD.Load <Texture>(tilesetPath); GD.Print($"Loaded Tileset texture {tilesetPath} {tilesetTexture.GetWidth()}x{tilesetTexture.GetHeight()}"); TileSet tileset = new TileSet(); for (int i = 0; i < tilesetCount; i++) { tileset.CreateTile(i); tileset.TileSetTexture(i, tilesetTexture); tileset.TileSetTileMode(i, TileSet.TileMode.SingleTile); tileset.TileSetRegion(i, new Rect2((i % tilesetColumns) * tileWidth, (i / tilesetColumns) * tileHeight, tileWidth, tileHeight)); //tileset.TileSetTextureOffset(i, new Vector2((i % tilesetColumns) * tileWidth, (i / tilesetColumns) * tileHeight)); //tileset.AutotileSetSize(0, new Vector2(tileWidth, tileHeight)); ConvexPolygonShape2D shape = new ConvexPolygonShape2D(); shape.Points = new Vector2[] { new Vector2(0, 0), new Vector2(16, 0), new Vector2(16, 16), new Vector2(0, 16) }; tileset.TileSetShape(i, 0, shape); } foreach (XmlNode layer in root.SelectNodes("layer")) { int layerWidth = int.Parse(layer.Attributes["width"].Value); int layerHeight = int.Parse(layer.Attributes["height"].Value); string layerName = layer.Attributes["name"].Value; string layerEncoding = layer["data"].Attributes["encoding"].Value; if (layerEncoding != "csv") { GD.Print($"{mapFilename} layer {layerName} invalid encoding {layerEncoding}!"); continue; } TileMap map = new TileMap();//GetNode<TileMap>(layerName); map.CollisionLayer = 1 << 1; map.CollisionMask = 0; map.CellSize = new Vector2(tileWidth, tileHeight); //if (map == null) continue; GD.Print($"Loading layer {layerName}."); string dataStr = layer["data"].InnerText; dataStr.Replace("\n", ""); string[] dataStrCells = dataStr.Split(","); map.Name = layerName; map.TileSet = tileset; int tileCount = 0; for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { string dataStrCell = dataStrCells[y * width + x]; long tileId = long.Parse(dataStrCell); tileId &= 0xffff; tileId -= firstgid; if (tileId >= 0) { map.SetCell(x, y, (int)tileId, false, false, false); tileCount++; } } } GD.Print($"Added {tileCount} tiles to layer {layerName}."); layers.Add(layerName, map); AddChild(map); } } else { GD.Print("Error loading map.tmx!"); } }