PDA

View Full Version : Isometric Worlds



Proph3t
10-10-2013, 07:48 AM
Hi guys.

So I have finished my platformer with great performance thanks to those of you who helped me! Once I finished the Super Mario lookalike, I got bored at drawing simple flat objects on the screen, so I decided to tackle Isometric worlds next. I found it to be much easier to program than my previous 2D game and I already have set up the map. Now I have two questions.

1. How do you implement zoom in an Isometric world? Like in Age Of Empires, you can zoom in and out. I have searched the NET, but found nothing.

2. I also created a map editor, but I need a little help with placing tiles where the user clicks. How will I determine the X and Y coordinates where the user clicked? And also how do I check if the user cliked on a tile that is inside map boundaries? I have gone through the tutorial given on DelphiGameDev, but to be honest, it lacks explanation...

Once again a big thanks to those who helped! :)

PS. I use tiles of 128x64 and my current map size is 50x50.


================================================== ================================================== =======

Below is the new code. Sorry for changing, but I have found a MUCH easier way...



Unit LoD;

Interface

Uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, DXDraws, DIB, DXClass, DXSprite, DXPlay, DXInput;

Type
TTile = Record
TileImage: Integer;
End;

TTileMap = Record
MapArray: Array[0..49, 0..49] Of TTile;
End;

TForm1 = Class( TDXForm )
DXDraw1: TDXDraw;
DXImageList1: TDXImageList;
DXTimer1: TDXTimer;
DXInput1: TDXInput;
Procedure FormCreate( Sender: TObject );
Function CartesianToIsometric( CartPoint: TPoint ): TPoint;
Function IsomectricToCartesian( IsoPoint: TPoint ): TPoint;
Procedure PlaceTile( PatternIndex: Integer );
Procedure DXTimer1Timer( Sender: TObject; LagCount: Integer );
Procedure FormKeyDown( Sender: TObject; var Key: Word; Shift: TShiftState );
Private
{ Private Declarations }
Public
{ Public Declarations }
End;

Var
Form1: TForm1;
Map: TTileMap;
StartX, StartY: Integer;

Implementation

{$R *.dfm}

Procedure TForm1.FormCreate( Sender: TObject );
Var
X, Y: Integer;
Begin
DXDraw1.Display.Width := Screen.Width;
DXDraw1.Display.Height := Screen.Height;

StartX := 0;
StartY := 0;

For X := 0 To 49 Do
Begin
For Y := 0 To 49 Do
Begin
Map.MapArray[X, Y].TileImage := 0;
End;{ For }
End;{ For }

DXTimer1.Enabled := True;
End;

Function TForm1.CartesianToIsometric( CartPoint: TPoint ): TPoint;
Var
IsoPoint: TPoint;
Begin
Result := Point( 0, 0 );

IsoPoint.X := CartPoint.X - CartPoint.Y;
IsoPoint.Y := Round( ( CartPoint.X + CartPoint.Y ) / 2 );

Result := IsoPoint;
End;

Function TForm1.IsomectricToCartesian( IsoPoint: TPoint ): TPoint;
Var
CartPoint: TPoint;
Begin
Result := Point( 0, 0 );

CartPoint.X := Round( ( 2 * IsoPoint.Y + IsoPoint.X ) / 2 );
CartPoint.Y := Round( ( 2 * IsoPoint.Y - IsoPoint.X ) / 2 );

Result := CartPoint;
End;

Procedure TForm1.PlaceTile( PatternIndex: Integer );
Var
i, j: Integer;
X, Y: Integer;
TileImage: Integer;
Begin
If DXDraw1.CanDraw
Then
Begin
For i := 0 To 49 Do { Loop through rows }
Begin
For j := 0 To 49 Do { Loop through columns }
Begin
X := J * 66; // Change to 64
Y := i * 66; // Change to 64
TileImage := Map.MapArray[i, j].TileImage;
DXImageList1.Items[TileImage].Draw( DXDraw1.Surface, StartX + CartesianToIsometric( Point( X, Y ) ).X, StartY + CartesianToIsometric( Point( X, Y ) ).Y, PatternIndex );
End;{ For }
End;{ For }
End
Else Exit;
End;

Procedure TForm1.DXTimer1Timer( Sender: TObject; LagCount: Integer );
Begin
DXDraw1.Surface.Fill( 0 );
PlaceTile( 0 );
DXDraw1.Flip;

DXInput1.Update;
If IsLeft In DXInput1.States
Then StartX := StartX + 16;
If IsRight In DXInput1.States
Then StartX := StartX - 16;
If IsUp In DXInput1.States
Then StartY := StartY + 8;
If IsDown In DXInput1.States
Then StartY := StartY - 8;
End;

Procedure TForm1.FormKeyDown( Sender: TObject; Var Key: Word; Shift: TShiftState );
Begin
If Key = VK_ESCAPE
Then Application.Terminate;
End;

End.


Here's the source for those who wish to compile the code.


1215

SilverWarior
10-10-2013, 11:27 AM
I'll try to ckech your code when I get home.
But for next time please use CODE tags when inserting code samples into posts.

Proph3t
10-10-2013, 03:14 PM
Thank you very much.

This is probably a stupid question, but Im new to forums. How do I add a code tag?

User137
10-10-2013, 07:08 PM
Click "Go Advanced" button, and you get more tools for message posting.

Proph3t
11-10-2013, 08:37 AM
Click "Go Advanced" button, and you get more tools for message posting.

Ah okay many thanks :) I will use that next time.

Andreaz
20-10-2013, 08:26 AM
1. How do you implement zoom in an Isometric world? Like in Age Of Empires, you can zoom in and out. I have searched the NET, but found nothing.


To get the best results with zoom you should create different graphics for different zoom levels (Transport Tycoon did this) or you can just scale the tiles, in other words to zoom in 2x set the tile size to 256x128 and draw all tiles with 2X scaling.



2. I also created a map editor, but I need a little help with placing tiles where the user clicks. How will I determine the X and Y coordinates where the user clicked? And also how do I check if the user cliked on a tile that is inside map boundaries? I have gone through the tutorial given on DelphiGameDev, but to be honest, it lacks explanation...


Theese are my isometric screen to world and world to screen functions:



const
TileWidth = 64;
TileHeight = 32;

MapWidth = 16;
MapHeight = 16;

MapOffsetX = 400;
MapOffsetY = 100;

function WorldToScreen(const Value: TVector2f): TVector2f;
begin
Result.X:= MapOffsetX + (Value.X - Value.Y) * (TileWidth div 2);
Result.Y:= MapOffsetY + (Value.X + Value.Y) * (TileHeight div 2);
end;

function ScreenToWorld(const Value: TVector2f): TVector2f;
var X,Y: Single;
begin
X:= (Value.X - MapOffsetX) / (TileWidth div 2);
Y:= (Value.Y - MapOffsetY) / (TileHeight div 2);

Result.X:= (X + Y) / 2;
Result.Y:= (Y - X) / 2;
end;

And to check if its inside the map just check the returned X and Y coordinates:



Position:= ScreenToWorld(Input.Mouse.X, Input.Mouse.Y);

X:= Trunc(Position.X);
Y:= Trunc(Position.Y);


if(X >= 0) and (X < MapWidth) and (Y>=0) and (Y < MapHeight) then
begin
MapData[0, Y, X]:= Tile;
end;



I have a working sample of this in Phoenix (Addons\01_Sprites\05_Isometric):

http://phoenixlib.net/wiki/doku.php?id=start