안녕하세요 제가 이번에 학교에서 하는 프로젝트로 아두이노를 배우면서 하고있습니다.
제가 테트리스 게임을 만들고있는데 그냥 게임만하는 것이아니라 시간이 지날수록 점점 빠르게 내려가게 하고
싶은데 코드를 어디부분을 어떻게 손봐줘야하는지 힘든부분이 있어 문의드려봅니다! 부탁드립니다!
#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};
// 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 reboots
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;
}
// 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() {
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();
}
|