Simulator experiments

This is my first attempt to use the simulator. It displays a bouncing line.
Hold down the A button (Z on the keyboard) to clear the screen before each line draw.

To build it, replace the code in “Hello.c” with this code:

#include "Pokitto.h"
Pokitto::Core game;
/*
	In this tutorial we are using fast screen mode.
	It means screen resolution is 110x88

*/
//setting variables
// x coordinates for each point
int16_t x[2];
// y coordinates for each point
int16_t y[2];
// x velocities (added to x each frame)
int16_t xv[2] = {2,2};
// y velocities (added to y each frame)
int16_t yv[2] = {2,2};
// index
int16_t i;
// color to make the line
uint16_t color = 1;



char screenW = 110;
char screenH = 88;

int main(){
	game.begin();
	game.display.width = screenW;
	game.display.height = screenH;
	game.setFrameRate(60);
	game.display.persistence = 1 ;

	for(i= 0 ; i < 2; i++)
{
        x[i] = random( screenW - 1); // randomly position the points
        y[i] = random(screenH -1);

}

	while (game.isRunning()) {
    	if (game.update()) {
    		//-----------buttons-------------
    		if (game.buttons.repeat(BTN_A,0)){ //if button a is pressed
    			game.display.persistence = 0 ;; //then turn off persistence (clear the screen each frame)
    		}
    		else {
                game.display.persistence = 1 ; // don't cleat the screen each frame
    		}

    		//----------logic----------
    		// move the points
			for(i= 0 ; i < 2; i++)
            {
                x[i] = x[i] + xv[i];                    // the the x velocity to the x points
                if ((x[i] >= screenW) || (x[i] < 0))    // if the point is off the screen
                {
                    xv[i] = - xv[i];                    // reverse the velocity
                    x[i] = x[i] + xv[i];                // and undo the move
                }
                y[i] = y[i] + yv[i];                    // the the x velocity to the x point
                if ((y[i] >= screenH) || (y[i] < 0))    // if the point is off the screen
                {
                    yv[i] = - yv[i];                    // reverse the velocity
                    y[i] = y[i] + yv[i];                // and undo the move
                }
            }
            // draw

    		game.display.color = color/4;                   // change the color every 4 frames
    		game.display.drawLine(x[0],y[0],x[1],y[1]);     // draw a line between the two invisible points
    		color = color + 1;                              // advance the color variable
    		if (color > 59) color = 1;                      // but keep it under 15 * 4

    	}
	}
	return(1);
}

Catsfolly

3 Likes

Angry Tunnel!

Here is a simple tunnel to try out the rotate palette function.
Rectangles are drawn in the different colors of the palette, and then the palette is rotated. The smallest rectangle is redrawn so it doesn’t flash all the time…
Somehow, the tunnel looks angry.:open_mouth:

I think it needs more perspective correct sizing of the rectangles…

the code (replaces hello.cpp):

#include "Pokitto.h"
Pokitto::Core game;
/*
	In this tutorial we are using fast screen mode.
	It means screen resolution is 110x88

*/
//setting variables
// upper left coordinates of rectangles
int16_t ulx;
int16_t uly;

uint16_t color = 0;
int16_t current_zero = 15; // remember where color zero is so we can redraw the last rectangle
                            // otherwise it flashes a lot.
uint16_t width;             // width of rectangle
uint16_t height;            // height of the rectangle
boolean first_time;         // only draw the boxes the first time


char screenW = 110;
char screenH = 88;
#define step (2)

int main(){
	game.begin();
	game.display.width = screenW;
	game.display.height = screenH;
	game.setFrameRate(60);
	game.display.persistence = 1 ;

	first_time = true;

	while (game.isRunning()) {
    	if (game.update()) {
            // there is no logic to this program
            // draw
            if (first_time == true)
            {
                ulx = 0;
                uly = 0;
                width = screenW - 1;
                height = screenH - 1;
                for(color = 0 ; color < 16; color++)
                {
                        game.display.color = color;
                        game.display.fillRectangle(ulx,uly,width,height);
                        ulx += step;  // should use different size steps for a perspective look
                        uly += step;
                        width -= step * 2;
                        height -= step * 2;

                }
                first_time = false;
            }
               game.display.color = current_zero;
                        game.display.fillRectangle(ulx,uly,width,height);
            game.display.rotatePalette(1);
            current_zero-- ;  // counter rotate the color number of the zero color
            if (current_zero < 0) current_zero = 15; // wrap around at 15

    	}
	}
	return(1);
}

These are just my first attempts to try out the api…

Catsfolly

1 Like

Here my first attempt to make something with the simulator, can’t wait to see it for real:

and the code:

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

//110x88
const int S=16;
const int S2=S/2;
int cx,cy=0;

void pir(int x,int y,int w,int h,int cx,int cy)
{
  game.display.color=1;
  game.display.fillTriangle(x,y,w/2+cx,h/2+cy,x+w,y);
  game.display.color=3;
  game.display.fillTriangle(x+w,y,w/2+cx,h/2+cy,x+w,y+h);
  game.display.color=6;
  game.display.fillTriangle(x,y,w/2+cx,h/2+cy,x,y+h);
  game.display.color=8;
  game.display.fillTriangle(x,y+h,w/2+cx,h/2+cy,x+w,y+h);
}

int main () {
game.begin();
while (game.isRunning()) {
    if (game.update()) {
        for (int x=0;x<game.display.width;x+=S)
        {
            for (int y=0;y<game.display.height;y+=S)
            {
                cx=S2*sin(game.frameCount/300.0*(x+2.0*y));
                cy=S2*cos(game.frameCount/300.0*(2.0*x+y));
                pir(x,y,S,S,x+cx,y+cy);
            }
        }
    }
}

return 1;
}

3 Likes

That’s a nice effect. It looks like flags waving in the breeze.

Thanks, I’ve ported a small LUA demo I made for virtual console here . Time to make it real :grinning: . Still don’t understand how to tune colors .

You can override the default pallet with a new one, the image converters can generate you one 4BS just need to give it a 1x16 image twice and you only need the pallet array, to explain its a 565 rgb encoding of colour

game.display.load565Palette(pallet);

1 Like

Thanks @adekto. Find out there’s already PICO8 palette definition ready to use.

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

//110x88
const int S=16;
const int S2=S/2;
int cx,cy=0;

void pir(int x,int y,int w,int h,int cx,int cy)
{
  game.display.color=C_WHITE;
  game.display.fillTriangle(x,y,w/2+cx,h/2+cy,x+w,y);
  game.display.color=C_LIGHTGRAY;
  game.display.fillTriangle(x+w,y,w/2+cx,h/2+cy,x+w,y+h);
  game.display.color=C_BLUE;
  game.display.fillTriangle(x,y,w/2+cx,h/2+cy,x,y+h);
  game.display.color=C_DARKBLUE;
  game.display.fillTriangle(x,y+h,w/2+cx,h/2+cy,x+w,y+h);
}

int main () {
//Load pico 8 palette
game.display.load565Palette(def565palette);
//Start game
game.begin();
while (game.isRunning()) {
    if (game.update()) {

        for (int x=0;x<game.display.width;x+=S)
        {
            for (int y=0;y<game.display.height;y+=S)
            {
                cx=S2*sin(game.frameCount/300.0*(1+x+y));
                cy=S2*cos(game.frameCount/300.0*(1+x+y));
                pir(x,y,S,S,x+cx,y+cy);
            }
        }
    }
}
return 1;
}

2 Likes

you have to include your image its prety trippy

#include "pokitto.h"
Pokitto::Core game;
const unsigned short pallet[]={
0xf800, 0xf80c, 0xf81c, 0xd01f,
0x681f, 0x101f, 0x1ff, 0x5bf,
0x7fe, 0x7f3, 0x7e6, 0x17e0,
0x77e0, 0xe7e0, 0xfea0, 0xfae0,
};
int main () {
game.begin();

game.display.load565Palette(pallet);
while (game.isRunning()) {
    if (game.update()) {
        game.display.rotatePalette(1);
        game.display.drawBitmap(0,0,sprite);
    }
}
return 1;
}
5 Likes

Is there a way to export gif directly from simulator?

Yes there is. I will write instructions for you all after 2 hours when I get back home (at a car show)

1 Like

That is so damn cool.

  1. #define SCREENCAPTURE 1 in POKITO_SIM\PokitoSimulator.h
  2. Create a Folder in c:\screencap
  3. Copy ffmpeg.exe there
  4. Run Pokitto Sim
  5. Close the Sim and hit Y in the console

You have an output.mp4 in c:\screencap

2 Likes

Thanks! You figured it out!

1 Like

Thank you @jonne to point out, the solution was already there.
Now I’m making some test to export also animated gif format, but the frame rate seems not being respected.
Cheers

Can someone have a look at this? I can’t seem to create/load a palette, nor can I get the palette to rotate.
What step am I missing here?

#include "pokitto.h"

Pokitto::Core game;

unsigned short pal[256];
char buff[220*174];

int PntClr(int x, int y){
	return buff[x+game.display.width*y];
}
void Dot (int x, int y, int c){
    // create a buffer for the screen image
	buff[x+game.display.width*y]=c;
}

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

int Adjust (int xa, int ya, int x, int y, int xb, int yb){
	if(PntClr(x, y) != 0) return 0;
	int q = abs(xa - xb) + abs(ya - yb);
	int v = (PntClr(xa, ya) + PntClr(xb, yb)) / 2 + (RandMinMax(0,q*10)) / 10;
	if (v < 1) v = 1;
	if (v > 255) v = 255;
	Dot(x, y, v);
	return 1;
}

void SubDivide (int x1, int y1, int x2, int y2){
	if ((x2 - x1 < 2) && (y2 - y1 < 2)) return;
	int x = (x1 + x2) / 2;
	int y = (y1 + y2) / 2;
	Adjust(x1, y1, x, y1, x2, y1);
	Adjust(x1, y2, x, y2, x2, y2);
	Adjust(x2, y1, x2, y, x2, y2);
	Adjust(x1, y1, x1, y, x1, y2);
	if(PntClr(x, y) == 0)	{
		int v = PntClr(x1, y1) + PntClr(x2, y1) + PntClr(x2, y2);
		v = v + PntClr(x1, y2) + PntClr(x1, y) + PntClr(x, y1);
		v = v + PntClr(x2, y) + PntClr(x, y2);
		v = v / 8;
		Dot(x, y, v);
	}
	SubDivide(x1, y1, x, y);
	SubDivide(x, y, x2, y2);
	SubDivide(x, y1, x2, y);
	SubDivide(x1, y, x, y2);
}

void make_plasma(void){
	int i=0;
	for(i=0; i<game.display.width*game.display.height; i++)	{
		buff[i]=0;
	}
	srand(1890462285);
	Dot(0, 0, RandMinMax(0,255) + 1);
	Dot(game.display.width-1, 0, RandMinMax(0,255) + 1);
	Dot(game.display.width-1, game.display.height-1, RandMinMax(0,255) + 1);
	Dot(0, game.display.height-1, RandMinMax(0,255) + 1);
	SubDivide(0, 0, game.display.width-1, game.display.height-1);
}

void make_pal(void){
	int a,s,r,g,b;
	for(a=0; a<=63; a++){
		s = 0; 	r = a; 		g = 63-a;	b = 0;		pal[a+s] = game.display.RGBto565(r*4,g*4,b*4);
		s = 64; r = 63-a;	g = 0;		b = a; 		pal[a+s] = game.display.RGBto565(r*4,g*4,b*4);
		s = 128; r = 0;	 	g = 0;		b = 63-a;	pal[a+s] = game.display.RGBto565(r*4,g*4,b*4);
		s = 192; r = 0;		g = a;		b = 0;	 	pal[a+s] = game.display.RGBto565(r*4,g*4,b*4);
	}
    game.display.load565Palette(&pal[0]);
}

int main(){
	game.begin();
	game.display.setColorDepth(8); // is this needed in the simulator?
	game.display.width = 220; // full size
	game.display.height = 174;
	game.setFrameRate(30); // doesn't matter what this is, speed isn't an issue with this demo
	make_pal();
    make_plasma();

	while (game.isRunning()) {
        game.display.rotatePalette(1);
        for(int y=0; y<game.display.height; y++){
            for(int x=0; x<game.display.width; x++){
                game.display.directPixel(x,y,buff[x+220*y]);
            }
        }
	}
	return 1;
}
1 Like

as far as i understand the pallet array will only be using the first 16 colors
also try game.display.load565Palette(pal);

I’m still trying to figure this stuff out myself, but these are my observations:

  1. As far as I know, in the current version of the emulator, only the fast mode (110 by 88) is guaranteed to work.

  2. It looks like the display.directPixel function writes a pixel to the screen without going through the pixel logic. Use display.drawPixel instead.

  3. It appears that you need the " if (game.update()) { " check if you are doing graphics updates.

This version appears to work (but it is very green…)

#include "pokitto.h"
Pokitto::Core game;
unsigned short pal[256];
char buff[220*174];
int PntClr(int x, int y){
	return buff[x+game.display.width*y];
}
void Dot (int x, int y, int c){
    // create a buffer for the screen image
	buff[x+game.display.width*y]=c;
}
int RandMinMax(int min, int max){
    return rand() % max + min;
}
int Adjust (int xa, int ya, int x, int y, int xb, int yb){
	if(PntClr(x, y) != 0) return 0;
	int q = abs(xa - xb) + abs(ya - yb);
	int v = (PntClr(xa, ya) + PntClr(xb, yb)) / 2 + (RandMinMax(0,q*10)) / 10;
	if (v < 1) v = 1;
	if (v > 255) v = 255;
	Dot(x, y, v);
	return 1;
}
void SubDivide (int x1, int y1, int x2, int y2){
	if ((x2 - x1 < 2) && (y2 - y1 < 2)) return;
	int x = (x1 + x2) / 2;
	int y = (y1 + y2) / 2;
	Adjust(x1, y1, x, y1, x2, y1);
	Adjust(x1, y2, x, y2, x2, y2);
	Adjust(x2, y1, x2, y, x2, y2);
	Adjust(x1, y1, x1, y, x1, y2);
	if(PntClr(x, y) == 0)	{
		int v = PntClr(x1, y1) + PntClr(x2, y1) + PntClr(x2, y2);
		v = v + PntClr(x1, y2) + PntClr(x1, y) + PntClr(x, y1);
		v = v + PntClr(x2, y) + PntClr(x, y2);
		v = v / 8;
		Dot(x, y, v);
	}
	SubDivide(x1, y1, x, y);
	SubDivide(x, y, x2, y2);
	SubDivide(x, y1, x2, y);
	SubDivide(x1, y, x, y2);
}
void make_plasma(void){
	int i=0;
	for(i=0; i<game.display.width*game.display.height; i++)	{
		buff[i]=0;
	}
	srand(1890462285);
	Dot(0, 0, RandMinMax(0,255) + 1);
	Dot(game.display.width-1, 0, RandMinMax(0,255) + 1);
	Dot(game.display.width-1, game.display.height-1, RandMinMax(0,255) + 1);
	Dot(0, game.display.height-1, RandMinMax(0,255) + 1);
	SubDivide(0, 0, game.display.width-1, game.display.height-1);
}
void make_pal(void){
	int a,s,r,g,b;
	for(a=0; a<=63; a++){
		s = 0; 	r = a; 		g = 63-a;	b = 0;		pal[a+s] = game.display.RGBto565(r*4,g*4,b*4);
		s = 64; r = 63-a;	g = 0;		b = a; 		pal[a+s] = game.display.RGBto565(r*4,g*4,b*4);
		s = 128; r = 0;	 	g = 0;		b = 63-a;	pal[a+s] = game.display.RGBto565(r*4,g*4,b*4);
		s = 192; r = 0;		g = a;		b = 0;	 	pal[a+s] = game.display.RGBto565(r*4,g*4,b*4);
	}
    game.display.load565Palette(&pal[0]);
}
int main(){
	game.begin();
	game.display.setColorDepth(8); // is this needed in the simulator?
	game.display.width = 110; // full size
	game.display.height = 88;
	game.setFrameRate(30); // doesn't matter what this is, speed isn't an issue with this demo
	make_pal();
    make_plasma();
    while (game.isRunning()) {
            if (game.update()) {
    game.display.rotatePalette(1);
    for(int y=0; y<game.display.height; y++){
        for(int x=0; x<game.display.width; x++){
            //game.display.directPixel(x,y,buff[x+220*y]);
            game.display.drawPixel(x,y,buff[x+110*y]);
        }
    }
            }
}
return 1;
}

Catsfolly

1 Like

I hacked the palette logic to limit it to the first 16 colors.

Here is the modified version:

#include "pokitto.h"
Pokitto::Core game;
unsigned short pal[256];
char buff[220*174];
int PntClr(int x, int y){
	return buff[x+game.display.width*y];
}
void Dot (int x, int y, int c){
    // create a buffer for the screen image
	buff[x+game.display.width*y]=c;
}
int RandMinMax(int min, int max){
    return rand() % max + min;
}
int Adjust (int xa, int ya, int x, int y, int xb, int yb){
	if(PntClr(x, y) != 0) return 0;
	int q = abs(xa - xb) + abs(ya - yb);
	int v = (PntClr(xa, ya) + PntClr(xb, yb)) / 2 + (RandMinMax(0,q*10)) / 10;
	if (v < 1) v = 1;
	if (v > 255) v = 255;
	Dot(x, y, v);
	return 1;
}
void SubDivide (int x1, int y1, int x2, int y2){
	if ((x2 - x1 < 2) && (y2 - y1 < 2)) return;
	int x = (x1 + x2) / 2;
	int y = (y1 + y2) / 2;
	Adjust(x1, y1, x, y1, x2, y1);
	Adjust(x1, y2, x, y2, x2, y2);
	Adjust(x2, y1, x2, y, x2, y2);
	Adjust(x1, y1, x1, y, x1, y2);
	if(PntClr(x, y) == 0)	{
		int v = PntClr(x1, y1) + PntClr(x2, y1) + PntClr(x2, y2);
		v = v + PntClr(x1, y2) + PntClr(x1, y) + PntClr(x, y1);
		v = v + PntClr(x2, y) + PntClr(x, y2);
		v = v / 8;
		Dot(x, y, v);
	}
	SubDivide(x1, y1, x, y);
	SubDivide(x, y, x2, y2);
	SubDivide(x, y1, x2, y);
	SubDivide(x1, y, x, y2);
}
void make_plasma(void){
	int i=0;
	for(i=0; i<game.display.width*game.display.height; i++)	{
		buff[i]=0;
	}
	srand(1890462285);
	Dot(0, 0, RandMinMax(0,255) + 1);
	Dot(game.display.width-1, 0, RandMinMax(0,255) + 1);
	Dot(game.display.width-1, game.display.height-1, RandMinMax(0,255) + 1);
	Dot(0, game.display.height-1, RandMinMax(0,255) + 1);
	SubDivide(0, 0, game.display.width-1, game.display.height-1);
}
void make_pal(void){
	int a,s,r,g,b;
	for(a=0; a<=3; a++){
		s = 0; 	r = a * 3; 		g = 48-(a * 3);	b = 0;		pal[a+s] = game.display.RGBto565(r*4,g*4,b*4);
		s = 4; r = 48-(a * 3);	g = 0;		b = (a * 3); 	pal[a+s] = game.display.RGBto565(r*4,g*4,b*4);
		s = 8; r = 0;	 	g = 0;		b = 48-(s * 3);	    pal[a+s] = game.display.RGBto565(r*4,g*4,b*4);
		s = 12; r = 0;		g = (a * 3);		b = 0;	 	pal[a+s] = game.display.RGBto565(r*4,g*4,b*4);
	}
    game.display.load565Palette(&pal[0]);
}
int main(){
	game.begin();
	game.display.setColorDepth(8); // is this needed in the simulator?
	game.display.width = 110; // full size
	game.display.height = 88;
	game.setFrameRate(30); // doesn't matter what this is, speed isn't an issue with this demo
	make_pal();
    make_plasma();
    while (game.isRunning()) {
            if (game.update()) {
    game.display.rotatePalette(1);
    for(int y=0; y<game.display.height; y++){
        for(int x=0; x<game.display.width; x++){
            //game.display.directPixel(x,y,buff[x+220*y]);
            game.display.drawPixel(x,y,buff[x+110*y]);
        }
    }
            }
}
return 1;
}

Catsfolly

2 Likes

Really cool stuff!!!

snaking experiment, single button , not real interaction
trying to fiddle with some delta time like stuff

#include "pokitto.h"
#include "math.h"
struct{
    float x;
    float y;
    float r;
    Uint16 speed;
    bool direction;
}snake;
short trail[16][2];
Pokitto::Core game;
int main () {
game.begin();
snake.x = 55;
snake.y = 44;
snake.r = 5;
snake.direction = true;
snake.speed = 300;
float camX = -snake.x;
float camY = -snake.y;
float t = 0.1;
int dt;
int elapse;
while (game.isRunning()) {
    if(game.buttons.pressed(BTN_A)) snake.direction = !snake.direction;
    if (game.update()) {

        dt = game.getTime()-elapse;
        elapse = game.getTime();

        if(snake.direction) t+=((float)dt)/snake.speed ;
        else t-=((float)dt)/snake.speed ;
        snake.x += cos(t)*snake.r;
        snake.y += sin(t)*snake.r;

        //game.display.print();
        camX = -snake.x +55;
        camY = -snake.y +44;
        game.display.fillCircle(snake.x+camX,snake.y+camY,2);
        trail[15][0] = snake.x;
        trail[15][1] = snake.y;
        for(int i =0; i<15; i++){
            trail[i][0] = trail[i+1][0];
            trail[i][1] = trail[i+1][1];
            game.display.fillCircle(trail[i][0]+camX ,trail[i][1]+camY,i/3);
        }
        for(int x =0; x<15; x++){
             for(int y =0; y<15; y++){
                    game.display.drawRect(x*16+camX,y*16+camY,x,y);
             }
        }
    }

}

return 1;
}
2 Likes