Olympe Engine 2.0
2D Game Engine with ECS Architecture
Loading...
Searching...
No Matches
IsometricProjection.cpp
Go to the documentation of this file.
1/*
2 * IsometricProjection.cpp - Isometric coordinate transformations for Olympe Engine
3 *
4 * ============================================================================
5 * TILED ISOMETRIC COORDINATE SYSTEM - COMPLETE REFERENCE
6 * ============================================================================
7 *
8 * CRITICAL DISCOVERY: Tiled stores object positions in TMJ files using a
9 * special isometric pixel coordinate system where BOTH X and Y are measured
10 * in units of tileHeight pixels along the isometric axes.
11 *
12 * TMJ TO WORLD CONVERSION (the correct formula):
13 * -----------------------------------------------
14 * 1. Convert TMJ pixel coords to tile coords:
15 * tileX = tmjPixelX / tileHeight (BOTH divided by tileHeight!)
16 * tileY = tmjPixelY / tileHeight
17 *
18 * 2. Apply standard isometric projection:
19 * worldX = (tileX - tileY) * (tileWidth / 2)
20 * worldY = (tileX + tileY) * (tileHeight / 2)
21 *
22 * WHY BOTH DIVIDED BY tileHeight?
23 * --------------------------------
24 * In Tiled's isometric view, the X and Y axes run diagonally. Movement along
25 * either axis covers the same diagonal distance on screen. Tiled normalizes
26 * this by using tileHeight as the unit for BOTH axes, making the coordinate
27 * system uniform along both isometric directions.
28 *
29 * VERIFIED EXAMPLE (184x128 map, 58x27 tile size):
30 * ------------------------------------------------
31 * player_1 in TMJ: (1818.4, 1064.26)
32 * tileX = 1818.4 / 27 = 67.35
33 * tileY = 1064.26 / 27 = 39.42
34 * worldX = (67.35 - 39.42) * 29 = 810
35 * worldY = (67.35 + 39.42) * 13.5 = 1441
36 * Result: Entity renders at tile (67, 39) as expected!
37 *
38 * NO ORIGIN OFFSET NEEDED:
39 * ------------------------
40 * The originX calculation (mapHeight * halfTileWidth) is for Tiled's SCREEN
41 * display only. In our engine, both tiles and objects use the same world
42 * coordinate system where tile (0,0) is at world (0,0). The camera handles
43 * screen positioning.
44 *
45 * ============================================================================
46 */
47
48#include "../include/IsometricProjection.h"
49#include <cmath>
50#include <algorithm>
51
52namespace Olympe {
53namespace Tiled {
54
55 Vector IsometricProjection::WorldToIso(float worldX, float worldY, int tileWidth, int tileHeight,
56 int startX, int startY, float offsetX, float offsetY,
57 float globalOffsetX, float globalOffsetY)
58 {
59 // Apply startx/starty offsets to world coordinates
60 float offsetWorldX = worldX + startX;
61 float offsetWorldY = worldY + startY;
62
63 // Standard isometric projection (diamond orientation)
64 // worldX/Y here are tile coordinates, output is screen pixels
66 result.x = ((offsetWorldX - offsetWorldY) * ((float)tileWidth * 0.5f)) + offsetX + globalOffsetX;
67 result.y = ((offsetWorldX + offsetWorldY) * ((float)tileHeight * 0.5f)) + offsetY + globalOffsetY;
68 return result;
69 }
70
71 Vector IsometricProjection::IsoToWorld(float isoX, float isoY, int tileWidth, int tileHeight,
72 int startX, int startY, float offsetX, float offsetY,
73 float globalOffsetX, float globalOffsetY)
74 {
75 // Inverse isometric projection (screen pixels to tile coordinates)
77 float halfWidth = tileWidth * 0.5f;
78 float halfHeight = tileHeight * 0.5f;
79
80 // Apply global offsets first (inverse) and pixel offsets
81 float adjIsoX = isoX - offsetX - globalOffsetX;
82 float adjIsoY = isoY - offsetY - globalOffsetY;
83
84 result.x = (adjIsoX / halfWidth + adjIsoY / halfHeight) * 0.5f;
85 result.y = (adjIsoY / halfHeight - adjIsoX / halfWidth) * 0.5f;
86
87 // Apply startx/starty offsets (inverse)
88 result.x -= startX;
89 result.y -= startY;
90
91 return result;
92 }
93
94 void IsometricProjection::ScreenToTile(float screenX, float screenY, int tileWidth, int tileHeight,
95 int& outTileX, int& outTileY)
96 {
97 Vector world = IsoToWorld(screenX, screenY, tileWidth, tileHeight);
98 outTileX = static_cast<int>(std::floor(world.x));
99 outTileY = static_cast<int>(std::floor(world.y));
100 }
101
102 Vector IsometricProjection::TileToScreen(int tileX, int tileY, int tileWidth, int tileHeight)
103 {
104 return WorldToIso(static_cast<float>(tileX), static_cast<float>(tileY),
105 tileWidth, tileHeight);
106 }
107
108 void IsometricProjection::CalculateTMJOrigin(int minTileX, int minTileY, int maxTileX, int maxTileY,
109 int tileWidth, int tileHeight,
110 float& outOriginX, float& outOriginY)
111 {
112 // Tiled's screen origin for display purposes (NOT used in world coords)
113 // This is only for reference - our coordinate system doesn't need it
114 (void)minTileX;
115 (void)minTileY;
116 (void)maxTileX;
117
118 int mapHeightTiles = maxTileY - minTileY + 1;
119 float halfTileWidth = tileWidth * 0.5f;
120
122 outOriginY = 0.0f;
123 }
124
125} // namespace Tiled
126} // namespace Olympe
ComponentTypeID GetComponentTypeID_Static()
Definition ECS_Entity.h:56
static Vector WorldToIso(float worldX, float worldY, int tileWidth, int tileHeight, int startX=0, int startY=0, float offsetX=0.0f, float offsetY=0.0f, float globalOffsetX=0.0f, float globalOffsetY=0.0f)
static void ScreenToTile(float screenX, float screenY, int tileWidth, int tileHeight, int &outTileX, int &outTileY)
static Vector IsoToWorld(float isoX, float isoY, int tileWidth, int tileHeight, int startX=0, int startY=0, float offsetX=0.0f, float offsetY=0.0f, float globalOffsetX=0.0f, float globalOffsetY=0.0f)
static Vector TileToScreen(int tileX, int tileY, int tileWidth, int tileHeight)
static void CalculateTMJOrigin(int minTileX, int minTileY, int maxTileX, int maxTileY, int tileWidth, int tileHeight, float &outOriginX, float &outOriginY)
float y
Definition vector.h:27
float x
Definition vector.h:27