Gtk+3.0 实现简单的俄罗斯方块

来源:互联网 发布:计算机考研学校知乎 编辑:程序博客网 时间:2024/05/01 23:36

最近学习GTK,顺便就写个小游戏练练手。也是又一个图形界面的小程序啊。不断的学习,才能不断的进步,不知不觉工作之余学习GTK也有几个月了。哈哈。贴上代码,大家共勉啊。

使用方法:

s 左移      f 右移    j 逆时针翻转     l 顺时针翻转      空格加速下降

具体可以参见 response_key_press函数里面的处理过程


图像



#include <gtk/gtk.h>#include <stdlib.h>#include <string.h>typedef struct stCellFlag {char status;char style_type;} CELL_FLAG_ST;enum {STYLE_TYPE_L1,STYLE_TYPE_L2,STYLE_TYPE_Z1,STYLE_TYPE_Z2,STYLE_TYPE_T,STYLE_TYPE_O,STYLE_TYPE_I,STYLE_TYPE_MAX};enum {STYLE_MODE_1,STYLE_MODE_2,STYLE_MODE_3,STYLE_MODE_4,STYLE_MODE_MAX,};#define SQURE_MAX_NUM 4typedef struct stXYLocationPair {int x, y;} XY_LOCATION_PAIR_ST;typedef struct stStylePointer {XY_LOCATION_PAIR_ST location[SQURE_MAX_NUM];} STYLE_POINTER_ST;typedef struct stStyleMatrix {STYLE_POINTER_ST style[STYLE_MODE_MAX];gchar * color_str;} STYLE_MAXTRIX_ST;STYLE_MAXTRIX_ST styleL1 = {{{{{-1, -1}, {-1, 0}, {0, 0}, {1, 0}}},{{{0, -1}, {-1, -1}, {-1, 0}, {-1, 1}}},{{{0, 0}, {0, -1}, {-1, -1}, {-2, -1}}},{{{-1, 0}, {0, 0}, {0, -1}, {0, -2}}}},"green"};STYLE_MAXTRIX_ST styleL2 = {{{{{0, -2}, {0, -1}, {-1, -1}, {-2, -1}}},{{{1, 0}, {0, 0}, {0, -1}, {0, -2}}},{{{-1, 1}, {-1, 0}, {0, 0}, {1, 0}}},{{{-2, -1}, {-1, -1}, {-1, 0}, {-1, 1}}}},"blue"};STYLE_MAXTRIX_ST styleT = {{{{{-1, -1}, {0, -1}, {1, -1}, {0, -2}}},{{{0, -1}, {0, 0}, {0, 1}, {1, 0}}},{{{0, 0}, {-1, 0}, {-2, 0}, {-1, 1}}},{{{-1, 0}, {-1, -1}, {-1, -2}, {-2, -1}}},},"red"};STYLE_MAXTRIX_ST styleZ1 = {{{{{-1, -1}, {-1, 0}, {0, 0}, {0, 1}}},{{{0, -1}, {-1, -1}, {-1, 0}, {-2, 0}}},{{{0, 0}, {0, -1}, {-1, -1}, {-1, -2}}},{{{-1, 0}, {0, 0}, {0, -1}, {1, -1}}},},"yellow"};STYLE_MAXTRIX_ST styleZ2 = {{{{{0, -1}, {0, 0}, {-1, 0}, {-1, 1}}},{{{0, 0}, {-1, 0}, {-1, -1}, {-2, -1}}},{{{-1, 0}, {-1, -1}, {0, -1}, {0, -2}}},{{{-1, -1}, {0, -1}, {0, 0}, {1, 0}}},},"coral"};STYLE_MAXTRIX_ST styleI = {{{{{-2, -1}, {-1, -1}, {0, -1}, {1, -1}}},{{{0, -2}, {0, -1}, {0, 0}, {0, 1}}},{{{1, 0}, {0, 0}, {-1, 0}, {-2, 0}}},{{{-1, 1}, {-1, 0}, {-1, -1}, {-1, -2}}},},"orange"};STYLE_MAXTRIX_ST styleO = {{{{{-1, -1}, {0, -1}, {0, 0}, {-1, 0}}},{{{-1, -1}, {0, -1}, {0, 0}, {-1, 0}}},{{{-1, -1}, {0, -1}, {0, 0}, {-1, 0}}},{{{-1, -1}, {0, -1}, {0, 0}, {-1, 0}}},},"gray"};STYLE_MAXTRIX_ST * styleMatrix[] = {[STYLE_TYPE_L1] = &styleL1,[STYLE_TYPE_L2] = &styleL2,[STYLE_TYPE_Z1] = &styleZ1,[STYLE_TYPE_Z2] = &styleZ2,[STYLE_TYPE_T] = &styleT,[STYLE_TYPE_I] = &styleI,[STYLE_TYPE_O] = &styleO,};GdkRGBA styleRgbaInfo[STYLE_TYPE_MAX];#define BASE_SCORE_VALUE 1#define MAX_SCORE_BUFFER_LEN 10#define COL_MAX_NUM 20#define ROW_MAX_NUM 30#define FLAG_ACTIVE 1#define FLAG_INACTIVE 0#define POSITION_Y_START -3gint squre_width = 20;gint col_num = COL_MAX_NUM;gint row_num = ROW_MAX_NUM;gint XPosition = COL_MAX_NUM / 2;gint YPosition = POSITION_Y_START;gint styleTypeMax;gint styleType = 0;gint styleMode = STYLE_MODE_1;gint timeout_mseconds = 250;GRand * rand_gen;gint Score;GtkWidget * Score_label;GtkWidget * NewGameButton;CELL_FLAG_ST flagTable[ROW_MAX_NUM][COL_MAX_NUM];STYLE_POINTER_ST * game_get_current_style(){return &styleMatrix[styleType]->style[styleMode];}STYLE_POINTER_ST * game_get_style(int type, int mode){return &styleMatrix[type]->style[mode];}GdkRGBA * game_get_current_style_color(){return &styleRgbaInfo[styleType];}#define LINE_WIDTH 1#define START_FIX 1void draw_box(cairo_t * cr, int xpointer, int ypointer, GdkRGBA * rgba){cairo_save(cr);cairo_rectangle(cr, START_FIX + xpointer * squre_width, START_FIX + ypointer * squre_width, squre_width, squre_width);cairo_stroke(cr);gdk_cairo_set_source_rgba(cr, rgba);cairo_rectangle(cr, START_FIX + xpointer * squre_width + LINE_WIDTH, START_FIX + ypointer * squre_width + LINE_WIDTH, squre_width - 2 * LINE_WIDTH, squre_width - 2 * LINE_WIDTH);cairo_fill(cr);cairo_restore(cr);}void draw_style(cairo_t * cr, STYLE_POINTER_ST * style, GdkRGBA * rgba, int xpointer, int ypointer){int i;XY_LOCATION_PAIR_ST * location;cairo_save(cr);for (i = 0; i < SQURE_MAX_NUM; ++i){location = &style->location[i];draw_box(cr, xpointer + location->x, ypointer + location->y, rgba);}cairo_restore(cr);}void draw_the_table_area(cairo_t * cr){cairo_save(cr);cairo_rectangle(cr, START_FIX, START_FIX, COL_MAX_NUM * squre_width, ROW_MAX_NUM * squre_width);cairo_stroke(cr);cairo_restore(cr);}void draw_the_table(cairo_t * cr){int c, r;cairo_save(cr);for (r = 0; r < ROW_MAX_NUM; ++r){for (c = 0; c < COL_MAX_NUM; ++c){if (flagTable[r][c].status == FLAG_ACTIVE){draw_box(cr, c, r, &styleRgbaInfo[flagTable[r][c].style_type]);}}}draw_the_table_area(cr);cairo_restore(cr);}gboolean draw_the_play_area(GtkWidget * widget, cairo_t * cr, gpointer data){draw_the_table(cr);draw_style(cr, game_get_current_style(), game_get_current_style_color(), XPosition, YPosition);return FALSE;}int game_check_position_valid(STYLE_POINTER_ST * style, int xpointer, int ypointer){int i;XY_LOCATION_PAIR_ST * location;int col, row;for (i = 0; i < SQURE_MAX_NUM; ++i){location = &style->location[i];row = ypointer + location->y;col = xpointer + location->x;if (row >= ROW_MAX_NUM)return FALSE;if (col < 0 || col >= COL_MAX_NUM)return FALSE;if (row < 0)continue;if (flagTable[row][col].status == FLAG_ACTIVE)return FALSE;}return TRUE;}gboolean gen_new_style(){int style, mode, xpointer, ypointer;style = g_rand_int_range(rand_gen, 0, STYLE_TYPE_MAX);mode = g_rand_int_range(rand_gen, 0, STYLE_MODE_MAX);xpointer = COL_MAX_NUM / 2;ypointer = POSITION_Y_START;if (game_check_position_valid(game_get_style(style, mode), xpointer, ypointer)){XPosition = xpointer;YPosition = ypointer;styleType = style;styleMode = mode;return TRUE;}return FALSE;}void game_fix_style(){STYLE_POINTER_ST * style = game_get_current_style();int i;XY_LOCATION_PAIR_ST * location;int col, row;for (i = 0; i < SQURE_MAX_NUM; ++i){location = &style->location[i];row = YPosition + location->y;col = XPosition + location->x;if (row < 0)continue;flagTable[row][col].status = FLAG_ACTIVE;flagTable[row][col].style_type = styleType;}}gboolean game_check_show_fix_style(int xpointer, int ypointer){STYLE_POINTER_ST * style = game_get_current_style();int i;XY_LOCATION_PAIR_ST * location;int col, row;for (i = 0; i < SQURE_MAX_NUM; ++i){location = &style->location[i];row = ypointer + location->y;col = xpointer + location->x;if (row >= ROW_MAX_NUM)break;if (row < 0)continue;if (flagTable[row][col].status == FLAG_ACTIVE)break;}if (i != SQURE_MAX_NUM)return TRUE;return FALSE;}void game_move_flag_status(int l, int h){int r, c;while (l >= 0){memcpy(flagTable[h], flagTable[l], sizeof(flagTable[l]));h--;l--;//flagTable[h--] = flagTable[l--];}while (h >= 0){for (c = 0; c < COL_MAX_NUM; ++c){flagTable[h][c].status = FLAG_INACTIVE;}h--;}}void game_fixup_score(int lines){Score += (1 << lines) * BASE_SCORE_VALUE;}void game_destroy_full_line(){int c, r, l, h;int count;int flag = FALSE;char score_buffer[MAX_SCORE_BUFFER_LEN];char destroy_flag[ROW_MAX_NUM];memset(destroy_flag, 0, sizeof(destroy_flag));for (r = 0; r < ROW_MAX_NUM; ++r){count = 0;for (c = 0; c < COL_MAX_NUM; ++c){if (flagTable[r][c].status == FLAG_ACTIVE)count++;}if (count == COL_MAX_NUM){destroy_flag[r] = TRUE;}}for (l = 0; l < ROW_MAX_NUM; ++l){if (destroy_flag[l]){for (h = l; h < ROW_MAX_NUM; ++h){if (!destroy_flag[h])break;}game_move_flag_status(l - 1, h - 1);game_fixup_score(h - l);flag = TRUE;l = h - 1;}}if (flag){sprintf(score_buffer, "%d", Score);gtk_label_set_text(GTK_LABEL(Score_label), score_buffer);}}gboolean game_auto_move_style(gpointer user_data){if (game_check_show_fix_style(XPosition, YPosition + 1)){if (YPosition < 0){g_message("Game Over");gtk_widget_set_sensitive(NewGameButton, TRUE);return FALSE;}game_fix_style();game_destroy_full_line();if (!gen_new_style())return FALSE;}else{YPosition += 1;}gtk_widget_queue_draw(GTK_WIDGET(user_data));return TRUE;}gboolean response_key_press(GtkWidget * widget, GdkEventKey * key, gpointer data){int mode_temp;switch (key->keyval){case GDK_KEY_J:case GDK_KEY_j:mode_temp = styleMode + 1;mode_temp %= STYLE_MODE_MAX;if (game_check_position_valid(&styleMatrix[styleType]->style[mode_temp], XPosition, YPosition))styleMode = mode_temp;break;case GDK_KEY_L:case GDK_KEY_l:mode_temp = styleMode + STYLE_MODE_MAX - 1;mode_temp %= STYLE_MODE_MAX;if (game_check_position_valid(&styleMatrix[styleType]->style[mode_temp], XPosition, YPosition))styleMode = mode_temp;break;case GDK_KEY_space:if (game_check_position_valid(game_get_current_style(), XPosition, YPosition + 1))YPosition += 1;break;case GDK_KEY_F:case GDK_KEY_f:if (game_check_position_valid(game_get_current_style(), XPosition + 1, YPosition))XPosition += 1;break;case GDK_KEY_S:case GDK_KEY_s:if (game_check_position_valid(game_get_current_style(), XPosition - 1, YPosition))XPosition -= 1;break;case GDK_KEY_Return:styleType += 1;styleType %= STYLE_TYPE_MAX;break;default:return FALSE;}gtk_widget_queue_draw(widget);return TRUE;}void init_game(){int r, c, i;styleTypeMax = sizeof(styleMatrix) / sizeof(void *);for (r = 0; r < ROW_MAX_NUM; ++r){for (c = 0; c < COL_MAX_NUM; ++c){flagTable[r][c].status = FLAG_INACTIVE;}}for (i = 0; i < STYLE_TYPE_MAX; ++i){gdk_rgba_parse(&styleRgbaInfo[i], styleMatrix[i]->color_str);}rand_gen = g_rand_new();Score = 0;}void restart_new_game(GtkWidget * button, GtkWidget * draw_area){init_game();gtk_widget_set_sensitive(button, FALSE);gtk_widget_queue_draw(draw_area);gtk_label_set_text(GTK_LABEL(Score_label), "0");g_timeout_add(timeout_mseconds, game_auto_move_style, draw_area);gtk_widget_grab_focus(draw_area);}intmain (int argc, char *argv[]){ GtkWidget * window;GtkWidget * draw_area;GtkWidget * grid;GtkWidget * label;GtkWidget * vbox;GtkWidget * reset_button;init_game();gtk_init(&argc, &argv);window = gtk_window_new(GTK_WINDOW_TOPLEVEL);gtk_container_set_border_width(GTK_CONTAINER(window), 5);gtk_window_set_resizable(GTK_WINDOW(window), FALSE);g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL);grid = gtk_grid_new();gtk_grid_set_column_spacing(GTK_GRID(grid), 5);gtk_grid_set_row_spacing(GTK_GRID(grid), 5);gtk_container_add(GTK_CONTAINER(window), grid);draw_area = gtk_drawing_area_new();gtk_widget_set_size_request(draw_area, col_num * squre_width + 2, row_num * squre_width + 2);gtk_widget_add_events(draw_area, GDK_KEY_PRESS_MASK);gtk_widget_set_can_focus(draw_area, TRUE);g_signal_connect(draw_area, "key-press-event", G_CALLBACK(response_key_press), NULL);g_signal_connect(draw_area, "draw", G_CALLBACK(draw_the_play_area), NULL);gtk_grid_attach(GTK_GRID(grid), draw_area, 0, 0, 1, 3);vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 5);gtk_grid_attach(GTK_GRID(grid), vbox, 1, 1, 1, 1);label = gtk_label_new("Scores");gtk_widget_set_vexpand(label, FALSE);gtk_widget_set_valign(label, GTK_ALIGN_END);gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 5);Score_label = gtk_label_new("0");gtk_widget_set_vexpand(Score_label, FALSE);gtk_widget_set_valign(Score_label, GTK_ALIGN_START);gtk_box_pack_start(GTK_BOX(vbox), Score_label, FALSE, FALSE, 5);NewGameButton = reset_button = gtk_button_new_with_label("New Game");gtk_widget_set_sensitive(reset_button, FALSE);gtk_widget_set_vexpand(reset_button, FALSE);gtk_widget_set_valign(reset_button, GTK_ALIGN_END);g_signal_connect(reset_button, "clicked", G_CALLBACK(restart_new_game), draw_area);gtk_grid_attach(GTK_GRID(grid), reset_button, 1, 2, 1, 1);gtk_widget_show_all(window);g_timeout_add(timeout_mseconds, game_auto_move_style, draw_area);gtk_main ();return 0;}

代码里面需要完善的地方还是很多的。不过这个也不是很大的项目,也没有一直维护的必要性,也就当练手了。等有了好的项目的话,就上github上弄个站点玩玩。现在就先这样了。有时间继续修改啊。好歹自己在linux下做了个小游戏,闲的无聊了也可以娱乐一下,顺便修改修改,哈哈


原创粉丝点击