Simulador com o objetivo de facilitar a prototipação de efeitos e jogos para matrizes de NeoPixel, imitando a sintaxe utilizada pela biblioteca para arduino.
Para utilizar o simulador basta criar um arquivo exemplo.cpp com a cara:
#include "fx.cpp"
void setup()
{
}
void loop()
{
}
E compilá-lo utilizando o script comp.sh
./comp.sh exemplo.cpp exemplo
O simulador possui uma classe Adafruit_NeoPixel com a mesma sintaxe da biblioteca para arduino, além de algumas definições de funções padrão do arduino como pinMode, digitalWrite e digitalRead.
Um exemplo de um programa para o simulador é:
#include "fx.cpp"
#define LED_PIN 6
#define LED_COUNT 144
Adafruit_NeoPixel strip(LED_COUNT, LED_PIN, NEO_GRB + NEO_KHZ800);
void setup()
{
strip.begin();
strip.show();
}
void loop()
{
strip.clear();
for(int i = 0; i < LED_COUNT; i++)
{
strip.setPixelColor(i, 255, 0, 0);
strip.show();
delay(100);
}
}
O tamanho da matriz é definido no arquivo grid_dim.config (padrão 12x12), e é considerado que os leds estão com a contagem em zig-zag, com o led 0 no canto superior esquerdo da mesa.
O simulador utiliza os seguintes arquivos:
- fx.cpp - Gerencia o grid e a thread de efeitos
- comp.sh - Script que facilita a compilação do código escrito para o simulador
- grid_dim.config - Especifica as dimensões da matriz de NeoPixel
- digital_input.config - Permite abstrair caracteres do teclado como pinos de entrada do arduino
E depende da biblioteca
- freeglut3-dev
Exemplo de um snake feito para o simulador
grid_dim.config:
12x12
digital_input.config:
w 7 2
s 6 2
a 5 2
d 4 2
snake.cpp
#include "fx.cpp"
char dir = 's';
char last_dir = 's';
#define LED_PIN 1
#define ROWS 12
#define COLS 12
#define LED_COUNT 144
#define UP 7
#define DOWN 6
#define LEFT 5
#define RIGHT 4
#define INTERRUPT 2
int map_px ( int l, int c ) {
return l * COLS + ((l % 2)?COLS-c-1:c);
}
Adafruit_NeoPixel strip(LED_COUNT, LED_PIN, NEO_GRB + NEO_KHZ800);
int snake_x = ROWS / 2;
int snake_y = COLS / 2;
int growing = 2;
int snake_size = 3;
int apple_x;
int apple_y;
int new_seed = 0;
uint32_t apple_color = 0xFF0000;
uint32_t snake_color = 0x00FF00;
uint32_t death_color = 0x0000FF;
#define MAX_SNAKE_SIZE 500
int snake[MAX_SNAKE_SIZE][2] = { 0 };
volatile int button_pressed = 0;
void set_button_pressed(void) {
button_pressed = 1;
}
void setup () {
pinMode(UP, INPUT);
pinMode(DOWN, INPUT);
pinMode(LEFT, INPUT);
pinMode(RIGHT, INPUT);
pinMode(INTERRUPT, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(INTERRUPT), set_button_pressed, RISING);
randomSeed(analogRead(0));
apple_x = random(ROWS);
apple_y = random(COLS);
if(apple_x == snake_x) while(apple_y == snake_y) apple_y = random(COLS);
for(int i = 0; i < snake_size; i++) {
snake[i][0] = snake_x;
snake[i][1] = snake_y;
}
strip.begin();
strip.setPixelColor(map_px(apple_x, apple_y), apple_color);
strip.setPixelColor(map_px(snake_x, snake_y), snake_color);
strip.show ();
}
void reset_game() {
strip.setPixelColor(map_px(snake_x, snake_y), death_color);
strip.show();
delay(1000);
dir = 's';
last_dir = 's';
snake_x = ROWS / 2; snake_y = COLS / 2;
snake_size = 3;
growing = 2;
apple_x = random(ROWS);
apple_y = random(COLS);
new_seed = 0;
if(apple_x == snake_x) while(apple_y == snake_y) apple_y = random(COLS);
for(int i = 0; i < snake_size; i++) {
snake[i][0] = snake_x;
snake[i][1] = snake_y;
}
strip.clear();
strip.setPixelColor(map_px(apple_x, apple_y), apple_color);
strip.setPixelColor(map_px(snake_x, snake_y), snake_color);
strip.show();
}
void seed_apple() {
apple_x = random(ROWS);
apple_y = random(COLS);
for(int i = 0; i < snake_size; i++) {
if(apple_x == snake[i][0] && apple_y == snake[i][1]) {
apple_x = random(ROWS);
apple_y = random(COLS);
i = 0;
}
}
strip.setPixelColor(map_px(apple_x, apple_y), apple_color);
}
void change_direction() {
//Debounce time
delay(0);
if(digitalRead(UP) == HIGH) {
dir = 'u';
} else if (digitalRead(DOWN) == HIGH) {
dir = 'd';
} else if (digitalRead(LEFT) == HIGH) {
dir = 'l';
} else if (digitalRead(RIGHT) == HIGH) {
dir = 'r';
}
button_pressed = 0;
}
void move_snake(char c) {
if(c == 'u' && last_dir == 'd') last_dir = 'd';
else if(c == 'd' && last_dir == 'u') last_dir = 'u';
else if(c == 'r' && last_dir == 'l') last_dir = 'l';
else if(c == 'l' && last_dir == 'r') last_dir = 'r';
else last_dir = c;
switch(last_dir) {
case 'u' :
snake_x = snake[0][0] - 1;
snake_y = snake[0][1];
if(snake_x == -1) snake_x = ROWS-1;
break;
case 'd' :
snake_x = snake[0][0] + 1;
snake_y = snake[0][1];
if(snake_x == ROWS) snake_x = 0;
break;
case 'l' :
snake_x = snake[0][0];
snake_y = snake[0][1] - 1;
if(snake_y == -1) snake_y = COLS-1;
break;
case 'r' :
snake_x = snake[0][0];
snake_y = snake[0][1] + 1;
if(snake_y == COLS) snake_y = 0;
break;
}
if(!growing) strip.setPixelColor(map_px(snake[snake_size-1][0], snake[snake_size-1][1]), 0);
else --growing;
if(snake_x == apple_x && snake_y == apple_y) {
++growing;
++snake_size;
new_seed = 1;
}
for(int i = snake_size - 1; i > 0; i--) {
snake[i][0] = snake[i-1][0];
snake[i][1] = snake[i-1][1];
if(snake_x == snake[i][0] && snake_y == snake[i][1]) { reset_game(); return; }
}
snake[0][0] = snake_x;
snake[0][1] = snake_y;
if(new_seed) { seed_apple(); new_seed = 0; }
strip.setPixelColor(map_px(snake_x, snake_y), snake_color);
}
void loop () {
if(button_pressed) change_direction();
if(dir != 's') move_snake(dir);
strip.show();
delay(100 - snake_size / 5);
}