Help rendering a realistic road

Hello fellow coders,
As I mentioned before, I’m coding frogger and want a nice road. I want it to not be repudiative, so I don’t want to tile an image, which i’ve done and looks alright, but not high enough for my standards. Right now, this is my code. On estimation, it would take 5.25 hours to render on my iPad 2.


Road = class()

function Road:init()
   self.lanes = 10
   self.lly = 0
   --self.pavement = pavement()
   self.pavementdots = makeArray(WIDTH)
   for x = 1, WIDTH do
       for y = 1, HEIGHT/7*5 do
           self.pavementdots[x][y] = math.random(125)
       end
   end
   self.pavement = image(WIDTH,HEIGHT/7*5)
   for x = 1, WIDTH do
       for y = 1, HEIGHT/7*5 do
           clearOutput()
           print(x.."\
"..y)
           print(WIDTH.."\
".. HEIGHT)
           self.pavement:set(x,y,self.pavementdots[x][y],
           self.pavementdots[x][y],
           self.pavementdots[x][y],255)
       end
   end
end

function Road:draw()
   --draw the pavement
   sprite(pavement,0,HEIGHT - HEIGHT/7*6)

   --draw the lines
   strokeWidth(8)
   for j = 1,(self.lanes-1) do
       self.lly = (HEIGHT - HEIGHT/7*6)+((HEIGHT/7*5)/(self.lanes))*j
       for i = 0, WIDTH/50 do
           sline = i * 50
           line(sline, self.lly,sline+25,self.lly)
       end
   end
end

function Road:touched(touch)
end

I’ve tried different methods, but I can’t get it fast. I’m wondering if meshing it is the solution… Although it’s kind of hard for me to understand meshes… Can someone please help?
Thanks!

Can someone please create a good mesh tutorial please?

Possible solution

Start with a small image and random it normally

Copy it

Rotate it 90 degrees

Randomly randomize only a small percent of it

Repeat

Possibly combine all the images onto one image when done (and draw the lines over it)

also the noise example only takes ~30 seconds to render when tileSize = 1 on an IPad1

you have to exit codea to stop it (sort of hard to time pressing exit between the long draws)

Sorry for the triple post …

Instant


function setup()
    pr = image(WIDTH,1)
    for x = 1, WIDTH do
        dot = math.random(125)
        pr:set(x,1,dot,dot,dot,255)
    end
    ps = {}
    for y = 1, HEIGHT do
        ps[y] = math.random(WIDTH)
    end
end

function draw()
    for y = 1, HEIGHT do
        sprite(pr,(WIDTH/2)-ps[y],y)
        sprite(pr,WIDTH+(WIDTH/2)-ps[y],y)
    end
end

Oh… Thanks. I forgot about noise.

I’ll try that put when I get a chance.

Maybe the array creation is the problem. You create a huge array of random numbers, then use those numbers to set pixels in the image, and then never use the array again. Why not just set the pixel components to random numbers and not use an array at all?

thx @nat, I was wondering why mine was so much faster. I thought it was just the reuse of a 1 pixel tall image, randomly stacked on itself, but, the direct random may have been a big boost as well.

Generating noise is working very well :slight_smile: Thanks guys!

@Zoyt I just put this together, not sure if it’s any use? You can specify a road’s x, y, width, height, ‘scale factor’ (basically the size of the pixels that make up the road’s texture), and an optional number of lanes.

--# Main

function setup()
    road1 = Road(WIDTH/2, 200, WIDTH, 250, 1, 5)
    road2 = Road(WIDTH/2, 450, WIDTH, 100, 2)
    road3 = Road(WIDTH/2, 600, WIDTH, 100, 4)
end

function draw()
    background(56, 201, 15, 255)
    road1:draw()
    road2:draw()
    road3:draw()
end


--# Road
RoadLineHeight = 2    -- base height of road markings
RoadLineWidth = 40    -- width of each road marking
RoadLineGap = 40      -- gap between each road marking

Road = class()

function Road:init(x,y,w,h,scaleFactor,lanes)
    self.x = x
    self.y = y
    self.s = scaleFactor    -- default of 2 - change to alter 'blockiness'
    if (not self.s) then self.s = 2 end
    self.lanes = lanes
    if (not self.lanes) then self.lanes = 2 end
    
    self.img = image(w, h)    -- our road image!    
    self:render()
end

function Road:draw()
    sprite(self.img, self.x, self.y)
end

function Road:render()
    -- for each block in the road    
    for xx = 1, self.img.width, self.s do
        for yy = 1, self.img.height, self.s do
            -- pick a random grey
            local grey = math.random(30) 
            -- fill in a scaleFactor x scaleFactor block of pixels
            for xoffset = 0, self.s-1 do
                for yoffset = 0, self.s-1 do
                    self.img:set(xx+xoffset, yy+yoffset, grey, grey, grey, 255)
                end
            end
        end
    end
    
    -- finally, draw on the markings
    setContext(self.img)
    pushStyle()
    
    stroke(255, 241, 0, 255)
    strokeWidth(RoadLineHeight*self.s)
    noSmooth()
    if self.lanes > 1 then
        local gap = self.img.height / self.lanes
        for i = 0, self.lanes-1 do
            local lineStart = RoadLineGap
            while (lineStart < self.img.width) do
                line(lineStart, gap * i, lineStart+RoadLineWidth, gap * i)
                lineStart = lineStart + RoadLineWidth + RoadLineGap
            end
        end
    end
    
    popStyle()
    setContext()
end

Wow. Thanks @frosty. I’ll try it out. As you may be able to tell, I’m picky w my graphics

We should make this into a side contest, which method is fastest. Mine is a bit of a cheat since it’s not a parameterized class, so, it would be hard to tell.

Haha. I think I’ll try it and tell you guys.

Mine takes a little bit of time to create the road in the first place, but it’s then rendered to a single image so drawing it is as fast as drawing any other sprite.

Here’s a quick image:

Roads

Most beautiful - @frosty :slight_smile: Much better looking than my meathod with darkening noise. Speed?.. I’ll see. An frosty, what ups are you using?

Haha. Can’t wait to release this M rated version of Frogger :slight_smile:

@Zoyt ups?

Sorry. iPad @frosty

Oh, still an iPad 1 at the moment. Can’t wait for the 3 to be released! :slight_smile: