Browse Source

Fixed TileMap2D::PositionToTileIndex() and use it in tile map sample

Mike3D 9 years ago
parent
commit
238f09c53d

+ 51 - 6
Source/Samples/36_Urho2DTileMap/Urho2DTileMap.cpp

@@ -21,19 +21,19 @@
 //
 
 #include <Urho3D/Core/CoreEvents.h>
-#include <Urho3D/Engine/Engine.h>
 #include <Urho3D/Graphics/Camera.h>
+#include <Urho3D/Engine/Engine.h>
+#include <Urho3D/UI/Font.h>
 #include <Urho3D/Graphics/Graphics.h>
+#include <Urho3D/Input/Input.h>
 #include <Urho3D/Graphics/Octree.h>
 #include <Urho3D/Graphics/Renderer.h>
-#include <Urho3D/Graphics/Zone.h>
-#include <Urho3D/Input/Input.h>
 #include <Urho3D/Resource/ResourceCache.h>
 #include <Urho3D/Scene/Scene.h>
-#include <Urho3D/UI/Font.h>
+#include <Urho3D/Urho2D/StaticSprite2D.h>
 #include <Urho3D/UI/Text.h>
-#include <Urho3D/Urho2D/Drawable2D.h>
 #include <Urho3D/Urho2D/TileMap2D.h>
+#include <Urho3D/Urho2D/TileMapLayer2D.h>
 #include <Urho3D/Urho2D/TmxFile2D.h>
 
 #include "Urho2DTileMap.h"
@@ -52,6 +52,9 @@ void Urho2DTileMap::Start()
     // Execute base class startup
     Sample::Start();
 
+    // Enable OS cursor
+    GetSubsystem<Input>()->SetMouseVisible(true);
+
     // Create the scene content
     CreateScene();
 
@@ -112,7 +115,7 @@ void Urho2DTileMap::CreateInstructions()
 
     // 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->SetText("Use WASD keys to move, use PageUp PageDown keys to zoom.\n LMB to remove a tile, RMB to swap grass and water.");
     instructionText->SetFont(cache->GetResource<Font>("Fonts/Anonymous Pro.ttf"), 15);
 
     // Position the text relative to the screen center
@@ -169,6 +172,9 @@ void Urho2DTileMap::SubscribeToEvents()
     // Subscribe HandleUpdate() function for processing update events
     SubscribeToEvent(E_UPDATE, URHO3D_HANDLER(Urho2DTileMap, HandleUpdate));
 
+    // Listen to mouse clicks
+    SubscribeToEvent(E_MOUSEBUTTONDOWN, URHO3D_HANDLER(Urho2DTileMap, HandleMouseButtonDown));
+
     // Unsubscribe the SceneUpdate event from base class to prevent camera pitch and yaw in 2D sample
     UnsubscribeFromEvent(E_SCENEUPDATE);
 }
@@ -183,3 +189,42 @@ void Urho2DTileMap::HandleUpdate(StringHash eventType, VariantMap& eventData)
     // Move the camera, scale movement with time step
     MoveCamera(timeStep);
 }
+
+void Urho2DTileMap::HandleMouseButtonDown(StringHash eventType, VariantMap& eventData)
+{
+    Input* input = GetSubsystem<Input>();
+
+    Node* tileMapNode = scene_->GetChild("TileMap", true);
+    TileMap2D* map = tileMapNode->GetComponent<TileMap2D>();
+    TileMapLayer2D* layer = map->GetLayer(0);
+
+    Vector2 pos = GetMousePositionXY();
+    int x, y;
+    if (map->PositionToTileIndex(x, y, pos))
+    {
+        // Get tile's sprite. Note that layer.GetTile(x, y).sprite is read-only, so we get the sprite through tile's node
+        Node* n = layer->GetTileNode(x, y);
+        if (!n)
+            return;
+        StaticSprite2D* sprite = n->GetComponent<StaticSprite2D>();
+
+        if (input->GetMouseButtonDown(MOUSEB_RIGHT))
+        {
+            // Swap grass and water
+            if (layer->GetTile(x, y)->GetGid() < 9) // First 8 sprites in the "isometric_grass_and_water.png" tileset are mostly grass and from 9 to 24 they are mostly water
+                sprite->SetSprite(layer->GetTile(0, 0)->GetSprite()); // Replace grass by water sprite used in top tile
+            else sprite->SetSprite(layer->GetTile(24, 24)->GetSprite()); // Replace water by grass sprite used in bottom tile
+        }
+        else sprite->SetSprite(NULL); // 'Remove' sprite
+    }
+}
+
+Vector2 Urho2DTileMap::GetMousePositionXY()
+{
+    Input* input = GetSubsystem<Input>();
+    Graphics* graphics = GetSubsystem<Graphics>();
+    Camera* camera = cameraNode_->GetComponent<Camera>();
+    Vector3 screenPoint = Vector3((float)input->GetMousePosition().x_ / graphics->GetWidth(), (float)input->GetMousePosition().y_ / graphics->GetHeight(), 10.0f);
+    Vector3 worldPoint = camera->ScreenToWorldPoint(screenPoint);
+    return Vector2(worldPoint.x_, worldPoint.y_);
+}

+ 5 - 6
Source/Samples/36_Urho2DTileMap/Urho2DTileMap.h

@@ -24,17 +24,12 @@
 
 #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
+///     - Interacting with the tile map
 class Urho2DTileMap : public Sample
 {
     URHO3D_OBJECT(Urho2DTileMap, Sample);
@@ -82,4 +77,8 @@ private:
     void SubscribeToEvents();
     /// Handle the logic update event.
     void HandleUpdate(StringHash eventType, VariantMap& eventData);
+    /// Handle the mouse click event.
+    void HandleMouseButtonDown(StringHash eventType, VariantMap& eventData);
+    /// Get mouse position in 2D world coordinates.
+    Vector2 GetMousePositionXY();
 };

+ 5 - 4
Source/Urho3D/Urho2D/TileMapDefs2D.cpp

@@ -103,10 +103,11 @@ bool TileMapInfo2D::PositionToTileIndex(int& x, int& y, const Vector2& position)
     {
     case O_ISOMETRIC:
     {
-        int x_sub_y = (int)(position.x_ * 2.0f / tileWidth_ + 1 - width_);
-        int x_add_y = (int)(height_ * 2.0f - position.y_ * 2.0f / tileHeight_ - 2.0f);
-        x = (x_sub_y - x_add_y) / 2;
-        y = (x_sub_y - x_add_y) / 2;
+        float ox = position.x_ / tileWidth_ - height_ * 0.5f;
+        float oy = position.y_ / tileHeight_;
+
+        x = (int)(width_ - oy + ox);
+        y = (int)(height_ - oy - ox);
     }
         break;
 

+ 38 - 1
bin/Data/LuaScripts/36_Urho2DTileMap.lua

@@ -3,6 +3,7 @@
 --     - Creating a 2D scene with tile map
 --     - Displaying the scene using the Renderer subsystem
 --     - Handling keyboard to move and zoom 2D camera
+--     - Interacting with the tile map
 
 require "LuaScripts/Utilities/Sample"
 
@@ -10,6 +11,9 @@ function Start()
     -- Execute the common startup for samples
     SampleStart()
 
+    -- Enable OS cursor
+    input.mouseVisible = true
+
     -- Create the scene content
     CreateScene()
 
@@ -67,7 +71,7 @@ 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:SetText("Use WASD keys and mouse to move, Use PageUp PageDown to zoom.\n LMB to remove a tile, RMB to swap grass and water.")
     instructionText:SetFont(cache:GetResource("Font", "Fonts/Anonymous Pro.ttf"), 15)
 
     -- Position the text relative to the screen center
@@ -122,6 +126,9 @@ function SubscribeToEvents()
     -- Subscribe HandleUpdate() function for processing update events
     SubscribeToEvent("Update", "HandleUpdate")
 
+    -- Listen to mouse clicks
+    SubscribeToEvent("MouseButtonDown", "HandleMouseButtonDown")
+
     -- Unsubscribe the SceneUpdate event from base class to prevent camera pitch and yaw in 2D sample
     UnsubscribeFromEvent("SceneUpdate")
 end
@@ -134,6 +141,36 @@ function HandleUpdate(eventType, eventData)
     MoveCamera(timeStep)
 end
 
+function HandleMouseButtonDown(eventType, eventData)
+    local tileMapNode = scene_:GetChild("TileMap", true)
+    local map = tileMapNode:GetComponent("TileMap2D")
+    local layer = map:GetLayer(0)
+
+    success, x, y = map:PositionToTileIndex(GetMousePositionXY())
+    if success then
+        -- Get tile's sprite. Note that layer.GetTile(x, y).sprite is read-only, so we get the sprite through tile's node
+        local n = layer:GetTileNode(x, y)
+        if n == nil then
+            return
+        end
+        local sprite = n:GetComponent("StaticSprite2D")
+
+        if input:GetMouseButtonDown(MOUSEB_RIGHT) then
+            -- Swap grass and water
+            if layer:GetTile(x, y).gid < 9 then -- First 8 sprites in the "isometric_grass_and_water.png" tileset are mostly grass and from 9 to 24 they are mostly water
+                sprite.sprite = layer:GetTile(0, 0).sprite -- Replace grass by water sprite used in top tile
+            else sprite.sprite = layer:GetTile(24, 24).sprite end -- Replace water by grass sprite used in bottom tile
+        else sprite.sprite = nil end -- 'Remove' sprite
+    end
+end
+
+function GetMousePositionXY()
+    local camera = cameraNode:GetComponent("Camera")
+    local screenPoint = Vector3(input.mousePosition.x / graphics.width, input.mousePosition.y / graphics.height, 10)
+    local worldPoint = camera:ScreenToWorldPoint(screenPoint)
+    return Vector2(worldPoint.x, worldPoint.y)
+end
+
 -- Create XML patch instructions for screen joystick layout specific to this sample app
 function GetScreenJoystickPatchString()
     return

+ 43 - 1
bin/Data/Scripts/36_Urho2DTileMap.as

@@ -3,6 +3,7 @@
 //     - Creating a 2D scene with tile map
 //     - Displaying the scene using the Renderer subsystem
 //     - Handling keyboard to move and zoom 2D camera
+//     - Interacting with the tile map
 
 #include "Scripts/Utilities/Sample.as"
 
@@ -11,6 +12,9 @@ void Start()
     // Execute the common startup for samples
     SampleStart();
 
+    // Enable OS cursor
+    input.mouseVisible = true;
+
     // Create the scene content
     CreateScene();
 
@@ -70,7 +74,7 @@ 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.text = "Use WASD keys and mouse to move, Use PageUp PageDown to zoom.\n LMB to remove a tile, RMB to swap grass and water.";
     instructionText.SetFont(cache.GetResource("Font", "Fonts/Anonymous Pro.ttf"), 15);
 
     // Position the text relative to the screen center
@@ -125,6 +129,9 @@ void SubscribeToEvents()
     // Subscribe HandleUpdate() function for processing update events
     SubscribeToEvent("Update", "HandleUpdate");
 
+    // Listen to mouse clicks
+    SubscribeToEvent("MouseButtonDown", "HandleMouseButtonDown");
+
     // Unsubscribe the SceneUpdate event from base class to prevent camera pitch and yaw in 2D sample
     UnsubscribeFromEvent("SceneUpdate");
 }
@@ -138,6 +145,41 @@ void HandleUpdate(StringHash eventType, VariantMap& eventData)
     MoveCamera(timeStep);
 }
 
+void HandleMouseButtonDown(StringHash eventType, VariantMap& eventData)
+{
+    Node@ tileMapNode = scene_.GetChild("TileMap", true);
+    TileMap2D@ map = tileMapNode.GetComponent("TileMap2D");
+    TileMapLayer2D@ layer = map.GetLayer(0);
+
+    Vector2 pos = GetMousePositionXY();
+    int x, y;
+    if (map.PositionToTileIndex(x, y, pos))
+    {
+        // Get tile's sprite. Note that layer.GetTile(x, y).sprite is read-only, so we get the sprite through tile's node
+        Node@ n = layer.GetTileNode(x, y);
+        if (n is null)
+            return;
+        StaticSprite2D@ sprite = n.GetComponent("StaticSprite2D");
+
+        if (input.mouseButtonDown[MOUSEB_RIGHT])
+        {
+            // Swap grass and water
+            if (layer.GetTile(x, y).gid < 9) // First 8 sprites in the "isometric_grass_and_water.png" tileset are mostly grass and from 9 to 24 they are mostly water
+                sprite.sprite = layer.GetTile(0, 0).sprite; // Replace grass by water sprite used in top tile
+            else sprite.sprite = layer.GetTile(24, 24).sprite; // Replace water by grass sprite used in bottom tile
+        }
+        else sprite.sprite = null; // 'Remove' sprite
+    }
+}
+
+Vector2 GetMousePositionXY()
+{
+    Camera@ camera = cameraNode.GetComponent("Camera");
+    Vector3 screenPoint = Vector3(float(input.mousePosition.x) / graphics.width, float(input.mousePosition.y) / graphics.height, 10.0f);
+    Vector3 worldPoint = camera.ScreenToWorldPoint(screenPoint);
+    return Vector2(worldPoint.x, worldPoint.y);
+}
+
 // Create XML patch instructions for screen joystick layout specific to this sample app
 String patchInstructions =
         "<patch>" +