Simulator experiments

Quick test with particles:

#include "pokitto.h"
#include "math.h"
Pokitto::Core game;

//110x88
unsigned char xp=55;
signed char xo=0;
unsigned char yp=80;

unsigned char partIndx=0;
struct Particle {
   float x;
   float y;
   float dx;
   float dy;
   float life=9999;
} ;
const unsigned MAX_PART=200;
static Particle particles[MAX_PART];

static unsigned char PAL_FILE[5]={C_YELLOW,C_ORANGE,C_RED,C_BROWN,C_DARKGRAY};

void addParticle(unsigned char x,unsigned char y)
{
    particles[partIndx].x=x;
    particles[partIndx].y=y;
    particles[partIndx].dx=random(-100,100)/300.0;
    particles[partIndx].dy=random(-100,-80)/80.0;
    particles[partIndx].life=0;
    partIndx++;
    if (partIndx>MAX_PART) {partIndx=0;}
}

void renderParticles()
{
    for (int i=0;i<MAX_PART;i++)
        {
            if(particles[i].life<50)
            {
                particles[i].life++;
                game.display.color=PAL_FILE[(int)particles[i].life/10];

                particles[i].x+=particles[i].dx;
                particles[i].y+=particles[i].dy;

                float radius= particles[i].life/10;
                game.display.fillCircle(particles[i].x,particles[i].y,radius);
                if(particles[i].life>10){
                    game.display.color=C_BLACK;
                    game.display.drawCircle(particles[i].x,particles[i].y,radius);
                }
            }
        }
}

int main () {
game.begin();
game.display.load565Palette(def565palette);
while (game.isRunning()) {
    if (game.update()) {

        if (game.upBtn()) {yp-=2;}
        if (game.downBtn()) {yp+=2;}
        if (game.rightBtn()) {xp+=2;}
        if (game.leftBtn()) {xp-=2;}

        //Particles
        renderParticles();

        //Cursor
        game.display.color=C_RED;
        xo=-15*sin(game.frameCount/10.0);
        addParticle(xp+xo,yp);
        addParticle(xp+xo,yp);
        addParticle(xp+xo,yp);
        game.display.drawCircle((xp+xo),yp,2);

        //Cross
        game.display.drawLine(xp-1,yp,xp+1,yp);
        game.display.drawLine(xp,yp-1,xp,yp+1);
    }
}
return 1;
}


5 Likes

Excellent work! Note to self: add particles to lib.

back again with a little bit of broken code…

It will run fine in the simulator as it is, but if you uncomment the second part of the draw routine it will crash.

It’s supposed to be this - https://www.khanacademy.org/computer-programming/Metaballs!/6209526669246464

#include "pokitto.h"
Pokitto::Core game;

int width=110;
int height=88;

int PX_SIZE = 3;
int PY_SIZE = PX_SIZE;
int SUM_THRESHOLD = 10;
const int NUM_CIRCLES = 8;

struct circle{
    int x;
    int y;
    int r;
    int vx;
    int vy;
};
static circle c[NUM_CIRCLES];

int RandMinMax(int min, int max){
    return rand() % max + min;
}

void draw_circles(){

    for (int i = 0; i < NUM_CIRCLES; i++) {

        c[i].x += c[i].vx;
        c[i].y += c[i].vy;

        if (c[i].x - c[i].r < 0) {
            c[i].vx = +abs(c[i].vx);
        }
        if (c[i].x + c[i].r > width) {
            c[i].vx = -abs(c[i].vx);
        }
        if (c[i].y - c[i].r < 0) {
            c[i].vy = +abs(c[i].vy);
        }
        if (c[i].y + c[i].r > height) {
            c[i].vy = -abs(c[i].vy);
        }

        game.display.color = i;
        game.display.drawCircle(c[i].x,c[i].y,c[i].r);

    }

/*
    for (int x = 0; x < width; x += PX_SIZE) {
        for (int y = 0; y < height; y += PY_SIZE) {
            int sum = 0;
            int closestD2 = 9999999;
            int closestColor = 0;
            for (int i = 0; i < NUM_CIRCLES; i++) {
                int dx = x - c[i].x;
                int dy = y - c[i].y;
                int d2 = dx * dx + dy * dy;
                sum += c[i].r * c[i].r / d2;

                if (d2 < closestD2) {
                    closestD2 = d2;
                    closestColor = 1;//[c.red, c.green, c.blue];
                }
            }
            if (sum > SUM_THRESHOLD) {
                game.display.color = closestColor;
                game.display.fillRectangle(x, y, PX_SIZE, PY_SIZE);
            }
        }
    }
*/

}

int main(){

    srand(game.getTime());
    for (int i = 0; i < NUM_CIRCLES; i++) {
        c[i].x = RandMinMax(0,width);
        c[i].y = RandMinMax(0,height);
        c[i].r = RandMinMax(5, 10);
        c[i].vx = RandMinMax(-2,2);
        c[i].vy = RandMinMax(-2,2);
    }



	game.begin();
	game.display.width = width; // full size
	game.display.height = height;
    game.setFrameRate(60);
    game.display.load565Palette(def565palette);

	while (game.isRunning()) {
        if (game.update()) {
            //game.display.drawPixel(x,y,pixel/16);
            draw_circles();
        }
}
return 1;
}

I think you are dividing by zero.

If you replace the line:

sum += c[i].r * c[i].r / d2;

with:

if (d2 != 0) sum += c[i].r * c[i].r / d2;

then it stops the crashing. But the result is not pretty.
The code is summing up fractional items, which doesn’t work well with integers.

Catsfolly

Spinal -

This version kinda works!

I multiplied the fractional things by 16 to make them integers.
And I got rid of the color zero circle by adding 1 to the circle index.

#include "pokitto.h"
Pokitto::Core game;
int width=110;
int height=88;
int PX_SIZE = 3;
int PY_SIZE = PX_SIZE;
int SUM_THRESHOLD = 10;
const int NUM_CIRCLES = 8;
struct circle{
    int x;
    int y;
    int r;
    int vx;
    int vy;
};
static circle c[NUM_CIRCLES];
int RandMinMax(int min, int max){
    return rand() % max + min;
}
void draw_circles(){
    for (int i = 0; i < NUM_CIRCLES; i++) {

    c[i].x += c[i].vx;
    c[i].y += c[i].vy;

    if (c[i].x - c[i].r < 0) {
        c[i].vx = +abs(c[i].vx);
    }
    if (c[i].x + c[i].r > width) {
        c[i].vx = -abs(c[i].vx);
    }
    if (c[i].y - c[i].r < 0) {
        c[i].vy = +abs(c[i].vy);
    }
    if (c[i].y + c[i].r > height) {
        c[i].vy = -abs(c[i].vy);
    }

    game.display.color = i+1;
    game.display.drawCircle(c[i].x,c[i].y,c[i].r);

}
// was commented out
    for (int x = 0; x < width; x += PX_SIZE) {
        for (int y = 0; y < height; y += PY_SIZE) {
            int sum = 0;
            int closestD2 = 32767;
            int closestColor = 0;
            for (int i = 0; i < NUM_CIRCLES; i++) {
                int dx = x - c[i].x;
                int dy = y - c[i].y;
                int d2 = dx * dx + dy * dy;
                if (d2 != 0) sum += ((c[i].r * c[i].r) * 16) / d2;
                if (d2 < closestD2) {
                closestD2 = d2;
                closestColor = i+1;//[c.red, c.green, c.blue];
            }
        }
        if (sum > SUM_THRESHOLD) {
            game.display.color = closestColor;
            game.display.fillRectangle(x, y, PX_SIZE, PY_SIZE);
        }
    }
}
// end commented out
}
int main(){
    srand(game.getTime());
for (int i = 0; i < NUM_CIRCLES; i++) {
    c[i].x = RandMinMax(0,width);
    c[i].y = RandMinMax(0,height);
    c[i].r = RandMinMax(5, 10);
    c[i].vx = RandMinMax(-2,2);
    c[i].vy = RandMinMax(-2,2);
}



game.begin();
game.display.width = width; // full size
game.display.height = height;
game.setFrameRate(60);
game.display.load565Palette(def565palette);

while (game.isRunning()) {
    if (game.update()) {
        //game.display.drawPixel(x,y,pixel/16);
        draw_circles();
    }
}
return 1;
}

Nice effect!

Catsfolly

Smoothed it a little…

#include "pokitto.h"
Pokitto::Core game;
int width=110;
int height=88;

int PX_SIZE = 1;
int PY_SIZE = PX_SIZE;
int SUM_THRESHOLD = 64;
const int NUM_CIRCLES = 6;
struct circle{
    int x;
    int y;
    int r;
    int vx;
    int vy;
};
static circle c[NUM_CIRCLES];
int RandMinMax(int min, int max){
    return rand() % max + min;
}
void draw_circles(){
    for (int i = 0; i < NUM_CIRCLES; i++) {

    c[i].x += c[i].vx;
    c[i].y += c[i].vy;

    if (c[i].x - c[i].r < 0) {
        c[i].vx = +abs(c[i].vx);
    }
    if (c[i].x + c[i].r > width) {
        c[i].vx = -abs(c[i].vx);
    }
    if (c[i].y - c[i].r < 0) {
        c[i].vy = +abs(c[i].vy);
    }
    if (c[i].y + c[i].r > height) {
        c[i].vy = -abs(c[i].vy);
    }

    game.display.color = i+1;
    game.display.drawCircle(c[i].x,c[i].y,c[i].r);

}
// was commented out
    for (int x = 0; x < width; x += PX_SIZE) {
        for (int y = 0; y < height; y += PY_SIZE) {
            int sum = 0;
            int closestD2 = 32767;
            int closestColor = 0;
            for (int i = 0; i < NUM_CIRCLES; i++) {
                int dx = x - c[i].x;
                int dy = y - c[i].y;
                int d2 = dx * dx + dy * dy;
                if (d2 != 0) sum += ((c[i].r * c[i].r) * 64) / d2;
                if (d2 < closestD2) {
                closestD2 = d2;
                closestColor = i+1;//[c.red, c.green, c.blue];
            }
        }
        if (sum > SUM_THRESHOLD) {
            game.display.color = closestColor;
            game.display.fillRectangle(x, y, PX_SIZE, PY_SIZE);
        }
    }
}
// end commented out
}
int main(){
    srand(game.getTime());
for (int i = 0; i < NUM_CIRCLES; i++) {
    c[i].x = RandMinMax(0,width);
    c[i].y = RandMinMax(0,height);
    c[i].r = RandMinMax(5, 15);
    c[i].vx = RandMinMax(-2,2);
    c[i].vy = RandMinMax(-2,2);
}



game.begin();
game.display.width = width; // full size
game.display.height = height;
game.setFrameRate(60);
game.display.load565Palette(def565palette);

while (game.isRunning()) {
    if (game.update()) {
        //game.display.drawPixel(x,y,pixel/16);
        draw_circles();
    }
}
return 1;
}
1 Like

Yeah. It has a nice multi-colored lava lamp feel to it now…

Something is cooking…

#include "pokitto.h"
#include "math.h"
Pokitto::Core game;

//110x88
float buf[110][90];
float m,b,t,l,r,c;
static unsigned char PAL[]={C_BLACK,C_WHITE,C_YELLOW,C_YELLOW,C_ORANGE,C_ORANGE,C_RED,C_RED,C_RED,C_BROWN,C_LIGHTGRAY,C_DARKGRAY,C_BLACK};

int main () {
game.begin();
game.display.load565Palette(def565palette);
while (game.isRunning()) {
    if (game.update()) {

    //Merge fire
    for (int y=88;y>1;y--)
    {
        for (int x=5;x<110-5;x++)
        {
            m=buf[x][y]-40;
            t=buf[x][y-1]-y;
            b=buf[x][y+1]-10;
            l=buf[x-1][y]-10;
            r=buf[x+1][y]-120;
            c=(ceil(m+b+t+l+r)/4.2);

			if(c>1000){c=1000;}
			if(c<0){c=0;}

			//move
            buf[x][y-1]=c;
        }
    }

    //Add more fire at bottom
	for (int x=10;x<110-10;x++){buf[x][88]=random(0,800);}

    //Draw Fire
	for (int x=1;x<110-1;x++)
    {
        for (int y=1;y<88;y++)
        {
            char f=ceil(buf[x][y]/1000*12);
            game.display.drawPixel(x,y,PAL[f]);
        }
    }

 }
}
return 1;
}


3 Likes

Classic 3d

#include "pokitto.h"
#include "math.h"

Pokitto::Core game;

//110x88
typedef struct
{
    float x;
    float y;
} Point2d;


typedef struct
{
    float x;
    float y;
    float z;
} Point3d;

const int LEN_POINTS=64;
Point3d points[LEN_POINTS];

float angle=0.1;

Point2d p2d(Point3d p3d)
{
    Point2d out2d;

    float fov = 128;
    float x0 = p3d.x;
    float y0 = p3d.y;
    float z0 = p3d.z;
    float x2d = fov * x0 / z0;
    float y2d = fov * y0 / z0;

    x2d = x2d + 55; //center w
    y2d = y2d + 44;  //center h

    out2d.x=x2d;
    out2d.y=y2d;

    return out2d;
}

Point3d rot3d(Point3d p3d,Point3d pivot,float ax,float ay,float az)
{
    float a;
    float b;
    float c;
    float a1;
    float b1;
    float c1;
    float a2;
    float b2;
    float c2;
    float a3;
    float b3;
    float c3;
    Point3d np3d;

    a = p3d.x-pivot.x;
    b = p3d.y-pivot.y;
    c = p3d.z-pivot.z;

    a1 = a*cos(az)-b*sin(az);
    b1 = a*sin(az)+b*cos(az);
    c1 = c;

    c2 = c1*cos(ay)-a1*sin(ay);
    a2 = c1*sin(ay)+a1*cos(ay);
    b2 = b1;

    b3 = b2*cos(ax)-c2*sin(ax);
    c3 = b2*sin(ax)+c2*cos(ax);
    a3 = a2;

    a3 = a3+pivot.x;
    b3 = b3+pivot.y;
    c3 = c3+pivot.z;

    np3d.x=a3;
    np3d.y=b3;
    np3d.z=c3;
    return np3d;
}

int main ()
{
    game.begin();
    game.display.load565Palette(def565palette);

    int i=0;
    for (int x=0; x<4; x++)
    {
        for (int y=0; y<4; y++)
        {
            for (int z=0; z<4; z++)
            {
                points[i].x=x*12;
                points[i].y=y*12;
                points[i].z=100+z*12;
                i++;
            }
        }
    }

    Point2d pp;
    Point3d pr;
    Point3d center;
    center.x=0;
    center.y=0;
    center.z=100;

    while (game.isRunning())
    {
        if (game.update())
        {
            angle+=0.1;
            game.display.setColor(C_YELLOW);
            for (int i=0; i<LEN_POINTS; i++)
            {
                pr = rot3d(points[i],center, angle,angle/2,0);
                pp = p2d(pr);
                game.display.fillCircle(pp.x,pp.y,2);
            }
        }
    }
    return 1;
}


3 Likes

Worked 1st try. Floating point is murder for ARM Cortex-M0+. Needs optimization.

2 Likes

Worked first time, no problems.

1 Like

@HomineLudens

This one looks awesome and runs 1:1 with simulator

2 Likes

Wow! Thanks @jonne for the preview. It really looks hypnotic!

1 Like

That’s definitely need it :sweat_smile: . I thought out out using floats without thinking about performance or optimization. There’s a lot of room for it. Thanks for test it!

1 Like

sine lookup table should help alot. also you should try a 16 color gradient palette to get even more “3d feel” (furthest balls are darkest)

1 Like

Look up table was one in my todolist. Gradient palette it’ll be a great addiction too.

Started porting my TIC-80 CGA Jam project.

3 Likes

Ooh! Looking lovely!

Edit: CGA is such a beautiful colorscheme :heart_eyes:

1 Like

Also started porting my first ever game “JETPAC” for practice :slight_smile:

5 Likes

message me if you want me to test that on the real hardware. lots of particle stuff, would be interesting to know the performance. also, if its code you do not want to be seen in public yet, I will delete it after testing

1 Like