(10-17-2025, 08:36 AM)kevin Wrote: ."But now I'm tempted to jump on the isometric train".....
If you find the time/inspiration, I would love to see that......
10-19-2025, 06:08 PM (This post was last modified: 10-19-2025, 06:11 PM by Marcus.)
I've started working on some isometric tests. I'm not even looking at the code I wrote in n6. There are so many ways to represent a map ... Should it actually be multi layered, or just single tiles but of different heights on a ground plane? I guess it depends on what type of game you're doing, but for now I'm going for the latter. Graphics by Kenney: https://opengameart.org/content/isometric-blocks
This is just a first rendering test and some awkward code to extract images from a spritesheet.
Here's the same example but with some functions to convert between screen and world coordinates. The tile that you hoover the mouse pointer over is marked.
' I don't know ... a format used by the assets by Kenney, don't know if it's standard. Quick hacky
' function to extract all images from the sheet.
images = LoadSpriteSheetXML("assets/platformerTiles_sheet", 0.5)
assert images, "Could not load sprite sheet"
vStepX = width(images[0].img)/2 - 1
vStepY = height(images[0].img)/4 - 1
vStepZ = height(images[0].img)/2 - 1
' Set base blocks. If a block has a base block, it will have that block rendered below itself if
' its height is larger than 1. For example, a dirt block with grass have a pure dirt block as base.
' Look at the image to see what I'm doing here!
foreach img in images img.base = unset
images[47].base = images[0].img
images[3].base = images[4].img
images[1].base = images[2].img
images[5].base = images[6].img
images[7].base = images[8].img
images[29].base = images[30].img
randomize 18
' A 2d map where each cell has an index for an image in images, a height and a sprite list.
map = fill([47, 1, []], 12, 12) ' 32x32x[image_index, height, sprite_list]
for y = 1 to sizeof(map) - 2 for x = 1 to sizeof(map[0]) - 2
if rnd(4) = 0
if rnd(2) = 0 map[y][x][0] = 29
else map[y][x][0] = 5
map[y][x][1] = 2 + rnd(3)
endif
next
' Draw offset for a centered map.
hw = sizeof(map[0])/2
hy = sizeof(map)/2
vDOffsX = width(primary)/2 - (hw*vStepX + hy*vStepX)
vDOffsY = height(primary)/2 - (-hw*vStepY + hy*vStepY + vStepZ)
while not keydown(KEY_ESCAPE, true)
' Convert mouse screen coordinates to world/tile coordinates.
mx = mousex(); my = mousey() - vStepY
vSelX = floor(ToWorldX(mx, my))
vSelY = floor(ToWorldY(mx, my))
' Draw.
set color 0, 0, 0
cls
set color 255, 255, 255
DrawMap(map, images)
set caret 4, 4
wln "Selected tile: " + vSelX + ", " + vSelY
redraw
fwait 60
wend
' ToScreenX
' ---------
' Return screen x coordinate from world coordinates.
function ToScreenX(x, y)
return vDOffsX + x*vStepX + y*vStepX
endfunc
' ToScreenY
' ---------
' Return screen y coordinate from world coordinates.
function ToScreenY(x, y, z)
return vDOffsY - x*vStepY + y*vStepY - z*vStepZ
endfunc
' ToWorldX
' --------
' Return world floor x coordinate from screen coordinates.
function ToWorldX(x, y)
return (x - vDOffsX)/vStepX - ToWorldY(x, y)
endfunc
' ToWorldY
' --------
' Return world floor y coordinate from screen coordinates.
function ToWorldY(x, y)
return (y - vDOffsY + vStepY*(x - vDOffsX)/vStepX)/(2*vStepY)
endfunc
' DrawMap
' -------
function DrawMap(map, images)
' My definitions of the axes:
' * x and y define the floor plane and z points up from that plane, so if a dude jumps his z
' coordinate increases
' * x goes right and up
' * y goes right and down
' * z goes straight up
for y = 0 to sizeof(map) - 1
row = map[y]
for x = sizeof(row) - 1 to 0
xdraw = vDOffsX + x*vStepX + y*vStepX
ydraw = vDOffsY - x*vStepY + y*vStepY
h = row[x][1] - 1
if x = vSelX and y = vSelY set color 128, 128, 128
else set color 255, 255, 255
for z = 0 to h
if z < h draw image images[row[x][0]].base, xdraw, ydraw - z*vStepZ
else draw image images[row[x][0]].img, xdraw, ydraw - z*vStepZ
next
next
next
endfunc
' LoadSpriteSheetXML
' ----------------
' Quick hack, not an xml parser, assumes matching filenames etc.
function LoadSpriteSheetXML(filename, scale)
img = loadimage(filename + ".png")
if not img return unset
xml = openfile(filename + ".xml")
if not xml
free image img
return unset
endif
images = []
ln = frln(xml)
while typeof(ln)
if instr(ln, "SubTexture") >= 0
name = GetValue(ln, "name")
x = int(GetValue(ln, "x"))
y = int(GetValue(ln, "y"))
w = int(GetValue(ln, "width"))
h = int(GetValue(ln, "height"))
subImg = CopyImage(img, x, y, w, h, scale)
images[sizeof(images)] = [name: name, img: subImg]
endif
ln = frln(xml)
wend
free image img
return images
function GetValue(txt, name)
pos = instr(txt, name + "=")
assert pos >= 0, "LoadSpriteSheetXML, GetValue: Could not find " + chr(34) + name + chr(34)
src = pos + len(name) + 2
e = instr(txt, chr(34), src)
assert e >= 0, "LoadSpriteSheetXML, GetValue: " + chr(34) + name + chr(34) +
" no matching " + chr(34)
return mid(txt, src, e - src)
endfunc
function CopyImage(src, subX, subY, subW, subH, scale)
' Eh, need w and h to be dividable by 2 and 4 for the drawing.
scaleW = 2*int(subW*scale/2); scaleH = 4*int(subH*scale/4)
img = createimage(scaleW, scaleH)
set image img
for y = 0 to scaleH - 1 for x = 0 to scaleW - 1
set colori pixeli(src, subX + x*subW/scaleW, subY + y*subH/scaleH)
set pixel x, y
next
set image primary
return img
endfunc
endfunc
Converting from world to screen is pretty straight forward (ToScreenX/ToScreenY). You can figure the formulas out just by drawing on a piece of paper. The inverse, converting from screen coordinates to world, is not quite as simple. But I took the two equations from ToScreenX/ToScreenY and solved them for the world coordinates on a piece of paper (attached ), and voila!
Code:
' ToWorldX
' --------
' Return world floor x coordinate from screen coordinates.
function ToWorldX(x, y)
return (x - vDOffsX)/vStepX - ToWorldY(x, y)
endfunc
' ToWorldY
' --------
' Return world floor y coordinate from screen coordinates.
function ToWorldY(x, y)
return (y - vDOffsY + vStepY*(x - vDOffsX)/vStepX)/(2*vStepY)
endfunc
However, this converts from screen coordinates to the floor plane of the world. There are infinite solutions to each pair of screen coordinates if we mix in height (z). So how do we solve the problem of selecting a tile and regarding its entire height? I'll show that next time.
Marcus. You hand wrote that? I'm impressed! How did you learn to write so neatly? My hand writing looks like a chicken that stepped in ink and ran across the page... *sigh*