# Infinite Scrolling

I’ve been working on a random path generator using Perlin noise, and it works pretty well, but I’ve been having problems trying to test its to create extremely long paths; right now I’m just plotting the path on a really big image, but it runs out of space pretty quickly. Is there any better way to do this?

For the record, here’s my current source:

```--# Main
-- Trails

-- Use this function to perform your initial setup
function setup()
displayMode(FULLSCREEN)

alg = 2
size = 1/100
speed = 1
rsize = 0.1

rot = 1

fspeed = 100

cp = vec2(WIDTH/2/rsize-100, HEIGHT/4/rsize+100)

background(255)
---[[
im = image(WIDTH*2, HEIGHT*2)

spriteMode(CORNER)

xmin = 9^99
xmax = -1
ymin = 9^99
ymax = -1

--points = {}
--backingMode(RETAINED)
end

-- This function gets called once every frame
function draw()
-- This sets a dark background color
background(255)

setContext(im)

if ElapsedTime < 0.5 then background(255) end -- Sometimes needed, idk
strokeWidth(1)
resetMatrix()

-- Do your drawing here
for n = 1, fspeed do
local p = cp
cp = algs[alg](cp, size, rot)

stroke(0, 0, 0, 255)
fill(0, 0, 0, 255)

line(p.x * rsize, p.y * rsize, cp.x * rsize, cp.y * rsize)
end

setContext()

translate(math.floor((WIDTH / 2) - cp.x*rsize), math.floor((HEIGHT - 50) - cp.y*rsize))
sprite(im, 0,0, im.width, im.height)

resetMatrix()

end

--# Algs
algs = {}

algs[1] = function(np, s)
np.x = np.x + noise(np.x*s)*speed
np.y = np.y + noise(np.y*s)*speed
return np
end

algs[2] = function(np, s, rot)
local r = noise(np.x*s, np.y*s)*speed

np.x = np.x + math.sin(r*6*math.pi*rot) * speed
np.y = np.y + math.cos(r*6*math.pi*rot) * speed
return np
end

algs[3] = function(np, s)
local x = noise(np.x*s)*speed
local y = noise(np.y*s)*speed

if x == 0 then x = 0.05 end
if y == 0 then y = 0.05 end

x, y = x / (x + y), y / (x + y)

np.x = np.x + x * speed
np.y = np.y + y * speed
return np
end

``````

@FLCode What do you mean it runs out of space. What I see is it is drawing beyond the edges of the image im. It’s still going, but you can’t see where it’s plotting. I’m going to try something else.

@FLCode Try this. I stripped out code I wasn’t using just to keep it small. Use your finger to scroll the image area around to follow the line. Once it goes off the image area, you can stop the code. Change the values in the line cp=vec2(6000,195) to cause different paths.

``````
--# Main
-- Trails

displayMode(FULLSCREEN)

function setup()
spriteMode(CORNER)
dx,dy=0,0
alg = 2
size = 1/100
speed = 1
rsize = 0.1
rot = 1
fspeed = 100
cp=vec2(6000,195)
im=image(WIDTH*2,HEIGHT*2)
setContext(im)
background(255)
setContext()
stroke(0)
strokeWidth(1)
end

function draw()
background(0)
setContext(im)
for n = 1, fspeed do
local p = cp
cp = algs(cp, size, rot)
line(p.x * rsize, p.y * rsize, cp.x * rsize, cp.y * rsize)
end
setContext()
sprite(im, dx,dy, im.width, im.height)
end

function touched(t)
if t.state==MOVING then
dx=dx+t.deltaX
dy=dy+t.deltaY
end
end

function algs(np, s, rot)
local r = noise(np.x*s, np.y*s)*speed
np.x = np.x + math.sin(r*6*math.pi*rot) * speed
np.y = np.y + math.cos(r*6*math.pi*rot) * speed
return np
end

``````

@FLCode this is completely off topic, but how did you get your code to format so nicely in your first post?

@yojimbo2000

< pre lang=“lua” >

code

< /pre >

but remove the space after < and before >

@dave1707 great, thanks! And apologies for thread hijacking

Here is a slightly modified version of @dave1707’s code which has a second image area directly above it (I’ve coloured it differently so you can see the difference) which gives you double the area.

Making it infinite is going to be difficult as you are going to need to store an infinite number of these images. However you could use this approach to detect if you were near the edge of an image and generate a new one at that edge to progress into.

``````

--# Main
-- Trails

displayMode(FULLSCREEN)

function setup()
spriteMode(CORNER)
dx,dy=0,0
alg = 2
size = 1/100
speed = 1
rsize = 0.1
rot = 1
fspeed = 100
cp=vec2(6000,195)
im=image(WIDTH*2,HEIGHT*2)
setContext(im)
background(255)
setContext()
im2=image(WIDTH*2,HEIGHT*2)
setContext(im2)
background(221, 232, 82, 255)
setContext()
stroke(0)
strokeWidth(1)
end

function draw()
background(0)
for n = 1, fspeed do
local p = cp
cp = algs(cp, size, rot)
if p.y*rsize>HEIGHT*2 then
setContext(im2)
line(p.x * rsize, p.y * rsize-2*HEIGHT, cp.x * rsize, cp.y * rsize-2*HEIGHT)
setContext()
else
setContext(im)
line(p.x * rsize, p.y * rsize, cp.x * rsize, cp.y * rsize)
setContext()
end
end
sprite(im, dx,dy, im.width, im.height)
sprite(im2, dx,dy+2*HEIGHT, im.width, im.height)
end

function touched(t)
if t.state==MOVING then
dx=dx+t.deltaX
dy=dy+t.deltaY
end
end

function algs(np, s, rot)
local r = noise(np.x*s, np.y*s)*speed
np.x = np.x + math.sin(r*6*math.pi*rot) * speed
np.y = np.y + math.cos(r*6*math.pi*rot) * speed
return np
end
``````

Problem with @West approach is because you can always scroll back you need to ultimately keep an infinite number of images.

Back to the original where it was walking, I’ve done something which I believe achieves the goal, except, for some reason there’s something with sprite scaling going on I don’t understand, it causes the trail to slowly blur behind you. Also, it does eventually stop, but I suspect this is the noise function blowing out a variable perhaps…

Also, note if it doubles back far enough it’ll find it’s trail had been trimmed.

``````--# Main
-- Trails

-- Use this function to perform your initial setup
function setup()
displayMode(FULLSCREEN)

alg = 2
size = 1/100
speed = 1
rsize = 0.1

rot = 1

fspeed = 100

cp = vec2(WIDTH/2/rsize-100, HEIGHT/4/rsize+100)

background(255)

im1 = image(WIDTH*2, HEIGHT*2)
im2 = image(WIDTH*2, HEIGHT*2)

setContext(im1)
background(255)
setContext(im2)
background(255)

spriteMode(CORNER)

xmin = 9^99
xmax = -1
ymin = 9^99
ymax = -1

curIm = 1
--points = {}
--backingMode(RETAINED)
end

-- This function gets called once every frame
function draw()
-- This sets a dark background color
background(255)

if curIm == 1 then
im = im1
previm = im2
curIm = 2
else
im = im2
previm = im1
curIm = 1
end

setContext(im)

strokeWidth(1)

translate(WIDTH, HEIGHT*3/2 - 50)

local pOrigin = vec2(cp.x,cp.y)
output.clear()
print(pOrigin)
for n = 1, fspeed do
local p = vec2(cp.x, cp.y)
cp = algs[alg](cp, size, rot)

stroke(0, 0, 0, 255)
fill(0, 0, 0, 255)

line(p.x * rsize - pOrigin.x * rsize, p.y * rsize - pOrigin.y * rsize, cp.x * rsize - pOrigin.x * rsize, cp.y * rsize - pOrigin.y * rsize)

end

setContext(previm)
background(255)
resetMatrix()
translate(pOrigin.x * rsize - cp.x * rsize, pOrigin.y * rsize - cp.y * rsize)

sprite(im , 0, 0, im.width, im.height)

setContext()
resetMatrix()
scale(2)
--sprite(im, 0,0,WIDTH, HEIGHT)
sprite(im, -WIDTH/2,-HEIGHT/2, im.width, im.height)

end

--# Algs
algs = {}

algs[1] = function(np, s)
np.x = np.x + noise(np.x*s)*speed
np.y = np.y + noise(np.y*s)*speed
return np
end

algs[2] = function(np, s, rot)
local r = noise(np.x*s, np.y*s)*speed

np.x = np.x + math.sin(r*6*math.pi*rot) * speed
np.y = np.y + math.cos(r*6*math.pi*rot) * speed
return np
end

algs[3] = function(np, s)
local x = noise(np.x*s)*speed
local y = noise(np.y*s)*speed

if x == 0 then x = 0.05 end
if y == 0 then y = 0.05 end

x, y = x / (x + y), y / (x + y)

np.x = np.x + x * speed
np.y = np.y + y * speed
return np
end
``````

Actually, playing with it a little more, I think it “stops” not because a variable broke, but because the noise is deterministic on the coordinate. I think it hit’s points where it will just oscillate between two points forever. Maybe trying getting ElapsedTime into the noise somewhere or trying some other noise function… The below tweaked version seems to run for a long time, if not forever…

Also fixed the fading… it was a smooth (anti aliasing) on the spriting building up over many cycles. This is also fixed below.

``````--# Main

-- Trails

-- Use this function to perform your initial setup

function setup()
displayMode(FULLSCREEN)

alg = 2
size = 1/100
speed = 1
rsize = 0.1

rot = 1

fspeed = 100

cp = vec2(15000,15000)
--cp = vec2(WIDTH/2/rsize-100, HEIGHT/4/rsize+100)

background(255)

im1 = image(WIDTH*2, HEIGHT*2)
im2 = image(WIDTH*2, HEIGHT*2)

setContext(im1)
background(255)
setContext(im2)
background(255)

spriteMode(CORNER)

xmin = 9^99
xmax = -1
ymin = 9^99
ymax = -1

curIm = 1

end

-- This function gets called once every frame

function draw()

-- This sets a dark background color

background(255)

if curIm == 1 then
im = im1
previm = im2
curIm = 2
else
im = im2
previm = im1
curIm = 1
end

setContext(im)

strokeWidth(1)
smooth()
translate(WIDTH, HEIGHT*3/2 - 50)

local pOrigin = vec2(cp.x,cp.y)

for n = 1, fspeed do
local p = vec2(cp.x, cp.y)
cp = algs[alg](cp, size, rot)
stroke(0, 0, 0, 255)
fill(0, 0, 0, 255)

line(p.x * rsize - pOrigin.x * rsize, p.y * rsize - pOrigin.y * rsize, cp.x * rsize - pOrigin.x * rsize, cp.y * rsize - pOrigin.y * rsize)
end
noSmooth()
--recenter in secondary buffer (I think this is where the blurring leaks in...)
setContext(previm)
background(255)
resetMatrix()
translate(pOrigin.x * rsize - cp.x * rsize, pOrigin.y * rsize - cp.y * rsize)
sprite(im , 0, 0, im.width, im.height)

--draw to screen
setContext()
resetMatrix()
scale(2)
sprite(im, -WIDTH/2,-HEIGHT/2, im.width, im.height)
end

--# Algs
algs = {}

algs[1] = function(np, s)
np.x = np.x + noise(np.x*s)*speed
np.y = np.y + noise(np.y*s)*speed
return np
end

algs[2] = function(np, s, rot)
local r = noise(np.x*s, np.y*s, ElapsedTime * 0.1)*speed
np.x = np.x + math.sin(r*6*math.pi*rot) * speed
np.y = np.y + math.cos(r*6*math.pi*rot) * speed
return np
end

algs[3] = function(np, s)
local x = noise(np.x*s)*speed
local y = noise(np.y*s)*speed
if x == 0 then x = 0.05 end
if y == 0 then y = 0.05 end
x, y = x / (x + y), y / (x + y)

np.x = np.x + x * speed
np.y = np.y + y * speed
return np
end
``````

@spacemonkey is correct. I altered my code so it went to 4 different images and when it stopped, I printed out the values. They just kept flipping between the same 2 values.