You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
138 lines
3.8 KiB
Arduino
138 lines
3.8 KiB
Arduino
5 years ago
|
/*
|
||
|
* good old starfield
|
||
|
*
|
||
|
* The way this one works is by first filling the screen with pixels at
|
||
|
* random coordinates. Then at each frame we calculate the new position of
|
||
|
* each pixel as if it was going away from the center of the screen. When a
|
||
|
* pixel is going off screen, it is reassigned at a new random position.
|
||
|
* To simulate a bit of depth, some pixels move twice as fast.
|
||
|
*
|
||
|
* Limitations: all the pixels/stars coordinates are stored in float arrays.
|
||
|
* Each float is 4 bytes in size (32 bits) and the Nano has 2 KB of SRAM.
|
||
|
* For each pixel/star we need to store 4 floats: x, y, vx, vy. That's
|
||
|
* 16 bytes per pixel/star, so we should be able to store quite few.
|
||
|
* However, the SRAM is already used by other parts of the code, and TVout.
|
||
|
* In practice with the current implementation, there's just enough free
|
||
|
* memory left for 25 pixels/stars :(
|
||
|
*
|
||
|
* See starfield51 for a modification that allows to have 51 stars :)
|
||
|
*/
|
||
|
|
||
|
#include <TVout.h>
|
||
|
|
||
|
TVout TV;
|
||
|
|
||
|
#define STARS 25
|
||
|
|
||
|
float x[STARS]; // x coordinates of all the stars
|
||
|
float y[STARS]; // y coordinates of all the stars
|
||
|
float vx[STARS]; // vx and vy are the increments that we add to x
|
||
|
float vy[STARS]; // and y at each frame to get the x,y position
|
||
|
|
||
|
/*
|
||
|
* new_star(i) generates the x, y, vx, and vy values for star i
|
||
|
* x is generated at random x-axis position around the centre
|
||
|
* y is generated at random y-axis position around the centre
|
||
|
* we calculate the distances dx and dy from the screen center ox,oy
|
||
|
* (we cheat a bit to make sure no 0 are left in a division later on)
|
||
|
* we use dx and dy to calculte the distance vl between the star
|
||
|
* and the center, ie the magnitude of the vector (center, star)
|
||
|
* we use the magnitude to normalize the vector, namely calculating
|
||
|
* the normalized components vx and vy
|
||
|
*/
|
||
|
void
|
||
|
new_star(uint8_t i)
|
||
|
{
|
||
|
uint8_t ox = 60;
|
||
|
uint8_t oy = 48;
|
||
|
float dx, dy, vl;
|
||
|
|
||
|
x[i] = 30 + random(60);
|
||
|
y[i] = 24 + random(48);
|
||
|
|
||
|
dx = x[i] - ox;
|
||
|
dy = y[i] - oy;
|
||
|
|
||
|
switch(int(dx))
|
||
|
case 0: dx = 1; // CHEAT
|
||
|
|
||
|
vl = sqrt(dx*dx + dy*dy);
|
||
|
vx[i] = dx / vl;
|
||
|
vy[i] = dy / vl;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* new_stars() creates as many stars as set by the STARS constant
|
||
|
*/
|
||
|
void
|
||
|
new_stars()
|
||
|
{
|
||
|
for (uint8_t i = 0; i < STARS; i++)
|
||
|
new_star(i);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Nothing exciting here, we initialize the PRNG with some noise,
|
||
|
* configure TV out, and generate coordinates for all stars.
|
||
|
*/
|
||
|
void
|
||
|
setup()
|
||
|
{
|
||
|
randomSeed(analogRead(6)); // effective?
|
||
|
TV.begin(NTSC,120,96);
|
||
|
new_stars();
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* update_stars() goes through all the x and y values and update
|
||
|
* them in such a way that:
|
||
|
* new x = current x + vx
|
||
|
* new y = current y + vy
|
||
|
* we also test if the new coordinates of the star are still in the
|
||
|
* visible part of the screen, and if not, we call new_star() to
|
||
|
* generate new x, y, vx, vy all over again
|
||
|
* Note: fancy effect, the first 20 stars are updated with regular
|
||
|
* vx and vy values, while the last 5 are a updated with 2 times vx and vy,
|
||
|
* which means that these 5 last stars will move twice the speed.
|
||
|
*/
|
||
|
void
|
||
|
update_stars()
|
||
|
{
|
||
|
for (uint8_t i = 0; i < 20; i++) {
|
||
|
x[i] = x[i] + vx[i];
|
||
|
y[i] = y[i] + vy[i];
|
||
|
if (x[i] > 120 || x[i] < 0 || y[i] < 0 || y[i] > 96)
|
||
|
new_star(i);
|
||
|
}
|
||
|
for (uint8_t i = 20; i < STARS; i++) {
|
||
|
x[i] = x[i] + vx[i] * 2;
|
||
|
y[i] = y[i] + vy[i] * 2;
|
||
|
if (x[i] > 120 || x[i] < 0 || y[i] < 0 || y[i] > 96)
|
||
|
new_star(i);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* draw_stars() walks through the x and y coordinates arrays and
|
||
|
* uses the value to draw a pixel for each star
|
||
|
*/
|
||
|
void
|
||
|
draw_stars()
|
||
|
{
|
||
|
for (uint8_t i = 0; i < STARS; i++)
|
||
|
TV.set_pixel(x[i], y[i], 1);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* loop() is stuck doing the same stuff forever because it dared to trick
|
||
|
* the gods...
|
||
|
*/
|
||
|
void
|
||
|
loop()
|
||
|
{
|
||
|
TV.delay_frame(1);
|
||
|
update_stars();
|
||
|
TV.clear_screen();
|
||
|
draw_stars();
|
||
|
}
|