PDA

View Full Version : ISO coordinates



peste1
22-07-2004, 10:08 AM
Hi all,
I want to retrieve the selected tile -record- (eg: clicked by mouse, with X and Y of mouse pointer) in an isometric map. How can I do this?



Example:


...

type
TIsoTile = record
image: integer;
zoffset: integer;
selected: boolean;
end;

...

procedure TForm1.DXDrawMouseDown(Sender: TObject; Button:
TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
IsoMap[ISOCoordX(x, y, isowidth, isoheight), ISOCoordY(x, y,
isowidth, isoheight)].image := 1;
end;


Thanks.

PS: sorry for my english :D

cairnswm
22-07-2004, 11:22 AM
function TDXCGIsoMap.PointToCell(X,Y : Integer): TPoint;
Var
BX,BY,CX,CY,DX,DY,AD, BD : Integer;
begin
X := X + MapLeft+32;
Y := Y + MapTop;
Y := Y - 192;
BX := X div 128;
BY := (Y div 64)*2;
DX := ABS(((BX * 128) + 64) - X);
// DY := ABS((((BY * 64) - 224)) - Y);
DY := ABS((((BY div 2) * 64) + 32) - Y);
AD := DX + 2 * DY;
X := X - 64;
Y := Y + 32;
CX := X div 128;
CY := (Y div 64) * 2 - 1;
DX := ABS(((CX * 128) + 64) - X);
DY := ABS((((CY div 2) * 64) + 96) - Y);
BD := DX + 2 * DY;
If AD < BD then
Begin
Result := Point(BX,BY);
End
Else
Begin
Result := Point(CX,CY);
End;
end;


My tiles were 128*64

Basically the logic I used was
- Every point could be in one of two different tiles.
- Identify these two tiles
- work out distance to center
- closest to center was the tile I wanted.

Not very clear I know but I hope it helps.

Useless Hacker
22-07-2004, 01:22 PM
If you are using a diamond shaped map (a la Age of Empires), this should work:

procedure MapToScreen(MapX, MapY: Double; out ScreenX, ScreenY: Integer);
begin
ScreenX := Trunc(32 *(MapY + MapX))- OffsetX;
ScreenY := Trunc(16 *(MapY - MapX))- OffsetY;
end;

procedure ScreenToMap(ScreenX, ScreenY: Integer; out MapX, MapY: Double);
var
t1, t2: Integer;
begin
t1 := ScreenX + OffsetX;
t2 := 2 *(ScreenY + OffsetY);
MapX := (t1 - t2)/ 64;
MapY := (t1 + t2)/ 64;
end;

OffsetX and OffsetY indicate the position of the top-left corner of the screen relative to the origin of the map, which was considered to be the far left corner of the map. Each tile is considered to be 1 unit in each direction; with the x-axis running from the left corner to the top corner, and the y-axis running from the left to the bottom.

This code is for 64x32 pixel tiles; you would need to adjust things a little if you were using different sizes. The screen to map function was come up with by algebraically rearranging the map to screen function.

Also, these only work for flat maps; maps with a height component are more complicated as a click could have been in different tiles on different layers.

Paulius
22-07-2004, 03:38 PM
You should be converting iso coordinates to screen coordinates when drawing, take that code and do everything the other way around

Useless Hacker
22-07-2004, 04:40 PM
I found an old program I wrote that demonstrates converting iso coodinates:
IsoDemo.zip (http://legion.gibbering.net/miketrim/dgdev/IsoDemo.zip) (6 KB)

peste1
22-07-2004, 04:48 PM
Thanks all!
But... I have some problems with the code.

Look at
http://www.tntdeveloping.com/jvcl/iso4.zip
and compile.

With this function CellAt, I have the same problem with your code.
Some tiles are translated by x + 1!!! :cry:

How can I solve?

Thank you for the help.

Useless Hacker
22-07-2004, 06:46 PM
Thanks all!
But... I have some problems with the code.

Look at
http://www.tntdeveloping.com/jvcl/iso4.zip
and compile.

With this function CellAt, I have the same problem with your code.
Some tiles are translated by x + 1!!! :cry:

How can I solve?

Thank you for the help.That is the trouble with using a 'rectangular' map with iso tiles; it is much easier to have a 'diamond' shaped map.

peste1
22-07-2004, 06:53 PM
oh :(
and how can I solve ?

cairnswm
23-07-2004, 05:27 AM
Change your Test procedure like this

procedure Test;
var
visx, visy, loopx, loopy : integer;
IsoHeight, IsoWidth, FCellWidthDiv2, FCellHeightDiv2: integer;
begin
IsoWidth := 64;
IsoHeight := 32;
FCellWidthDiv2 := IsoWidth div 2;
FCellHeightDiv2 := IsoHeight div 2;
Point.x := Point.x; //+ (FXOffset + ScrollXOffset);
Point.y := Point.y; //+ (FYOffset + ScrollYOffset);
result.X := -1; // set no tile
result.y := -1;
if (isowidth = 0) then Exit;
visx := MaxInt(0, Point.x div IsoWidth - 1); // guess what tile left
visy := MaxInt(0, Point.y div (FCellheightdiv2) - 1); // guess what tile top
for loopy := visy - 1 to // just loop through 9 tiles
MinInt(MaxMapHeight, visy + 1) do
for loopx := visx - 1 to
MinInt(MaxMapWidth, visx + 1) do
if isoPointInQuad(
(loopx * IsoWidth) + ((loopy mod 2) * (FCellwidthdiv2)),
(loopy * (FCellheightdiv2)) + (FCellheightdiv2),
(loopx * IsoWidth) + ((loopy mod 2) * (FCellwidthdiv2)) + (FCellwidthdiv2),
(loopy * (FCellheightdiv2)) + IsoHeight,
(loopx * IsoWidth) + ((loopy mod 2) * (FCellwidthdiv2)) + IsoWidth,
(loopy * (FCellheightdiv2)) + (IsoHeight div 2),
(loopx * IsoWidth) + ((loopy mod 2) * (FCellwidthdiv2)) + (FCellwidthdiv2),
(loopy * (FCellheightdiv2)),
Point.x, Point.y) then
begin
If loopy mod 2 = 1 then
result.x := loopx + 1
else
result.x := loopx;
result.y := loopy + 1;
Exit;
end;
end; // get co-ords relative to tile


This is the bit that changed:

If loopy mod 2 = 1 then
result.x := loopx + 1
else
result.x := loopx;

Basically it says if a line os offset by one tile to the right then dont add the one to the X coordinates.

peste1
23-07-2004, 08:57 AM
:shock:
Thanks thanks thanks!!! :!: