mirror of
https://github.com/LHY0125/Gobang-Game.git
synced 2026-05-10 02:19:46 +08:00
feat(gui): 添加主菜单和游戏模式选择界面
- 新增 GUI 主菜单,支持玩家对战、人机对战、复盘模式和设置选项 - 新增游戏设置对话框,可配置棋盘大小、禁手、计时器和 AI 难度 - 重构 GUI 游戏窗口,集成悔棋、保存和返回菜单功能 - 更新 Makefile 以支持 PowerShell 并添加新源文件编译 - 调整窗口尺寸为 1000x800 以提供更好的游戏体验
This commit is contained in:
+264
@@ -0,0 +1,264 @@
|
||||
#include <iup.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include "gui_menu.h"
|
||||
#include "gui.h"
|
||||
#include "globals.h"
|
||||
#include "config.h"
|
||||
|
||||
static Ihandle *menu_dlg = NULL;
|
||||
|
||||
static int btn_pvp_cb(Ihandle *ih)
|
||||
{
|
||||
(void)ih;
|
||||
hide_main_menu();
|
||||
start_pvp_game_gui();
|
||||
return IUP_DEFAULT;
|
||||
}
|
||||
|
||||
static int btn_pve_cb(Ihandle *ih)
|
||||
{
|
||||
(void)ih;
|
||||
hide_main_menu();
|
||||
start_pve_game_gui();
|
||||
return IUP_DEFAULT;
|
||||
}
|
||||
|
||||
static int btn_replay_cb(Ihandle *ih)
|
||||
{
|
||||
(void)ih;
|
||||
hide_main_menu();
|
||||
start_replay_gui();
|
||||
return IUP_DEFAULT;
|
||||
}
|
||||
|
||||
static int btn_save_settings_cb(Ihandle *ih)
|
||||
{
|
||||
Ihandle *dlg = IupGetDialog(ih);
|
||||
|
||||
// Get values
|
||||
Ihandle *txt_board_size = IupGetDialogChild(dlg, "BOARD_SIZE");
|
||||
Ihandle *tgl_forbidden = IupGetDialogChild(dlg, "FORBIDDEN");
|
||||
Ihandle *tgl_timer = IupGetDialogChild(dlg, "TIMER");
|
||||
Ihandle *txt_time_limit = IupGetDialogChild(dlg, "TIME_LIMIT");
|
||||
Ihandle *lst_ai = IupGetDialogChild(dlg, "AI_DIFFICULTY");
|
||||
|
||||
// Update globals
|
||||
int new_size = IupGetInt(txt_board_size, "VALUE");
|
||||
if (new_size < MIN_BOARD_SIZE) new_size = MIN_BOARD_SIZE;
|
||||
if (new_size > MAX_BOARD_SIZE) new_size = MAX_BOARD_SIZE;
|
||||
BOARD_SIZE = new_size;
|
||||
|
||||
use_forbidden_moves = IupGetInt(tgl_forbidden, "VALUE");
|
||||
|
||||
use_timer = IupGetInt(tgl_timer, "VALUE");
|
||||
if (use_timer) {
|
||||
int minutes = IupGetInt(txt_time_limit, "VALUE");
|
||||
if (minutes < 1) minutes = 1;
|
||||
time_limit = minutes * 60;
|
||||
}
|
||||
|
||||
int ai_level = IupGetInt(lst_ai, "VALUE");
|
||||
if (ai_level < 1) ai_level = 1;
|
||||
if (ai_level > 5) ai_level = 5;
|
||||
ai_difficulty = ai_level;
|
||||
defense_coefficient = DEFAULT_DEFENSE_COEFFICIENT + (ai_difficulty - 1) * 0.1;
|
||||
|
||||
// Save config
|
||||
save_game_config();
|
||||
|
||||
IupHide(dlg);
|
||||
return IUP_DEFAULT;
|
||||
}
|
||||
|
||||
static int btn_cancel_settings_cb(Ihandle *ih)
|
||||
{
|
||||
Ihandle *dlg = IupGetDialog(ih);
|
||||
IupHide(dlg);
|
||||
return IUP_DEFAULT;
|
||||
}
|
||||
|
||||
static int tgl_timer_cb(Ihandle *ih, int state)
|
||||
{
|
||||
Ihandle *dlg = IupGetDialog(ih);
|
||||
Ihandle *txt_time_limit = IupGetDialogChild(dlg, "TIME_LIMIT");
|
||||
IupSetAttribute(txt_time_limit, "ACTIVE", state ? "YES" : "NO");
|
||||
return IUP_DEFAULT;
|
||||
}
|
||||
|
||||
static int btn_settings_cb(Ihandle *ih)
|
||||
{
|
||||
(void)ih;
|
||||
|
||||
// 1. Board Size
|
||||
Ihandle *lbl_board_size = IupLabel("棋盘大小 (5-25):");
|
||||
Ihandle *txt_board_size = IupText(NULL);
|
||||
IupSetAttribute(txt_board_size, "NAME", "BOARD_SIZE");
|
||||
IupSetAttribute(txt_board_size, "SPIN", "YES");
|
||||
IupSetAttribute(txt_board_size, "SPINMIN", "5");
|
||||
IupSetAttribute(txt_board_size, "SPINMAX", "25");
|
||||
IupSetInt(txt_board_size, "VALUE", BOARD_SIZE);
|
||||
IupSetAttribute(txt_board_size, "SIZE", "50x");
|
||||
|
||||
// 2. Forbidden Moves
|
||||
Ihandle *tgl_forbidden = IupToggle("启用禁手规则", NULL);
|
||||
IupSetAttribute(tgl_forbidden, "NAME", "FORBIDDEN");
|
||||
IupSetInt(tgl_forbidden, "VALUE", use_forbidden_moves);
|
||||
|
||||
// 3. Timer
|
||||
Ihandle *tgl_timer = IupToggle("启用计时器", NULL);
|
||||
IupSetAttribute(tgl_timer, "NAME", "TIMER");
|
||||
IupSetInt(tgl_timer, "VALUE", use_timer);
|
||||
IupSetCallback(tgl_timer, "ACTION", (Icallback)tgl_timer_cb);
|
||||
|
||||
// 4. Time Limit
|
||||
Ihandle *lbl_time_limit = IupLabel("时间限制 (分钟):");
|
||||
Ihandle *txt_time_limit = IupText(NULL);
|
||||
IupSetAttribute(txt_time_limit, "NAME", "TIME_LIMIT");
|
||||
IupSetAttribute(txt_time_limit, "SPIN", "YES");
|
||||
IupSetAttribute(txt_time_limit, "SPINMIN", "1");
|
||||
IupSetAttribute(txt_time_limit, "SPINMAX", "60");
|
||||
IupSetInt(txt_time_limit, "VALUE", time_limit / 60);
|
||||
IupSetAttribute(txt_time_limit, "ACTIVE", use_timer ? "YES" : "NO");
|
||||
IupSetAttribute(txt_time_limit, "SIZE", "50x");
|
||||
|
||||
// 5. AI Difficulty
|
||||
Ihandle *lbl_ai = IupLabel("AI 难度 (1-5):");
|
||||
Ihandle *lst_ai = IupList(NULL);
|
||||
IupSetAttribute(lst_ai, "NAME", "AI_DIFFICULTY");
|
||||
IupSetAttribute(lst_ai, "DROPDOWN", "YES");
|
||||
IupSetAttribute(lst_ai, "1", "1 (简单)");
|
||||
IupSetAttribute(lst_ai, "2", "2 (普通)");
|
||||
IupSetAttribute(lst_ai, "3", "3 (中等)");
|
||||
IupSetAttribute(lst_ai, "4", "4 (困难)");
|
||||
IupSetAttribute(lst_ai, "5", "5 (专家)");
|
||||
IupSetInt(lst_ai, "VALUE", ai_difficulty);
|
||||
IupSetAttribute(lst_ai, "SIZE", "80x");
|
||||
|
||||
// Buttons
|
||||
Ihandle *btn_save = IupButton("保存", NULL);
|
||||
IupSetCallback(btn_save, "ACTION", (Icallback)btn_save_settings_cb);
|
||||
IupSetAttribute(btn_save, "SIZE", "60x");
|
||||
|
||||
Ihandle *btn_cancel = IupButton("取消", NULL);
|
||||
IupSetCallback(btn_cancel, "ACTION", (Icallback)btn_cancel_settings_cb);
|
||||
IupSetAttribute(btn_cancel, "SIZE", "60x");
|
||||
|
||||
// Layout
|
||||
Ihandle *hbox_board = IupHbox(lbl_board_size, txt_board_size, NULL);
|
||||
IupSetAttribute(hbox_board, "ALIGNMENT", "ACENTER");
|
||||
IupSetAttribute(hbox_board, "GAP", "10");
|
||||
|
||||
Ihandle *hbox_time = IupHbox(lbl_time_limit, txt_time_limit, NULL);
|
||||
IupSetAttribute(hbox_time, "ALIGNMENT", "ACENTER");
|
||||
IupSetAttribute(hbox_time, "GAP", "10");
|
||||
|
||||
Ihandle *hbox_ai = IupHbox(lbl_ai, lst_ai, NULL);
|
||||
IupSetAttribute(hbox_ai, "ALIGNMENT", "ACENTER");
|
||||
IupSetAttribute(hbox_ai, "GAP", "10");
|
||||
|
||||
Ihandle *hbox_btns = IupHbox(btn_save, btn_cancel, NULL);
|
||||
IupSetAttribute(hbox_btns, "GAP", "20");
|
||||
IupSetAttribute(hbox_btns, "MARGIN", "10x0");
|
||||
IupSetAttribute(hbox_btns, "ALIGNMENT", "ACENTER");
|
||||
|
||||
Ihandle *vbox = IupVbox(
|
||||
hbox_board,
|
||||
tgl_forbidden,
|
||||
tgl_timer,
|
||||
hbox_time,
|
||||
hbox_ai,
|
||||
IupLabel(NULL), // Spacer
|
||||
hbox_btns,
|
||||
NULL);
|
||||
|
||||
IupSetAttribute(vbox, "GAP", "15");
|
||||
IupSetAttribute(vbox, "MARGIN", "30x30");
|
||||
|
||||
Ihandle *dlg = IupDialog(vbox);
|
||||
IupSetAttribute(dlg, "TITLE", "游戏设置");
|
||||
IupSetAttribute(dlg, "RESIZE", "NO");
|
||||
IupSetAttribute(dlg, "MINBOX", "NO");
|
||||
IupSetAttribute(dlg, "MAXBOX", "NO");
|
||||
|
||||
IupPopup(dlg, IUP_CENTER, IUP_CENTER);
|
||||
IupDestroy(dlg);
|
||||
|
||||
return IUP_DEFAULT;
|
||||
}
|
||||
|
||||
static int btn_exit_cb(Ihandle *ih)
|
||||
{
|
||||
(void)ih;
|
||||
cleanup_gui(); // 清理GUI资源
|
||||
exit(0);
|
||||
return IUP_DEFAULT;
|
||||
}
|
||||
|
||||
void create_main_menu()
|
||||
{
|
||||
if (menu_dlg) return;
|
||||
|
||||
Ihandle *lbl_title = IupLabel("五子棋 (Gobang)");
|
||||
IupSetAttribute(lbl_title, "FONT", "SimHei, 24");
|
||||
IupSetAttribute(lbl_title, "ALIGNMENT", "ACENTER");
|
||||
|
||||
Ihandle *btn_pvp = IupButton("玩家对战 (PvP)", NULL);
|
||||
IupSetCallback(btn_pvp, "ACTION", (Icallback)btn_pvp_cb);
|
||||
IupSetAttribute(btn_pvp, "SIZE", "120x30");
|
||||
IupSetAttribute(btn_pvp, "FONT", "SimHei, 12");
|
||||
|
||||
Ihandle *btn_pve = IupButton("人机对战 (PvE)", NULL);
|
||||
IupSetCallback(btn_pve, "ACTION", (Icallback)btn_pve_cb);
|
||||
IupSetAttribute(btn_pve, "SIZE", "120x30");
|
||||
IupSetAttribute(btn_pve, "FONT", "SimHei, 12");
|
||||
|
||||
Ihandle *btn_replay = IupButton("复盘模式", NULL);
|
||||
IupSetCallback(btn_replay, "ACTION", (Icallback)btn_replay_cb);
|
||||
IupSetAttribute(btn_replay, "SIZE", "120x30");
|
||||
IupSetAttribute(btn_replay, "FONT", "SimHei, 12");
|
||||
|
||||
Ihandle *btn_settings = IupButton("设置", NULL);
|
||||
IupSetCallback(btn_settings, "ACTION", (Icallback)btn_settings_cb);
|
||||
IupSetAttribute(btn_settings, "SIZE", "120x30");
|
||||
IupSetAttribute(btn_settings, "FONT", "SimHei, 12");
|
||||
|
||||
Ihandle *btn_exit = IupButton("退出", NULL);
|
||||
IupSetCallback(btn_exit, "ACTION", (Icallback)btn_exit_cb);
|
||||
IupSetAttribute(btn_exit, "SIZE", "120x30");
|
||||
IupSetAttribute(btn_exit, "FONT", "SimHei, 12");
|
||||
|
||||
Ihandle *vbox = IupVbox(
|
||||
lbl_title,
|
||||
btn_pvp,
|
||||
btn_pve,
|
||||
btn_replay,
|
||||
btn_settings,
|
||||
btn_exit,
|
||||
NULL);
|
||||
IupSetAttribute(vbox, "ALIGNMENT", "ACENTER");
|
||||
IupSetAttribute(vbox, "GAP", "15");
|
||||
IupSetAttribute(vbox, "MARGIN", "40x40");
|
||||
|
||||
menu_dlg = IupDialog(vbox);
|
||||
IupSetAttribute(menu_dlg, "TITLE", "五子棋 - 主菜单");
|
||||
IupSetAttribute(menu_dlg, "RESIZE", "NO");
|
||||
IupSetAttribute(menu_dlg, "MINBOX", "NO");
|
||||
IupSetAttribute(menu_dlg, "MAXBOX", "NO");
|
||||
|
||||
// 设置对话框关闭回调 (点X关闭程序)
|
||||
IupSetCallback(menu_dlg, "CLOSE_CB", (Icallback)btn_exit_cb);
|
||||
}
|
||||
|
||||
void show_main_menu()
|
||||
{
|
||||
if (!menu_dlg)
|
||||
create_main_menu();
|
||||
IupShowXY(menu_dlg, IUP_CENTER, IUP_CENTER);
|
||||
}
|
||||
|
||||
void hide_main_menu()
|
||||
{
|
||||
if (menu_dlg)
|
||||
IupHide(menu_dlg);
|
||||
}
|
||||
Reference in New Issue
Block a user