NaaLaa
How to make a race track ? - Printable Version

+- NaaLaa (https://www.naalaa.com/forum)
+-- Forum: NaaLaa (https://www.naalaa.com/forum/forum-1.html)
+--- Forum: NaaLaa 7 Questions (https://www.naalaa.com/forum/forum-3.html)
+--- Thread: How to make a race track ? (/thread-160.html)



How to make a race track ? - 1micha.elok - 11-06-2024

Hi, Marcus,

   
I wonder how to make a race track (see the picture above), could you please advice me ?

This is the code that you made some months ago. 
I believe there are some minor changes with the latest s3d library 

I haven't use it (.... just kidding ...)  Big Grin

Code:
' A library that I'm working on, not finished at all, don't use it!
include "s3d.n7"

#dbg
set window "test", 320, 240, false, 2
set redraw off

roadImg = loadimage("road.png")
roadImgW = width(roadImg)
roadImgH = height(roadImg)
decorImg = loadimage("winter_tree.png")
tunnelImg = loadimage("tunnel_winter.png")
bgImg = loadimage("sky_winter.png")

' Set up 3d view.
S3D_SetView(primary, rad(90), 0.1, 20)
' Render polygons as we add them. If direct mode is false, all polygons are batched, sorted by
' distance and rendered when we call S3D_Render. Here we draw from back to front manually.
S3D_SetDirectMode(true)

road = []
for z = 0 to 999  road[z] = [x: sin(z*0.05)*6, y: sin(z*0.1)*3]

playerz = 0.0
playerx = 0
playery = -1
projected = dim(4) ' Don't want to spawn too many tables in a game loop, reused for calculations.
lastTick = clock()
while not keydown(KEY_ESCAPE, true)
    t = clock()
    dt = (t - lastTick)/1000
    lastTick = t

    playerz = playerz + 4*dt

    ' calculate camera y
    if int(playerz) < sizeof(road) - 2
        k = playerz%1
        playery = (1 - k)*road[int(playerz)].y + k*road[int(playerz) + 1].y - 0.5
    else
        playery = road[sizeof(road) - 1].y - 0.5
    endif
    ' move left and right
    if keydown(KEY_LEFT)  playerx = playerx - 4*dt
    if keydown(KEY_RIGHT) playerx = playerx + 4*dt

    set color 255, 255, 255
    draw image bgImg, 0, -80 - playery*5
   
    S3D_Clear()
    S3D_Translate(-playerx, -playery, -playerz)
    S3D_Begin(S3D_QUADS)
    didFill = false

    strips = 0
    fills = 0

    for i = int(playerz) + 20 to int(playerz)
        if i < sizeof(road) - 2
            strips = strips + 1
            ' Do we need to fill with snow color to hide distant objects?
            S3D_Project(projected, 0, road[i + 1].y, i + 1)
            y0 = round(projected[1])
            S3D_Project(projected, 0, road[i].y, i)
            y1 = round(projected[1])
            if y1 > y0
                if not didFill
                    didFill = true
                    fills = fills + 1
                    set color 218, 218, 218
                    draw rect 0, y0, width(primary), height(primary) - y0, true
                    set color 255, 255, 255
                endif
            else
                didFill = false
            endif

            ' Draw road.
            x0 = road[i].x
            x1 = road[i + 1].x
            set color 255, 255, 255
            S3D_Texture(roadImg)
            S3D_Vertex(x0 - 2, road[i].y, i, 0, roadImgH)
            S3D_Vertex(x0 + 2, road[i].y, i, roadImgW, roadImgH)
            S3D_Vertex(x1 + 2, road[i + 1].y, i + 1, roadImgW, 0)
            S3D_Vertex(x1 - 2, road[i + 1].y, i + 1, 0, 0)
           
            ' Draw sprites.
            ' Fade in.
            z = (i + 1) - playerz
            if z > 15
                a = ((20 - z)/5)*255
                set color 255, 255, 255, a
            endif
            if i%20 = 0
                S3D_Texture(tunnelImg)
                S3D_Vertex(road[i].x - 5, road[i].y + 0.2, i, 0, height(tunnelImg))
                S3D_Vertex(road[i].x + 5, road[i].y + 0.2, i, width(tunnelImg), height(tunnelImg))
                S3D_Vertex(road[i].x + 5, road[i].y - 3.5, i, width(tunnelImg), 0)
                S3D_Vertex(road[i].x - 5, road[i].y - 3.5, i, 0, 0)               
            else
                if i%2 = 0
                    S3D_Texture(decorImg)
                    x = x0 - 2.5               
                    S3D_Vertex(x - 0.4, road[i].y, i, 0, height(decorImg))
                    S3D_Vertex(x + 0.4, road[i].y, i, width(decorImg), height(decorImg))
                    S3D_Vertex(x + 0.4, road[i].y - 1, i, width(decorImg), 0)
                    S3D_Vertex(x - 0.4, road[i].y - 1, i, 0, 0)
                else
                    S3D_Texture(decorImg)
                    x = x0 + 2.5               
                    S3D_Vertex(x - 0.4, road[i].y, i, 0, height(decorImg))
                    S3D_Vertex(x + 0.4, road[i].y, i, width(decorImg), height(decorImg))
                    S3D_Vertex(x + 0.4, road[i].y - 1, i, width(decorImg), 0)
                    S3D_Vertex(x - 0.4, road[i].y - 1, i, 0, 0)
                endif
            endif
        endif
    next
    S3D_End()
    'S3D_Render()
    set caret 0, 0
    wln round(1/dt)
    wln strips
    wln fills
    redraw
    wait 1
wend



RE: How to make a race track ? - johnno56 - 11-06-2024

Cool demo...

J


RE: How to make a race track ? - 1micha.elok - 11-06-2024

(11-06-2024, 04:39 AM)johnno56 Wrote: Cool demo...

J

The demo was made some months ago by the creator of S3D Library (a.k.a Marcus  Big Grin )
 
I have almost forgotten the S3D library.... but it is really interesting to learn.

Regarding the car racing, I have still some questions :
1. how to make a race track ( a little map on the right upper corner) to track the player
2. there should be some opponents, how to add those opponents' car to the game, and they should appear on the little map on the right upper corner too.
3. to make a start and a finish line

Still scratching my head on how to make them ...  Big Grin


RE: How to make a race track ? - Marcus - 11-06-2024

Yes, the car racing test initiated the entire 3D thing in n7 Smile

That code is pretty useless for a real game though. For example, there are no real turns or turning. The "track" is just a sine curve going forward, and the car just moves left and right - it never turns.

We need to create a real road, based on a polygon or a closed curve. And I actually started writing some code for that a while ago. I shall have a look at the code when I come home from work.


RE: How to make a race track ? - Marcus - 11-06-2024

I checked the code I wrote a while ago and replaced the texture with one generated by code. But this truely isn't much to look at, it was just a test for creating a road from a curve (polyline library, which is full of bugs btw).

Code:
include "s3d.n7"
include "file.n7"
include "polyline.n7"

visible vRes = 480

set window "Futuracer", vRes*screenw()/screenh(), vRes, false
set redraw off

texture = createimage(128, 128)
set image texture
for y = 0 to 127  for x = 0 to 127
    i = 16 + rnd(64)
    set color i, i, i
    set pixel x, y
next
set image primary
BoxBlur(texture, 2, 2)
set image texture
set color 255, 255, 255, 128
draw rect 60, 0, 8, 64, true
set image primary
BoxBlur(texture, 1, 1)

p = PolyLine([[-50, 50], [50, 50], [50, -50], [-50, -50]], true)

mesh = S3D_BeginMesh()
S3D_Begin(S3D_QUADS)
hrw = 8
stp = 15
i = 0
while i < p.GetLength()
    pos = p.GetPoint(i, true)
    dir = p.GetDirection(i, true)
    x0 = pos[0]; y0 = pos[1]
    tx0 = dir[1]; ty0 = -dir[0]
    j = i + stp
    if j > p.GetLength() j = 0   
    pos = p.GetPoint(j, true)
    dir = p.GetDirection(j, true)               
    x1 = pos[0]; y1 = pos[1]
    tx1 = dir[1]; ty1 = -dir[0]
    S3D_Vertex(x0 - tx0*hrw, 0, y0 - ty0*hrw, 0, 1)
    S3D_Vertex(x1 - tx1*hrw, 0, y1 - ty1*hrw, 0, 0)
    S3D_Vertex(x1 + tx1*hrw, 0, y1 + ty1*hrw, 1, 0)
    S3D_Vertex(x0 + tx0*hrw, 0, y0 + ty0*hrw, 1, 1)
    i = i + stp
wend
S3D_End()
S3D_EndMesh()

S3D_SetView(primary, rad(74), 0.1, 100)

x = -70
z = 0
a = 0
lastTick = clock()

while not keydown(KEY_ESCAPE, true)
    t = clock()
    dt = (min(t - lastTick, 100))/1000
    lastTick = t

    if keydown(KEY_LEFT) a = a - 90*dt
    if keydown(KEY_RIGHT) a = a + 90*dt
    if keydown(KEY_UP)
        x = x + sin(rad(a))*10*dt
        z = z + cos(rad(a))*10*dt
    elseif keydown(KEY_DOWN)
        x = x - sin(rad(a))*10*dt
        z = z - cos(rad(a))*10*dt
    endif
    set color 0, 0, 0
    cls
   
    S3D_Clear()
    S3D_RotateY(-rad(a))
    S3D_Translate(-x, 2, -z)
    S3D_Texture(texture)
    S3D_Mesh(mesh, 0)   
    S3D_Render()
    S3D_RenderFog(0, 0, 0, false)
   
    set caret width(primary) - fwidth(" "), height(primary) - fheight()
    set justification right
    set color 0, 255, 0
    write "FPS: " + str(round(1/dt))
    set justification left

    redraw
    wait 1
wend

' BoxBlur
' -------
function BoxBlur(img, rx, ry)
    rx = max(int(rx), 0); ry = max(int(ry), 0)
    set image img
    w = width(img); h = height(img)
    data = dim(w, h)

    ' Blur vertically
    for y = 0 to h - 1  for x = 0 to w - 1  data[x][y] = pixeli(img, x, y)
    count = ry*2 + 1
    for x = 0 to w - 1
        sr = 0; sg = 0; sb = 0; sa = 0
        for y = -ry to ry
            p = data[x][y%h];
            sr = sr + Red(p); sg = sg + Green(p); sb = sb + Blue(p); sa = sa + Alpha(p)
        next
        for y = 0 to h - 1
            set color sr/count, sg/count, sb/count, sa/count
            set pixel x, y
            p = data[x][(y - ry)%h]
            sr = sr - Red(p); sg = sg - Green(p); sb = sb - Blue(p); sa = sa - Alpha(p)
            p = data[x][(y + ry + 1)%h]
            sr = sr + Red(p); sg = sg + Green(p); sb = sb + Blue(p); sa = sa + Alpha(p)
        next
    next
    ' Blur horizontally.
    for y = 0 to h - 1  for x = 0 to w - 1  data[x][y] = pixeli(img, x, y)
    count = rx*2 + 1
    for y = 0 to h - 1
        sr = 0; sg = 0; sb = 0; sa = 0
        for x = -rx to rx
            p = data[x%w][y]
            sr = sr + Red(p); sg = sg + Green(p); sb = sb + Blue(p); sa = sa + Alpha(p)
        next
        for x = 0 to w - 1
            set color sr/count, sg/count, sb/count, sa/count
            set pixel x, y
            p = data[(x - rx)%w][y]
            sr = sr - Red(p); sg = sg - Green(p); sb = sb - Blue(p); sa = sa - Alpha(p)
            p = data[(x + rx + 1)%w][y]
            sr = sr + Red(p); sg = sg + Green(p); sb = sb + Blue(p); sa = sa + Alpha(p)
        next
    next
    set image primary

    ' Pixeli helpers.
    function Alpha(c); return int(c/16777216); endfunc
    function Red(c); return int((c/65536))%256; endfunc
    function Green(c); return int((c/256))%256; endfunc
    function Blue(c); return c%256; endfunc
endfunc

I have never made a racing game, except for a mode7 experiment. And I frankly don't know what is the best way to store a track in memory or how to render it in a good way. It probably depends on what type of racing game you're doing.

Anyhow, as I wrote earlier, the thing I wrote this spring is not good for anything. I'll see if I can think of a good way to make a racing game, either based on road segments (like above, but with heights) or a heightmap.

Sorry for not being to any help here, it's an unexplored area for me.


RE: How to make a race track ? - Marcus - 11-06-2024

https://youtu.be/Pw-RBsfM4v4?si=MriLCHSYrEQnjNSu

This is the mode7 racer I wrote many years ago. The enemies TRY to follow pre-recorded paths, which worked quite well.


RE: How to make a race track ? - 1micha.elok - 11-07-2024

(11-06-2024, 04:07 PM)Marcus Wrote: I checked the code I wrote a while ago and replaced the texture with one generated by code.
...

How blown away I am by the code you sent over for coding a race track. It is truly beyond my expectations and has given me a whole new insight on how to approach coding in general, including the code generated texture. I can't thank you enough for taking the time to create such a detailed and thoughtful piece of code. I will dig into it and learn as much as I can from it. Your expertise and talent in coding never ceases to amaze me.

It's very cool  Cool


RE: How to make a race track ? - 1micha.elok - 11-07-2024

   

What I've learned so far :
1. The 2D polyline can be transformed to 3D race track 
2. Control key modification
    - Display control key indication : on/off
    - If UP is on, the car moves forward until SPACEBAR is on

I haven't still succeeded to show the car position on the little 2D polyline race track  Big Grin Big Grin Big Grin
Don't worry, it is just my curiousity. I am amazed that 2D polyline can be transformed to 3D race track. 

Code:
'=====================================
' Some modification on Futuracer
'
' Resources :
' * Futuracer, original code by Marcus
'
'=====================================


'----------------
' INITIALIZATION
'----------------
'library
include "s3d.n7"
include "polyline.n7"

'screen size
visible vRes = 480
set window "Futuracer", vRes*screenw()/screenh(), vRes, false

set redraw off

'color definition
black = [0,0,0]
white = [255,255,255]
green = [0,255,0]

'create road and white strips image
texture = createimage(128, 128)
set image texture 'road
    for y = 0 to 127  for x = 0 to 127
        i = 16 + rnd(64)
        set color i, i, i
        set pixel x, y
    next
    set image primary
    BoxBlur(texture, 2, 2)
set image texture 'white strips
    set color white
    draw rect 60, 0, 8, 64, true
    set image primary
    BoxBlur(texture, 1, 1)

'race track
points = [[-50, 50], [50, 50], [50, -50], [-50, -50]]
p = PolyLine(points, true) 'true = closed loop

'draw race track in 3D
mesh = S3D_BeginMesh()
S3D_Begin(S3D_QUADS)
hrw = 8
stp = 15
i = 0
while i < p.GetLength()
    pos = p.GetPoint(i, true)
    dir = p.GetDirection(i, true)
    x0 = pos[0]; y0 = pos[1]
    tx0 = dir[1]; ty0 = -dir[0]
    j = i + stp
    if j > p.GetLength() j = 0   
    pos = p.GetPoint(j, true)
    dir = p.GetDirection(j, true)               
    x1 = pos[0]; y1 = pos[1]
    tx1 = dir[1]; ty1 = -dir[0]
    S3D_Vertex(x0 - tx0*hrw, 0, y0 - ty0*hrw, 0, 1)
    S3D_Vertex(x1 - tx1*hrw, 0, y1 - ty1*hrw, 0, 0)
    S3D_Vertex(x1 + tx1*hrw, 0, y1 + ty1*hrw, 1, 0)
    S3D_Vertex(x0 + tx0*hrw, 0, y0 + ty0*hrw, 1, 1)
    i = i + stp
wend
S3D_End()
S3D_EndMesh()


'--------------
' MAIN PROGRAM
'--------------
S3D_SetView(primary, rad(74), 0.1, 100)

'initial values
x = -70
z = 0
a = 0
lastTick   = clock()
toggleUp   = 0
toggleDown = 0
infoLeft   = "OFF"
infoRight  = "OFF"
infoUp     = "OFF"
infoDown   = "OFF"
infoBrake  = "OFF"

while not keydown(KEY_ESCAPE, true)
    'delta time
    t = clock()
    dt = (min(t - lastTick, 100))/1000
    lastTick = t

    'control keys
    if keydown(KEY_LEFT)
        a = a - 90*dt
        infoLeft = "ON"
    else
        infoLeft = "OFF"
    endif
    if keydown(KEY_RIGHT)
        a = a + 90*dt
        infoRight = "ON"
    else
        infoRight = "OFF"
    endif
    if keydown(KEY_UP) or toggleUp = 1
        x = x + sin(rad(a))*10*dt
        z = z + cos(rad(a))*10*dt
        toggleUp = 1 'keep forward
        toggleDown = 0
        infoUp    = "ON"
        infoDown  = "OFF"
        infoBrake = "OFF"
    endif
    if keydown(KEY_DOWN) or toggleDown = 1
        x = x - sin(rad(a))*10*dt
        z = z - cos(rad(a))*10*dt
        toggleUp = 0   'stop
        toggleDown = 1 'keep backward
        infoUp    = "OFF"
        infoDown  = "ON"
        infoBrake = "OFF"
    endif
    if keydown(KEY_SPACE)
        toggleUp = 0 'stop
        toggleDown = 0 'stop
        infoUp    = "OFF"
        infoDown  = "OFF"
        infoBrake = "ON"
    endif
   
    'clear background
    set color black; cls

    'draw race track in 2D
    shiftX = 320
    shiftY = 90
    set color green
    for i = 0 to sizeof(points) - 1
        j = (i + 1)%sizeof(points)
        draw line shiftX+points[i][0], shiftY+points[i][1], shiftX+points[j][0], shiftY+points[j][1]
    next
    set caret 270,10 ; write "Race Track" 

    d = d + 1   
    pos = p.GetPoint(d, true)
    dir = p.GetDirection(d, true)
    draw line pos[0] - dir[0]*16+shiftX, pos[1] - dir[1]*16+shiftY, pos[0]+shiftX, pos[1]+shiftY
                                                 
    'S3D rendering process
    S3D_Clear()
    S3D_RotateY(-rad(a))
    S3D_Translate(-x, 2, -z)
    S3D_Texture(texture)
    S3D_Mesh(mesh, 0)   
    S3D_Render()
    S3D_RenderFog(0, 0, 0, false)
   
    'FPS info
    set caret 10,10
    set color green
    wln "FPS: " + str(round(1/dt))
    wln ""
    wln "Control keys : "
    wln " Left     (Left)      : "+infoLeft
    wln " Right    (Right)     : "+infoRight
    wln " Forward  (Up)        : "+infoUp
    wln " Backward (Down)      : "+infoDown
    wln " Brake    (Space Bar) : "+infoBrake

    redraw
    wait 1
wend


'-----------
' FUNCTIONS
'-----------

' BoxBlur
' -------
function BoxBlur(img, rx, ry)
    rx = max(int(rx), 0); ry = max(int(ry), 0)
    set image img
    w = width(img); h = height(img)
    data = dim(w, h)

    ' Blur vertically
    for y = 0 to h - 1  for x = 0 to w - 1  data[x][y] = pixeli(img, x, y)
    count = ry*2 + 1
    for x = 0 to w - 1
        sr = 0; sg = 0; sb = 0; sa = 0
        for y = -ry to ry
            p = data[x][y%h];
            sr = sr + Red(p); sg = sg + Green(p); sb = sb + Blue(p); sa = sa + Alpha(p)
        next
        for y = 0 to h - 1
            set color sr/count, sg/count, sb/count, sa/count
            set pixel x, y
            p = data[x][(y - ry)%h]
            sr = sr - Red(p); sg = sg - Green(p); sb = sb - Blue(p); sa = sa - Alpha(p)
            p = data[x][(y + ry + 1)%h]
            sr = sr + Red(p); sg = sg + Green(p); sb = sb + Blue(p); sa = sa + Alpha(p)
        next
    next
    ' Blur horizontally.
    for y = 0 to h - 1  for x = 0 to w - 1  data[x][y] = pixeli(img, x, y)
    count = rx*2 + 1
    for y = 0 to h - 1
        sr = 0; sg = 0; sb = 0; sa = 0
        for x = -rx to rx
            p = data[x%w][y]
            sr = sr + Red(p); sg = sg + Green(p); sb = sb + Blue(p); sa = sa + Alpha(p)
        next
        for x = 0 to w - 1
            set color sr/count, sg/count, sb/count, sa/count
            set pixel x, y
            p = data[(x - rx)%w][y]
            sr = sr - Red(p); sg = sg - Green(p); sb = sb - Blue(p); sa = sa - Alpha(p)
            p = data[(x + rx + 1)%w][y]
            sr = sr + Red(p); sg = sg + Green(p); sb = sb + Blue(p); sa = sa + Alpha(p)
        next
    next
    set image primary

    ' Pixeli helpers.
    function Alpha(c); return int(c/16777216); endfunc
    function Red(c); return int((c/65536))%256; endfunc
    function Green(c); return int((c/256))%256; endfunc
    function Blue(c); return c%256; endfunc
endfunc



RE: How to make a race track ? - kevin - 11-10-2024

This looks very interesting, and I look forward to seeing any updates that you post on it. I have tried in the past to make a car racing game, but never succeeded. Thank you for posting.