📄 ntetris.c
字号:
{
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;
}
static void drop_block(nstate *state)
{
while(!drop_block_1(state)) msleep(DROP_BLOCK_DELAY);
}
static 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;
}
}
static 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;
}
}
static 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;
}
}
static 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;
}
}
static 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 */
static int random8(int limit)
{
int ret;
do { ret = random() & 7; } while(ret > limit);
return ret;
}
static 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)];
}
static 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;
}
static 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);
}
static 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;
}
static 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;
}
static 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);
}
}
static 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);
}
static 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);
}
static 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);
}
}
static 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);
}
}
#ifdef __ECOS
#define main ntetris_main
#endif
int main(int argc, char *argv[])
{
nstate *state = my_malloc(sizeof(nstate));
bzero(state, sizeof(*state));
init_game(state);
main_game_loop(state);
write_hiscore(state);
GrClose();
return 0;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -