An in development game that is heavy on perspective and animation, needed a little something extra for it’s intro and cut scenes. The solution was to create a hyperspace star field effect with individual, animated pixels.
My first attempt at the effect was to start each pixel at the screens center and randomly animate the stars outward, the result was less than satisfactory, either the range of the animation was too narrow or it was erratic.
The solution was to at initialization, create two tables, one for Y and one for y with randomly generated locations on the screen. Interestingly, to limit the resolution of the values in Pico8, we set the upper limit as a parameter of rnd(x) and subtract an amount to set the negative limit of the range, for example :
for i=1,stars do -- Generate the two co-ordinate tables used to store each stars x and y
add(starx,((rnd(256)-128))) -- 256 - 128 gives us a resolution between positive 128 and negative 128 i.e. the size of our screen
add(stary,((rnd(256)-128)))
end
The remainder of the _init() function comprises of mostly table and variable declarations. The other statement I would like to point out in the global var: a=0.0001. This tiny number is used reduce the larger random numbers in the X and Y tables to near zero, or in other words, the center of the screen. Using a multiplier later on, we’ll see how these small numbers are used animate out each star.
function _init()
center = 64 -- Set the center of the screen, the starting point for each star
stars = 200 -- Number of stars to be generated
starx={} -- Create the x co-ordinates table for each star
stary={} -- Create the x co-ordinates table for each star
oldx = 0 -- Used to store x co-ordinates before they get animated
oldy = 0 -- Used to store x co-ordinates before they get animated
x_vol = 0 -- These two variables are used to accelerate the randomly created points for each star
y_vol = 0
a=0.0001 -- This itty bitty number basiclly reduces the large random x,y positions to near zero and then slowly brings them up to the full number
for i=1,stars do -- Generate the two co-orindate tables used to store each stars x and y
add(starx,((rnd(256)-128))) -- 256 - 128 gives us a resolution between positive 128 and negative 128 i.e. the size of our screen
add(stary,((rnd(256)-128)))
end
star_array_x = {} -- Empty tables to populate with the final rendered pixel position
star_array_y = {}
end
Animating the Stars
The last part of this particle animation cart is the gen_stars() function that is called by Pico-8’s _draw() function. Now we take the previously established x_vol and y_vol variables and randomly increment them with the tiny “a” var.
x_vol+=rnd(3*a) -- Here's the magic for the star acceleration, an iterated tiny number that controls the speed of the stars
y_vol+=rnd(3*a)
X_vol and y_vol are used by used by the indexes in the position tables to produce a slightly varying starting point for each star but each position is very close 0, the starting point. As each starx[i] and stary[i] are incremented, the differences grow and the stars start to separate.
But first, we store the original location of each coordinate in a holding var.
oldx = starx[i] -- Storing the original position of each star
oldy = stary[i]
star_array_x[i] = center + (starx[i] * x_vol) /2 -- Putting all the calculations together to write each stars x and y
star_array_y[i] = center + (stary[i] * y_vol) /2
Now we can put it altogether into the gen_stars() function. I added little secondary animation sequence using the stored original coordinates to simulate coming out of hyperspace.
function gen_stars() -- Called by _draw
for i=1, stars do -- Start the star loop
x_vol+=rnd(3*a) -- Here's the magic for the star acceleration, an iterated tiny number that controls the speed of the stars
y_vol+=rnd(3*a)
oldx = starx[i] -- Storing the original position of each star
oldy = stary[i]
star_array_x[i] = center + (starx[i] * x_vol) /2 -- Putting all the calculations together to write each stars x and y
star_array_y[i] = center + (stary[i] * y_vol) /2
-- Do the 2nd star wave when each a point off screen
if(star_array_x[i]>128 or star_array_y[i]>128 or star_array_x[i] < 0 or star_array_y[i] < 0) then
x_vol+=rnd(1*a)
y_vol+=rnd(1*a)
starx[i] = rnd(256)-128
stary[i] = rnd(256)-128
starx[i]=oldx
stary[i]=oldy
star_array_x[i] = center + (starx[i] * x_vol) / 15
star_array_y[i] = center + (stary[i] * y_vol) / 15
end
pset(star_array_x[i], star_array_y[i] , 7) -- write the pixels!
end
end
The full cart is available over at Github, thanks for reading!