~[Introduction]~
Icon Legend/Key
= Separates Sections
= Bullet Points for lists
= Formula or Calculation
= Media (necessary to compile example code)
= Caution. Not following this could be Evil.
= Discussion. Info... Talking points... etc...
= Hopefully a helpful hint.
= The Working Source Code/Snippet. At times I'll present other code snippets to illustrate concepts... the
Current Updated/Compileable Source will have the joypad icon!
Fairly regularly I see posts asking about 2D Isometric Games. So I figured it might be an interesting and valuable topic to explore. Before things get complex,, I thought it would be best to start off with the basic plotting functions/formulas of the three common types of Isometric Maps; Diamond, Slide, and Staggered. The following code snippet does just that.
REFERENCE image ONLY!
The GrassIso1.png (BELOW) is the graphic image that is required with the source code. This IsoTile in .jpg format is used to show the actual shape of the tile with it's rectangular border. The pink color is transparent via Alpha Channel in the GrassIso1.png.
This is a standard Isometric Tile template. It's twice as wide as it is in height. Generally I like to keep my image sizes in powers of 2, if possible. This tile image is 128 pixels wide by 64 pixels high. This image is needed to compile the code snippet.
=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~
[GrassIso1.png] media 1_1
source 1_1
Rem Project: Dark Basic Pro Project
Rem Created: Monday, February 20, 2012
Rem ***** Main Source File *****
Rem Basic Display Setup
sync on
sync rate 60
set display mode 1280,768,32
ink rgb(255,255,255)
Rem Globals for Map and Tile Sizes
Global Map_Size_X = 7
Global Map_Size_Y = 7
Global Map_Layers_Z = 5
Global Tile_Width = 128
Global Tile_Height = 64
REM Set choice to Default: Diamond
choice = 2
Rem Load Image
load image "GrassIso1.png",2,1
DO
CLS
if (scancode()>=2 AND scancode()<=4)
choice=scancode()
endif
if choice = 2 then Plot_Diamond()
if choice = 3 then Plot_Slide()
if choice = 4 then Plot_Staggered()
sync
LOOP
function Plot_Diamond()
for MapY = 0 to Map_Size_Y
for MapX = 0 to Map_Size_X
PlotX=(MapX-MapY)*(Tile_Width/2)+576
PlotY=(MapX+MapY)*Tile_Height/2
paste image 2,PlotX,PlotY,1
center text PlotX+Tile_Width/2,PlotY+Tile_Height/2,"("+str$(MapX)+","+str$(MapY)+")"
Next MapX
Next MapY
center text 640, 700, "ISO DIAMOND MAP"
endfunction
function Plot_Slide()
for MapY = 0 to Map_Size_Y
for MapX = 0 to Map_Size_X
PlotX=(MapX*Tile_Width)+(MapY*Tile_Width/2)
PlotY=(MapY*Tile_Height/2)
paste image 2,PlotX,PlotY,1
center text PlotX+Tile_Width/2,PlotY+Tile_Height/2,"("+str$(MapX)+","+str$(MapY)+")"
Next MapX
Next MapY
center text 640, 700, "ISO SLIDE MAP"
endfunction
function Plot_Staggered()
for MapY = 0 to Map_Size_Y
for MapX = 0 to Map_Size_X
PlotX=(MapX*Tile_Width)+((MapY && 1)*(Tile_Width/2))
PlotY=(MapY*Tile_Height/2)
paste image 2,PlotX,PlotY,1
center text PlotX+Tile_Width/2,PlotY+Tile_Height/2,"("+str$(MapX)+","+str$(MapY)+")"
Next MapX
Next MapY
center text 640, 700, "ISO STAGGERED MAP"
endfunction
Compile the source 1_1 with media 1_1
(To select the type of map being plotted)....
press '
1' for Diamond
press '
2' for Slide
press '
3' for Staggered
=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~
Now, some explanation behind the Plotting
~[Tile Plotting IsoMaps]~
At this point in the code I am focusing on concepts and formulas. In time speeding up the drawing by use of sprites, textured plains, etc... can be worked in, but I'd rather not have that get in the way of what is important. The following images are screen-shots of code above running. I think it's important to discuss the 3 types of maps (Strengths/Weaknesses) and their corresponding Plotting functions.
DIAMOND MAP
Diamond Maps are preferred in "Simulation", "Real-Time Strategy", generally games where the edges of the World Map will be displayed. Due to it's layout, the edges of the map are smooth.
(Age of Empires, Sim City 2000/3000, Roller Coaster Tycoon)
Diamond Map : Coordinate System
Following Ernest Pazera's "Isometric Game Programming with DirectX 7.0" method, I've started map position (0,0) at the top corner.
Origin of world map(0,0) is at the top corner of the map.
x-axis increases to the southeast.
y-axis increases to the southwest.
When working with Iso Diamond & Staggered maps we need to calculate the x and y Pixel Screen Coordinates;(
PlotX and
PlotY),, based on x and y index of the Map Coordinates(
MapX and
MapY).
"BOTH" Map axes affect "BOTH" Pixel axes as far as tile plotting goes.
So to find PlotX and PlotY;
EACH will would need
two calculations...
(First, a calcualtion with regard to
MapX)
PlotX = MapX*Tile_Width/2
PlotY = MapX*Tile_Height/2
(Then adding calcualtion with regard to
MapY)
PlotX = PlotX+(MapY*(-Tile_Width/2))
PlotY = PlotY+(MapY*(Tile_Height/2))
These equations can be condensed into 2 equations rather than 4 (1 for PlotX, and 1 for PlotY)...
PlotX = (MapX*Tile_Width/2)-(MapY*Tile_Width/2)
PlotY = (MapX*Tile_Height/2)+(MapY*Tile_Height/2)
Using some basic Algebra,, we can simplify the above to...
PlotX = (MapX-MapY)*(Tile_Width/2)
PlotY = (MapX+MapY)*(Tile_Height/2)
SLIDE MAP
Slide Maps, aren't used often, But it would be incomplete to omit them. I've seen them used in some scrollers... and the only advantage is the straight-forward nature and consistency of their TilePlotting, MouseMapping, TileWalking, & Scrolling functions. Terms that I'll cover next.
Slide Map: Coordinate System
The coordinate system used in this particular variant (There are generally 4 variants, they differ by movement direction of the map,, but all generally look similar) is as follows...
Origin world map(0,0) is at the top left.
x-axis increases to the east.
y-axis increases to the southeast.
(Some descriptions of vars are described in Diamond Map : Coordinate System [above])
With Slide Maps MapX
does not affect PlotY at all,, However MapY affects both PlotX and PlotY by +Tile_Width/2.
PlotX = (MapX*Tile_Width)+(MapY*Tile_Width/2)
PlotY = (MapY*Tile_Height/2)
STAGGERED MAP
Staggered Maps (Isometric/Hexagonal) are preferred in "Turn-Based Strategy" games. They are also well suited for maps that wrap-around.
(Civilization II, Civilization: Call to Power, Alpha Centauri)
Staggered Map : Coordinate System
Origin world map(0,0) is at the top left.
x-axis increases to the east.
y-axis
alternately increases southeast and southwest.
The unusual part with Staggered Maps is the MapY Axis, it alternates southeast and southwest depending on what tile row you are on. This gives it a somewhat zigzagging look along the southern direction of MapY axis.
We could use the MOD operator with an if statement to determine if we are on an EVEN row or an ODD row. But that is bit cumbersome. Rather we will use && operator directly in our equation. For all even number MapY && 1 will yield 0,, and for all odd numbers MapY && 1 will yield 1.
PlotX = MapX*Tile_Width+(MapY && 1) * (Tile_Width/2)
PlotY = MapY*(Tile_Height/2)
~[World Space, Screen Space, Anchors & Scrolling]~
Before things get too out of hand, we will need to begin using types. A
point_type will consist of
x and
y as integers, and a
rect_type will consist of
left, top, right, bottom as integers.
type point_type
x as integer
y as integer
endtype
type rect_type
left as integer
top as integer
right as integer
bottom as integer
endtype
PlotX and
PlotY will now be a point_type; (ptPlot.x and ptPlot.y)
ptPlot
ptPlot as point_type
ptPlot.x = 0
ptPlot.y = 0
We will also define some other variables of point_type and rect_type...
ptScreenAnchor
ptScreenAnchor as point_type
ptScreenAnchor.x = 0
ptScreenAnchor.y = 0
NEED TO EDIT IN VARIABLES
I'm going to list some terms/definitions that are used to describe IsoHex worlds. Don't worry if you are confused by these definitions at first. I'll do my best in the following examples to bring clarity to them.
Space ~ Any sized and shaped 2-dimensional space. Usually a space is rectangular.
Screen Space ~ The space on the screen used for rendering the play area, not including any borders, status panels, menus bars, message bars, or any other non-play area structures. Most often the screen space is smaller than the actual display max.
View Space ~ The same size as screen space, but the upper-left corner is always at (0,0).
Tile Space ~ The smallest space that is taken up by an individual tile. (usually rectangular)
World Space ~ The space that allow the display of an entire map of tiles and their associated objects.
Anchor ~ A correlation of one point of a space (usually (0,0)) to another space. Anchors can help convert between screen space and view space,, or determine which tiles have to be rendered by translating the tile's world space coordinates into view space coordinates.
Anchor Space ~ A space that defines legal values for the view-to-world anchor. Clipping your anchor point with anchor space lets you easily manage the view-to-world anchor and prevent the player from having an unintended view.
Basically all of the above boils down to is this:
A lot of different points, and spaces (mainly rectangles) are used to ensure we properly render IsoMaps to the display. There are also a number of conversions that must take place between the Global World Space,, and the Local Screen Space and View Space.
Moving on.......
~[Scrolling]~
.oO()Oo.oO (I'm not a real programmer,, I just play one on the Forums!!!) Oo.oO()Oo.