📄 ntetris.c
字号:
}int drop_block_1(nstate *state){ if(will_collide(state, state->current_shape.x, (state->current_shape.y + 1), state->current_shape.orientation)) { block_reached_bottom(state); return 1; } draw_shape(state, state->current_shape.x, state->current_shape.y, 1); state->current_shape.y++; draw_shape(state, state->current_shape.x, state->current_shape.y, 0); draw_well(state, 0); return 0;}void drop_block(nstate *state){ while(!drop_block_1(state)) msleep(DROP_BLOCK_DELAY);}void handle_exposure_event(nstate *state){ GR_EVENT_EXPOSURE *event = &state->event.exposure; if(event->wid == state->score_window) { draw_score(state); return; } if(event->wid == state->next_shape_window) { draw_next_shape(state); return; } if(event->wid == state->new_game_button) { draw_new_game_button(state); return; } if(event->wid == state->pause_continue_button) { draw_pause_continue_button(state); return; } if(event->wid == state->anticlockwise_button) { draw_anticlockwise_button(state); return; } if(event->wid == state->clockwise_button) { draw_clockwise_button(state); return; } if(event->wid == state->left_button) { draw_left_button(state); return; } if(event->wid == state->right_button) { draw_right_button(state); return; } if(event->wid == state->drop_button) { draw_drop_button(state); return; } if(event->wid == state->well_window) { draw_well(state, 1); return; }}void handle_mouse_event(nstate *state){ GR_EVENT_MOUSE *event = &state->event.mouse; if(event->wid == state->new_game_button) { state->state = STATE_NEWGAME; return; } if(event->wid == state->pause_continue_button) { if(state->state == STATE_PAUSED) state->state = STATE_RUNNING; else state->state = STATE_PAUSED; return; } if(event->wid == state->anticlockwise_button) { if(state->state == STATE_PAUSED) state->state = STATE_RUNNING; rotate_block(state, 0); return; } if(event->wid == state->clockwise_button) { if(state->state == STATE_PAUSED) state->state = STATE_RUNNING; rotate_block(state, 1); return; } if(event->wid == state->left_button) { if(state->state == STATE_PAUSED) state->state = STATE_RUNNING; move_block(state, 0); return; } if(event->wid == state->right_button) { if(state->state == STATE_PAUSED) state->state = STATE_RUNNING; move_block(state, 1); return; } if(event->wid == state->drop_button) { if(state->state == STATE_PAUSED) state->state = STATE_RUNNING; drop_block(state); return; }}void handle_keyboard_event(nstate *state){ GR_EVENT_KEYSTROKE *event = &state->event.keystroke; switch(event->ch) { case 'q': case 'Q': case MWKEY_CANCEL: state->state = STATE_EXIT; return; case 'n': case 'N': case MWKEY_APP1: state->state = STATE_NEWGAME; return; } if(state->state == STATE_STOPPED) return; state->state = STATE_RUNNING; switch(event->ch) { case 'p': case 'P': state->state = STATE_PAUSED; break; case 'j': case 'J': case MWKEY_LEFT: move_block(state, 0); break; case 'k': case 'K': case MWKEY_RIGHT: move_block(state, 1); break; case 'd': case 'D': case MWKEY_UP: rotate_block(state, 0); break; case 'f': case 'F': case MWKEY_DOWN: rotate_block(state, 1); break; case ' ': case MWKEY_MENU: drop_block(state); break; }}void handle_event(nstate *state){ switch(state->event.type) { case GR_EVENT_TYPE_EXPOSURE: handle_exposure_event(state); break; case GR_EVENT_TYPE_BUTTON_DOWN: handle_mouse_event(state); break; case GR_EVENT_TYPE_KEY_DOWN: handle_keyboard_event(state); break; case GR_EVENT_TYPE_CLOSE_REQ: state->state = STATE_EXIT; break; case GR_EVENT_TYPE_TIMEOUT: break; default: fprintf(stderr, "Unhandled event type %d\n", state->event.type); break; }}void clear_well(nstate *state){ int x, y; for(y = 0; y < WELL_HEIGHT; y++) for(x = 0; x < WELL_WIDTH; x++) { state->blocks[0][y][x] = 0; state->blocks[1][y][x] = 0; }}/* Dirty hack alert- this is to avoid using any floating point math */int random8(int limit){ int ret; do { ret = random() & 7; } while(ret > limit); return ret;}void choose_new_shape(nstate *state){ state->current_shape.type = state->next_shape.type; state->current_shape.orientation = state->next_shape.orientation; state->current_shape.colour = state->next_shape.colour; state->current_shape.x = (WELL_WIDTH / 2) - 2; state->current_shape.y = WELL_NOTVISIBLE - shape_sizes[state->next_shape.type] [state->next_shape.orientation][1] - 1; state->next_shape.type = random8(MAXSHAPES - 1); state->next_shape.orientation = random8(MAXORIENTATIONS - 1); state->next_shape.colour = block_colours[random8(MAX_BLOCK_COLOUR)];}void new_game(nstate *state){ clear_well(state); if(state->score > state->hiscore) state->hiscore = state->score; state->score = 0; state->level = 0; draw_score(state); choose_new_shape(state); draw_next_shape(state); draw_well(state, 1); if(state->state == STATE_NEWGAME) state->state = STATE_RUNNING;}void init_game(nstate *state){ GR_WM_PROPERTIES props; if(GrOpen() < 0) { fprintf(stderr, "Couldn't connect to Nano-X server\n"); exit(1); } state->main_window = GrNewWindow(GR_ROOT_WINDOW_ID, MAIN_WINDOW_X_POSITION, MAIN_WINDOW_Y_POSITION, MAIN_WINDOW_WIDTH, MAIN_WINDOW_HEIGHT, 0, MAIN_WINDOW_BACKGROUND_COLOUR, 0); /* set title */ props.flags = GR_WM_FLAGS_TITLE | GR_WM_FLAGS_PROPS; props.props = GR_WM_PROPS_BORDER | GR_WM_PROPS_CAPTION; props.title = "Nano-Tetris"; GrSetWMProperties(state->main_window, &props); GrSelectEvents(state->main_window, GR_EVENT_MASK_EXPOSURE | GR_EVENT_MASK_CLOSE_REQ | GR_EVENT_MASK_KEY_DOWN | GR_EVENT_MASK_TIMEOUT); state->score_window = GrNewWindow(state->main_window, SCORE_WINDOW_X_POSITION, SCORE_WINDOW_Y_POSITION, SCORE_WINDOW_WIDTH, SCORE_WINDOW_HEIGHT, 0, SCORE_WINDOW_BACKGROUND_COLOUR, 0); GrSelectEvents(state->score_window, GR_EVENT_MASK_EXPOSURE); GrMapWindow(state->score_window); state->scoregcf = GrNewGC(); GrSetGCForeground(state->scoregcf, SCORE_WINDOW_FOREGROUND_COLOUR); GrSetGCBackground(state->scoregcf, SCORE_WINDOW_BACKGROUND_COLOUR); state->scoregcb = GrNewGC(); GrSetGCForeground(state->scoregcb, SCORE_WINDOW_BACKGROUND_COLOUR); state->next_shape_window = GrNewWindow(state->main_window, NEXT_SHAPE_WINDOW_X_POSITION, NEXT_SHAPE_WINDOW_Y_POSITION, NEXT_SHAPE_WINDOW_WIDTH, NEXT_SHAPE_WINDOW_HEIGHT, 0, NEXT_SHAPE_WINDOW_BACKGROUND_COLOUR, 0); GrSelectEvents(state->next_shape_window, GR_EVENT_MASK_EXPOSURE); GrMapWindow(state->next_shape_window); state->nextshapegcf = GrNewGC(); state->nextshapegcb = GrNewGC(); GrSetGCForeground(state->nextshapegcb, NEXT_SHAPE_WINDOW_BACKGROUND_COLOUR); state->new_game_button = GrNewWindow(state->main_window, NEW_GAME_BUTTON_X_POSITION, NEW_GAME_BUTTON_Y_POSITION, NEW_GAME_BUTTON_WIDTH, NEW_GAME_BUTTON_HEIGHT, 0, BUTTON_BACKGROUND_COLOUR, 0); GrSelectEvents(state->new_game_button, GR_EVENT_MASK_EXPOSURE | GR_EVENT_MASK_BUTTON_DOWN); GrMapWindow(state->new_game_button); state->buttongcf = GrNewGC(); GrSetGCForeground(state->buttongcf, BUTTON_FOREGROUND_COLOUR); GrSetGCBackground(state->buttongcf, BUTTON_BACKGROUND_COLOUR); state->buttongcb = GrNewGC(); GrSetGCForeground(state->buttongcb, BUTTON_BACKGROUND_COLOUR); state->pause_continue_button = GrNewWindow(state->main_window, PAUSE_CONTINUE_BUTTON_X_POSITION, PAUSE_CONTINUE_BUTTON_Y_POSITION, PAUSE_CONTINUE_BUTTON_WIDTH, PAUSE_CONTINUE_BUTTON_HEIGHT, 0, BUTTON_BACKGROUND_COLOUR, 0); GrSelectEvents(state->pause_continue_button, GR_EVENT_MASK_EXPOSURE | GR_EVENT_MASK_BUTTON_DOWN); state->anticlockwise_button = GrNewWindow(state->main_window, ANTICLOCKWISE_BUTTON_X_POSITION, ANTICLOCKWISE_BUTTON_Y_POSITION, ANTICLOCKWISE_BUTTON_WIDTH, ANTICLOCKWISE_BUTTON_HEIGHT, 0, BUTTON_BACKGROUND_COLOUR, 0); GrSelectEvents(state->anticlockwise_button, GR_EVENT_MASK_EXPOSURE | GR_EVENT_MASK_BUTTON_DOWN); state->clockwise_button = GrNewWindow(state->main_window, CLOCKWISE_BUTTON_X_POSITION, CLOCKWISE_BUTTON_Y_POSITION, CLOCKWISE_BUTTON_WIDTH, CLOCKWISE_BUTTON_HEIGHT, 0, BUTTON_BACKGROUND_COLOUR, 0); GrSelectEvents(state->clockwise_button, GR_EVENT_MASK_EXPOSURE | GR_EVENT_MASK_BUTTON_DOWN); state->left_button = GrNewWindow(state->main_window, LEFT_BUTTON_X_POSITION, LEFT_BUTTON_Y_POSITION, LEFT_BUTTON_WIDTH, LEFT_BUTTON_HEIGHT, 0, BUTTON_BACKGROUND_COLOUR, 0); GrSelectEvents(state->left_button, GR_EVENT_MASK_EXPOSURE | GR_EVENT_MASK_BUTTON_DOWN); state->right_button = GrNewWindow(state->main_window, RIGHT_BUTTON_X_POSITION, RIGHT_BUTTON_Y_POSITION, RIGHT_BUTTON_WIDTH, RIGHT_BUTTON_HEIGHT, 0, BUTTON_BACKGROUND_COLOUR, 0); GrSelectEvents(state->right_button, GR_EVENT_MASK_EXPOSURE | GR_EVENT_MASK_BUTTON_DOWN); state->drop_button = GrNewWindow(state->main_window, DROP_BUTTON_X_POSITION, DROP_BUTTON_Y_POSITION, DROP_BUTTON_WIDTH, DROP_BUTTON_HEIGHT, 0, BUTTON_BACKGROUND_COLOUR, 0); GrSelectEvents(state->drop_button, GR_EVENT_MASK_EXPOSURE | GR_EVENT_MASK_BUTTON_DOWN); state->well_window = GrNewWindow(state->main_window, WELL_WINDOW_X_POSITION, WELL_WINDOW_Y_POSITION, WELL_WINDOW_WIDTH, WELL_WINDOW_HEIGHT, 0, WELL_WINDOW_BACKGROUND_COLOUR, 0); GrSelectEvents(state->well_window, GR_EVENT_MASK_EXPOSURE); GrMapWindow(state->well_window); state->wellgc = GrNewGC(); GrMapWindow(state->main_window); state->state = STATE_STOPPED; state->score = 0; read_hiscore(state); state->level = 0; state->running_buttons_mapped = 0; srandom(time(0)); choose_new_shape(state); new_game(state);}void calculate_timeout(nstate *state){ struct timeval t; long u; gettimeofday(&t, NULL); u = t.tv_usec + (delays[state->level] * 1000); state->timeout.tv_sec = t.tv_sec + (u / 1000000); state->timeout.tv_usec = u % 1000000;}unsigned long timeout_delay(nstate *state){ struct timeval t; signed long s, m, ret; gettimeofday(&t, NULL); if((t.tv_sec > state->timeout.tv_sec) || ((t.tv_sec == state->timeout.tv_sec) && t.tv_usec >= state->timeout.tv_usec)) return 1; s = state->timeout.tv_sec - t.tv_sec; m = ((state->timeout.tv_usec - t.tv_usec) / 1000); ret = (unsigned long)((1000 * s) + m);/* fprintf(stderr, "t.tv_sec = %ld, t.tv_usec = %ld, timeout.tv_sec = " "%ld, timeout.tv_usec = %ld, s = %ld, m = %ld, ret = %ld\n", t.tv_sec, t.tv_usec, state->timeout.tv_sec, state->timeout.tv_usec, s, m, ret);*/ if(ret <= 0) return 1; else return ret;}void do_update(nstate *state){ struct timeval t; gettimeofday(&t, NULL); if((t.tv_sec > state->timeout.tv_sec) || ((t.tv_sec == state->timeout.tv_sec) && (t.tv_usec >= state->timeout.tv_usec))) { drop_block_1(state); calculate_timeout(state); } }void do_pause(nstate *state){ draw_pause_continue_button(state); while(state->state == STATE_PAUSED) { GrGetNextEvent(&state->event); handle_event(state); } draw_pause_continue_button(state);}void wait_for_start(nstate *state){ draw_pause_continue_button(state); while(state->state == STATE_STOPPED) { GrGetNextEvent(&state->event); handle_event(state); } if(state->state == STATE_NEWGAME) state->state = STATE_RUNNING; draw_pause_continue_button(state); calculate_timeout(state);}void run_game(nstate *state){ while(state->state == STATE_RUNNING) { GrGetNextEventTimeout(&state->event, timeout_delay(state)); handle_event(state); if(state->state == STATE_PAUSED) do_pause(state); if(state->state == STATE_RUNNING) do_update(state); }}void main_game_loop(nstate *state){ wait_for_start(state); while(state->state != STATE_EXIT) { if(state->state == STATE_RUNNING) run_game(state); if(state->state == STATE_STOPPED) wait_for_start(state); if(state->state != STATE_EXIT) new_game(state); }}int main(int argc, char *argv[]){ nstate *state = my_malloc(sizeof(nstate)); init_game(state); main_game_loop(state); write_hiscore(state); GrClose(); return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -