Guest User

Creating a Farseer Physics Body from a TiledLib map

a guest
Dec 12th, 2011
398
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 7.80 KB | None | 0 0
  1. /* #############################################################################
  2.  *
  3.  * Copyright (C) 2011 Scott Franks
  4.  *
  5.  * Permission is hereby granted, free of charge, to any person obtaining a copy of
  6.  * this software and associated documentation files (the "Software"), to deal in
  7.  * the Software without restriction, including without limitation the rights to
  8.  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
  9.  * of the Software, and to permit persons to whom the Software is furnished to do
  10.  * so, subject to the following conditions:
  11.  *
  12.  * The above copyright notice and this permission notice shall be included in all
  13.  * copies or substantial portions of the Software.
  14.  *
  15.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16.  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17.  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  18.  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19.  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  20.  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  21.  * SOFTWARE.
  22.  *
  23. ############################################################################# */
  24.  
  25. using System;
  26. using System.IO;
  27. using FarseerPhysics.Common;
  28. using FarseerPhysics.Common.Decomposition;
  29. using FarseerPhysics.Common.PolygonManipulation;
  30. using FarseerPhysics.Dynamics;
  31. using FarseerPhysics.Factories;
  32. using Microsoft.Xna.Framework;
  33. using Microsoft.Xna.Framework.Graphics;
  34. using Ruminate.GUI.Framework;
  35. using Ruminate.Utils;
  36. using TiledLib;
  37.  
  38. namespace Ruminate.Engine2D {
  39.  
  40.     /// <summary>
  41.     /// Extensions to the TiledLib library by Nick Gravelyn
  42.     /// </summary>
  43.     public static class TiledLibExtentions {
  44.  
  45.         /// <summary>
  46.         /// Renders the entire map and then saves it to disk as a .png
  47.         /// </summary>
  48.         /// <param name="map">The Map to save to disk.</param>
  49.         /// <param name="device">The Games current device.</param>
  50.         /// <param name="fileName">The location to save the current file.</param>
  51.         public static void SaveAsPng(this Map map, GraphicsDevice device, string fileName) {
  52.            
  53.             var width = map.Width * map.TileWidth;
  54.             var height = map.Height * map.TileHeight;
  55.  
  56.             var baker = new TextureBaker(device, new Vector2(width, height), RenderState.Tile);
  57.             map.Draw(baker);
  58.             using (var stream = new FileStream(fileName, FileMode.Create)) {
  59.                 baker.GetTexture().SaveAsPng(stream, width, height);
  60.             }
  61.         }
  62.  
  63.         /// <summary>
  64.         /// Performs a basic rendering of a the specified layer in the map.
  65.         /// </summary>
  66.         /// <param name="map">The Map containing the layer to draw.</param>
  67.         /// <param name="spriteBatch">The SpriteBatch to use to render the map.</param>
  68.         /// <param name="layerName">The name of the layer to draw.</param>
  69.         public static void DrawLayer(this Map map, SpriteBatch spriteBatch, string layerName) {
  70.  
  71.             var area = new Rectangle(0, 0, map.Width * map.TileWidth, map.Height * map.TileHeight);
  72.             map.DrawLayer(spriteBatch, area, layerName);
  73.         }
  74.  
  75.         /// <summary>
  76.         /// Draws a layer of the map defined in world space (pixel) coordinates.
  77.         /// </summary>
  78.         /// <param name="map">The Map containing the layer to draw.</param>
  79.         /// <param name="spriteBatch">The SpriteBatch to use to render the map.</param>
  80.         /// <param name="viewArea">The area of the map to draw in world coordinates.</param>
  81.         /// <param name="layerName">The name of the layer to draw.</param>
  82.         public static void DrawLayer(this Map map, SpriteBatch spriteBatch, Rectangle viewArea, string layerName) {
  83.  
  84.             if (spriteBatch == null) {
  85.                 throw new ArgumentNullException("spriteBatch");
  86.             }
  87.  
  88.             switch (map.Orientation) {
  89.                 case Orientation.Orthogonal:
  90.  
  91.                     // figure out the min and max tile indices to draw
  92.                     var minX = Math.Max((int)Math.Floor((float)viewArea.Left / map.TileWidth), 0);
  93.                     var maxX = Math.Min((int)Math.Ceiling((float)viewArea.Right / map.TileWidth), map.Width);
  94.  
  95.                     var minY = Math.Max((int)Math.Floor((float)viewArea.Top / map.TileHeight), 0);
  96.                     var maxY = Math.Min((int)Math.Ceiling((float)viewArea.Bottom / map.TileHeight), map.Height);
  97.  
  98.                     foreach (var l in map.Layers) {
  99.  
  100.                         if (!l.Visible) { continue; }
  101.                         if (l.Name.Equals(layerName)) { continue; }
  102.  
  103.                         var tileLayer = l as TileLayer;
  104.  
  105.                         if (tileLayer == null) { continue; }
  106.  
  107.                         for (var x = minX; x < maxX; x++) {
  108.                             for (var y = minY; y < maxY; y++) {
  109.  
  110.                                 var tile = tileLayer.Tiles[x, y];
  111.  
  112.                                 if (tile == null) { continue; }
  113.  
  114.                                 var destination = new Rectangle(
  115.                                     x * map.TileWidth - viewArea.Left,
  116.                                     y * map.TileHeight - tile.Source.Height + map.TileHeight - viewArea.Top,
  117.                                     map.TileWidth,
  118.                                     map.TileHeight);
  119.  
  120.                                 tile.DrawOrthographic(spriteBatch, destination, tileLayer.Opacity, l.LayerDepth);
  121.                             }
  122.                         }
  123.                     }
  124.                     break;
  125.                 default:
  126.                     throw new NotSupportedException("TileLib does not have built in support for rendering isometric tile maps.");
  127.             }
  128.         }
  129.  
  130. /// <summary>
  131. /// Converts a the specified layer of the map into a polygon body for use in the
  132. /// Farseer Physics Engine. Requires that you set the ConvertUnits.DisplayUnitToSimUnitRatio
  133. /// to an appropriate value for your game. Defaults to 100px = 1m.
  134. /// </summary>
  135. /// <param name="map">The Map containing the later to convert to a Body.</param>
  136. /// <param name="device">The graphics device of the current Game.</param>
  137. /// <param name="world">The world to add the created body to.</param>
  138. /// <param name="meterInPixels">The number of pixels equivalent to 1 Body unit.</param>
  139. /// <param name="layer">The name of the Layer to convert to a Body.</param>
  140. /// <returns>The body created and added to the world.</returns>
  141. public static Body LayerToBody(this Map map, GraphicsDevice device, World world, float meterInPixels, string layer) {
  142.            
  143.     //Pixel size of the map
  144.     var width = map.Width * map.TileWidth;
  145.     var height = map.Height * map.TileHeight;
  146.  
  147.     //Create the baker
  148.     var baker = new TextureBaker(
  149.         device,
  150.         new Vector2(width, height),
  151.         RenderState.Tile);
  152.  
  153.     //Render the map to a texture
  154.     map.Draw(baker);
  155.     var polygonTexture = baker.GetTexture();
  156.  
  157.     //Get the data from the texture
  158.     var data = new uint[polygonTexture.Width * polygonTexture.Height];
  159.     polygonTexture.GetData(data);
  160.  
  161.     //Create a poly from the texture
  162.     var verts = PolygonTools.CreatePolygon(data, polygonTexture.Width, true);
  163.  
  164.     //These 2 seem to work the best with tile maps
  165.     verts = SimplifyTools.CollinearSimplify(verts);
  166.     verts = SimplifyTools.DouglasPeuckerSimplify(verts, 0f);
  167.  
  168.     var list = BayazitDecomposer.ConvexPartition(verts);
  169.  
  170.     var vertScale = new Vector2(1f / meterInPixels);
  171.     foreach (var vertices in list) {
  172.         vertices.Scale(ref vertScale);
  173.     }
  174.  
  175.     //Create a body from the poly
  176.     var body = BodyFactory.CreateCompoundPolygon(world, list, 1);
  177.  
  178.     return body;
  179. }
  180.     }
  181. }
  182.  
  183.  
Advertisement
Add Comment
Please, Sign In to add comment