Para o teclado foi utilizado a serial, através de uma arquivo .bat
Por enquanto as explicações estão no vídeo.
Arquivo .bat
MODE COM6 BAUD=9600 PARITY=n DATA=8 :LOOP CHOICE /C:1235 /M "1: liga; 2: desliga; 3: pisca; 4: sair " IF errorlevel 4 GOTO TOP IF errorlevel 3 GOTO RIGHT IF errorlevel 2 GOTO BOTTOM IF errorlevel 1 GOTO LEFT :RIGHT ECHO b > COM6 GOTO END :LEFT ECHO a > COM6 GOTO END :TOP ECHO c > COM6 GOTO END :BOTTOM ECHO d > COM6 :END CLS GOTO LOOP :SAIR
Código-Fonte:
/*************************************************************************************************************
*******************************LEDCONTROL ALTERADA************************************************************
**************************************************************************************************************
mais informações aqui: http://fabianoallex.blogspot.com.br/2015/09/arduino-alteracoes-na-biblioteca.html
**************************************************************************************************************/
//the opcodes for the MAX7221 and MAX7219
#define OP_DECODEMODE 9
#define OP_INTENSITY 10
#define OP_SCANLIMIT 11
#define OP_SHUTDOWN 12
#define OP_DISPLAYTEST 15
class LedControl {
private :
byte spidata[16];
byte * status;
int SPI_MOSI;
int SPI_CLK;
int SPI_CS;
int maxDevices;
int _auto_send;
void spiTransfer(int addr, volatile byte opcode, volatile byte data) {
int offset = addr*2;
int maxbytes = maxDevices*2;
for(int i=0;i<maxbytes;i++) { spidata[i]=(byte)0; }
spidata[offset+1] = opcode;
spidata[offset] = data;
digitalWrite(SPI_CS,LOW);
for(int i=maxbytes;i>0;i--) { shiftOut(SPI_MOSI,SPI_CLK,MSBFIRST,spidata[i-1]); }
digitalWrite(SPI_CS,HIGH);
}
public:
LedControl(int dataPin, int clkPin, int csPin, int numDevices) {
_auto_send = true;
SPI_MOSI = dataPin;
SPI_CLK = clkPin;
SPI_CS = csPin;
maxDevices = numDevices;
pinMode(SPI_MOSI, OUTPUT);
pinMode(SPI_CLK, OUTPUT);
pinMode(SPI_CS, OUTPUT);
digitalWrite(SPI_CS, HIGH);
status = new byte[maxDevices * 8]; //instancia o array de acordo com a quantia de displays usados
for(int i=0;i<maxDevices * 8 ;i++) { status[i]=0x00; }
for(int i=0;i<maxDevices;i++) {
spiTransfer(i, OP_DISPLAYTEST,0);
setScanLimit(i, 7); //scanlimit is set to max on startup
spiTransfer(i, OP_DECODEMODE,0); //decode is done in source
clearDisplay(i);
shutdown(i,true); //we go into shutdown-mode on startup
}
}
void startWrite() { _auto_send = false; };
void send() {
for (int j=0; j<maxDevices; j++) {
int offset = j*8;
for(int i=0;i<8;i++) { spiTransfer(j, i+1, status[offset+i]); }
}
_auto_send = true;
}
int getDeviceCount(){ return maxDevices; }
void shutdown(int addr, bool b){
if(addr<0 || addr>=maxDevices) return;
spiTransfer(addr, OP_SHUTDOWN, b ? 0 : 1);
}
void setScanLimit(int addr, int limit){
if(addr<0 || addr>=maxDevices) return;
if(limit>=0 && limit<8) spiTransfer(addr, OP_SCANLIMIT,limit);
}
void setIntensity(int addr, int intensity) {
if(addr<0 || addr>=maxDevices) { return; }
if(intensity>=0 && intensity<16) { spiTransfer(addr, OP_INTENSITY, intensity); }
}
void clearDisplay(int addr){
if(addr<0 || addr>=maxDevices) return;
int offset = addr*8;
for(int i=0;i<8;i++) {
status[offset+i] = 0;
if (_auto_send) { spiTransfer(addr, i+1, status[offset+i]); }
}
}
void setLed(int addr, int row, int column, boolean state) {
if(addr<0 || addr>=maxDevices) { return; }
if(row<0 || row>7 || column<0 || column>7) { return; }
int offset = addr*8;
byte val = B10000000 >> column;
if(state) { status[offset+row] = status[offset+row] | val; }
else {
val=~val;
status[offset+row] = status[offset+row]&val;
}
if (_auto_send) { spiTransfer(addr, row+1, status[offset+row]); }
}
void setRow(int addr, int row, byte value) {
if(addr<0 || addr>=maxDevices) return;
if(row<0 || row>7) return;
int offset = addr*8;
status[offset+row] = value;
if (_auto_send) {
spiTransfer(addr, row+1, status[offset+row]);
}
}
void setColumn(int addr, int col, byte value) {
if(addr<0 || addr>=maxDevices) return;
if(col<0 || col>7) return;
byte val;
for(int row=0; row<8; row++) {
val=value >> (7-row);
val=val & 0x01;
setLed(addr,row,col,val);
}
}
};
/*************************************************************************************************************
*******************************FIM LEDCONTROL ALTERADA********************************************************
**************************************************************************************************************/
/*************************************************************************************************************
*******************************BIT ARRAY *********************************************************************
**************************************************************************************************************
mais informações aqui: http://fabianoallex.blogspot.com.br/2015/09/arduino-array-de-bits.html
**************************************************************************************************************/
class BitArray{
private:
int _num_bits; //quantidade de bits a serem gerenciados
int _num_bytes; //quantidade de bytes utilizados para armazenar os bits a serem gerenciados
byte * _bytes; //array de bytes onde estaram armazenados os bits
public:
BitArray(int num_bits){
_num_bits = num_bits;
_num_bytes = _num_bits/8 + (_num_bits%8 ? 1 : 0) + 1;
_bytes = (byte *)(malloc( _num_bytes * sizeof(byte) ) );
}
void write(int index, byte value) {
byte b = _bytes[ index/8 + (index%8 ? 1 : 0) ];
unsigned int bit = index%8;
if (value) { b |= (1 << bit); } else { b &= ~(1 << bit); }
_bytes[ index/8 + (index%8 ? 1 : 0) ] = b;
}
void write(byte value) {
for(int j=0; j<_num_bytes;j++) { _bytes[j] = value ? B11111111 : B00000000; }
}
int read(int index) {
byte b = _bytes[ index/8 + (index%8 ? 1 : 0) ];
unsigned int bit = index%8;
return (b & (1 << bit)) != 0;
}
~BitArray(){ free ( _bytes ); }
};
class BitArray2D {
private:
unsigned int _rows;
unsigned int _columns;
unsigned int _cols_array; //pra cada 8 colunas, 1 byte é usado
byte** _bits;
public:
BitArray2D(unsigned int rows, unsigned int columns){
_rows = rows;
_columns = columns;
_cols_array = columns/8 + (_columns%8 ? 1 : 0) + 1; //divide por 8 o número de colunas
_bits = (byte **)malloc(_rows * sizeof(byte *));
for(int i=0;i<_rows;i++){ _bits[i] = (byte *)malloc( _cols_array * sizeof(byte)); } //cria varios arrays
clear();
}
unsigned int rows(){ return _rows; }
unsigned int columns(){ return _columns; }
void clear() {
for(int i=0;i<_rows;i++){
for(int j=0; j<_cols_array;j++) { _bits[i][j] = B00000000; }
}
}
void write(unsigned int row, unsigned int column, int value){
byte b = _bits[row][ column/8 + (column%8 ? 1 : 0) ];
unsigned int bit = column%8;
if (value) { b |= (1 << bit); } else { b &= ~(1 << bit); }
_bits[row][ column/8 + (column%8 ? 1 : 0) ] = b;
}
void write(byte value){
for(int i=0;i<_rows;i++){
for(int j=0; j<_cols_array;j++) {
_bits[i][j] = value ? B11111111 : B00000000;
}
}
}
int read(unsigned int row, unsigned int column){
byte b = _bits[row][ column/8 + (column%8 ? 1 : 0) ];
unsigned int bit = column%8;
return (b & (1 << bit)) != 0;
}
void toggle(unsigned int row, unsigned int column){ write(row, column, !read(row, column)); }
void toggle(){ for(int i=0;i<_rows;i++){ for(int j=0; j<_columns;j++) { toggle(i,j); } } }
};
/*************************************************************************************************************
*******************************FIM BIT ARRAY *****************************************************************
**************************************************************************************************************/
/*************************************************************************************************************
************************************CLASSE UNIQUE RANDOM******************************************************
**************************************************************************************************************
mais informações aqui: http://fabianoallex.blogspot.com.br/2015/09/arduino-numeros-aleatorio-repetidos-e.html
*************************************************************************************************************/
class UniqueRandom{
private:
int _index;
int _min;
int _max;
int _size;
int* _list;
void _init(int min, int max) {
_list = 0;
if (min < max) { _min = min; _max = max; } else { _min = max; _max = min; }
_size = _max - _min;
_index = 0;
}
public:
UniqueRandom(int max) { _init(0, max); randomize(); } //construtor com 1 parametro
UniqueRandom(int min, int max) { _init(min, max); randomize(); } //construtor com 2 parametros
void randomize() {
_index = 0;
if (_list == 0) { _list = (int*) malloc(size() * sizeof(int)); }
for (int i=0; i<size(); i++) { _list[i] = _min+i; } //preenche a lista do menor ao maior valor
//embaralha a lista
for (int i=0; i<size(); i++) {
int r = random(0, size()); //sorteia uma posição qualquer
int aux = _list[i];
_list[i] = _list[r];
_list[r] = aux;
}
}
int next() { //retorna o proximo numero da lista
int n = _list[_index++];
if (_index >= size() ) { _index = 0;} //após recuper o ultimo numero, recomeça na posicao 0
return n;
}
int size() { return _size; }
~UniqueRandom(){ free ( _list ); } //destrutor
};
/*************************************************************************************************************
************************************FIM CLASSE UNIQUE RANDOM**************************************************
*************************************************************************************************************/
/*************************************************************************************************************
*******************************DISPLAY************************************************************************
**************************************************************************************************************/
/*
rotation indica qual parte do display estará para cima
TOP
L . . . . . . . . R
E . . . . . . . . I
F . . . . . . . . G
T . . . . . . . . H
. . . . . . . . T
. . . . . . . .
. . . . . . . .
. . . . . . . .
BOTTOM
*/
enum Rotation {TOP, LEFT, BOTTOM, RIGHT};
struct Position {
int lin;
int col;
};
struct Display {
int index;
Position position;
Rotation rotation;
};
/*************************************************************************************************************
*******************************FIM DISPLAY********************************************************************
**************************************************************************************************************/
/*************************************************************************************************************
*******************************CLASSE SNAKE GAME**************************************************************
**************************************************************************************************************/
const int SNAKE_MAX_LEN = 50; //tamanho maximo da cobra
const int SNAKE_TIME_INIT = 500; //tempo entre deslocamento da cobra (velocidade)
const int SNAKE_TIME_INC = 15; //incremento da velocidade
enum Direction { DIR_STOP, DIR_TOP, DIR_LEFT, DIR_BOTTOM, DIR_RIGHT};
enum SnakeStatus { SNAKE_GAME_ON, SNAKE_GAME_OVER };
class SnakeGame{
private:
BitArray2D * _display;
Position _snake_positions[SNAKE_MAX_LEN];
Position _apple;
int _length;
Direction _direction;
unsigned long _last_millis;
int _time;
int _score;
SnakeStatus _snakeStatus;
UniqueRandom * _ur; //utilizado no game over
void _generateApple() {
int lin, col;
boolean random_ok = false;
while (!random_ok) {
random_ok = true;
lin = random(0, _display->rows()-1);
col = random(0, _display->columns()-1);
for (int p=0; p<_length; p++){
if (_snake_positions[p].col==col && _snake_positions[p].lin==lin){ //verifica se gerou em um local que não seja a cobra
random_ok = false;
break;
}
}
}
_apple.lin = lin;
_apple.col = col;
}
void _gameOver(){
_snakeStatus = SNAKE_GAME_OVER;
_direction = DIR_STOP;
_time = 20;
}
void _inc_length(){
_length++; _score++;
_time -= SNAKE_TIME_INC;
}
void _runGameOver(){
int r = _ur->next();
int lin = (r / _display->columns());
int col = (r % _display->columns());
_display->write(lin, col, HIGH );
if ( r>=(_ur->size()-1) || _direction != DIR_STOP ) {
_ur->randomize();
start();
}
}
void _run(){
for (int i=_length-1; i>0; i--){
_snake_positions[i].lin = _snake_positions[i-1].lin;
_snake_positions[i].col = _snake_positions[i-1].col;
}
if (_direction == DIR_TOP ) { _snake_positions[0].lin--; }
if (_direction == DIR_BOTTOM ) { _snake_positions[0].lin++; }
if (_direction == DIR_LEFT ) { _snake_positions[0].col--; }
if (_direction == DIR_RIGHT ) { _snake_positions[0].col++; }
//verifica se ultrapassou o limite do display
if (_snake_positions[0].lin < 0) { _gameOver(); }
if (_snake_positions[0].lin >= _display->rows() ) { _gameOver(); }
if (_snake_positions[0].col < 0) { _gameOver(); }
if (_snake_positions[0].col >= _display->columns() ) { _gameOver(); }
//verifica se colidiu na cobra
for (int i=_length-1; i>0; i--){
if (_snake_positions[i].lin == _snake_positions[0].lin && _snake_positions[i].col == _snake_positions[0].col) {
_gameOver();
}
}
//verifica se comeu a maça
if (_snake_positions[0].col == _apple.col && _snake_positions[0].lin == _apple.lin){
_inc_length();
if (_length > SNAKE_MAX_LEN) { _length = SNAKE_MAX_LEN; } else {
_snake_positions[_length-1].lin = _snake_positions[_length-2].lin;
_snake_positions[_length-1].col = _snake_positions[_length-2].col;
}
_generateApple();
}
//update display
for (int lin=0; lin<_display->rows(); lin++) {
for (int col=0; col<_display->columns(); col++) {
for (int p=0; p<_length; p++){
boolean val = _snake_positions[p].col==col && _snake_positions[p].lin==lin;
_display->write( lin, col, val );
if (val) {break;}
}
}
}
_display->write(_apple.lin, _apple.col, HIGH);
//--
}
public:
SnakeGame(BitArray2D * display){
_display = display;
_ur = new UniqueRandom( _display->rows() * _display->columns() );
start();
}
void start(){
_length = 1;
_score = 0;
_time = SNAKE_TIME_INIT;
_last_millis = 0;
_snake_positions[0].lin = _display->rows() / 2;
_snake_positions[0].col = _display->columns() / 2;
_direction = DIR_STOP;
_snakeStatus = SNAKE_GAME_ON;
_generateApple();
}
void left() { if (_direction == DIR_RIGHT) return; _direction = DIR_LEFT; }
void right() { if (_direction == DIR_LEFT) return; _direction = DIR_RIGHT; }
void top() { if (_direction == DIR_BOTTOM) return; _direction = DIR_TOP; }
void bottom() { if (_direction == DIR_TOP) return; _direction = DIR_BOTTOM; }
int getScore(){ return _score; }
int update(){
int r = false;
if (millis() - _last_millis > _time) {
r = true;
_last_millis = millis();
if (_snakeStatus == SNAKE_GAME_ON) { _run(); }
if (_snakeStatus == SNAKE_GAME_OVER) { _runGameOver(); }
}
return r; //r-->indica se houve mudança no display
}
};
/*************************************************************************************************************
*******************************FIM CLASSE SNAKE GAME**********************************************************
**************************************************************************************************************/
const int LINHAS = 16;
const int COLUNAS = 8;
/*
* * * * * * * *
* * * * * * * *
* * * * * * * *
* * * * * * * *
* * * * * * * *
* * * * * * * *
* * * * * * * *
* * * * * * * *
* * * * * * * *
* * * * * * * *
* * * * * * * *
* * * * * * * *
* * * * * * * *
* * * * * * * *
* * * * * * * *
* * * * * * * *
*/
Display displays_8x8[] = {
{0, {0,0}, TOP},
{1, {8,0}, BOTTOM}
};
BitArray2D ba(LINHAS, COLUNAS); //8 linhas e 20 colunas
SnakeGame snake(&ba);
const int PIN_CLOCK = 5;
const int PIN_DATA = 7;
const int PIN_LOAD = 6;
const int QTD_MAX7219 = 2;
LedControl lc = LedControl(PIN_DATA,PIN_CLOCK,PIN_LOAD, QTD_MAX7219);
void update_displays_8x8() {
lc.startWrite();
for (int lin=0; lin<ba.rows(); lin++) {
for (int col=0; col<ba.columns(); col++) {
for (int i=0; i<sizeof(displays_8x8)/sizeof(Display); i++) {
int l = lin - displays_8x8[i].position.lin;
int c = col - displays_8x8[i].position.col;
if (l>=0 && l<=7 && c>=0 && c<=7) {
if (displays_8x8[i].rotation == BOTTOM) { c=7-c; l=7-l; }
if (displays_8x8[i].rotation == LEFT) { int aux=c; c=l; l=7-aux; }
if (displays_8x8[i].rotation == RIGHT) { int aux=l; l=c; c=7-aux; }
lc.setLed(displays_8x8[i].index, l, c, ba.read(lin, col) );
}
}
}
}
lc.send();
}
void setup() {
Serial.begin(9600);
lc.shutdown(0,false);
lc.setIntensity(0,8);
lc.clearDisplay(0);
lc.shutdown(1,false);
lc.setIntensity(1,8);
lc.clearDisplay(1);
randomSeed(analogRead(A0));
}
void loop() {
int c = Serial.read();
if (c == 97) { snake.left(); } //a ->
if (c == 98) { snake.right(); } //b ->
if (c == 99) { snake.top(); } //c ->
if (c == 100) { snake.bottom(); } //d ->
if ( snake.update() ) { update_displays_8x8(); }
}
amigo seria bueno que dejaras las explicaciones por escrito para poder traducirlas. saludo desde colombia.
ResponderExcluirOlá amigo, td bem?
ResponderExcluirCopiei o codigo e fiz algumas modificações, construí o jogo com 4 telas e fiz o corpo em uma impressora 3d, vou postar em meu blog um tutorial de montagem do jogo com os devidos créditos (inclusive no codigo também). tudo bem para vc? Meu blog é o circuitomaker.com , a postagem deve aparecer nos próximos dias. obrigado!
Legal. Sem problemas, quando estiver publicado me manda o link.
ExcluirEstou com um problema no código, sempre que a cobrinha come 34 maçãs, o jogo simplesmente trava
ResponderExcluir