#define GRID_W (8)
#define GRID_H (8)
// max size of each tetris piece
#define PIECE_W (4)
#define PIECE_H (4)
#define JOYSTICK_DEAD_ZONE (10)
// a list of anode pins, sorted by top to bottom of the grid
const int anode[8] = { 8, 13, 7, 11, 0, 6, 1, 4 };
// a list of cathode pins, sorted by left to right of the grid
const int cathode[8] = { 12, 2, 3, 9, 5, 10, 14, 15 };
// translate the pins on the LED panel to pins on the Arduino
const int arduino_to_grid[16] = {5, 4, 3, 2, 14, 15, 16, 17, 13, 12, 11, 10, 9, 8, 7, 6};
int led = 1;
//
// 1 color drawings of each piece in each rotation.
// Each piece is max 4 wide, 4 tall, and 4 rotations.
const char piece_I[] = {
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
1, 1, 1, 1,
0, 1, 0, 0,
0, 1, 0, 0,
0, 1, 0, 0,
0, 1, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
1, 1, 1, 1,
0, 1, 0, 0,
0, 1, 0, 0,
0, 1, 0, 0,
0, 1, 0, 0,
};
const char piece_L1[] = {
0, 1, 0, 0,
0, 1, 0, 0,
0, 1, 1, 0,
0, 0, 0, 0,
0, 0, 0, 0,
1, 1, 1, 0,
1, 0, 0, 0,
0, 0, 0, 0,
1, 1, 0, 0,
0, 1, 0, 0,
0, 1, 0, 0,
0, 0, 0, 0,
0, 0, 1, 0,
1, 1, 1, 0,
0, 0, 0, 0,
0, 0, 0, 0,
};
const char piece_L2[] = {
0, 1, 0, 0,
0, 1, 0, 0,
1, 1, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
1, 0, 0, 0,
1, 1, 1, 0,
0, 0, 0, 0,
0, 1, 1, 0,
0, 1, 0, 0,
0, 1, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
1, 1, 1, 0,
0, 0, 1, 0,
0, 0, 0, 0,
};
const char piece_T[] = {
0, 0, 0, 0,
1, 1, 1, 0,
0, 1, 0, 0,
0, 0, 0, 0,
0, 1, 0, 0,
1, 1, 0, 0,
0, 1, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 1, 0, 0,
1, 1, 1, 0,
0, 0, 0, 0,
0, 1, 0, 0,
0, 1, 1, 0,
0, 1, 0, 0,
0, 0, 0, 0,
};
const char piece_S1[] = {
1, 0, 0, 0,
1, 1, 0, 0,
0, 1, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 1, 1, 0,
1, 1, 0, 0,
0, 0, 0, 0,
1, 0, 0, 0,
1, 1, 0, 0,
0, 1, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 1, 1, 0,
1, 1, 0, 0,
0, 0, 0, 0,
};
const char piece_S2[] = {
0, 1, 0, 0,
1, 1, 0, 0,
1, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
1, 1, 0, 0,
0, 1, 1, 0,
0, 0, 0, 0,
0, 1, 0, 0,
1, 1, 0, 0,
1, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
1, 1, 0, 0,
0, 1, 1, 0,
0, 0, 0, 0,
};
const char piece_O[] = {
1, 1, 0, 0,
1, 1, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
1, 1, 0, 0,
1, 1, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
1, 1, 0, 0,
1, 1, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
1, 1, 0, 0,
1, 1, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
};
// how many kinds of pieces
#define NUM_PIECE_TYPES (7)
// An array of pointers!
const char *pieces[NUM_PIECE_TYPES] = {
piece_S1,
piece_S2,
piece_L1,
piece_L2,
piece_O,
piece_T,
piece_I,
};
// length of the chances array
#define MAX_CHANCES (13)
// chances[12] is 6,
// pieces[chances[12]] is piece_I,
// pieces[chances[12]][8] is 1.
const char chances[MAX_CHANCES] = {
0, 0,
1, 1,
2, 2,
3, 3,
4, 4,
5, 5,
6, // 1 in 13 chance of an I piece
};
//--------------------------------------------------------------------------------
// GLOBALS
//--------------------------------------------------------------------------------
// this is how arduino remembers what the button was doing in the past,
// so arduino can tell when it changes.
int old_button = 0;
// so arduino can tell when user moves sideways
int old_px = 0;
// so arduino can tell when user tries to turn
int old_i_want_to_turn = 0;
// this is how arduino remembers the falling piece.
int piece_id;
int piece_rotation;
int piece_x;
int piece_y;
// this controls how fast the player can move.
long last_move;
long move_delay = 100; // 100ms = 5 times a second
// this controls when the piece automatically falls.
long last_drop;
long drop_delay = 1500; // 500ms = 2 times a second
// this is how arduino remembers where pieces are on the grid.
char grid[8 * 8];
//--------------------------------------------------------------------------------
// METHODS
//--------------------------------------------------------------------------------
// I want to turn on the column N from the left.
// this figures out which pin on the LED that is,
// then figures out which pin on the arduino matches that LED pin.
// two translations!
int out(int x) {
return arduino_to_grid[anode[x]];
}
// I want to turn on the row N from the top.
// this figures out which pin on the LED that is,
// then figures out which pin on the arduino matches that LED pin.
// two translations!
int in(int y) {
return arduino_to_grid[cathode[y]];
}
// I want to turn on point P(x,y), which is X from the left and Y from the top.
// I might also want to hold it on for us microseconds.
void p(int x, int y, int us) {
// don't try to turn on a light that doesn't exist
//if(x<0 || x>GRID_W) return;
//if(y<0 || y>GRID_H) return;
// now light it
digitalWrite(out(x), HIGH);
digitalWrite(in(y), LOW);
delayMicroseconds(us);
digitalWrite(in(y), HIGH);
digitalWrite(out(x), LOW);
}
// grid contains the arduino's memory of the game board, including the piece that is falling.
void draw_grid() {
int x, y;
for (y = 0; y < GRID_H; ++y) {
for (x = 0; x < GRID_W; ++x) {
if ( grid[y * GRID_W + x] != 0 ) {
p(x, y, 150);
}
}
}
}
void choose_new_piece() {
// make the chances array longer to change the odds of different pieces appearing.
piece_id = chances[rand() % MAX_CHANCES];
// always start the piece top center.
piece_y = -4; // -4 squares off the top of the screen.
piece_x = 3;
// always start in the same orientation.
piece_rotation = 0;
}
void erase_piece_from_grid() {
int x, y;
const char *piece = pieces[piece_id] + (piece_rotation * PIECE_H * PIECE_W);
for (y = 0; y < PIECE_H; ++y) {
for (x = 0; x < PIECE_W; ++x) {
int nx = piece_x + x;
int ny = piece_y + y;
if (ny < 0 || ny > GRID_H) continue;
if (nx < 0 || nx > GRID_W) continue;
if (piece[y * PIECE_W + x] == 1) {
grid[ny * GRID_W + nx] = 0; // zero erases the grid location.
}
}
}
}
void add_piece_to_grid() {
int x, y;
const char *piece = pieces[piece_id] + (piece_rotation * PIECE_H * PIECE_W);
for (y = 0; y < PIECE_H; ++y) {
for (x = 0; x < PIECE_W; ++x) {
int nx = piece_x + x;
int ny = piece_y + y;
if (ny < 0 || ny > GRID_H) continue;
if (nx < 0 || nx > GRID_W) continue;
if (piece[y * PIECE_W + x] == 1) {
grid[ny * GRID_W + nx] = 1; // zero erases the grid location.
}
}
}
}
// Move everything down 1 space, destroying the old row number y in the process.
void delete_row(int y) {
int x;
for (; y > 0; --y) {
for (x = 0; x < GRID_W; ++x) {
grid[y * GRID_W + x] = grid[(y - 1) * GRID_W + x];
}
}
// everything moved down 1, so the top row must be empty or the game would be over.
for (x = 0; x < GRID_W; ++x) {
grid[x] = 0;
}
}
void remove_full_rows() {
int x, y, c;
for (y = 0; y < GRID_H; ++y) {
// count the full spaces in this row
c = 0;
for (x = 0; x < GRID_W; ++x) {
if ( grid[y * GRID_W + x] > 0 ) c++;
}
if (c == GRID_W) {
// row full!
delete_row(y);
}
}
}
void try_to_move_piece_sideways() {
// what does the joystick angle say
int dx = map(analogRead(4), 0, 1023, 500, -500);
Serial.print(dx);
int new_px = 0;
// is the joystick really being pushed?
if (dx > JOYSTICK_DEAD_ZONE) {
new_px = 1;
}
if (dx < -JOYSTICK_DEAD_ZONE) {
new_px = -1;
}
if (new_px != old_px && piece_can_fit(piece_x + new_px, piece_y, piece_rotation) == 1) {
piece_x += new_px;
}
old_px = new_px;
}
void try_to_rotate_piece() {
int i_want_to_turn = 0;
// what does the joystick button say
int new_button = digitalRead(1);
// if the button state has just changed AND it is being let go,
if ( new_button > 0 && old_button != new_button ) {
i_want_to_turn = 1;
}
old_button = new_button;
// up on joystick to rotate
int dy = map(analogRead(5), 0, 1023, -500, 500);
if (dy < -JOYSTICK_DEAD_ZONE) i_want_to_turn = 1;
if (i_want_to_turn == 1 && i_want_to_turn != old_i_want_to_turn) {
// figure out what it will look like at that new angle
int new_pr = ( piece_rotation + 1 ) % 4;
// if it can fit at that new angle (doesn't bump anything)
if (piece_can_fit(piece_x, piece_y, new_pr)) {
// then make the turn.
piece_rotation = new_pr;
}
}
old_i_want_to_turn = i_want_to_turn;
}
// can the piece fit in this new location?
int piece_can_fit(int px, int py, int pr) {
if ( piece_off_edge(px, py, pr) ) return 0;
if ( piece_hits_rubble(px, py, pr) ) return 0;
return 1;
}
int piece_off_edge(int px, int py, int pr) {
int x, y;
const char *piece = pieces[piece_id] + (pr * PIECE_H * PIECE_W);
for (y = 0; y < PIECE_H; ++y) {
for (x = 0; x < PIECE_W; ++x) {
int nx = px + x;
int ny = py + y;
if (ny < 0) continue; // off top, don't care
if (piece[y * PIECE_W + x] > 0) {
if (nx < 0) return 1; // yes: off left side
if (nx >= GRID_W ) return 1; // yes: off right side
}
}
}
return 0; // inside limits
}
int piece_hits_rubble(int px, int py, int pr) {
int x, y;
const char *piece = pieces[piece_id] + (pr * PIECE_H * PIECE_W);
for (y = 0; y < PIECE_H; ++y) {
int ny = py + y;
if (ny < 0) continue;
for (x = 0; x < PIECE_W; ++x) {
int nx = px + x;
if (piece[y * PIECE_W + x] > 0) {
if (ny >= GRID_H ) return 1; // yes: goes off bottom of grid
if (grid[ny * GRID_W + nx] == 1 ) return 1; // yes: grid already full in this space
}
}
}
return 0; // doesn't hit
}
void game_over() {
int x, y;
while (1) {
// Your homework: add a 'game over' animation here, then film it and tweet it to @marginallyc.
for (x = 0; x < GRID_W; ++x) {
for (y = 0; y < GRID_H; ++y) {
p(x, y, 150);
}
}
// click the button?
if (digitalRead(1) == 0) {
// restart!
setup();
return;
}
}
}
void try_to_drop_piece() {
erase_piece_from_grid();
if (piece_can_fit(piece_x, piece_y + 1, piece_rotation)) {
piece_y++; // move piece down
add_piece_to_grid();
} else {
// hit something!
// put it back
add_piece_to_grid();
remove_full_rows();
if (game_is_over() == 1) {
game_over();
}
// game isn't over, choose a new piece
choose_new_piece();
}
}
void try_to_drop_faster() {
int y = analogRead(5);
if(y == 0){
try_to_drop_piece();
}
/*
int y = map(analogRead(5), 1023, 0, -500, 500);
if (y < JOYSTICK_DEAD_ZONE) {
// player is holding joystick down, drop a little faster.
try_to_drop_piece();
}
*/
}
void react_to_player() {
erase_piece_from_grid();
try_to_move_piece_sideways();
try_to_rotate_piece();
add_piece_to_grid();
try_to_drop_faster();
}
// can the piece fit in this new location
int game_is_over() {
int x, y;
const char *piece = pieces[piece_id] + (piece_rotation * PIECE_H * PIECE_W);
for (y = 0; y < PIECE_H; ++y) {
for (x = 0; x < PIECE_W; ++x) {
int ny = piece_y + y;
int nx = piece_x + x;
if (piece[y * PIECE_W + x] > 0) {
if (ny < 0) return 1; // yes: off the top!
}
}
}
return 0; // not over yet...
}
// called once when arduino res
void setup() {
int i;
// set all the pins to output.
for (i = 0; i < 16; ++i) {
pinMode(arduino_to_grid[i], OUTPUT);
}
// turn on all resistors, should produce no light
for (i = 0; i < 8; ++i) {
digitalWrite(out(i), LOW);
digitalWrite(in(i), HIGH);
}
// set up joystick button
pinMode(1, INPUT);
digitalWrite(1, HIGH);
// make sure arduino knows the grid is empty.
for (i = 0; i < GRID_W * GRID_H; ++i) {
grid[i] = 0;
pinMode(led, OUTPUT);
}
// make the game a bit more random - pull a number from space and use it to 'seed' a crop of random numbers.
randomSeed(analogRead(4));
// get ready to start the game.
choose_new_piece();
// start the game clock after everything else is ready.
last_move = millis();
last_drop = last_move;
Serial.begin(9600);
// called over and over after setup()
}
void loop() {
digitalWrite(led, HIGH); // turn the LED on (HIGH is the voltage level)
delay(1000); // wait for a second
digitalWrite(led, LOW); // turn the LED off by making the voltage LOW
delay(3000); // wait for a second
Serial.println(analogRead(5));
// the game plays at one speed,
if (millis() - last_move > move_delay ) {
last_move = millis();
react_to_player();
}
// ...and drops the falling block at a different speed.
if (millis() - last_drop > drop_delay ) {
last_drop = millis();
try_to_drop_piece();
}
// when it isn't doing those two things, it's redrawing the grid.
draw_grid();
}
현재 진행중인 테트리스 프로젝트인데 led매트릭스외에 led 전구를 를 꽂았을때 불빛을 들어오는데 켜지기만하고 loop 설정값대로 작동이 되지않는데 무엇이 문제인지 알 수 있을까요 ?
저번에 답변주신 drop_delay 를 사용하여 속도를 빠르게 내려가게 하는건 터득을 하였는데
시간이 지날수록 점점 빨리지게 하고싶은데 이떄 사용해야하는 함수나 간단한 예제가 있으면 알려주실수 있을까요 ?
|