Browse Source

Merge branch 'tile-map'

aster 11 years ago
parent
commit
8c99b8d866

+ 153 - 0
Bin/Data/LuaScripts/36_Urho2DTileMap.lua

@@ -0,0 +1,153 @@
+-- Urho2D tile map example.
+-- This sample demonstrates:
+--     - Creating a 2D scene with tile map
+--     - Displaying the scene using the Renderer subsystem
+--     - Handling keyboard to move and zoom 2D camera
+
+require "LuaScripts/Utilities/Sample"
+
+function Start()
+    -- Execute the common startup for samples
+    SampleStart()
+
+    -- Create the scene content
+    CreateScene()
+
+    -- Create the UI content
+    CreateInstructions()
+
+    -- Setup the viewport for displaying the scene
+    SetupViewport()
+
+    -- Hook up to the frame update events
+    SubscribeToEvents()
+end
+
+function CreateScene()
+    scene_ = Scene()
+
+    -- Create the Octree component to the scene. This is required before adding any drawable components, or else nothing will
+    -- show up. The default octree volume will be from (-1000, -1000, -1000) to (1000, 1000, 1000) in world coordinates it
+    -- is also legal to place objects outside the volume but their visibility can then not be checked in a hierarchically
+    -- optimizing manner
+    scene_:CreateComponent("Octree")
+
+    -- Create a scene node for the camera, which we will move around
+    -- The camera will use default settings (1000 far clip distance, 45 degrees FOV, set aspect ratio automatically)
+    cameraNode = scene_:CreateChild("Camera")
+    -- Set an initial position for the camera scene node above the plane
+    cameraNode.position = Vector3(0.0, 0.0, -10.0)
+    local camera = cameraNode:CreateComponent("Camera")
+    camera.orthographic = true
+    camera.orthoSize = graphics.height * PIXEL_SIZE
+
+    -- Get tmx file
+    local tmxFile = cache:GetResource("TmxFile2D", "Urho2D/isometric_grass_and_water.tmx")
+    if tmxFile == nil then
+        return
+    end
+
+    local tileMapNode = scene_:CreateChild("TileMap")
+    tileMapNode.position = Vector3(0.0, 0.0, -1.0)
+
+    local tileMap = tileMapNode:CreateComponent("TileMap2D")
+    tileMap.tmxFile = tmxFile
+
+    -- Set camera's position
+    local x = tileMap.width * tileMap.tileWidth * 0.5
+    local y = tileMap.height * tileMap.tileHeight * 0.5
+    cameraNode.position = Vector3(x, y, -10.0)
+end
+
+function CreateInstructions()
+    -- Construct new Text object, set string to display and font to use
+    local instructionText = ui.root:CreateChild("Text")
+    instructionText:SetText("Use WASD keys and mouse to move, Use PageUp PageDown to zoom.")
+    instructionText:SetFont(cache:GetResource("Font", "Fonts/Anonymous Pro.ttf"), 15)
+
+    -- Position the text relative to the screen center
+    instructionText.horizontalAlignment = HA_CENTER
+    instructionText.verticalAlignment = VA_CENTER
+    instructionText:SetPosition(0, ui.root.height / 4)
+end
+
+function SetupViewport()
+    -- Set up a viewport to the Renderer subsystem so that the 3D scene can be seen. We need to define the scene and the camera
+    -- at minimum. Additionally we could configure the viewport screen size and the rendering path (eg. forward / deferred) to
+    -- use, but now we just use full screen and default render path configured in the engine command line options
+    local viewport = Viewport:new(scene_, cameraNode:GetComponent("Camera"))
+    renderer:SetViewport(0, viewport)
+end
+
+function MoveCamera(timeStep)
+    -- Do not move if the UI has a focused element (the console)
+    if ui.focusElement ~= nil then
+        return
+    end
+
+    -- Movement speed as world units per second
+    local MOVE_SPEED = 4.0
+
+    -- Read WASD keys and move the camera scene node to the corresponding direction if they are pressed
+    if input:GetKeyDown(KEY_W) then
+        cameraNode:Translate(Vector3(0.0, 1.0, 0.0) * MOVE_SPEED * timeStep)
+    end
+    if input:GetKeyDown(KEY_S) then
+        cameraNode:Translate(Vector3(0.0, -1.0, 0.0) * MOVE_SPEED * timeStep)
+    end
+    if input:GetKeyDown(KEY_A) then
+        cameraNode:Translate(Vector3(-1.0, 0.0, 0.0) * MOVE_SPEED * timeStep)
+    end
+    if input:GetKeyDown(KEY_D) then
+        cameraNode:Translate(Vector3(1.0, 0.0, 0.0) * MOVE_SPEED * timeStep)
+    end
+
+    if input:GetKeyDown(KEY_PAGEUP) then
+        local camera = cameraNode:GetComponent("Camera")
+        camera.zoom = camera.zoom * 1.01
+    end
+
+    if input:GetKeyDown(KEY_PAGEDOWN) then
+        local camera = cameraNode:GetComponent("Camera")
+        camera.zoom = camera.zoom * 0.99
+    end
+end
+
+function SubscribeToEvents()
+    -- Subscribe HandleUpdate() function for processing update events
+    SubscribeToEvent("Update", "HandleUpdate")
+
+    -- Unsubscribe the SceneUpdate event from base class to prevent camera pitch and yaw in 2D sample
+    UnsubscribeFromEvent("SceneUpdate")
+end
+
+function HandleUpdate(eventType, eventData)
+    -- Take the frame time step, which is stored as a float
+    local timeStep = eventData:GetFloat("TimeStep")
+
+    -- Move the camera, scale movement with time step
+    MoveCamera(timeStep)
+end
+
+-- Create XML patch instructions for screen joystick layout specific to this sample app
+function GetScreenJoystickPatchString()
+    return
+        "<patch>" ..
+        "    <remove sel=\"/element/element[./attribute[@name='Name' and @value='Button0']]/attribute[@name='Is Visible']\" />" ..
+        "    <replace sel=\"/element/element[./attribute[@name='Name' and @value='Button0']]/element[./attribute[@name='Name' and @value='Label']]/attribute[@name='Text']/@value\">Zoom In</replace>" ..
+        "    <add sel=\"/element/element[./attribute[@name='Name' and @value='Button0']]\">" ..
+        "        <element type=\"Text\">" ..
+        "            <attribute name=\"Name\" value=\"KeyBinding\" />" ..
+        "            <attribute name=\"Text\" value=\"PAGEUP\" />" ..
+        "        </element>" ..
+        "    </add>" ..
+        "    <remove sel=\"/element/element[./attribute[@name='Name' and @value='Button1']]/attribute[@name='Is Visible']\" />" ..
+        "    <replace sel=\"/element/element[./attribute[@name='Name' and @value='Button1']]/element[./attribute[@name='Name' and @value='Label']]/attribute[@name='Text']/@value\">Zoom Out</replace>" ..
+        "    <add sel=\"/element/element[./attribute[@name='Name' and @value='Button1']]\">" ..
+        "        <element type=\"Text\">" ..
+        "            <attribute name=\"Name\" value=\"KeyBinding\" />" ..
+        "            <attribute name=\"Text\" value=\"PAGEDOWN\" />" ..
+        "        </element>" ..
+        "    </add>" ..
+        "</patch>"
+end

+ 155 - 0
Bin/Data/Scripts/36_Urho2DTileMap.as

@@ -0,0 +1,155 @@
+// Urho2D tile map example.
+// This sample demonstrates:
+//     - Creating a 2D scene with tile map
+//     - Displaying the scene using the Renderer subsystem
+//     - Handling keyboard to move and zoom 2D camera
+
+#include "Scripts/Utilities/Sample.as"
+
+void Start()
+{
+    // Execute the common startup for samples
+    SampleStart();
+
+    // Create the scene content
+    CreateScene();
+
+    // Create the UI content
+    CreateInstructions();
+
+    // Setup the viewport for displaying the scene
+    SetupViewport();
+
+    // Hook up to the frame update events
+    SubscribeToEvents();
+}
+
+void CreateScene()
+{
+    scene_ = Scene();
+
+    // Create the Octree component to the scene. This is required before adding any drawable components, or else nothing will
+    // show up. The default octree volume will be from (-1000, -1000, -1000) to (1000, 1000, 1000) in world coordinates; it
+    // is also legal to place objects outside the volume but their visibility can then not be checked in a hierarchically
+    // optimizing manner
+    scene_.CreateComponent("Octree");
+
+    // Create a scene node for the camera, which we will move around
+    // The camera will use default settings (1000 far clip distance, 45 degrees FOV, set aspect ratio automatically)
+    cameraNode = scene_.CreateChild("Camera");
+    // Set an initial position for the camera scene node above the plane
+    cameraNode.position = Vector3(0.0f, 0.0f, -10.0f);
+
+    Camera@ camera = cameraNode.CreateComponent("Camera");
+    camera.orthographic = true;
+    camera.orthoSize = graphics.height * PIXEL_SIZE;
+
+    // Get tmx file
+    TmxFile2D@ tmxFile = cache.GetResource("TmxFile2D", "Urho2D/isometric_grass_and_water.tmx");
+    if (tmxFile == null)
+        return;
+    
+    Node@ tileMapNode = scene_.CreateChild("TileMap");
+    tileMapNode.position = Vector3(0.0f, 0.0f, -1.0f);
+
+    TileMap2D@ tileMap = tileMapNode.CreateComponent("TileMap2D");
+    tileMap.tmxFile = tmxFile;
+    
+    // Set camera's position;
+    float x = tileMap.width * tileMap.tileWidth * 0.5f;
+    float y = tileMap.height * tileMap.tileHeight * 0.5f;
+    cameraNode.position = Vector3(x, y, -10.0f);
+}
+
+void CreateInstructions()
+{
+    // Construct new Text object, set string to display and font to use
+    Text@ instructionText = ui.root.CreateChild("Text");
+    instructionText.text = "Use WASD keys and mouse to move, Use PageUp PageDown to zoom.";
+    instructionText.SetFont(cache.GetResource("Font", "Fonts/Anonymous Pro.ttf"), 15);
+
+    // Position the text relative to the screen center
+    instructionText.horizontalAlignment = HA_CENTER;
+    instructionText.verticalAlignment = VA_CENTER;
+    instructionText.SetPosition(0, ui.root.height / 4);
+}
+
+void SetupViewport()
+{
+    // Set up a viewport to the Renderer subsystem so that the 3D scene can be seen. We need to define the scene and the camera
+    // at minimum. Additionally we could configure the viewport screen size and the rendering path (eg. forward / deferred) to
+    // use, but now we just use full screen and default render path configured in the engine command line options
+    Viewport@ viewport = Viewport(scene_, cameraNode.GetComponent("Camera"));
+    renderer.viewports[0] = viewport;
+}
+
+void MoveCamera(float timeStep)
+{
+    // Do not move if the UI has a focused element (the console)
+    if (ui.focusElement !is null)
+        return;
+
+    // Movement speed as world units per second
+    const float MOVE_SPEED = 4.0f;
+
+    // Read WASD keys and move the camera scene node to the corresponding direction if they are pressed
+    if (input.keyDown['W'])
+        cameraNode.Translate(Vector3(0.0f, 1.0f, 0.0f) * MOVE_SPEED * timeStep);
+    if (input.keyDown['S'])
+        cameraNode.Translate(Vector3(0.0f, -1.0f, 0.0f) * MOVE_SPEED * timeStep);
+    if (input.keyDown['A'])
+        cameraNode.Translate(Vector3(-1.0f, 0.0f, 0.0f) * MOVE_SPEED * timeStep);
+    if (input.keyDown['D'])
+        cameraNode.Translate(Vector3(1.0f, 0.0f, 0.0f) * MOVE_SPEED * timeStep);
+
+    if (input.keyDown[KEY_PAGEUP])
+    {
+        Camera@ camera = cameraNode.GetComponent("Camera");
+        camera.zoom = camera.zoom * 1.01f;
+    }
+
+    if (input.keyDown[KEY_PAGEDOWN])
+    {
+        Camera@ camera = cameraNode.GetComponent("Camera");
+        camera.zoom = camera.zoom * 0.99f;
+    }
+}
+
+void SubscribeToEvents()
+{
+    // Subscribe HandleUpdate() function for processing update events
+    SubscribeToEvent("Update", "HandleUpdate");
+
+    // Unsubscribe the SceneUpdate event from base class to prevent camera pitch and yaw in 2D sample
+    UnsubscribeFromEvent("SceneUpdate");
+}
+
+void HandleUpdate(StringHash eventType, VariantMap& eventData)
+{
+    // Take the frame time step, which is stored as a float
+    float timeStep = eventData["TimeStep"].GetFloat();
+
+    // Move the camera, scale movement with time step
+    MoveCamera(timeStep);
+}
+
+// Create XML patch instructions for screen joystick layout specific to this sample app
+String patchInstructions =
+        "<patch>" +
+        "    <remove sel=\"/element/element[./attribute[@name='Name' and @value='Button0']]/attribute[@name='Is Visible']\" />" +
+        "    <replace sel=\"/element/element[./attribute[@name='Name' and @value='Button0']]/element[./attribute[@name='Name' and @value='Label']]/attribute[@name='Text']/@value\">Zoom In</replace>" +
+        "    <add sel=\"/element/element[./attribute[@name='Name' and @value='Button0']]\">" +
+        "        <element type=\"Text\">" +
+        "            <attribute name=\"Name\" value=\"KeyBinding\" />" +
+        "            <attribute name=\"Text\" value=\"PAGEUP\" />" +
+        "        </element>" +
+        "    </add>" +
+        "    <remove sel=\"/element/element[./attribute[@name='Name' and @value='Button1']]/attribute[@name='Is Visible']\" />" +
+        "    <replace sel=\"/element/element[./attribute[@name='Name' and @value='Button1']]/element[./attribute[@name='Name' and @value='Label']]/attribute[@name='Text']/@value\">Zoom Out</replace>" +
+        "    <add sel=\"/element/element[./attribute[@name='Name' and @value='Button1']]\">" +
+        "        <element type=\"Text\">" +
+        "            <attribute name=\"Name\" value=\"KeyBinding\" />" +
+        "            <attribute name=\"Text\" value=\"PAGEDOWN\" />" +
+        "        </element>" +
+        "    </add>" +
+        "</patch>";

+ 2 - 0
Bin/Data/Scripts/Editor/AttributeEditor.as

@@ -886,6 +886,7 @@ void InitResourcePicker()
     Array<String> materialFilters = {"*.xml", "*.material"};
     Array<String> anmSetFilters = {"*.scml"};
     Array<String> pexFilters = {"*.pex"};
+    Array<String> tmxFilters = {"*.tmx"};
     resourcePickers.Push(ResourcePicker("Animation", "*.ani", ACTION_PICK | ACTION_TEST));
     resourcePickers.Push(ResourcePicker("Font", fontFilters));
     resourcePickers.Push(ResourcePicker("Image", imageFilters));
@@ -903,6 +904,7 @@ void InitResourcePicker()
     resourcePickers.Push(ResourcePicker("Sprite2D", textureFilters, ACTION_PICK | ACTION_OPEN));
     resourcePickers.Push(ResourcePicker("AnimationSet2D", anmSetFilters, ACTION_PICK | ACTION_OPEN));
     resourcePickers.Push(ResourcePicker("ParticleEffect2D", pexFilters, ACTION_PICK | ACTION_OPEN));
+    resourcePickers.Push(ResourcePicker("TmxFile2D", tmxFilters, ACTION_PICK | ACTION_OPEN));
 }
 
 ResourcePicker@ GetResourcePicker(StringHash resourceType)

BIN
Bin/Data/Urho2D/isometric_grass_and_water.png


+ 664 - 0
Bin/Data/Urho2D/isometric_grass_and_water.tmx

@@ -0,0 +1,664 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<map version="1.0" orientation="isometric" width="25" height="25" tilewidth="64" tileheight="32">
+ <tileset firstgid="1" name="isometric_grass_and_water" tilewidth="64" tileheight="64">
+  <tileoffset x="0" y="16"/>
+  <image source="isometric_grass_and_water.png" width="256" height="384"/>
+  <terraintypes>
+   <terrain name="Grass" tile="0"/>
+   <terrain name="Water" tile="22"/>
+  </terraintypes>
+  <tile id="0" terrain="0,0,0,0"/>
+  <tile id="1" terrain="0,0,0,0"/>
+  <tile id="2" terrain="0,0,0,0"/>
+  <tile id="3" terrain="0,0,0,0"/>
+  <tile id="4" terrain="0,0,0,1"/>
+  <tile id="5" terrain="0,0,1,0"/>
+  <tile id="6" terrain="1,0,0,0"/>
+  <tile id="7" terrain="0,1,0,0"/>
+  <tile id="8" terrain="0,1,1,1"/>
+  <tile id="9" terrain="1,0,1,1"/>
+  <tile id="10" terrain="1,1,1,0"/>
+  <tile id="11" terrain="1,1,0,1"/>
+  <tile id="12" terrain="0,0,1,1"/>
+  <tile id="13" terrain="1,0,1,0"/>
+  <tile id="14" terrain="1,1,0,0"/>
+  <tile id="15" terrain="0,1,0,1"/>
+  <tile id="16" terrain="0,0,1,1"/>
+  <tile id="17" terrain="1,0,1,0"/>
+  <tile id="18" terrain="1,1,0,0"/>
+  <tile id="19" terrain="0,1,0,1"/>
+  <tile id="20" terrain="0,1,1,0"/>
+  <tile id="21" terrain="1,0,0,1"/>
+  <tile id="22" terrain="1,1,1,1"/>
+  <tile id="23" terrain="1,1,1,1"/>
+ </tileset>
+ <layer name="Tile Layer 1" width="25" height="25">
+  <data>
+   <tile gid="24"/>
+   <tile gid="24"/>
+   <tile gid="23"/>
+   <tile gid="11"/>
+   <tile gid="19"/>
+   <tile gid="19"/>
+   <tile gid="12"/>
+   <tile gid="23"/>
+   <tile gid="24"/>
+   <tile gid="24"/>
+   <tile gid="23"/>
+   <tile gid="7"/>
+   <tile gid="2"/>
+   <tile gid="2"/>
+   <tile gid="1"/>
+   <tile gid="4"/>
+   <tile gid="2"/>
+   <tile gid="2"/>
+   <tile gid="3"/>
+   <tile gid="4"/>
+   <tile gid="4"/>
+   <tile gid="1"/>
+   <tile gid="3"/>
+   <tile gid="4"/>
+   <tile gid="1"/>
+   <tile gid="24"/>
+   <tile gid="23"/>
+   <tile gid="23"/>
+   <tile gid="14"/>
+   <tile gid="3"/>
+   <tile gid="3"/>
+   <tile gid="8"/>
+   <tile gid="12"/>
+   <tile gid="24"/>
+   <tile gid="24"/>
+   <tile gid="18"/>
+   <tile gid="4"/>
+   <tile gid="1"/>
+   <tile gid="3"/>
+   <tile gid="1"/>
+   <tile gid="3"/>
+   <tile gid="3"/>
+   <tile gid="4"/>
+   <tile gid="4"/>
+   <tile gid="1"/>
+   <tile gid="3"/>
+   <tile gid="1"/>
+   <tile gid="4"/>
+   <tile gid="3"/>
+   <tile gid="4"/>
+   <tile gid="11"/>
+   <tile gid="15"/>
+   <tile gid="15"/>
+   <tile gid="7"/>
+   <tile gid="1"/>
+   <tile gid="4"/>
+   <tile gid="3"/>
+   <tile gid="20"/>
+   <tile gid="23"/>
+   <tile gid="11"/>
+   <tile gid="7"/>
+   <tile gid="2"/>
+   <tile gid="1"/>
+   <tile gid="3"/>
+   <tile gid="1"/>
+   <tile gid="3"/>
+   <tile gid="4"/>
+   <tile gid="4"/>
+   <tile gid="3"/>
+   <tile gid="2"/>
+   <tile gid="2"/>
+   <tile gid="3"/>
+   <tile gid="4"/>
+   <tile gid="2"/>
+   <tile gid="1"/>
+   <tile gid="18"/>
+   <tile gid="4"/>
+   <tile gid="3"/>
+   <tile gid="2"/>
+   <tile gid="2"/>
+   <tile gid="4"/>
+   <tile gid="3"/>
+   <tile gid="8"/>
+   <tile gid="12"/>
+   <tile gid="18"/>
+   <tile gid="2"/>
+   <tile gid="4"/>
+   <tile gid="4"/>
+   <tile gid="3"/>
+   <tile gid="3"/>
+   <tile gid="1"/>
+   <tile gid="4"/>
+   <tile gid="2"/>
+   <tile gid="1"/>
+   <tile gid="4"/>
+   <tile gid="4"/>
+   <tile gid="4"/>
+   <tile gid="1"/>
+   <tile gid="1"/>
+   <tile gid="1"/>
+   <tile gid="14"/>
+   <tile gid="2"/>
+   <tile gid="1"/>
+   <tile gid="4"/>
+   <tile gid="2"/>
+   <tile gid="1"/>
+   <tile gid="4"/>
+   <tile gid="2"/>
+   <tile gid="8"/>
+   <tile gid="7"/>
+   <tile gid="5"/>
+   <tile gid="17"/>
+   <tile gid="6"/>
+   <tile gid="3"/>
+   <tile gid="3"/>
+   <tile gid="3"/>
+   <tile gid="4"/>
+   <tile gid="3"/>
+   <tile gid="4"/>
+   <tile gid="4"/>
+   <tile gid="3"/>
+   <tile gid="2"/>
+   <tile gid="4"/>
+   <tile gid="3"/>
+   <tile gid="4"/>
+   <tile gid="10"/>
+   <tile gid="6"/>
+   <tile gid="2"/>
+   <tile gid="1"/>
+   <tile gid="4"/>
+   <tile gid="4"/>
+   <tile gid="1"/>
+   <tile gid="3"/>
+   <tile gid="4"/>
+   <tile gid="3"/>
+   <tile gid="8"/>
+   <tile gid="12"/>
+   <tile gid="10"/>
+   <tile gid="6"/>
+   <tile gid="2"/>
+   <tile gid="1"/>
+   <tile gid="1"/>
+   <tile gid="1"/>
+   <tile gid="1"/>
+   <tile gid="2"/>
+   <tile gid="1"/>
+   <tile gid="4"/>
+   <tile gid="2"/>
+   <tile gid="1"/>
+   <tile gid="1"/>
+   <tile gid="24"/>
+   <tile gid="18"/>
+   <tile gid="1"/>
+   <tile gid="2"/>
+   <tile gid="4"/>
+   <tile gid="3"/>
+   <tile gid="3"/>
+   <tile gid="5"/>
+   <tile gid="6"/>
+   <tile gid="5"/>
+   <tile gid="13"/>
+   <tile gid="9"/>
+   <tile gid="11"/>
+   <tile gid="7"/>
+   <tile gid="3"/>
+   <tile gid="4"/>
+   <tile gid="1"/>
+   <tile gid="3"/>
+   <tile gid="1"/>
+   <tile gid="3"/>
+   <tile gid="4"/>
+   <tile gid="2"/>
+   <tile gid="4"/>
+   <tile gid="4"/>
+   <tile gid="4"/>
+   <tile gid="24"/>
+   <tile gid="14"/>
+   <tile gid="4"/>
+   <tile gid="2"/>
+   <tile gid="5"/>
+   <tile gid="6"/>
+   <tile gid="2"/>
+   <tile gid="8"/>
+   <tile gid="22"/>
+   <tile gid="9"/>
+   <tile gid="23"/>
+   <tile gid="24"/>
+   <tile gid="10"/>
+   <tile gid="6"/>
+   <tile gid="2"/>
+   <tile gid="1"/>
+   <tile gid="3"/>
+   <tile gid="1"/>
+   <tile gid="5"/>
+   <tile gid="6"/>
+   <tile gid="2"/>
+   <tile gid="3"/>
+   <tile gid="4"/>
+   <tile gid="4"/>
+   <tile gid="2"/>
+   <tile gid="19"/>
+   <tile gid="7"/>
+   <tile gid="3"/>
+   <tile gid="1"/>
+   <tile gid="8"/>
+   <tile gid="7"/>
+   <tile gid="4"/>
+   <tile gid="1"/>
+   <tile gid="8"/>
+   <tile gid="12"/>
+   <tile gid="24"/>
+   <tile gid="23"/>
+   <tile gid="23"/>
+   <tile gid="10"/>
+   <tile gid="17"/>
+   <tile gid="6"/>
+   <tile gid="3"/>
+   <tile gid="1"/>
+   <tile gid="8"/>
+   <tile gid="7"/>
+   <tile gid="1"/>
+   <tile gid="3"/>
+   <tile gid="3"/>
+   <tile gid="3"/>
+   <tile gid="1"/>
+   <tile gid="1"/>
+   <tile gid="2"/>
+   <tile gid="4"/>
+   <tile gid="2"/>
+   <tile gid="2"/>
+   <tile gid="3"/>
+   <tile gid="3"/>
+   <tile gid="4"/>
+   <tile gid="3"/>
+   <tile gid="20"/>
+   <tile gid="24"/>
+   <tile gid="23"/>
+   <tile gid="23"/>
+   <tile gid="23"/>
+   <tile gid="23"/>
+   <tile gid="18"/>
+   <tile gid="2"/>
+   <tile gid="2"/>
+   <tile gid="3"/>
+   <tile gid="1"/>
+   <tile gid="4"/>
+   <tile gid="4"/>
+   <tile gid="1"/>
+   <tile gid="1"/>
+   <tile gid="1"/>
+   <tile gid="3"/>
+   <tile gid="3"/>
+   <tile gid="5"/>
+   <tile gid="13"/>
+   <tile gid="6"/>
+   <tile gid="1"/>
+   <tile gid="2"/>
+   <tile gid="2"/>
+   <tile gid="5"/>
+   <tile gid="9"/>
+   <tile gid="23"/>
+   <tile gid="23"/>
+   <tile gid="24"/>
+   <tile gid="23"/>
+   <tile gid="24"/>
+   <tile gid="14"/>
+   <tile gid="1"/>
+   <tile gid="3"/>
+   <tile gid="1"/>
+   <tile gid="1"/>
+   <tile gid="3"/>
+   <tile gid="3"/>
+   <tile gid="4"/>
+   <tile gid="4"/>
+   <tile gid="4"/>
+   <tile gid="2"/>
+   <tile gid="4"/>
+   <tile gid="16"/>
+   <tile gid="24"/>
+   <tile gid="10"/>
+   <tile gid="6"/>
+   <tile gid="2"/>
+   <tile gid="4"/>
+   <tile gid="20"/>
+   <tile gid="23"/>
+   <tile gid="23"/>
+   <tile gid="24"/>
+   <tile gid="23"/>
+   <tile gid="23"/>
+   <tile gid="24"/>
+   <tile gid="14"/>
+   <tile gid="2"/>
+   <tile gid="4"/>
+   <tile gid="2"/>
+   <tile gid="4"/>
+   <tile gid="5"/>
+   <tile gid="6"/>
+   <tile gid="4"/>
+   <tile gid="3"/>
+   <tile gid="1"/>
+   <tile gid="3"/>
+   <tile gid="1"/>
+   <tile gid="20"/>
+   <tile gid="23"/>
+   <tile gid="24"/>
+   <tile gid="10"/>
+   <tile gid="6"/>
+   <tile gid="3"/>
+   <tile gid="8"/>
+   <tile gid="12"/>
+   <tile gid="24"/>
+   <tile gid="23"/>
+   <tile gid="23"/>
+   <tile gid="23"/>
+   <tile gid="24"/>
+   <tile gid="14"/>
+   <tile gid="1"/>
+   <tile gid="2"/>
+   <tile gid="1"/>
+   <tile gid="5"/>
+   <tile gid="9"/>
+   <tile gid="18"/>
+   <tile gid="4"/>
+   <tile gid="3"/>
+   <tile gid="4"/>
+   <tile gid="4"/>
+   <tile gid="2"/>
+   <tile gid="8"/>
+   <tile gid="12"/>
+   <tile gid="23"/>
+   <tile gid="24"/>
+   <tile gid="18"/>
+   <tile gid="4"/>
+   <tile gid="3"/>
+   <tile gid="16"/>
+   <tile gid="24"/>
+   <tile gid="24"/>
+   <tile gid="24"/>
+   <tile gid="23"/>
+   <tile gid="24"/>
+   <tile gid="18"/>
+   <tile gid="1"/>
+   <tile gid="3"/>
+   <tile gid="1"/>
+   <tile gid="16"/>
+   <tile gid="24"/>
+   <tile gid="14"/>
+   <tile gid="1"/>
+   <tile gid="3"/>
+   <tile gid="2"/>
+   <tile gid="4"/>
+   <tile gid="1"/>
+   <tile gid="2"/>
+   <tile gid="8"/>
+   <tile gid="12"/>
+   <tile gid="24"/>
+   <tile gid="14"/>
+   <tile gid="4"/>
+   <tile gid="1"/>
+   <tile gid="8"/>
+   <tile gid="15"/>
+   <tile gid="12"/>
+   <tile gid="24"/>
+   <tile gid="23"/>
+   <tile gid="11"/>
+   <tile gid="7"/>
+   <tile gid="2"/>
+   <tile gid="1"/>
+   <tile gid="2"/>
+   <tile gid="16"/>
+   <tile gid="23"/>
+   <tile gid="18"/>
+   <tile gid="1"/>
+   <tile gid="4"/>
+   <tile gid="2"/>
+   <tile gid="3"/>
+   <tile gid="4"/>
+   <tile gid="3"/>
+   <tile gid="2"/>
+   <tile gid="8"/>
+   <tile gid="19"/>
+   <tile gid="7"/>
+   <tile gid="2"/>
+   <tile gid="2"/>
+   <tile gid="3"/>
+   <tile gid="3"/>
+   <tile gid="8"/>
+   <tile gid="15"/>
+   <tile gid="19"/>
+   <tile gid="7"/>
+   <tile gid="3"/>
+   <tile gid="1"/>
+   <tile gid="2"/>
+   <tile gid="5"/>
+   <tile gid="9"/>
+   <tile gid="24"/>
+   <tile gid="14"/>
+   <tile gid="1"/>
+   <tile gid="2"/>
+   <tile gid="3"/>
+   <tile gid="2"/>
+   <tile gid="2"/>
+   <tile gid="1"/>
+   <tile gid="4"/>
+   <tile gid="4"/>
+   <tile gid="1"/>
+   <tile gid="2"/>
+   <tile gid="5"/>
+   <tile gid="6"/>
+   <tile gid="2"/>
+   <tile gid="2"/>
+   <tile gid="2"/>
+   <tile gid="1"/>
+   <tile gid="3"/>
+   <tile gid="4"/>
+   <tile gid="3"/>
+   <tile gid="5"/>
+   <tile gid="13"/>
+   <tile gid="9"/>
+   <tile gid="24"/>
+   <tile gid="24"/>
+   <tile gid="18"/>
+   <tile gid="4"/>
+   <tile gid="3"/>
+   <tile gid="4"/>
+   <tile gid="1"/>
+   <tile gid="4"/>
+   <tile gid="1"/>
+   <tile gid="3"/>
+   <tile gid="2"/>
+   <tile gid="5"/>
+   <tile gid="13"/>
+   <tile gid="9"/>
+   <tile gid="14"/>
+   <tile gid="3"/>
+   <tile gid="1"/>
+   <tile gid="3"/>
+   <tile gid="2"/>
+   <tile gid="4"/>
+   <tile gid="4"/>
+   <tile gid="5"/>
+   <tile gid="21"/>
+   <tile gid="19"/>
+   <tile gid="12"/>
+   <tile gid="24"/>
+   <tile gid="11"/>
+   <tile gid="7"/>
+   <tile gid="1"/>
+   <tile gid="2"/>
+   <tile gid="3"/>
+   <tile gid="2"/>
+   <tile gid="1"/>
+   <tile gid="3"/>
+   <tile gid="3"/>
+   <tile gid="3"/>
+   <tile gid="20"/>
+   <tile gid="23"/>
+   <tile gid="24"/>
+   <tile gid="18"/>
+   <tile gid="4"/>
+   <tile gid="4"/>
+   <tile gid="2"/>
+   <tile gid="3"/>
+   <tile gid="1"/>
+   <tile gid="1"/>
+   <tile gid="8"/>
+   <tile gid="7"/>
+   <tile gid="5"/>
+   <tile gid="9"/>
+   <tile gid="23"/>
+   <tile gid="18"/>
+   <tile gid="1"/>
+   <tile gid="3"/>
+   <tile gid="4"/>
+   <tile gid="2"/>
+   <tile gid="4"/>
+   <tile gid="2"/>
+   <tile gid="4"/>
+   <tile gid="1"/>
+   <tile gid="2"/>
+   <tile gid="8"/>
+   <tile gid="15"/>
+   <tile gid="19"/>
+   <tile gid="7"/>
+   <tile gid="4"/>
+   <tile gid="5"/>
+   <tile gid="6"/>
+   <tile gid="4"/>
+   <tile gid="2"/>
+   <tile gid="4"/>
+   <tile gid="5"/>
+   <tile gid="17"/>
+   <tile gid="9"/>
+   <tile gid="23"/>
+   <tile gid="11"/>
+   <tile gid="22"/>
+   <tile gid="13"/>
+   <tile gid="6"/>
+   <tile gid="4"/>
+   <tile gid="1"/>
+   <tile gid="3"/>
+   <tile gid="2"/>
+   <tile gid="2"/>
+   <tile gid="4"/>
+   <tile gid="4"/>
+   <tile gid="3"/>
+   <tile gid="2"/>
+   <tile gid="1"/>
+   <tile gid="4"/>
+   <tile gid="2"/>
+   <tile gid="8"/>
+   <tile gid="7"/>
+   <tile gid="4"/>
+   <tile gid="2"/>
+   <tile gid="3"/>
+   <tile gid="16"/>
+   <tile gid="24"/>
+   <tile gid="23"/>
+   <tile gid="11"/>
+   <tile gid="7"/>
+   <tile gid="16"/>
+   <tile gid="23"/>
+   <tile gid="18"/>
+   <tile gid="3"/>
+   <tile gid="1"/>
+   <tile gid="1"/>
+   <tile gid="3"/>
+   <tile gid="1"/>
+   <tile gid="2"/>
+   <tile gid="3"/>
+   <tile gid="3"/>
+   <tile gid="3"/>
+   <tile gid="4"/>
+   <tile gid="2"/>
+   <tile gid="1"/>
+   <tile gid="3"/>
+   <tile gid="2"/>
+   <tile gid="3"/>
+   <tile gid="4"/>
+   <tile gid="3"/>
+   <tile gid="8"/>
+   <tile gid="15"/>
+   <tile gid="15"/>
+   <tile gid="7"/>
+   <tile gid="4"/>
+   <tile gid="8"/>
+   <tile gid="19"/>
+   <tile gid="7"/>
+   <tile gid="3"/>
+   <tile gid="4"/>
+   <tile gid="1"/>
+   <tile gid="2"/>
+   <tile gid="3"/>
+   <tile gid="4"/>
+   <tile gid="1"/>
+   <tile gid="3"/>
+   <tile gid="4"/>
+   <tile gid="4"/>
+   <tile gid="4"/>
+   <tile gid="1"/>
+   <tile gid="4"/>
+   <tile gid="4"/>
+   <tile gid="3"/>
+   <tile gid="2"/>
+   <tile gid="3"/>
+   <tile gid="4"/>
+   <tile gid="1"/>
+   <tile gid="2"/>
+   <tile gid="4"/>
+   <tile gid="2"/>
+   <tile gid="1"/>
+   <tile gid="2"/>
+   <tile gid="2"/>
+   <tile gid="4"/>
+   <tile gid="1"/>
+   <tile gid="4"/>
+   <tile gid="2"/>
+   <tile gid="3"/>
+   <tile gid="2"/>
+   <tile gid="1"/>
+   <tile gid="4"/>
+   <tile gid="2"/>
+   <tile gid="2"/>
+   <tile gid="1"/>
+   <tile gid="2"/>
+   <tile gid="2"/>
+   <tile gid="2"/>
+   <tile gid="4"/>
+   <tile gid="3"/>
+   <tile gid="3"/>
+   <tile gid="2"/>
+   <tile gid="3"/>
+   <tile gid="3"/>
+   <tile gid="2"/>
+   <tile gid="3"/>
+   <tile gid="2"/>
+   <tile gid="4"/>
+   <tile gid="1"/>
+   <tile gid="3"/>
+   <tile gid="1"/>
+   <tile gid="1"/>
+   <tile gid="1"/>
+   <tile gid="1"/>
+   <tile gid="4"/>
+   <tile gid="1"/>
+   <tile gid="3"/>
+   <tile gid="3"/>
+   <tile gid="2"/>
+   <tile gid="1"/>
+   <tile gid="4"/>
+   <tile gid="2"/>
+   <tile gid="1"/>
+   <tile gid="3"/>
+   <tile gid="1"/>
+   <tile gid="3"/>
+   <tile gid="3"/>
+   <tile gid="4"/>
+   <tile gid="3"/>
+   <tile gid="4"/>
+   <tile gid="2"/>
+   <tile gid="1"/>
+   <tile gid="2"/>
+   <tile gid="3"/>
+   <tile gid="1"/>
+   <tile gid="1"/>
+  </data>
+ </layer>
+</map>

+ 22 - 0
Source/Engine/LuaScript/pkgs/Urho2D/TileMap2D.pkg

@@ -0,0 +1,22 @@
+$#include "TileMap2D.h"
+
+class TileMap2D : Component
+{
+    void SetTmxFile(TmxFile2D* tmxFile);
+    TmxFile2D* GetTmxFile() const;
+    Orientation2D GetOrientation() const;
+    int GetWidth() const;
+    int GetHeight() const;
+    float GetTileWidth() const;
+    float GetTileHeight() const;
+    unsigned GetNumLayers() const;
+    TileMapLayer2D* GetLayer(unsigned index) const;
+
+    tolua_property__get_set TmxFile2D* tmxFile;
+    tolua_readonly tolua_property__get_set Orientation2D orientation;
+    tolua_readonly tolua_property__get_set int width;
+    tolua_readonly tolua_property__get_set int height;
+    tolua_readonly tolua_property__get_set float tileWidth;
+    tolua_readonly tolua_property__get_set float tileHeight;
+    tolua_readonly tolua_property__get_set unsigned numLayers;
+};

+ 62 - 0
Source/Engine/LuaScript/pkgs/Urho2D/TileMapDefs2D.pkg

@@ -0,0 +1,62 @@
+$#include "TileMapDefs2D.h"
+
+enum Orientation2D
+{
+    O_ORTHOGONAL,
+    O_ISOMETRIC
+};
+
+enum TileMapLayerType2D
+{
+    LT_TILE_LAYER,
+    LT_OBJECT_GROUP,
+    LT_IMAGE_LAYER,
+    LT_INVALID
+};
+
+enum TileObjectType2D
+{
+    OT_RECTANGLE,
+    OT_ELLIPSE,
+    OT_POLYGON,
+    OT_POLYLINE,
+    OT_TILE,
+    OT_INVALID
+};
+
+class PropertySet2D
+{
+    bool HasProperty(const String& name) const;
+    const String& GetProperty(const String& name) const;
+};
+
+class Tile2D
+{
+    int GetGid() const;
+    Sprite2D* GetSprite() const;
+    bool HasProperty(const String& name) const;
+    const String& GetProperty(const String& name) const;
+
+    tolua_readonly tolua_property__get_set int gid;
+    tolua_readonly tolua_property__get_set Sprite2D* sprite;
+};
+
+class TileObject2D
+{
+    TileObjectType2D GetType() const;
+    const Vector2& GetPosition() const;
+    const Vector2& GetSize() const;
+    unsigned GetNumPoints() const;
+    const Vector2& GetPoint(unsigned index) const;
+    int GetTileGid() const;
+    Sprite2D* GetTileSprite() const;
+    bool HasProperty(const String& name) const;
+    const String& GetProperty(const String& name) const;
+
+    tolua_readonly tolua_property__get_set TileObjectType2D type;
+    tolua_readonly tolua_property__get_set Vector2 position;
+    tolua_readonly tolua_property__get_set Vector2 size;
+    tolua_readonly tolua_property__get_set unsigned numPoints;
+    tolua_readonly tolua_property__get_set int tileGid;
+    tolua_readonly tolua_property__get_set Sprite2D* tileSprite;
+};

+ 32 - 0
Source/Engine/LuaScript/pkgs/Urho2D/TileMapLayer2D.pkg

@@ -0,0 +1,32 @@
+$#include "TileMapLayer2D.h"
+
+class TileMapLayer2D : Component
+{
+    void SetDrawOrder(int drawOrder);
+    void SetVisible(bool visible);
+
+    int GetDrawOrder() const;
+    bool IsVisible() const;
+    bool HasProperty(const String& name) const;
+    const String& GetProperty(const String& name) const;
+    TileMapLayerType2D GetLayerType() const;
+
+    int GetWidth() const;
+    int GetHeight() const;
+    Node* GetTileNode(int x, int y) const;
+    Tile2D* GetTile(int x, int y) const;
+    
+    unsigned GetNumObjects() const;
+    TileObject2D* GetObject(unsigned index) const;
+    Node* GetObjectNode(unsigned index) const;
+
+    Node* GetImageNode() const;
+
+    tolua_readonly tolua_property__get_set int drawOrder;
+    tolua_readonly tolua_property__is_set bool visible;
+    tolua_readonly tolua_property__get_set TileMapLayerType2D layerType;
+    tolua_readonly tolua_property__get_set int width;
+    tolua_readonly tolua_property__get_set int height;
+    tolua_readonly tolua_property__get_set unsigned numObjects;
+    tolua_readonly tolua_property__get_set Node* imageNode;
+};

+ 5 - 0
Source/Engine/LuaScript/pkgs/Urho2D/TmxFile2D.pkg

@@ -0,0 +1,5 @@
+$#include "TmxFile2D.h"
+
+class TmxFile2D : Resource
+{
+};

+ 5 - 0
Source/Engine/LuaScript/pkgs/Urho2DLuaAPI.pkg

@@ -10,6 +10,11 @@ $pfile "Urho2D/AnimatedSprite2D.pkg"
 $pfile "Urho2D/ParticleEffect2D.pkg"
 $pfile "Urho2D/ParticleEmitter2D.pkg"
 
+$pfile "Urho2D/TileMapDefs2D.pkg"
+$pfile "Urho2D/TmxFile2D.pkg"
+$pfile "Urho2D/TileMap2D.pkg"
+$pfile "Urho2D/TileMapLayer2D.pkg"
+
 $pfile "Urho2D/RigidBody2D.pkg"
 $pfile "Urho2D/PhysicsWorld2D.pkg"
 

+ 98 - 2
Source/Engine/Script/Urho2DAPI.cpp

@@ -21,9 +21,9 @@
 //
 
 #include "Precompiled.h"
+#include "AnimatedSprite2D.h"
 #include "Animation2D.h"
 #include "AnimationSet2D.h"
-#include "AnimatedSprite2D.h"
 #include "APITemplates.h"
 #include "CollisionBox2D.h"
 #include "CollisionChain2D.h"
@@ -40,9 +40,9 @@
 #include "ConstraintPrismatic2D.h"
 #include "ConstraintPulley2D.h"
 #include "ConstraintRevolute2D.h"
+#include "ConstraintRope2D.h"
 #include "ConstraintWeld2D.h"
 #include "ConstraintWheel2D.h"
-#include "ConstraintRope2D.h"
 #include "Drawable2D.h"
 #include "ParticleEffect2D.h"
 #include "ParticleEmitter2D.h"
@@ -52,6 +52,10 @@
 #include "Sprite2D.h"
 #include "SpriteSheet2D.h"
 #include "StaticSprite2D.h"
+#include "TileMap2D.h"
+#include "TileMapDefs2D.h"
+#include "TileMapLayer2D.h"
+#include "TmxFile2D.h"
 
 #ifdef _MSC_VER
 #pragma warning(disable:4345)
@@ -189,6 +193,93 @@ static void RegisterParticleEmitter2D(asIScriptEngine* engine)
     engine->RegisterObjectMethod("ParticleEmitter2D", "ParticleEffect2D@+ get_effect() const", asMETHOD(ParticleEmitter2D, GetEffect), asCALL_THISCALL);
 }
 
+static void RegisterTileMapDefs2D(asIScriptEngine* engine)
+{
+    engine->RegisterEnum("Orientation2D");
+    engine->RegisterEnumValue("Orientation2D", "O_ORTHOGONAL", O_ORTHOGONAL);
+    engine->RegisterEnumValue("Orientation2D", "O_ISOMETRIC", O_ISOMETRIC);
+
+    engine->RegisterEnum("TileMapLayerType2D");
+    engine->RegisterEnumValue("TileMapLayerType2D", "LT_TILE_LAYER", LT_TILE_LAYER);
+    engine->RegisterEnumValue("TileMapLayerType2D", "LT_OBJECT_GROUP", LT_OBJECT_GROUP);
+    engine->RegisterEnumValue("TileMapLayerType2D", "LT_IMAGE_LAYER", LT_IMAGE_LAYER);
+    engine->RegisterEnumValue("TileMapLayerType2D", "LT_INVALID", LT_INVALID);
+
+    engine->RegisterEnum("TileObjectType2D");
+    engine->RegisterEnumValue("TileObjectType2D", "OT_RECTANGLE", OT_RECTANGLE);
+    engine->RegisterEnumValue("TileObjectType2D", "OT_ELLIPSE", OT_ELLIPSE);
+    engine->RegisterEnumValue("TileObjectType2D", "OT_POLYGON", OT_POLYGON);
+    engine->RegisterEnumValue("TileObjectType2D", "OT_POLYLINE", OT_POLYLINE);
+    engine->RegisterEnumValue("TileObjectType2D", "OT_TILE", OT_TILE);
+    engine->RegisterEnumValue("TileObjectType2D", "OT_INVALID", OT_INVALID);
+
+    RegisterRefCounted<PropertySet2D>(engine, "PropertySet2D");
+    engine->RegisterObjectMethod("PropertySet2D", "bool HasProperty(const String&in) const", asMETHOD(PropertySet2D, HasProperty), asCALL_THISCALL);
+    engine->RegisterObjectMethod("PropertySet2D", "const String& GetProperty(const String&in) const", asMETHOD(PropertySet2D, HasProperty), asCALL_THISCALL);
+
+    RegisterRefCounted<Tile2D>(engine, "Tile2D");
+    engine->RegisterObjectMethod("Tile2D", "int get_gid() const", asMETHOD(Tile2D, GetGid), asCALL_THISCALL);
+    engine->RegisterObjectMethod("Tile2D", "Sprite2D@ get_sprite() const", asMETHOD(Tile2D, GetSprite), asCALL_THISCALL);
+    engine->RegisterObjectMethod("Tile2D", "bool HasProperty(const String&in) const", asMETHOD(Tile2D, HasProperty), asCALL_THISCALL);
+    engine->RegisterObjectMethod("Tile2D", "const String& GetProperty(const String&in) const", asMETHOD(Tile2D, HasProperty), asCALL_THISCALL);
+
+    RegisterRefCounted<TileObject2D>(engine, "TileObject2D");
+    engine->RegisterObjectMethod("TileObject2D", "TileObjectType2D get_type() const", asMETHOD(TileObject2D, GetType), asCALL_THISCALL);
+    engine->RegisterObjectMethod("TileObject2D", "const Vector2& get_position() const", asMETHOD(TileObject2D, GetPosition), asCALL_THISCALL);
+    engine->RegisterObjectMethod("TileObject2D", "const Vector2& get_size() const", asMETHOD(TileObject2D, GetSize), asCALL_THISCALL);
+    engine->RegisterObjectMethod("TileObject2D", "uint get_numPoints() const", asMETHOD(TileObject2D, GetNumPoints), asCALL_THISCALL);
+    engine->RegisterObjectMethod("TileObject2D", "const Vector2& GetPoint(uint) const", asMETHOD(TileObject2D, GetPoint), asCALL_THISCALL);
+    engine->RegisterObjectMethod("TileObject2D", "int get_tileGid() const", asMETHOD(TileObject2D, GetTileGid), asCALL_THISCALL);
+    engine->RegisterObjectMethod("TileObject2D", "Sprite2D@ get_tileSprite() const", asMETHOD(TileObject2D, GetTileSprite), asCALL_THISCALL);
+    engine->RegisterObjectMethod("TileObject2D", "bool HasProperty(const String&in) const", asMETHOD(TileObject2D, HasProperty), asCALL_THISCALL);
+    engine->RegisterObjectMethod("TileObject2D", "const String& GetProperty(const String&in) const", asMETHOD(TileObject2D, HasProperty), asCALL_THISCALL);
+}
+
+static void RegisterTmxFile2D(asIScriptEngine* engine)
+{
+    RegisterResource<TmxFile2D>(engine, "TmxFile2D");
+}
+
+static void RegisterTileMapLayer2D(asIScriptEngine* engine)
+{
+    RegisterComponent<TileMap2D>(engine, "TileMap2D");
+    RegisterComponent<TileMapLayer2D>(engine, "TileMapLayer2D");
+    engine->RegisterObjectMethod("TileMapLayer2D", "void set_drawOrder(int)", asMETHOD(TileMapLayer2D, SetDrawOrder), asCALL_THISCALL);
+    engine->RegisterObjectMethod("TileMapLayer2D", "int get_rrawOrder() const", asMETHOD(TileMapLayer2D, GetDrawOrder), asCALL_THISCALL);
+    engine->RegisterObjectMethod("TileMapLayer2D", "void set_visible()", asMETHOD(TileMapLayer2D, SetVisible), asCALL_THISCALL);
+    engine->RegisterObjectMethod("TileMapLayer2D", "bool get_visible() const", asMETHOD(TileMapLayer2D, IsVisible), asCALL_THISCALL);
+    engine->RegisterObjectMethod("TileMapLayer2D", "bool HasProperty(const String&in) const", asMETHOD(TileMapLayer2D, HasProperty), asCALL_THISCALL);
+    engine->RegisterObjectMethod("TileMapLayer2D", "const String& GetProperty(const String&in) const", asMETHOD(TileMapLayer2D, HasProperty), asCALL_THISCALL);
+    engine->RegisterObjectMethod("TileMapLayer2D", "TileMapLayerType2D get_layerType() const", asMETHOD(TileMapLayer2D, GetLayerType), asCALL_THISCALL);
+
+    // For tile layer only
+    engine->RegisterObjectMethod("TileMapLayer2D", "int get_width() const", asMETHOD(TileMapLayer2D, GetWidth), asCALL_THISCALL);
+    engine->RegisterObjectMethod("TileMapLayer2D", "int get_height() const", asMETHOD(TileMapLayer2D, GetHeight), asCALL_THISCALL);
+    engine->RegisterObjectMethod("TileMapLayer2D", "Tile2D@ GetTile(int, int) const", asMETHOD(TileMapLayer2D, GetTile), asCALL_THISCALL);
+    engine->RegisterObjectMethod("TileMapLayer2D", "Node@ GetTileNode(int, int) const", asMETHOD(TileMapLayer2D, GetTileNode), asCALL_THISCALL);
+
+    // For object group only
+    engine->RegisterObjectMethod("TileMapLayer2D", "uint get_numObjects() const", asMETHOD(TileMapLayer2D, GetNumObjects), asCALL_THISCALL);
+    engine->RegisterObjectMethod("TileMapLayer2D", "TileObject2D@ GetObject(uint) const", asMETHOD(TileMapLayer2D, GetObject), asCALL_THISCALL);
+    engine->RegisterObjectMethod("TileMapLayer2D", "Node@ GetObjectNode(uint) const", asMETHOD(TileMapLayer2D, GetObjectNode), asCALL_THISCALL);
+    
+    // For image layer only
+    engine->RegisterObjectMethod("TileMapLayer2D", "Node@ get_imageNode() const", asMETHOD(TileMapLayer2D, GetImageNode), asCALL_THISCALL);
+}
+
+static void RegisterTileMap2D(asIScriptEngine* engine)
+{
+    engine->RegisterObjectMethod("TileMap2D", "void set_tmxFile(TmxFile2D@)", asMETHOD(TileMap2D, SetTmxFile), asCALL_THISCALL);
+    engine->RegisterObjectMethod("TileMap2D", "TmxFile2D@ get_tmxFile() const", asMETHOD(TileMap2D, GetTmxFile), asCALL_THISCALL);
+    engine->RegisterObjectMethod("TileMap2D", "Orientation2D get_orientation() const", asMETHOD(TileMap2D, GetOrientation), asCALL_THISCALL);
+    engine->RegisterObjectMethod("TileMap2D", "int get_width() const", asMETHOD(TileMap2D, GetWidth), asCALL_THISCALL);
+    engine->RegisterObjectMethod("TileMap2D", "int get_height() const", asMETHOD(TileMap2D, GetHeight), asCALL_THISCALL);
+    engine->RegisterObjectMethod("TileMap2D", "float get_tileWidth() const", asMETHOD(TileMap2D, GetTileWidth), asCALL_THISCALL);
+    engine->RegisterObjectMethod("TileMap2D", "float get_tileHeight() const", asMETHOD(TileMap2D, GetTileHeight), asCALL_THISCALL);
+    engine->RegisterObjectMethod("TileMap2D", "uint get_numLayers() const", asMETHOD(TileMap2D, GetNumLayers), asCALL_THISCALL);
+    engine->RegisterObjectMethod("TileMap2D", "TileMapLayer2D@ GetLayer(uint) const", asMETHOD(TileMap2D, GetLayer), asCALL_THISCALL);
+}
+
 static void RegisterRigidBody2D(asIScriptEngine* engine)
 {
     engine->RegisterEnum("BodyType2D");
@@ -626,6 +717,11 @@ void RegisterUrho2DAPI(asIScriptEngine* engine)
     RegisterParticleEffect2D(engine);
     RegisterParticleEmitter2D(engine);
 
+    RegisterTileMapDefs2D(engine);
+    RegisterTmxFile2D(engine);
+    RegisterTileMapLayer2D(engine);
+    RegisterTileMap2D(engine);
+
     RegisterRigidBody2D(engine);
     RegisterPhysicsWorld2D(engine);
 

+ 1 - 1
Source/Engine/Urho2D/AnimatedSprite2D.cpp

@@ -250,7 +250,7 @@ void AnimatedSprite2D::SetAnimationSetAttr(ResourceRef value)
     SetAnimationSet(cache->GetResource<AnimationSet2D>(value.name_));
 }
 
-Urho3D::ResourceRef AnimatedSprite2D::GetAnimationSetAttr() const
+ResourceRef AnimatedSprite2D::GetAnimationSetAttr() const
 {
     return GetResourceRef(animationSet_, AnimationSet2D::GetTypeStatic());
 }

+ 1 - 1
Source/Engine/Urho2D/ParticleEmitter2D.cpp

@@ -167,7 +167,7 @@ void ParticleEmitter2D::SetParticleEffectAttr(ResourceRef value)
     SetEffect(cache->GetResource<ParticleEffect2D>(value.name_));
 }
 
-Urho3D::ResourceRef ParticleEmitter2D::GetParticleEffectAttr() const
+ResourceRef ParticleEmitter2D::GetParticleEffectAttr() const
 {
     return GetResourceRef(effect_, ParticleEffect2D::GetTypeStatic());
 }

+ 8 - 0
Source/Engine/Urho2D/StaticSprite2D.cpp

@@ -186,10 +186,18 @@ void StaticSprite2D::UpdateVertices()
         hotSpotY = flipY_ ? (1.0f - hotSpot.y_) : hotSpot.y_;
     }
 
+#ifdef URHO3D_OPENGL
     float leftX = -width * hotSpotX;
     float rightX = width * (1.0f - hotSpotX);
     float bottomY = -height * hotSpotY;
     float topY = height * (1.0f - hotSpotY);
+#else
+    const float halfPixelOffset = 0.5f * PIXEL_SIZE;
+    float leftX = -width * hotSpotX + halfPixelOffset;
+    float rightX = width * (1.0f - hotSpotX) + halfPixelOffset;
+    float bottomY = -height * hotSpotY + halfPixelOffset;
+    float topY = height * (1.0f - hotSpotY) + halfPixelOffset;
+#endif
 
     const Matrix3x4& worldTransform = node_->GetWorldTransform();
 

+ 140 - 0
Source/Engine/Urho2D/TileMap2D.cpp

@@ -0,0 +1,140 @@
+//
+// Copyright (c) 2008-2014 the Urho3D project.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+
+#include "Precompiled.h"
+#include "Context.h"
+#include "Node.h"
+#include "ResourceCache.h"
+#include "TileMap2D.h"
+#include "TileMapLayer2D.h"
+#include "TmxFile2D.h"
+
+#include "DebugNew.h"
+
+namespace Urho3D
+{
+
+extern const float PIXEL_SIZE;
+extern const char* URHO2D_CATEGORY;
+
+TileMap2D::TileMap2D(Context* context) :
+    Component(context)
+{
+}
+
+TileMap2D::~TileMap2D()
+{
+}
+
+void TileMap2D::RegisterObject(Context* context)
+{
+    context->RegisterFactory<TileMap2D>(URHO2D_CATEGORY);
+
+    ACCESSOR_ATTRIBUTE(TileMap2D, VAR_RESOURCEREF, "Tmx File", GetTmxFileAttr, SetTmxFileAttr, ResourceRef, ResourceRef(TmxFile2D::GetTypeStatic()), AM_DEFAULT);
+}
+
+void TileMap2D::SetTmxFile(TmxFile2D* tmxFile)
+{
+    if (tmxFile == tmxFile_)
+        return;
+
+    if (tmxFile_)
+    {
+        for (unsigned i = 0; i < layers_.Size(); ++i)
+            layers_[i]->GetNode()->Remove();
+        layers_.Clear();
+    }
+
+    tmxFile_ = tmxFile;
+    
+    if (!tmxFile_)
+        return;
+
+    unsigned numLayers = tmxFile_->GetNumLayers();
+    layers_.Resize(numLayers);
+
+    for (unsigned i = 0; i < numLayers; ++i)
+    {
+        const TmxLayer2D* tmxLayer = tmxFile_->GetLayer(i);
+
+        SharedPtr<Node> layerNode(GetNode()->CreateChild(tmxLayer->GetName(), LOCAL));
+        layerNode->SetTemporary(true);
+
+        SharedPtr<TileMapLayer2D> layer(layerNode->CreateComponent<TileMapLayer2D>());
+        layer->SetTmxLayer(tmxLayer);
+        layer->SetDrawOrder(i * 10);
+
+        layers_[i] = layer;
+    }
+}
+
+TmxFile2D* TileMap2D::GetTmxFile() const
+{
+    return tmxFile_;
+}
+
+Orientation2D TileMap2D::GetOrientation() const
+{
+    return tmxFile_ ? tmxFile_->GetOrientation() : O_ORTHOGONAL;
+}
+
+int TileMap2D::GetWidth() const
+{
+    return tmxFile_ ? tmxFile_->GetWidth() : 0;
+}
+
+int TileMap2D::GetHeight() const
+{
+    return tmxFile_ ? tmxFile_->GetHeight() : 0;
+
+}
+
+float TileMap2D::GetTileWidth() const
+{
+    return tmxFile_ ? tmxFile_->GetTileWidth() : 0.0f;
+}
+
+float TileMap2D::GetTileHeight() const
+{
+    return tmxFile_ ? tmxFile_->GetTileHeight() : 0.0f;
+}
+
+TileMapLayer2D* TileMap2D::GetLayer(unsigned index) const
+{
+    if (index >= layers_.Size())
+        return 0;
+
+    return layers_[index];
+}
+
+void TileMap2D::SetTmxFileAttr(ResourceRef value)
+{
+    ResourceCache* cache = GetSubsystem<ResourceCache>();
+    SetTmxFile(cache->GetResource<TmxFile2D>(value.name_));
+}
+
+ResourceRef TileMap2D::GetTmxFileAttr() const
+{
+    return GetResourceRef(tmxFile_, TmxFile2D::GetTypeStatic());
+}
+
+}

+ 79 - 0
Source/Engine/Urho2D/TileMap2D.h

@@ -0,0 +1,79 @@
+//
+// Copyright (c) 2008-2014 the Urho3D project.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+
+#pragma once
+
+#include "Component.h"
+#include "TileMapDefs2D.h"
+
+namespace Urho3D
+{
+
+class TileMapLayer2D;
+class TmxFile2D;
+
+/// Tile map component.
+class URHO3D_API TileMap2D : public Component
+{
+    OBJECT(TileMap2D);
+
+public:
+    /// Construct.
+    TileMap2D(Context* context);
+    /// Destruct.
+    ~TileMap2D();
+    /// Register object factory.
+    static void RegisterObject(Context* context);
+
+    /// Set tmx file.
+    void SetTmxFile(TmxFile2D* tmxFile);
+
+    /// Return tmx file.
+    TmxFile2D* GetTmxFile() const;
+    /// Return orientation.
+    Orientation2D GetOrientation() const;
+    /// Return width.
+    int GetWidth() const;
+    /// Return height.
+    int GetHeight() const;
+    /// Return tile width
+    float GetTileWidth() const;
+    /// Return tile height in pixel.
+    float GetTileHeight() const;
+    /// Return number of layers.
+    unsigned GetNumLayers() const { return layers_.Size(); }
+    /// Return tile map layer at index.
+    TileMapLayer2D* GetLayer(unsigned index) const;
+
+    /// Set tile map file attribute.
+    void SetTmxFileAttr(ResourceRef value);
+    /// Return tile map file attribute.
+    ResourceRef GetTmxFileAttr() const;
+
+private:
+    /// Tmx file.
+    SharedPtr<TmxFile2D> tmxFile_;
+    /// Tile map layers.
+    Vector<SharedPtr<TileMapLayer2D> > layers_;
+};
+
+}

+ 122 - 0
Source/Engine/Urho2D/TileMapDefs2D.cpp

@@ -0,0 +1,122 @@
+//
+// Copyright (c) 2008-2014 the Urho3D project.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+
+#include "Precompiled.h"
+#include "TileMapDefs2D.h"
+#include "XMLElement.h"
+
+#include "DebugNew.h"
+
+namespace Urho3D
+{
+
+PropertySet2D::PropertySet2D()
+{
+}
+
+PropertySet2D::~PropertySet2D()
+{
+}
+
+void PropertySet2D::Load(const XMLElement& element)
+{
+    assert(element.GetName() == "properties");
+    for (XMLElement propertyElem = element.GetChild("property"); propertyElem; propertyElem = propertyElem.GetNext("property"))
+        nameToValueMapping_[propertyElem.GetAttribute("name")] = propertyElem.GetAttribute("value");
+}
+
+bool PropertySet2D::HasProperty(const String& name) const
+{
+    return nameToValueMapping_.Find(name) != nameToValueMapping_.End();
+}
+
+const String& PropertySet2D::GetProperty(const String& name) const
+{
+    HashMap<String, String>::ConstIterator i = nameToValueMapping_.Find(name);
+    if (i == nameToValueMapping_.End())
+        return String::EMPTY;
+
+    return i->second_;
+}
+
+Tile2D::Tile2D() : 
+    gid_(0) 
+{
+}
+
+Sprite2D* Tile2D::GetSprite() const
+{
+    return sprite_;
+}
+
+bool Tile2D::HasProperty(const String& name) const
+{
+    if (!propertySet_)
+        return false;
+    return propertySet_->HasProperty(name);
+}
+
+const String& Tile2D::GetProperty(const String& name) const
+{
+    if (!propertySet_)
+        return String::EMPTY;
+
+    return propertySet_->GetProperty(name);
+}
+
+TileObject2D::TileObject2D()
+{
+}
+
+unsigned TileObject2D::GetNumPoints() const
+{
+    return points_.Size();
+}
+
+const Vector2& TileObject2D::GetPoint(unsigned index) const
+{
+    if (index >= points_.Size())
+        return Vector2::ZERO;
+
+    return points_[index];
+}
+
+Sprite2D* TileObject2D::GetTileSprite() const
+{
+    return sprite_;
+}
+
+bool TileObject2D::HasProperty(const String& name) const
+{
+    if (!propertySet_)
+        return false;
+    return propertySet_->HasProperty(name);
+}
+
+const String& TileObject2D::GetProperty(const String& name) const
+{
+    if (!propertySet_)
+        return String::EMPTY;
+    return propertySet_->GetProperty(name);
+}
+
+}

+ 163 - 0
Source/Engine/Urho2D/TileMapDefs2D.h

@@ -0,0 +1,163 @@
+//
+// Copyright (c) 2008-2014 the Urho3D project.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+
+#pragma once
+
+#include "RefCounted.h"
+#include "Sprite2D.h"
+
+namespace Urho3D
+{
+
+class XMLElement;
+
+/// Orientation.
+enum Orientation2D
+{
+    /// Orthogonal.
+    O_ORTHOGONAL = 0,
+    /// Isometric.
+    O_ISOMETRIC
+};
+
+/// Tile map layer type.
+enum TileMapLayerType2D
+{
+    /// Tile layer.
+    LT_TILE_LAYER = 0,
+    /// Object group.
+    LT_OBJECT_GROUP,
+    /// Image layer.
+    LT_IMAGE_LAYER,
+    /// Invalid.
+    LT_INVALID = 0xffff
+};
+
+/// Tile object type.
+enum TileObjectType2D
+{
+    /// Rectangle.
+    OT_RECTANGLE = 0,
+    /// Ellipse.
+    OT_ELLIPSE,
+    /// Polygon.
+    OT_POLYGON,
+    /// Polyline.
+    OT_POLYLINE,
+    /// Tile.
+    OT_TILE,
+    /// Invalid.
+    OT_INVALID = 0xffff
+};
+
+/// Property set.
+class URHO3D_API PropertySet2D : public RefCounted
+{
+public:
+    PropertySet2D();
+    virtual ~PropertySet2D();
+
+    /// Load from XML element.
+    void Load(const XMLElement& element);
+    /// Return has property.
+    bool HasProperty(const String& name) const;
+    /// Return property value.
+    const String& GetProperty(const String& name) const;
+
+protected:
+    /// Property name to property value mapping.
+    HashMap<String, String> nameToValueMapping_;
+};
+
+/// Tile define.
+class URHO3D_API Tile2D : public RefCounted
+{
+public:
+    /// Construct.
+    Tile2D();
+
+    /// Return gid.
+    int GetGid() const { return gid_; }
+    /// Return sprite.
+    Sprite2D* GetSprite() const;
+    /// Return has property.
+    bool HasProperty(const String& name) const;
+    /// Return property.
+    const String& GetProperty(const String& name) const;
+
+private:
+    friend class TmxTileLayer2D;
+
+    /// Gid.
+    int gid_;
+    /// Sprite.
+    SharedPtr<Sprite2D> sprite_;
+    /// Property set.
+    SharedPtr<PropertySet2D> propertySet_;
+};
+
+/// Tile map object.
+class URHO3D_API TileObject2D : public RefCounted
+{
+public:
+    TileObject2D();
+
+    /// Return type.
+    TileObjectType2D GetType() const { return type_; }
+    /// Return position.
+    const Vector2& GetPosition() const { return position_; }
+    /// Return size (for rectangle and ellipse).
+    const Vector2& GetSize() const { return size_; }
+    /// Return number of points (use for script).
+    unsigned GetNumPoints() const;
+    /// Return point at index (use for script).
+    const Vector2& GetPoint(unsigned index) const;
+    /// Return tile Gid.
+    int GetTileGid() const { return gid_; }
+    /// Return tile sprite.
+    Sprite2D* GetTileSprite() const;
+    /// Return has property.
+    bool HasProperty(const String& name) const;
+    /// Return property value.
+    const String& GetProperty(const String& name) const;
+
+private:
+    friend class TmxObjectGroup2D;
+
+    /// Object type.
+    TileObjectType2D type_;
+    /// Position.
+    Vector2 position_;
+    /// Size (for rectangle and ellipse).
+    Vector2 size_;
+    /// Points(for polygon and polyline).
+    Vector<Vector2> points_;
+    /// Gid (for tile).
+    int gid_;
+    /// Sprite (for tile).
+    SharedPtr<Sprite2D> sprite_;
+    /// Property set.
+    SharedPtr<PropertySet2D> propertySet_;
+};
+
+
+}

+ 315 - 0
Source/Engine/Urho2D/TileMapLayer2D.cpp

@@ -0,0 +1,315 @@
+//
+// Copyright (c) 2008-2014 the Urho3D project.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+
+#include "Precompiled.h"
+#include "Context.h"
+#include "Node.h"
+#include "ResourceCache.h"
+#include "StaticSprite2D.h"
+#include "TileMapLayer2D.h"
+#include "TileMapLayer2D.h"
+#include "TmxFile2D.h"
+
+#include "DebugNew.h"
+
+namespace Urho3D
+{
+
+TileMapLayer2D::TileMapLayer2D(Context* context) :
+    Component(context),
+    tmxLayer_(0),
+    drawOrder_(0),
+    visible_(true)
+{
+}
+
+TileMapLayer2D::~TileMapLayer2D()
+{
+}
+
+void TileMapLayer2D::RegisterObject(Context* context)
+{
+    context->RegisterFactory<TileMapLayer2D>();
+}
+
+void TileMapLayer2D::SetTmxLayer(const TmxLayer2D* tmxLayer)
+{
+    if (tmxLayer == tmxLayer_)
+        return;
+
+    if (tmxLayer_)
+    {
+        for (unsigned i = 0; i < nodes_.Size(); ++i)
+        {
+            if (nodes_[i])
+                nodes_[i]->Remove();
+        }
+
+        nodes_.Clear();
+    }
+
+    tileLayer_ = 0;
+    objectGroup_ = 0;
+    imageLayer_ = 0;
+    
+    tmxLayer_ = tmxLayer;
+    
+    if (!tmxLayer_)
+        return;
+
+    switch (tmxLayer_->GetType())
+    {
+    case LT_TILE_LAYER:
+        SetTileLayer((const TmxTileLayer2D*)tmxLayer_);
+        break;
+
+    case LT_OBJECT_GROUP:
+        SetObjectGroup((const TmxObjectGroup2D*)tmxLayer_);
+        break;
+
+    case LT_IMAGE_LAYER:
+        SetImageLayer((const TmxImageLayer2D*)tmxLayer_);
+        break;
+
+    default:
+        break;
+    }
+
+    SetVisible(tmxLayer_->IsVisible());
+}
+
+void TileMapLayer2D::SetDrawOrder(int drawOrder)
+{
+    if (drawOrder == drawOrder_)
+        return;
+
+    drawOrder_ = drawOrder;
+
+    for (unsigned i = 0; i < nodes_.Size(); ++i)
+    {
+        if (!nodes_[i])
+            continue;
+
+        StaticSprite2D* staticSprite = nodes_[i]->GetComponent<StaticSprite2D>();
+        if (staticSprite)
+            staticSprite->SetLayer(drawOrder_);
+    }
+}
+
+void TileMapLayer2D::SetVisible(bool visible)
+{
+    if (visible == visible_)
+        return;
+
+    visible_ = visible;
+
+    for (unsigned i = 0; i < nodes_.Size(); ++i)
+    {
+        if (nodes_[i])
+            nodes_[i]->SetEnabled(visible_);
+    }
+}
+
+bool TileMapLayer2D::HasProperty(const String& name) const
+{
+    if (!tmxLayer_)
+        return false;
+
+    return tmxLayer_->HasProperty(name);
+}
+
+const String& TileMapLayer2D::GetProperty(const String& name) const
+{
+    if (!tmxLayer_)
+        return String::EMPTY;
+    return tmxLayer_->GetProperty(name);
+}
+
+TileMapLayerType2D TileMapLayer2D::GetLayerType() const
+{
+    return tmxLayer_ ? tmxLayer_->GetType() : LT_INVALID;
+}
+
+int TileMapLayer2D::GetWidth() const
+{
+    return tmxLayer_ ? tmxLayer_->GetWidth(): 0;
+}
+
+int TileMapLayer2D::GetHeight() const
+{
+    return tmxLayer_ ? tmxLayer_->GetHeight(): 0;
+}
+
+Tile2D* TileMapLayer2D::GetTile(int x, int y) const
+{
+    if (!tileLayer_)
+        return 0;
+
+    return tileLayer_->GetTile(x, y);
+}
+
+Node* TileMapLayer2D::GetTileNode(int x, int y) const
+{
+    if (!tileLayer_)
+        return 0;
+    
+    if (x < 0 || x >= tileLayer_->GetWidth() || y < 0 || y >= tileLayer_->GetHeight())
+        return 0;
+    
+    return nodes_[y * tileLayer_->GetWidth() + x];
+}
+
+unsigned TileMapLayer2D::GetNumObjects() const
+{
+    if (!objectGroup_)
+        return 0;
+
+    return objectGroup_->GetNumObjects();
+}
+
+TileObject2D* TileMapLayer2D::GetObject(unsigned index) const
+{
+    if (objectGroup_)
+        return 0;
+
+    return objectGroup_->GetObject(index);
+}
+
+Node* TileMapLayer2D::GetObjectNode(unsigned index) const
+{
+    if (!objectGroup_)
+        return 0;
+
+    if (index >= nodes_.Size())
+        return 0;
+
+    return nodes_[index];
+}
+
+Node* TileMapLayer2D::GetImageNode() const
+{
+    if (!imageLayer_)
+        return 0;
+
+    if (nodes_.Empty())
+        return 0;
+
+    return nodes_[0];
+}
+
+void TileMapLayer2D::SetTileLayer(const TmxTileLayer2D* tileLayer)
+{
+    tileLayer_ = tileLayer;
+
+    int width = tileLayer->GetWidth();
+    int height = tileLayer->GetHeight();
+    nodes_.Resize(width * height);
+
+    TmxFile2D* tmxFile = tileLayer->GetTmxFile();
+    Orientation2D orientation = tmxFile->GetOrientation();
+
+    float scaleX = tmxFile->GetTileWidth();
+    float scaleY = tmxFile->GetTileHeight();
+    
+    if (orientation == O_ISOMETRIC)
+    {
+        scaleX *= 0.5f;
+        scaleY *= 0.5f;
+    }
+
+    for (int y = 0; y < height; ++y)
+    {
+        for (int x = 0; x < width; ++x)
+        {
+            const Tile2D* tile = tileLayer->GetTile(x, y);
+            if (!tile)
+                continue;
+
+            SharedPtr<Node> tileNode(GetNode()->CreateChild("Tile"));
+            tileNode->SetTemporary(true);
+            if (orientation == O_ORTHOGONAL)
+                tileNode->SetPosition(Vector3((x + 0.5f) * scaleX, (y + 0.5f) * scaleY, 0.0f));
+            else if (orientation == O_ISOMETRIC)
+                tileNode->SetPosition(Vector3(((x + y) + 0.5f) * scaleX, (height - (x - y) + 0.5f) * scaleY, 0.0f));
+
+            StaticSprite2D* staticSprite = tileNode->CreateComponent<StaticSprite2D>();
+            staticSprite->SetSprite(tile->GetSprite());
+            staticSprite->SetLayer(drawOrder_);
+            staticSprite->SetOrderInLayer((height - 1 - y) * width + x);
+
+            nodes_[y * width + x] = tileNode;
+        }
+    }
+}
+
+void TileMapLayer2D::SetObjectGroup(const TmxObjectGroup2D* objectGroup)
+{
+    objectGroup_ = objectGroup;
+
+    TmxFile2D* tmxFile = objectGroup->GetTmxFile();
+    nodes_.Resize(objectGroup->GetNumObjects());
+
+    for (unsigned i = 0; i < objectGroup->GetNumObjects(); ++i)
+    {
+        const TileObject2D* object = objectGroup->GetObject(i);
+
+        // Create dummy node for all object
+        SharedPtr<Node> objectNode(GetNode()->CreateChild("Object"));
+        objectNode->SetTemporary(true);
+        objectNode->SetPosition(object->GetPosition());
+
+        // If object is tile, create static sprite component
+        if (object->GetType() == OT_TILE && object->GetTileGid() && object->GetTileSprite())
+        {
+            StaticSprite2D* staticSprite = objectNode->CreateComponent<StaticSprite2D>();
+            staticSprite->SetSprite(object->GetTileSprite());
+            staticSprite->SetLayer(drawOrder_);
+            staticSprite->SetOrderInLayer((int)((10.0f - object->GetPosition().y_) * 100));
+        }
+
+        nodes_[i] = objectNode;
+    }
+}
+
+void TileMapLayer2D::SetImageLayer(const TmxImageLayer2D* imageLayer)
+{
+    imageLayer_ = imageLayer;
+
+    if (!imageLayer->GetSprite())
+        return;
+
+    TmxFile2D* tmxFile = imageLayer->GetTmxFile();
+    int height = tmxFile->GetHeight();
+    float tileHeight = tmxFile->GetTileHeight();
+
+    SharedPtr<Node> imageNode(GetNode()->CreateChild("Tile"));
+    imageNode->SetTemporary(true);
+    imageNode->SetPosition(Vector3(0.0f, height * tileHeight, 0.0f));
+
+    StaticSprite2D* staticSprite = imageNode->CreateComponent<StaticSprite2D>();
+    staticSprite->SetSprite(imageLayer->GetSprite());
+    staticSprite->SetOrderInLayer(0);
+
+    nodes_.Push(imageNode);
+}
+
+}

+ 113 - 0
Source/Engine/Urho2D/TileMapLayer2D.h

@@ -0,0 +1,113 @@
+//
+// Copyright (c) 2008-2014 the Urho3D project.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+
+#pragma once
+
+#include "Component.h"
+#include "TileMapDefs2D.h"
+
+namespace Urho3D
+{
+
+class Node;
+class TmxImageLayer2D;
+class TmxLayer2D;
+class TmxObjectGroup2D;
+class TmxTileLayer2D;
+
+/// Tile map component.
+class URHO3D_API TileMapLayer2D : public Component
+{
+    OBJECT(TileMapLayer2D);
+
+public:
+    /// Construct.
+    TileMapLayer2D(Context* context);
+    /// Destruct.
+    ~TileMapLayer2D();
+    /// Register object factory.
+    static void RegisterObject(Context* context);
+
+    /// Set tmx layer.
+    void SetTmxLayer(const TmxLayer2D* tmxLayer);
+    /// Set draw order
+    void SetDrawOrder(int drawOrder);
+    /// Set visible.
+    void SetVisible(bool visible);
+
+    /// Return tmx layer.
+    const TmxLayer2D* GetTmxLayer() const { return tmxLayer_; }
+    /// Return draw order.
+    int GetDrawOrder() const { return drawOrder_; }
+    /// Return visible.
+    bool IsVisible() const { return visible_; }
+    /// Return has property
+    bool HasProperty(const String& name) const;
+    /// Return property.
+    const String& GetProperty(const String& name) const;
+    /// Return layer type.
+    TileMapLayerType2D GetLayerType() const;
+
+    /// Return width (for tile layer only).
+    int GetWidth() const;
+    /// Return height (for tile layer only).
+    int GetHeight() const;
+    /// Return tile node (for tile layer only).
+    Node* GetTileNode(int x, int y) const;
+    /// Return tile (for tile layer only).
+    Tile2D* GetTile(int x, int y) const;
+
+    /// Return number of objects (for object group only).
+    unsigned GetNumObjects() const;
+    /// Return object (for object group only).
+    TileObject2D* GetObject(unsigned index) const;
+    /// Return object node (for object group only).
+    Node* GetObjectNode(unsigned index) const;
+    
+    /// Return image node (for image layer only).
+    Node* GetImageNode() const;
+
+private:
+    /// Set tile layer.
+    void SetTileLayer(const TmxTileLayer2D* tileLayer);
+    /// Set object group.
+    void SetObjectGroup(const TmxObjectGroup2D* objectGroup);
+    /// Set image layer.
+    void SetImageLayer(const TmxImageLayer2D* imageLayer);
+
+    /// Tmx layer.
+    const TmxLayer2D* tmxLayer_;
+    /// Tile layer.
+    const TmxTileLayer2D* tileLayer_;
+    /// Object group.
+    const TmxObjectGroup2D* objectGroup_;
+    /// Image layer.
+    const TmxImageLayer2D* imageLayer_;
+    /// Draw order.
+    int drawOrder_;
+    /// Visible.
+    bool visible_;
+    /// Tile node or image nodes.
+    Vector<SharedPtr<Node> > nodes_;
+};
+
+}

+ 524 - 0
Source/Engine/Urho2D/TmxFile2D.cpp

@@ -0,0 +1,524 @@
+//
+// Copyright (c) 2008-2014 the Urho3D project.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+
+#include "Precompiled.h"
+#include "Context.h"
+#include "FileSystem.h"
+#include "Log.h"
+#include "ResourceCache.h"
+#include "Sprite2D.h"
+#include "Texture2D.h"
+#include "TmxFile2D.h"
+#include "XMLFile.h"
+
+#include "DebugNew.h"
+
+namespace Urho3D
+{
+
+extern const float PIXEL_SIZE;
+
+TmxLayer2D::TmxLayer2D(TmxFile2D* tmxFile, TileMapLayerType2D type) :
+    tmxFile_(tmxFile),
+    type_(type)
+{
+
+}
+
+TmxLayer2D::~TmxLayer2D()
+{
+}
+
+TmxFile2D* TmxLayer2D::GetTmxFile() const
+{
+    return tmxFile_;
+}
+
+bool TmxLayer2D::HasProperty(const String& name) const
+{
+    if (!propertySet_)
+        return false;
+    return propertySet_->HasProperty(name);
+}
+
+const String& TmxLayer2D::GetProperty(const String& name) const
+{
+    if (!propertySet_)
+        return String::EMPTY;
+    return propertySet_->GetProperty(name);
+}
+
+void TmxLayer2D::LoadInfo(const XMLElement& element)
+{
+    name_ = element.GetAttribute("name");
+    width_ = element.GetInt("width");
+    height_ = element.GetInt("height");
+    if (element.HasAttribute("visible"))
+        visible_ = element.GetInt("visible") != 0;
+    else
+        visible_ = true;
+}
+
+void TmxLayer2D::LoadPropertySet(const XMLElement& element)
+{
+    propertySet_ = new PropertySet2D();
+    propertySet_->Load(element);
+}
+
+TmxTileLayer2D::TmxTileLayer2D(TmxFile2D* tmxFile) :
+    TmxLayer2D(tmxFile, LT_TILE_LAYER)
+{
+}
+
+bool TmxTileLayer2D::Load(const XMLElement& element)
+{
+    LoadInfo(element);
+
+    XMLElement dataElem = element.GetChild("data");
+    if (!dataElem)
+    {
+        LOGERROR("Could not find data in layer");
+        return false;
+    }
+
+    if (dataElem.HasAttribute("encoding") && dataElem.GetAttribute("encoding") != "xml")
+    {
+        LOGERROR("Encoding not support now");
+        return false;
+    }
+
+    XMLElement tileElem = dataElem.GetChild("tile");
+    tiles_.Resize(width_ * height_);
+
+    // Flip y
+    for (int y = height_ - 1; y >= 0; --y)
+    {
+        for (int x = 0; x < width_; ++x)
+        {
+            if (!tileElem)
+                return false;
+
+            int gid = tileElem.GetInt("gid");
+            if (gid > 0)
+            {
+                SharedPtr<Tile2D> tile(new Tile2D());
+                tile->gid_ = gid;
+                tile->sprite_ = tmxFile_->GetTileSprite(gid);
+                tile->propertySet_ = tmxFile_->GetTilePropertySet(gid);
+                tiles_[y * width_ + x] = tile;
+            }
+
+            tileElem = tileElem.GetNext("tile");
+        }
+    }
+
+    if (element.HasChild("properties"))
+        LoadPropertySet(element.GetChild("properties"));
+    
+    return true;
+}
+
+Tile2D* TmxTileLayer2D::GetTile(int x, int y) const
+{
+    if (x < 0 || x > width_ || y < 0 || y > height_)
+        return 0;
+
+    return tiles_[y * width_ + x];
+}
+
+TmxObjectGroup2D::TmxObjectGroup2D(TmxFile2D* tmxFile) :
+    TmxLayer2D(tmxFile, LT_OBJECT_GROUP)
+{
+}
+
+bool TmxObjectGroup2D::Load(const XMLElement& element)
+{
+    LoadInfo(element);
+   
+    const float mapHeight = height_ * tmxFile_->GetTileHeight();
+
+    for (XMLElement objectElem = element.GetChild("object"); objectElem; objectElem = objectElem.GetNext("object"))
+    {
+        SharedPtr<TileObject2D> object(new TileObject2D());
+        
+        object->position_ = Vector2(objectElem.GetInt("x") * PIXEL_SIZE, mapHeight - objectElem.GetInt("y") * PIXEL_SIZE);
+        if (objectElem.HasAttribute("width") || objectElem.HasAttribute("height"))
+        {
+            if (!objectElem.HasChild("ellipse"))
+                object->type_ = OT_RECTANGLE;
+            else
+                object->type_ = OT_ELLIPSE;
+
+            object->size_ = Vector2(objectElem.GetInt("width") * PIXEL_SIZE, objectElem.GetInt("height") * PIXEL_SIZE);
+            object->position_.y_ -= object->size_.y_;
+        }
+        else if (objectElem.HasAttribute("gid"))
+        {
+            object->type_ = OT_TILE;
+            object->gid_ = objectElem.GetInt("gid");
+            object->sprite_ = tmxFile_->GetTileSprite(object->gid_);
+        }
+        else
+        {
+            XMLElement childElem = objectElem.GetChild();
+            if (childElem.GetName() == "polygon")
+                object->type_ = OT_POLYGON;
+            else if (childElem.GetName() == "polyline")
+                object->type_ = OT_POLYLINE;
+            else
+                return false;
+
+            Vector<String> points = childElem.GetAttribute("points").Split(' ');
+            object->points_.Resize(points.Size());
+
+            for (unsigned i = 0; i < points.Size(); ++i)
+            {
+                points[i].Replace(',', ' ');
+                Vector2 point = ToVector2(points[i]) * PIXEL_SIZE;
+                point.y_ = mapHeight - point.y_;
+                object->points_[i] = point;
+            }
+        }
+
+        if (objectElem.HasChild("properties"))
+        {
+            object->propertySet_ = new PropertySet2D();
+            object->propertySet_->Load(objectElem.GetChild("properties"));
+        }
+
+        objects_.Push(object);
+    }
+
+    if (element.HasChild("properties"))
+        LoadPropertySet(element.GetChild("properties"));
+
+    return true;
+}
+
+TileObject2D* TmxObjectGroup2D::GetObject(unsigned index) const
+{
+    if (index >= objects_.Size())
+        return 0;
+    return objects_[index];
+}
+
+
+TmxImageLayer2D::TmxImageLayer2D(TmxFile2D* tmxFile) :
+    TmxLayer2D(tmxFile, LT_IMAGE_LAYER)
+{
+}
+
+bool TmxImageLayer2D::Load(const XMLElement& element)
+{
+    LoadInfo(element);
+
+    XMLElement imageElem = element.GetChild("image");
+    if (!imageElem)
+        return false;
+
+    source_ = imageElem.GetAttribute("source");
+    String textureFilePath = GetParentPath(GetName()) + source_;
+    ResourceCache* cache = tmxFile_->GetSubsystem<ResourceCache>();
+    SharedPtr<Texture2D> texture(cache->GetResource<Texture2D>(textureFilePath));
+    if (!texture)
+    {
+        LOGERROR("Could not load texture " + textureFilePath);
+        return false;
+    }
+
+    sprite_ = new Sprite2D(tmxFile_->GetContext());
+    sprite_->SetTexture(texture);
+    sprite_->SetRectangle(IntRect(0, 0, texture->GetWidth(), texture->GetHeight()));
+    // Left top
+    sprite_->SetHotSpot(Vector2(0.0f, 1.0f));
+
+    if (element.HasChild("properties"))
+        LoadPropertySet(element.GetChild("properties"));
+
+    return true;
+}
+
+Sprite2D* TmxImageLayer2D::GetSprite() const
+{
+    return sprite_;
+}
+
+TmxFile2D::TmxFile2D(Context* context) :
+    Resource(context),
+    width_(0),
+    height_(0),
+    tileWidth_(0.0f),
+    tileHeight_(0.0f)
+{
+}
+
+TmxFile2D::~TmxFile2D()
+{
+    for (unsigned i = 0; i < layers_.Size(); ++i)
+        delete layers_[i];
+}
+
+void TmxFile2D::RegisterObject(Context* context)
+{
+    context->RegisterFactory<TmxFile2D>();
+}
+
+bool TmxFile2D::BeginLoad(Deserializer& source)
+{
+    loadXMLFile_ = new XMLFile(context_);
+    if (!loadXMLFile_->Load(source))
+    {
+        LOGERROR("Load XML failed " + source.GetName());
+        loadXMLFile_.Reset();
+        return false;
+    }
+
+    XMLElement rootElem = loadXMLFile_->GetRoot("map");
+    if (!rootElem)
+    {
+        LOGERROR("Invalid tmx file " + source.GetName());
+        loadXMLFile_.Reset();
+        return false;
+    }
+
+    // If we're async loading, request the texture now. Finish during EndLoad().
+    if (GetAsyncLoadState() == ASYNC_LOADING)
+    {
+        for (XMLElement tileSetElem = rootElem.GetChild("tileset"); tileSetElem; tileSetElem = tileSetElem.GetNext("tileset"))
+        {
+            // Tile set defined in TSX file
+            if (tileSetElem.HasAttribute("source"))
+            {
+                String source = tileSetElem.GetAttribute("source");
+                SharedPtr<XMLFile> tsxXMLFile = LoadTSXFile(source);
+                if (!tsxXMLFile)
+                    return false;
+
+                tsxXMLFiles_[source] = tsxXMLFile;
+                
+                String textureFilePath = GetParentPath(GetName()) + tsxXMLFile->GetRoot("tileset").GetChild("image").GetAttribute("source");
+                GetSubsystem<ResourceCache>()->BackgroundLoadResource<Texture2D>(textureFilePath, true, this);
+            }
+            else
+            {
+                String textureFilePath = GetParentPath(GetName()) + tileSetElem.GetChild("image").GetAttribute("source");
+                GetSubsystem<ResourceCache>()->BackgroundLoadResource<Texture2D>(textureFilePath, true, this);
+            }
+        }
+
+        for (XMLElement imageLayerElem = rootElem.GetChild("imagelayer"); imageLayerElem; imageLayerElem = imageLayerElem.GetNext("imagelayer"))
+        {
+            String textureFilePath = GetParentPath(GetName()) + imageLayerElem.GetChild("image").GetAttribute("source");
+            GetSubsystem<ResourceCache>()->BackgroundLoadResource<Texture2D>(textureFilePath, true, this);
+        }
+    }
+
+    return true;
+}
+
+bool TmxFile2D::EndLoad()
+{
+    if (!loadXMLFile_)
+        return false;
+
+    XMLElement rootElem = loadXMLFile_->GetRoot("map");
+    String version = rootElem.GetAttribute("version");
+    if (version != "1.0")
+    {
+        LOGERROR("Invalid version");
+        return false;
+    }
+
+    String orientation = rootElem.GetAttribute("orientation");
+    if (orientation == "orthogonal")
+        orientation_ = O_ORTHOGONAL;
+    else if (orientation == "isometric")
+        orientation_ = O_ISOMETRIC;
+    else
+    {
+        LOGERROR("Invalid orientation type " + orientation);
+        return false;
+    }
+
+    width_ = rootElem.GetInt("width");
+    height_ = rootElem.GetInt("height");
+    tileWidth_ = rootElem.GetFloat("tilewidth") * PIXEL_SIZE;
+    tileHeight_ = rootElem.GetFloat("tileheight") * PIXEL_SIZE;
+
+    for (unsigned i = 0; i < layers_.Size(); ++i)
+        delete layers_[i];
+    layers_.Clear();
+
+    for (XMLElement childElement = rootElem.GetChild(); childElement; childElement = childElement.GetNext())
+    {
+        bool ret = true;
+        String name = childElement.GetName();
+        if (name == "tileset")
+            ret = LoadTileSet(childElement);
+        else if (name == "layer")
+        {
+            TmxTileLayer2D* tileLayer = new TmxTileLayer2D(this);
+            ret = tileLayer->Load(childElement);
+            
+            layers_.Push(tileLayer);
+        }
+        else if (name == "objectgroup")
+        {
+            TmxObjectGroup2D* objectGroup = new TmxObjectGroup2D(this);
+            ret = objectGroup->Load(childElement);
+            
+            layers_.Push(objectGroup);
+
+        }
+        else if (name == "imagelayer")
+        {
+            TmxImageLayer2D* imageLayer = new TmxImageLayer2D(this);
+            ret = imageLayer->Load(childElement);
+
+            layers_.Push(imageLayer);
+        }
+
+        if (!ret)
+        {
+            loadXMLFile_.Reset();
+            tsxXMLFiles_.Clear();
+            return false;
+        }
+    }
+   
+    loadXMLFile_.Reset();
+    tsxXMLFiles_.Clear();
+    return true;
+}
+
+Sprite2D* TmxFile2D::GetTileSprite(int gid) const
+{
+    HashMap<int, SharedPtr<Sprite2D> >::ConstIterator i = gidToSpriteMapping_.Find(gid);
+    if (i == gidToSpriteMapping_.End())
+        return 0;
+
+    return i->second_;
+}
+
+PropertySet2D* TmxFile2D::GetTilePropertySet(int gid) const
+{
+    HashMap<int, SharedPtr<PropertySet2D> >::ConstIterator i = gidToPropertySetMapping_.Find(gid);
+    if (i == gidToPropertySetMapping_.End())
+        return 0;
+    return i->second_;
+}
+
+const TmxLayer2D* TmxFile2D::GetLayer(unsigned index) const
+{
+    if (index >= layers_.Size())
+        return 0;
+
+    return layers_[index];
+}
+
+
+SharedPtr<XMLFile> TmxFile2D::LoadTSXFile(const String& source)
+{
+    String tsxFilePath = GetParentPath(GetName()) + source;
+    SharedPtr<File> tsxFile = GetSubsystem<ResourceCache>()->GetFile(tsxFilePath);
+    SharedPtr<XMLFile> tsxXMLFile(new XMLFile(context_));
+    if (!tsxFile || !tsxXMLFile->Load(*tsxFile))
+    {
+        LOGERROR("Load TSX file failed " + tsxFilePath);
+        return SharedPtr<XMLFile>();
+    }
+
+    return tsxXMLFile;
+}
+
+bool TmxFile2D::LoadTileSet(const XMLElement& element)
+{
+    int firstgid = element.GetInt("firstgid"); 
+    
+    XMLElement tileSetElem;
+    if (element.HasAttribute("source"))
+    {
+        String source = element.GetAttribute("source");
+        HashMap<String, SharedPtr<XMLFile> >::Iterator i = tsxXMLFiles_.Find(source);
+        if (i == tsxXMLFiles_.End())
+        {
+            SharedPtr<XMLFile> tsxXMLFile = LoadTSXFile(source);
+            if (!tsxXMLFile)
+                return false;
+
+            // Add to napping to avoid release
+            tsxXMLFiles_[source] = tsxXMLFile;
+
+            tileSetElem = tsxXMLFile->GetRoot("tileset");
+        }
+        else
+            tileSetElem = i->second_->GetRoot("tileset");
+    }
+    else
+        tileSetElem = element;
+    
+    XMLElement imageElem = tileSetElem.GetChild("image");
+    String textureFilePath = GetParentPath(GetName()) + imageElem.GetAttribute("source");
+    ResourceCache* cache = GetSubsystem<ResourceCache>();
+    SharedPtr<Texture2D> texture(cache->GetResource<Texture2D>(textureFilePath));
+    if (!texture)
+    {
+        LOGERROR("Could not load texture " + textureFilePath);
+        return false;
+    }
+
+    tileSetTextures_.Push(texture);
+
+    int tileWidth = tileSetElem.GetInt("tilewidth");
+    int tileHeight = tileSetElem.GetInt("tileheight");
+    int spacing = tileSetElem.GetInt("spacing");
+    int margin = tileSetElem.GetInt("margin");
+    int imageWidth = imageElem.GetInt("width");
+    int imageHeight = imageElem.GetInt("height");
+
+    int gid = firstgid;
+    for (int y = margin; y < imageHeight - margin; y += tileHeight + spacing)
+    {
+        for (int x = margin; x < imageWidth - margin; x += tileWidth + spacing)
+        {
+            SharedPtr<Sprite2D> sprite(new Sprite2D(context_));
+            sprite->SetTexture(texture);
+            sprite->SetRectangle(IntRect(x, y, x + tileWidth, y + tileHeight));
+            
+            gidToSpriteMapping_[gid++] = sprite;
+        }
+    }
+
+    for (XMLElement tileElem = tileSetElem.GetChild("tile"); tileElem; tileElem = tileElem.GetNext("tile"))
+    {
+        if (tileElem.HasChild("properties"))
+        {
+            SharedPtr<PropertySet2D> propertySet(new PropertySet2D());
+            propertySet->Load(tileElem.GetChild("properties"));
+            gidToPropertySetMapping_[firstgid + tileElem.GetInt("id")] = propertySet;
+        }
+    }
+
+    return true;
+}
+
+}

+ 206 - 0
Source/Engine/Urho2D/TmxFile2D.h

@@ -0,0 +1,206 @@
+//
+// Copyright (c) 2008-2014 the Urho3D project.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+
+#pragma once
+
+#include "Resource.h"
+#include "TileMapDefs2D.h"
+
+namespace Urho3D
+{
+
+class Sprite2D;
+class Texture2D;
+class TmxFile2D;
+class XMLElement;
+class XMLFile;
+
+/// Tmx layer.
+class TmxLayer2D : public RefCounted
+{
+public:
+    TmxLayer2D(TmxFile2D* tmxFile, TileMapLayerType2D type);
+    virtual ~TmxLayer2D();
+
+    /// Return tmx file.
+    TmxFile2D* GetTmxFile() const;
+    /// Return type.
+    TileMapLayerType2D GetType() const { return type_; }
+    /// Return name.
+    const String& GetName() const { return name_; }
+    /// Return width.
+    int GetWidth() const { return width_; }
+    /// Return height.
+    int GetHeight() const { return height_; }
+    /// Return is visible.
+    bool IsVisible() const { return visible_; }
+    /// Return has property (use for script).
+    bool HasProperty(const String& name) const;
+    /// Return property value (use for script).
+    const String& GetProperty(const String& name) const;
+
+
+protected:
+    /// Load layer info.
+    void LoadInfo(const XMLElement& element);
+    /// Load property set.
+    void LoadPropertySet(const XMLElement& element);
+
+    /// Tmx file.
+    WeakPtr<TmxFile2D> tmxFile_;
+    /// Layer type.
+    TileMapLayerType2D type_;
+    /// Name.
+    String name_;
+    /// Width.
+    int width_;
+    /// Height.
+    int height_;
+    /// Visible.
+    bool visible_;
+    /// Property set.
+    SharedPtr<PropertySet2D> propertySet_;
+};
+
+/// Tmx tile layer.
+class TmxTileLayer2D : public TmxLayer2D
+{
+public:
+    TmxTileLayer2D(TmxFile2D* tmxFile);
+
+    /// Load from XML element.
+    bool Load(const XMLElement& element);
+    /// Return tile.
+    Tile2D* GetTile(int x, int y) const;
+
+protected:
+    /// Tile.
+    Vector<SharedPtr<Tile2D> > tiles_;
+};
+
+/// Tmx image layer.
+class TmxObjectGroup2D : public TmxLayer2D
+{
+public:
+    TmxObjectGroup2D(TmxFile2D* tmxFile);
+
+    /// Load from XML element.
+    bool Load(const XMLElement& element);
+    /// Return number of objects.
+    unsigned GetNumObjects() const { return objects_.Size(); }
+    /// Return object at index.
+    TileObject2D* GetObject(unsigned index) const;
+
+private:
+    /// Objects.
+    Vector<SharedPtr<TileObject2D> > objects_;
+};
+
+/// Tmx image layer.
+class TmxImageLayer2D : public TmxLayer2D
+{
+public:
+    TmxImageLayer2D(TmxFile2D* tmxFile);
+
+    /// Load from XML element.
+    bool Load(const XMLElement& element);
+    /// Return source.
+    const String& GetSource() const { return source_; }
+    /// Return sprite.
+    Sprite2D* GetSprite() const;
+    
+private:
+    /// Source.
+    String source_;
+    /// Sprite.
+    SharedPtr<Sprite2D> sprite_;
+};
+
+/// Tile map file.
+class URHO3D_API TmxFile2D : public Resource
+{
+    OBJECT(TmxFile2D);
+
+public:
+    /// Construct.
+    TmxFile2D(Context* context);
+    /// Destruct.
+    virtual ~TmxFile2D();
+    /// Register object factory. 
+    static void RegisterObject(Context* context);
+
+    /// Load resource from stream. May be called from a worker thread. Return true if successful.
+    virtual bool BeginLoad(Deserializer& source);
+    /// Finish resource loading. Always called from the main thread. Return true if successful.
+    virtual bool EndLoad();
+
+    /// Return orientation.
+    Orientation2D GetOrientation() const { return orientation_; }
+    /// Return width in tiles.
+    int GetWidth() const { return width_; }
+    /// Return height in tiles.
+    int GetHeight() const { return height_; }
+    /// Return tile width.
+    float GetTileWidth() const { return tileWidth_; }
+    /// Return tile height.
+    float GetTileHeight() const { return tileHeight_; }
+    /// Return tile sprite by gid, if not exist return 0.
+    Sprite2D* GetTileSprite(int gid) const;
+    /// Return tile property set by gid, if not exist return 0.
+    PropertySet2D* GetTilePropertySet(int gid) const;
+    /// Return number of layers.
+    unsigned GetNumLayers() const { return layers_.Size(); }
+    /// Return layer at index.
+    const TmxLayer2D* GetLayer(unsigned index) const;
+
+private:
+    /// Load TSX file.
+    SharedPtr<XMLFile> LoadTSXFile(const String& source);
+    /// Load tile set.
+    bool LoadTileSet(const XMLElement& element);
+    
+    /// XML file used during loading.
+    SharedPtr<XMLFile> loadXMLFile_;
+    /// TSX name to XML file mapping.
+    HashMap<String, SharedPtr<XMLFile> > tsxXMLFiles_;
+    /// Orientation type.
+    Orientation2D orientation_;
+    /// Width.
+    int width_;
+    /// Height.
+    int height_;
+    /// Tile width.
+    float tileWidth_;
+    /// Tile height.
+    float tileHeight_;
+    /// Tile set textures.
+    Vector<SharedPtr<Texture2D> > tileSetTextures_;
+    /// Gid to tile sprite mapping.
+    HashMap<int, SharedPtr<Sprite2D> > gidToSpriteMapping_;
+    /// Gid to tile property set mapping.
+    HashMap<int, SharedPtr<PropertySet2D> > gidToPropertySetMapping_;
+    /// Layers.
+    Vector<TmxLayer2D*> layers_;
+};
+
+}
+

+ 7 - 0
Source/Engine/Urho2D/Urho2D.cpp

@@ -52,6 +52,9 @@
 #include "Sprite2D.h"
 #include "SpriteSheet2D.h"
 #include "StaticSprite2D.h"
+#include "TileMap2D.h"
+#include "TileMapLayer2D.h"
+#include "TmxFile2D.h"
 
 #include "DebugNew.h"
 
@@ -78,6 +81,10 @@ void RegisterUrho2DLibrary(Context* context)
     ParticleEffect2D::RegisterObject(context);
     ParticleEmitter2D::RegisterObject(context);
 
+    TmxFile2D::RegisterObject(context);
+    TileMap2D::RegisterObject(context);
+    TileMapLayer2D::RegisterObject(context);
+
     PhysicsWorld2D::RegisterObject(context);
     RigidBody2D::RegisterObject(context);
 

+ 33 - 0
Source/Samples/36_Urho2DTileMap/CMakeLists.txt

@@ -0,0 +1,33 @@
+#
+# Copyright (c) 2008-2014 the Urho3D project.
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+#
+
+# Define target name
+set (TARGET_NAME 36_Urho2DTileMap)
+
+# Define source files
+define_source_files (EXTRA_H_FILES ${COMMON_SAMPLE_H_FILES})
+
+# Setup target with resource copying
+setup_main_executable ()
+
+# Setup test cases
+add_test (NAME ${TARGET_NAME} COMMAND ${TARGET_NAME} -timeout ${URHO3D_TEST_TIME_OUT})

+ 183 - 0
Source/Samples/36_Urho2DTileMap/Urho2DTileMap.cpp

@@ -0,0 +1,183 @@
+//
+// Copyright (c) 2008-2014 the Urho3D project.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+
+#include "Camera.h"
+#include "CoreEvents.h"
+#include "Engine.h"
+#include "Font.h"
+#include "Graphics.h"
+#include "Input.h"
+#include "Octree.h"
+#include "Renderer.h"
+#include "ResourceCache.h"
+#include "Scene.h"
+#include "Text.h"
+#include "Urho2DTileMap.h"
+#include "Zone.h"
+#include "TmxFile2D.h"
+#include "TileMap2D.h"
+#include "Drawable2D.h"
+
+#include "DebugNew.h"
+
+// Number of static sprites to draw
+static const StringHash VAR_MOVESPEED("MoveSpeed");
+static const StringHash VAR_ROTATESPEED("RotateSpeed");
+
+DEFINE_APPLICATION_MAIN(Urho2DTileMap)
+
+Urho2DTileMap::Urho2DTileMap(Context* context) :
+    Sample(context)
+{
+}
+
+void Urho2DTileMap::Start()
+{
+    // Execute base class startup
+    Sample::Start();
+
+    // Create the scene content
+    CreateScene();
+
+    // Create the UI content
+    CreateInstructions();
+
+    // Setup the viewport for displaying the scene
+    SetupViewport();
+
+    // Hook up to the frame update events
+    SubscribeToEvents();
+}
+
+void Urho2DTileMap::CreateScene()
+{
+    scene_ = new Scene(context_);
+    scene_->CreateComponent<Octree>();
+
+    // Create camera node
+    cameraNode_ = scene_->CreateChild("Camera");
+    // Set camera's position
+    cameraNode_->SetPosition(Vector3(0.0f, 0.0f, -10.0f));
+
+    Camera* camera = cameraNode_->CreateComponent<Camera>();
+    camera->SetOrthographic(true);
+
+    Graphics* graphics = GetSubsystem<Graphics>();
+    camera->SetOrthoSize((float)graphics->GetHeight() * PIXEL_SIZE);
+
+    ResourceCache* cache = GetSubsystem<ResourceCache>();
+    // Get tmx file
+    TmxFile2D* tmxFile = cache->GetResource<TmxFile2D>("Urho2D/isometric_grass_and_water.tmx");
+    if (!tmxFile)
+        return;
+
+    SharedPtr<Node> tileMapNode(scene_->CreateChild("TileMap"));
+    tileMapNode->SetPosition(Vector3(0.0f, 0.0f, -1.0f));
+
+    TileMap2D* tileMap = tileMapNode->CreateComponent<TileMap2D>();
+    // Set animation
+    tileMap->SetTmxFile(tmxFile);
+
+    // Set camera's position
+    float x = tileMap->GetWidth() * tileMap->GetTileWidth() * 0.5f;
+    float y = tileMap->GetHeight() * tileMap->GetTileHeight() * 0.5f;
+    cameraNode_->SetPosition(Vector3(x, y, -10.0f));
+}
+
+void Urho2DTileMap::CreateInstructions()
+{
+    ResourceCache* cache = GetSubsystem<ResourceCache>();
+    UI* ui = GetSubsystem<UI>();
+
+    // Construct new Text object, set string to display and font to use
+    Text* instructionText = ui->GetRoot()->CreateChild<Text>();
+    instructionText->SetText("Use WASD keys to move, use PageUp PageDown keys to zoom.");
+    instructionText->SetFont(cache->GetResource<Font>("Fonts/Anonymous Pro.ttf"), 15);
+
+    // Position the text relative to the screen center
+    instructionText->SetHorizontalAlignment(HA_CENTER);
+    instructionText->SetVerticalAlignment(VA_CENTER);
+    instructionText->SetPosition(0, ui->GetRoot()->GetHeight() / 4);
+}
+
+void Urho2DTileMap::SetupViewport()
+{
+    Renderer* renderer = GetSubsystem<Renderer>();
+
+    // Set up a viewport to the Renderer subsystem so that the 3D scene can be seen
+    SharedPtr<Viewport> viewport(new Viewport(context_, scene_, cameraNode_->GetComponent<Camera>()));
+    renderer->SetViewport(0, viewport);
+}
+
+void Urho2DTileMap::MoveCamera(float timeStep)
+{
+    // Do not move if the UI has a focused element (the console)
+    if (GetSubsystem<UI>()->GetFocusElement())
+        return;
+
+    Input* input = GetSubsystem<Input>();
+
+    // Movement speed as world units per second
+    const float MOVE_SPEED = 4.0f;
+
+    // Read WASD keys and move the camera scene node to the corresponding direction if they are pressed
+    if (input->GetKeyDown('W'))
+        cameraNode_->Translate(Vector3::UP * MOVE_SPEED * timeStep);
+    if (input->GetKeyDown('S'))
+        cameraNode_->Translate(Vector3::DOWN * MOVE_SPEED * timeStep);
+    if (input->GetKeyDown('A'))
+        cameraNode_->Translate(Vector3::LEFT * MOVE_SPEED * timeStep);
+    if (input->GetKeyDown('D'))
+        cameraNode_->Translate(Vector3::RIGHT * MOVE_SPEED * timeStep);
+
+    if (input->GetKeyDown(KEY_PAGEUP))
+    {
+        Camera* camera = cameraNode_->GetComponent<Camera>();
+        camera->SetZoom(camera->GetZoom() * 1.01f);
+    }
+
+    if (input->GetKeyDown(KEY_PAGEDOWN))
+    {
+        Camera* camera = cameraNode_->GetComponent<Camera>();
+        camera->SetZoom(camera->GetZoom() * 0.99f);
+    }
+}
+
+void Urho2DTileMap::SubscribeToEvents()
+{
+    // Subscribe HandleUpdate() function for processing update events
+    SubscribeToEvent(E_UPDATE, HANDLER(Urho2DTileMap, HandleUpdate));
+
+    // Unsubscribe the SceneUpdate event from base class to prevent camera pitch and yaw in 2D sample
+    UnsubscribeFromEvent(E_SCENEUPDATE);
+}
+
+void Urho2DTileMap::HandleUpdate(StringHash eventType, VariantMap& eventData)
+{
+    using namespace Update;
+
+    // Take the frame time step, which is stored as a float
+    float timeStep = eventData[P_TIMESTEP].GetFloat();
+
+    // Move the camera, scale movement with time step
+    MoveCamera(timeStep);
+}

+ 85 - 0
Source/Samples/36_Urho2DTileMap/Urho2DTileMap.h

@@ -0,0 +1,85 @@
+//
+// Copyright (c) 2008-2014 the Urho3D project.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+
+#pragma once
+
+#include "Sample.h"
+
+namespace Urho3D
+{
+    class Node;
+    class Scene;
+}
+
+/// Urho2D tile map example.
+/// This sample demonstrates:
+///     - Creating a 2D scene with tile map
+///     - Displaying the scene using the Renderer subsystem
+///     - Handling keyboard to move and zoom 2D camera
+class Urho2DTileMap : public Sample
+{
+    OBJECT(Urho2DTileMap);
+
+public:
+    /// Construct.
+    Urho2DTileMap(Context* context);
+
+    /// Setup after engine initialization and before running the main loop.
+    virtual void Start();
+
+protected:
+    /// Return XML patch instructions for screen joystick layout for a specific sample app, if any.
+    virtual String GetScreenJoystickPatchString() const { return
+        "<patch>"
+        "    <remove sel=\"/element/element[./attribute[@name='Name' and @value='Button0']]/attribute[@name='Is Visible']\" />"
+        "    <replace sel=\"/element/element[./attribute[@name='Name' and @value='Button0']]/element[./attribute[@name='Name' and @value='Label']]/attribute[@name='Text']/@value\">Zoom In</replace>"
+        "    <add sel=\"/element/element[./attribute[@name='Name' and @value='Button0']]\">"
+        "        <element type=\"Text\">"
+        "            <attribute name=\"Name\" value=\"KeyBinding\" />"
+        "            <attribute name=\"Text\" value=\"PAGEUP\" />"
+        "        </element>"
+        "    </add>"
+        "    <remove sel=\"/element/element[./attribute[@name='Name' and @value='Button1']]/attribute[@name='Is Visible']\" />"
+        "    <replace sel=\"/element/element[./attribute[@name='Name' and @value='Button1']]/element[./attribute[@name='Name' and @value='Label']]/attribute[@name='Text']/@value\">Zoom Out</replace>"
+        "    <add sel=\"/element/element[./attribute[@name='Name' and @value='Button1']]\">"
+        "        <element type=\"Text\">"
+        "            <attribute name=\"Name\" value=\"KeyBinding\" />"
+        "            <attribute name=\"Text\" value=\"PAGEDOWN\" />"
+        "        </element>"
+        "    </add>"
+        "</patch>";
+    }
+
+private:
+    /// Construct the scene content.
+    void CreateScene();
+    /// Construct an instruction text to the UI.
+    void CreateInstructions();
+    /// Set up a viewport for displaying the scene.
+    void SetupViewport();
+    /// Read input and moves the camera.
+    void MoveCamera(float timeStep);
+    /// Subscribe to application-wide logic update events.
+    void SubscribeToEvents();
+    /// Handle the logic update event.
+    void HandleUpdate(StringHash eventType, VariantMap& eventData);
+};

+ 2 - 1
Source/Samples/CMakeLists.txt

@@ -72,4 +72,5 @@ add_subdirectory (31_MaterialAnimation)
 add_subdirectory (32_Urho2DConstraints)
 add_subdirectory (33_Urho2DSpriterAnimation)
 add_subdirectory (34_DynamicGeometry)
-add_subdirectory (35_SignedDistanceFieldText)
+add_subdirectory (35_SignedDistanceFieldText)
+add_subdirectory (36_Urho2DTileMap)