Thread Rating:
  • 1 Vote(s) - 4 Average
  • 1
  • 2
  • 3
  • 4
  • 5
An isometric demo from N6
#11
."But now I'm tempted to jump on the isometric train".....
If you find the time/inspiration, I would love to see that......
Reply
#12
(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......

agree  Big Grin
Reply
#13
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.


Attached Files Thumbnail(s)
   

.zip   isometric_test.zip (Size: 192.31 KB / Downloads: 7)
Reply
#14
Ah yes... the unmistakable 'kenney' tile set... Very cool...

Awkward or not... Very nicely done... Big Grin

By the way... the space bar did not work... no 'pew pew'.... lol
Logic is the beginning of wisdom.

Live long and prosper.
Reply
#15
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.

Code:
' test_1.n7
' ---------

visible vStepX, vStepY, vStepZ
visible vDOffsX, vDOffsY

visible vSelX, vSelY

set window "test 1", 640, 480
set redraw off

' 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 Big Grin ), 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.


Attached Files Thumbnail(s)
   
Reply
#16
Many thanks Marcus. It is so useful to see how you are building the program in stages - a very useful educational tool.
Reply
#17
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*
Logic is the beginning of wisdom.

Live long and prosper.
Reply


Forum Jump:


Users browsing this thread: 1 Guest(s)