diff --git a/.gitignore b/.gitignore index e001aa4..d2cfed0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ .godot/ -.vscode/ \ No newline at end of file +.vscode/ +.idea/ \ No newline at end of file diff --git a/README.md b/README.md index 2103c97..bdeeff3 100644 --- a/README.md +++ b/README.md @@ -14,38 +14,44 @@ game/ - project.godot - icon.svg - assets/ - - fonts/ - - AlibabaPuHuiTi-3-65-Medium.ttf # 阿里巴巴普惠体 - - translation/ - - trans.csv + - fonts/ + - AlibabaPuHuiTi-3-65-Medium.ttf # 阿里巴巴普惠体 + - translation/ + - trans.csv - scenes/ - - menus/ - - main_menu.tscn - - settings.tscn - - game/ - - game.tscn - - card.tscn + - menus/ + - main_menu.tscn + - settings.tscn + - game/ + - game.tscn + - card.tscn - scripts/ - - autoload/ - - GameManager.gd # 游戏管理 - - DownloadManager.gd # 下载管理 - - MultiGame.gd # 多人游戏功能 - - SceneManager.gd # 场景管理 - - main_menu/ - - main_menu.gd - - join_game_ui.gd - - create_game_ui.gd - - game/ - - game.gd - - card.gd - - settings/ - - settings.gd + - autoload/ + - GameManager.gd # 游戏管理 + - DownloadManager.gd # 下载管理 + - SceneManager.gd # 场景管理 + - GameLoopManager.gd # 游戏循环管理 + - main_menu/ + - main_menu.gd + - join_game_ui.gd + - create_game_ui.gd + - game/ + - game.gd + - card.gd + - settings/ + - settings.gd ``` ## 如何运行 请先运行数据后端,在游戏设置中输入后端 URL(包含端口号和 `http://` 或 `https://` 前缀),或者选择本地已有的数据源,然后创建游戏或加入游戏开始游玩。 +## 部分游戏逻辑介绍 + +### 游戏循环 + +游戏循环管理器(GameLoopManager.gd)负责游戏游戏循环的管理。 + ## 最佳实践 本项目目前正在使用 Godot 4.6.2 进行开发。开发用语言为 GDScript。 @@ -56,4 +62,4 @@ game/ - 除连接了信号或 HTTPRequest、MultiplayerAPI 的函数外,任何函数都不应该以下划线(`_`)开头。 -- 函数之间只需间隔一行,无需间隔两行。 +- 函数之间既可间隔一行,也可间隔两行。建议函数间隔两行,部分间隔一行的函数为遗留问题。 diff --git a/ai-summon/GameLoopManager.gd b/ai-summon/GameLoopManager.gd new file mode 100644 index 0000000..06d227b --- /dev/null +++ b/ai-summon/GameLoopManager.gd @@ -0,0 +1,317 @@ +extends Node + +var peer: ENetMultiplayerPeer = ENetMultiplayerPeer.new() + +var max_player_num: int +var player_num: int + +# 玩家数据字典 [peer_id: {"name": str, "hand": Array, "score": int, "is_ready": bool}] +var players_data: Dictionary = {} +var current_turn: int = 1 # 当前回合数 +var current_player_id: int = 1 # 当前行动玩家的 peer_id +var game_started: bool = false +var game_phase: String = "waiting" # waiting, playing, ended +var deck: Array = [] # 游戏牌组 + +func create_server(playern: int) -> void: + max_player_num = playern + player_num = 1 + + if peer.create_server(GameManager.port, playern) != OK: + print("Failed to create server on port: ", GameManager.port) + return + + setup_multiplayer() + + # 服务器自己也是玩家 + players_data[1] = { + "name": "Host", + "hand": [], + "score": 0, + "is_ready": false + } + print("Server created on port: ", GameManager.port) + +func create_client(ip: String) -> void: + if peer.create_client(ip, GameManager.port) != OK: + print("Failed to connect to server: ", ip) + return + + setup_multiplayer() + print("Connecting to server: ", ip) + +func setup_multiplayer() -> void: + multiplayer.multiplayer_peer = peer + multiplayer.peer_connected.connect(_on_peer_connected) + multiplayer.peer_disconnected.connect(_on_peer_disconnected) + multiplayer.connected_to_server.connect(_on_connected_to_server) + multiplayer.connection_failed.connect(_on_connection_failed) + +func _on_connected_to_server() -> void: + print("Connected to server successfully!") + +func _on_connection_failed() -> void: + print("Failed to connect to server") + +func _on_peer_connected(id: int) -> void: + print("Peer connected: ", id) + add_player(id) + + # 如果游戏未开始且达到最大玩家数,询问是否开始游戏 + if !game_started and players_data.size() >= max_player_num: + check_all_players_ready() + +func _on_peer_disconnected(id: int): + print("Peer disconnected: ", id) + remove_player(id) + + # 如果当前玩家断开,切换到下一个玩家 + if id == current_player_id and game_started: + next_turn() + +func add_player(id: int) -> void: + # 只有服务器才能添加玩家 + if multiplayer.is_server(): + players_data[id] = { + "name": "Player_" + str(id), + "hand": [], + "score": 0, + "is_ready": false + } + player_num = players_data.size() + + # 广播新玩家加入 + broadcast_player_list() + print("Player added: ", id, " Total players: ", player_num) + +func remove_player(id: int) -> void: + if multiplayer.is_server() and players_data.has(id): + players_data.erase(id) + player_num = players_data.size() + broadcast_player_list() + print("Player removed: ", id) + +# RPC: 设置玩家准备状态 +@rpc("any_peer", "call_remote", "reliable") +func set_player_ready(is_ready: bool) -> void: + var peer_id = multiplayer.get_remote_sender_id() + if players_data.has(peer_id): + players_data[peer_id]["is_ready"] = is_ready + broadcast_player_list() + + if is_ready: + check_all_players_ready() + +# RPC: 设置玩家名称 +@rpc("any_peer", "call_remote", "reliable") +func set_player_name(name: String) -> void: + var peer_id = multiplayer.get_remote_sender_id() + if players_data.has(peer_id): + players_data[peer_id]["name"] = name + broadcast_player_list() + +# RPC: 开始游戏(仅主机调用) +@rpc("call_remote", "reliable") +func start_game() -> void: + if multiplayer.is_server(): + if players_data.size() < 2: + print("Need at least 2 players to start game") + return + + game_started = true + game_phase = "playing" + current_turn = 1 + initialize_deck() + deal_initial_cards() + + # 随机选择第一个玩家 + var player_ids = players_data.keys() + current_player_id = player_ids[randi() % player_ids.size()] + + print("Game started! Current player: ", current_player_id) + broadcast_game_state() + +# 初始化牌组 +func initialize_deck() -> void: + deck = [] + # 这里可以根据 GameManager 中的卡牌列表初始化牌组 + if GameManager.card_list: + for card_id in GameManager.card_list: + # 每张卡牌加入多次(根据游戏需求调整) + for i in range(3): # 每张卡牌3份 + deck.append(card_id) + + # 洗牌 + deck.shuffle() + print("Deck initialized with ", deck.size(), " cards") + +# 发放初始手牌 +func deal_initial_cards() -> void: + var cards_per_player = 5 # 每个玩家初始手牌数 + + for peer_id in players_data: + for i in range(cards_per_player): + if deck.size() > 0: + var card_id = deck.pop_front() + players_data[peer_id]["hand"].append(card_id) + + broadcast_hands() + +# RPC: 抽牌 +@rpc("any_peer", "call_remote", "reliable") +func draw_card() -> void: + var peer_id = multiplayer.get_remote_sender_id() + + # 检查是否是该玩家的回合 + if peer_id != current_player_id: + return + + # 检查牌组是否还有牌 + if deck.size() == 0: + print("Deck is empty!") + return + + var card_id = deck.pop_front() + players_data[peer_id]["hand"].append(card_id) + + print("Player ", peer_id, " drew card: ", card_id) + broadcast_hands() + +# RPC: 打出卡牌 +@rpc("any_peer", "call_remote", "reliable") +func play_card(card_index: int, target_player_id: int = -1) -> void: + var peer_id = multiplayer.get_remote_sender_id() + + # 检查是否是该玩家的回合 + if peer_id != current_player_id: + return + + # 检查卡牌索引是否有效 + if card_index < 0 or card_index >= players_data[peer_id]["hand"].size(): + return + + var card_id = players_data[peer_id]["hand"][card_index] + + # 移除手牌中的卡牌 + players_data[peer_id]["hand"].remove_at(card_index) + + # 执行卡牌效果 + execute_card_effect(card_id, peer_id, target_player_id) + + print("Player ", peer_id, " played card: ", card_id) + broadcast_hands() + broadcast_game_state() + +# 执行卡牌效果 +func execute_card_effect(card_id: int, player_id: int, target_id: int) -> void: + # 这里根据卡牌ID执行具体效果 + # 示例:简单加分效果 + if players_data.has(player_id): + players_data[player_id]["score"] += 10 + + # 可以添加更多复杂的卡牌效果逻辑 + print("Card ", card_id, " effect executed by player ", player_id) + +# RPC: 结束回合 +@rpc("any_peer", "call_remote", "reliable") +func end_turn() -> void: + var peer_id = multiplayer.get_remote_sender_id() + + if peer_id != current_player_id: + return + + next_turn() + +# 切换到下一个玩家 +func next_turn() -> void: + var player_ids = players_data.keys() + var current_index = player_ids.find(current_player_id) + + if current_index != -1: + current_index = (current_index + 1) % player_ids.size() + current_player_id = player_ids[current_index] + current_turn += 1 + + print("Turn ", current_turn, ". Current player: ", current_player_id) + broadcast_game_state() + +# 检查所有玩家是否都准备好了 +func check_all_players_ready() -> void: + var all_ready = true + for player_id in players_data: + if !players_data[player_id]["is_ready"]: + all_ready = false + break + + if all_ready and players_data.size() >= 2: + print("All players ready! Starting game...") + start_game.rpc() + +# 广播玩家列表 +func broadcast_player_list() -> void: + update_players_data.rpc(players_data) + +# RPC: 更新玩家数据 +@rpc("call_remote", "reliable") +func update_players_data(data: Dictionary) -> void: + players_data = data + player_num = players_data.size() + emit_signal("players_updated", players_data) + +# 广播游戏状态 +func broadcast_game_state() -> void: + update_game_state.rpc(game_started, game_phase, current_turn, current_player_id) + +# RPC: 更新游戏状态 +@rpc("call_remote", "reliable") +func update_game_state(started: bool, phase: String, turn: int, current_id: int) -> void: + game_started = started + game_phase = phase + current_turn = turn + current_player_id = current_id + emit_signal("game_state_updated", game_started, game_phase, current_turn, current_player_id) + +# 广播手牌信息(只发给对应玩家) +func broadcast_hands() -> void: + for peer_id in players_data: + send_hand.rpc_id(peer_id, players_data[peer_id]["hand"]) + + # 发送其他玩家的手牌数量 + var hand_sizes = {} + for peer_id in players_data: + hand_sizes[peer_id] = players_data[peer_id]["hand"].size() + broadcast_hand_sizes.rpc(hand_sizes) + +# RPC: 发送手牌 +@rpc("call_remote", "reliable") +func send_hand(hand: Array) -> void: + var peer_id = multiplayer.get_unique_id() + if players_data.has(peer_id): + players_data[peer_id]["hand"] = hand + emit_signal("hand_updated", hand) + +# RPC: 广播手牌数量 +@rpc("call_remote", "reliable") +func broadcast_hand_sizes(sizes: Dictionary) -> void: + emit_signal("hand_sizes_updated", sizes) + +# RPC: 结束游戏 +@rpc("call_remote", "reliable") +func end_game() -> void: + game_started = false + game_phase = "ended" + broadcast_game_state() + + # 计算并显示最终得分 + var scores = {} + for player_id in players_data: + scores[player_id] = players_data[player_id]["score"] + + emit_signal("game_ended", scores) + +# 信号定义(需要在编辑器中连接或在其他脚本中连接) +signal players_updated(players: Dictionary) +signal game_state_updated(started: bool, phase: String, turn: int, current_player: int) +signal hand_updated(hand: Array) +signal hand_sizes_updated(sizes: Dictionary) +signal game_ended(scores: Dictionary) \ No newline at end of file diff --git a/ai-summon/GameLoopManager.gd.uid b/ai-summon/GameLoopManager.gd.uid new file mode 100644 index 0000000..c92d0e7 --- /dev/null +++ b/ai-summon/GameLoopManager.gd.uid @@ -0,0 +1 @@ +uid://dkwc5qney4yee diff --git a/ai-summon/README.md b/ai-summon/README.md new file mode 100644 index 0000000..5a71200 --- /dev/null +++ b/ai-summon/README.md @@ -0,0 +1,5 @@ +# AI 生成代码文件 + +这个目录下的代码都是 AI 生成的,仅作参考。 + +不要将本目录下的代码直接复制到被使用的代码处。 \ No newline at end of file diff --git a/assets/translation/trans.csv b/assets/translation/trans.csv index 9b1905a..c6ce3d5 100644 --- a/assets/translation/trans.csv +++ b/assets/translation/trans.csv @@ -31,4 +31,4 @@ SETTINGS_TIP_LOADED,Tip: Finish Loading,提示:完成加载 SETTINGS_TIP_NOLOCALSOURCE,Tip: No local data or no selection,提示:无本地数据或未选择,无法加载 GAMEUI_URNULL,Room Running: You are XXX XXXX,啊啊啊啊啊:啊啊啊啊 GAMEUI_URHOST,Room Running: You are the Host,房间运行中:您是房主 -GAMEUI_URGUEST,Room Running: You are a Guest,房间运行中:您是房客 \ No newline at end of file +GAMEUI_URGUEST,Room Running: You are a Guest,房间运行中:您是房客 diff --git a/project.godot b/project.godot index 4f3512f..7c02f1f 100644 --- a/project.godot +++ b/project.godot @@ -21,10 +21,10 @@ config/icon="res://icon.svg" [autoload] -MultiGame="*res://scripts/autoload/MultiGame.gd" SceneManager="*res://scripts/autoload/SceneManager.gd" GameManager="*res://scripts/autoload/GameManager.gd" DownloadManager="*res://scripts/autoload/DownloadManager.gd" +GameLoopManager="*uid://qxowgxfp4iwm" [display] diff --git a/scenes/game/game.tscn b/scenes/game/game.tscn index f1966ed..8feaa79 100644 --- a/scenes/game/game.tscn +++ b/scenes/game/game.tscn @@ -7,10 +7,10 @@ script = ExtResource("1_yqjtg") [node name="Background" type="ColorRect" parent="." unique_id=802635055] -offset_left = -34.0 -offset_top = -27.0 -offset_right = 2594.0 -offset_bottom = 1476.0 +offset_left = -29.0 +offset_top = -18.0 +offset_right = 2599.0 +offset_bottom = 1485.0 color = Color(0.7058824, 0.6862745, 0, 1) [node name="IsServerLabel" type="Label" parent="." unique_id=592205212] diff --git a/scenes/menus/settings.tscn b/scenes/menus/settings.tscn index 461323f..ae08286 100644 --- a/scenes/menus/settings.tscn +++ b/scenes/menus/settings.tscn @@ -34,7 +34,7 @@ theme_override_fonts/font = ExtResource("2_6wm04") theme_override_font_sizes/font_size = 24 [node name="IPBeginSetting" type="Node2D" parent="." unique_id=1428256194] -position = Vector2(-1, 94) +position = Vector2(0, 100) metadata/_edit_group_ = true [node name="IPBeginSetLabel" type="Label" parent="IPBeginSetting" unique_id=561890346] @@ -55,7 +55,7 @@ theme_override_fonts/font = ExtResource("2_6wm04") theme_override_font_sizes/font_size = 24 [node name="UsernameSetting" type="Node2D" parent="." unique_id=564366013] -position = Vector2(0, 208) +position = Vector2(0, 200) metadata/_edit_group_ = true [node name="UsernameSetLabel" type="Label" parent="UsernameSetting" unique_id=1569658441] @@ -76,7 +76,7 @@ theme_override_fonts/font = ExtResource("2_6wm04") theme_override_font_sizes/font_size = 24 [node name="LoadSource" type="Node2D" parent="." unique_id=230611076] -position = Vector2(44, 314) +position = Vector2(40, 300) metadata/_edit_group_ = true [node name="LoadSourceLabel" type="Label" parent="LoadSource" unique_id=299353496] @@ -96,7 +96,7 @@ offset_bottom = 60.0 theme_override_font_sizes/font_size = 25 [node name="ChooseLanguage" type="Node2D" parent="." unique_id=323270128] -position = Vector2(39, 405) +position = Vector2(40, 400) metadata/_edit_group_ = true [node name="ChooseLanguageLabel" type="Label" parent="ChooseLanguage" unique_id=1719434618] @@ -130,18 +130,18 @@ theme_override_font_sizes/font_size = 30 text = "SETTINGS_SAVESETTINGS" [node name="DownloadButton" type="Button" parent="." unique_id=315804661] -offset_left = 598.0 -offset_top = 1316.0 -offset_right = 774.0 -offset_bottom = 1405.0 +offset_left = 554.0 +offset_top = 1309.0 +offset_right = 761.0 +offset_bottom = 1398.0 theme_override_fonts/font = ExtResource("2_6wm04") theme_override_font_sizes/font_size = 30 text = "SETTINGS_DOWNLOAD" [node name="CancelButton" type="Button" parent="." unique_id=135993345] -offset_left = 371.0 +offset_left = 347.0 offset_top = 1305.0 -offset_right = 550.0 +offset_right = 581.0 offset_bottom = 1394.0 theme_override_fonts/font = ExtResource("2_6wm04") theme_override_font_sizes/font_size = 30 diff --git a/scripts/autoload/DownloadManager.gd b/scripts/autoload/DownloadManager.gd index 2bc2689..b848630 100644 --- a/scripts/autoload/DownloadManager.gd +++ b/scripts/autoload/DownloadManager.gd @@ -3,32 +3,35 @@ extends Node var uuid: String func create_file(file_path: String) -> void: - var base_dir = file_path.get_base_dir() + var base_dir: String = file_path.get_base_dir() if !DirAccess.dir_exists_absolute(base_dir): DirAccess.make_dir_recursive_absolute(base_dir) - var file = FileAccess.open(file_path, FileAccess.WRITE) + var file: FileAccess = FileAccess.open(file_path, FileAccess.WRITE) file.close() + func download_file(server_path: String, local_path: String) -> void: - var http = HTTPRequest.new() + var http: HTTPRequest = HTTPRequest.new() add_child(http) - var file_path = local_path + var file_path: String = local_path if !FileAccess.file_exists(file_path): create_file(file_path) http.download_file = file_path http.request(server_path) await http.request_completed + func get_uuid() -> void: - var index_file = FileAccess.open("user://download/sources/temp/index.json", FileAccess.READ) - var index_text = index_file.get_as_text() + var index_file: FileAccess = FileAccess.open("user://download/sources/temp/index.json", FileAccess.READ) + var index_text: String = index_file.get_as_text() var content = JSON.parse_string(index_text) index_file.close() uuid = content["uuid"] + func download_defs(type: String, origin: String) -> void: - var list_file = FileAccess.open("user://download/sources/%s/%ss/list.json" % [uuid, type], FileAccess.READ) - var list_text = list_file.get_as_text() + var list_file: FileAccess = FileAccess.open("user://download/sources/%s/%ss/list.json" % [uuid, type], FileAccess.READ) + var list_text: String = list_file.get_as_text() var list = JSON.parse_string(list_text) list_file.close() if !list: @@ -37,9 +40,10 @@ func download_defs(type: String, origin: String) -> void: var filename = list[k] await download_file("%s%s/id/%s" % [origin, type, k], "user://download/sources/%s/%ss/%s.json" % [uuid, type, filename]) + func download_assets(origin: String) -> void: - var list_file = FileAccess.open("user://download/sources/%s/assets/list.json" % [uuid], FileAccess.READ) - var list_text = list_file.get_as_text() + var list_file: FileAccess = FileAccess.open("user://download/sources/%s/assets/list.json" % [uuid], FileAccess.READ) + var list_text: String = list_file.get_as_text() var list = JSON.parse_string(list_text) list_file.close() if !list: @@ -51,9 +55,10 @@ func download_assets(origin: String) -> void: var filename = list["sounds"][k] await download_file("%sasset/sound/%s" % [origin, k], "user://download/sources/%s/assets/sounds/%s" % [uuid, filename]) + func download_from_origin() -> int: - var origin = GameManager.data_origin - var http = HTTPRequest.new() + var origin: String = GameManager.data_origin + var http: HTTPRequest = HTTPRequest.new() add_child(http) if origin.substr(0, 4) != "http": @@ -88,35 +93,37 @@ func download_from_origin() -> int: return 0 + func load_resource(): - var card_file = FileAccess.open("user://download/sources/%s/cards/list.json" % [uuid], FileAccess.READ) + var card_file: FileAccess = FileAccess.open("user://download/sources/%s/cards/list.json" % [uuid], FileAccess.READ) GameManager.card_list = JSON.parse_string(card_file.get_as_text()) card_file.close() - var reaction_file = FileAccess.open("user://download/sources/%s/reactions/list.json" % [uuid], FileAccess.READ) + var reaction_file: FileAccess = FileAccess.open("user://download/sources/%s/reactions/list.json" % [uuid], FileAccess.READ) GameManager.reaction_list = JSON.parse_string(reaction_file.get_as_text()) reaction_file.close() - var matter_file = FileAccess.open("user://download/sources/%s/matters/list.json" % [uuid], FileAccess.READ) + var matter_file: FileAccess = FileAccess.open("user://download/sources/%s/matters/list.json" % [uuid], FileAccess.READ) GameManager.matter_list = JSON.parse_string(matter_file.get_as_text()) matter_file.close() - var asset_file = FileAccess.open("user://download/sources/%s/assets/list.json" % [uuid], FileAccess.READ) - var asset_list = JSON.parse_string(asset_file.get_as_text()) + var asset_file: FileAccess = FileAccess.open("user://download/sources/%s/assets/list.json" % [uuid], FileAccess.READ) + var asset_list: Dictionary = JSON.parse_string(asset_file.get_as_text()) GameManager.pic_list = asset_list["pics"] GameManager.sound_list = asset_list["sounds"] asset_file.close() + func get_sources(): if !DirAccess.dir_exists_absolute("user://download/sources/"): DirAccess.make_dir_recursive_absolute("user://download/sources/") - var dir = DirAccess.open("user://download/sources/") + var dir: DirAccess = DirAccess.open("user://download/sources/") var subdirs: PackedStringArray = dir.get_directories() for subdir in subdirs: - if subdir == "temp": + if subdir as String == "temp": continue - var file = FileAccess.open("user://download/sources/%s/index.json" % [subdir], FileAccess.READ) - var text = file.get_as_text() + var file: FileAccess = FileAccess.open("user://download/sources/%s/index.json" % [subdir], FileAccess.READ) + var text: String = file.get_as_text() var content = JSON.parse_string(text) file.close() var source_name = content["name"] diff --git a/scripts/autoload/GameLoopManager.gd b/scripts/autoload/GameLoopManager.gd new file mode 100644 index 0000000..efc6d2b --- /dev/null +++ b/scripts/autoload/GameLoopManager.gd @@ -0,0 +1,45 @@ +extends Node + +var peer: ENetMultiplayerPeer = ENetMultiplayerPeer.new() + +var max_player_num: int +var player_num: int + +func create_server(playern: int) -> void: + max_player_num = playern + player_num = 1 + if peer.create_server(GameManager.port, playern) != OK: + return + setup_multiplayer() + + +func create_client(ip: String) -> void: + if peer.create_client(ip, GameManager.port) != OK: + return + setup_multiplayer() + + +func setup_multiplayer() -> void: + multiplayer.multiplayer_peer = peer + multiplayer.peer_connected.connect(_on_peer_connected) + multiplayer.peer_disconnected.connect(_on_peer_disconnected) + + +func _on_peer_connected(id: int) -> void: + add_player(id) + + +func _on_peer_disconnected(id: int): + remove_player(id) + + +func add_player(id: int) -> void: + pass + + +func remove_player(id: int) -> void: + pass + + +func start_game() -> void: + pass diff --git a/scripts/autoload/GameLoopManager.gd.uid b/scripts/autoload/GameLoopManager.gd.uid new file mode 100644 index 0000000..5d90182 --- /dev/null +++ b/scripts/autoload/GameLoopManager.gd.uid @@ -0,0 +1 @@ +uid://qxowgxfp4iwm diff --git a/scripts/autoload/GameManager.gd b/scripts/autoload/GameManager.gd index 2bb2e44..05db204 100644 --- a/scripts/autoload/GameManager.gd +++ b/scripts/autoload/GameManager.gd @@ -2,6 +2,7 @@ extends Node var data_origin: String = "" var ip_begin: String = "192.168." +var port: int var username: String = "Player1" var source: int = -1 diff --git a/scripts/autoload/MultiGame.gd b/scripts/autoload/MultiGame.gd deleted file mode 100644 index a95ea23..0000000 --- a/scripts/autoload/MultiGame.gd +++ /dev/null @@ -1,128 +0,0 @@ -extends Node - -var peer = ENetMultiplayerPeer.new() - -var players: Array -var cards: Array -var my_card: Array -var max_players: int -var player_cards: Dictionary -var player_turns: Dictionary -var player_username: Dictionary -var player_hp: Dictionary - -var server_round: int -var client_round: int - -func add_player(id: int): - if players.size() < max_players: - players.append(id) - player_cards[id] = [] - -func remove_player(id: int): - for i in range(players.size()): - if players[i] == id: - players.pop_at(i) - player_cards.erase(id) - break - -func create_server(playern: int) -> void: - max_players = playern - var error = peer.create_server(8989, playern) - if error != OK: - printerr(error) - return - multiplayer.multiplayer_peer = peer - multiplayer.peer_connected.connect(_on_peer_connected) - multiplayer.peer_disconnected.connect(_on_peer_disconnected) - -func create_client(ip: String) -> void: - peer.create_client(ip, 8989) - multiplayer.multiplayer_peer = peer - -func _on_peer_connected(id: int) -> void: - add_player(id) - -func _on_peer_disconnected(id: int) -> void: - remove_player(id) - -func start_game() -> void: - if players.size() != max_players: - return - deal_cards() - server_round = 1 - remote_variable() - -func extract() -> String: - if cards.size() == 0: - return "" - var index = randi() % cards.size() - var card = cards[index] - cards.pop_at(index) - return card - -func deal_cards() -> void: - for player in players: - while player_cards[player].size() < 8: - var card = extract() - if card != "": - player_cards[player].append(card) - -func next_round() -> void: - settle_round() - server_round += 1 - -func settle_round() -> void: - for player in players: - request_card_draw(player) - remote_variable() - -func request_card_draw(player_id: int) -> void: - if server_round == 1 and 0 <= player_turns[player_id] <= 1: - for i in range(3): - if player_cards[player_id].size() >= 8: - break - var card = extract() - if card != "": - player_cards[player_id].append(card) - else: - for i in range(4): - if player_cards[player_id].size() >= 8: - break - var card = extract() - if card != "": - player_cards[player_id].append(card) - remote_variable() - -func get_my_cards() -> void: - request_cards.rpc() - -@rpc("any_peer", "call_remote", "reliable") -func request_cards() -> void: - var sender_id = multiplayer.get_remote_sender_id() - var data: Array = player_cards.get(sender_id, [-1]) - send_cards.rpc_id(sender_id, data) - -@rpc("authority", "call_remote", "reliable") -func send_cards(data: Array) -> void: - my_card = data - -func remote_variable() -> void: - if not multiplayer.is_server(): - return - var data: Dictionary = {} - data["cards"] = cards - data["player_cards"] = player_cards - data["player_turns"] = player_turns - data["player_hp"] = player_hp - data["server_round"] = server_round - - get_remote_variable.rpc(data) - -@rpc("authority", "call_remote", "reliable") -func get_remote_variable(data: Dictionary) -> void: - cards = data["cards"] - player_cards = data["player_cards"] - player_turns = data["player_turns"] - player_hp = data["player_hp"] - server_round = data["server_round"] diff --git a/scripts/autoload/MultiGame.gd.uid b/scripts/autoload/MultiGame.gd.uid deleted file mode 100644 index 2a42f7c..0000000 --- a/scripts/autoload/MultiGame.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://dwbuaieufg51g diff --git a/scripts/autoload/SceneManager.gd b/scripts/autoload/SceneManager.gd index c9cbd52..6c03cab 100644 --- a/scripts/autoload/SceneManager.gd +++ b/scripts/autoload/SceneManager.gd @@ -2,13 +2,14 @@ extends Node var current_scene = null -var Card = ResourceLoader.load("res://prefabs/game/card.tscn") +var Card: Resource = ResourceLoader.load("res://scenes/game/card.tscn") func _ready(): - var root = get_tree().root - current_scene = root.get_child(root.get_child_count() - 1) + var root: Window = get_tree().root + current_scene = root.get_child(root.get_child_count() - 1) + func goto_scene(path: String): - get_tree().change_scene_to_file("res://scenes/%s.tscn" % [path]) - var root = get_tree().root - current_scene = root.get_child(root.get_child_count() - 1) \ No newline at end of file + get_tree().change_scene_to_file("res://scenes/%s.tscn" % [path]) + var root: Window = get_tree().root + current_scene = root.get_child(root.get_child_count() - 1) \ No newline at end of file diff --git a/scripts/game/card.gd b/scripts/game/card.gd index 5f20fb4..88fcd4a 100644 --- a/scripts/game/card.gd +++ b/scripts/game/card.gd @@ -4,17 +4,21 @@ var description: String var type: String var card_name: String + func set_texture(pic: String) -> void: - var image = Image.new() + var image: Image = Image.new() image.load(pic) $Sprite.texture = ImageTexture.create_from_image(image) + func set_card(cname: String) -> void: card_name = cname set_texture("user://download/sources/%s/assets/pics/%s" % [DownloadManager.uuid, GameManager.pic_list[card_name]]) + func set_pos(x: int, y: int) -> void: $Sprite.position = Vector2(x, y) + func get_pos() -> Vector2: return $Sprite.position diff --git a/scripts/game/game.gd b/scripts/game/game.gd index c240936..f9d2e94 100644 --- a/scripts/game/game.gd +++ b/scripts/game/game.gd @@ -1,22 +1,22 @@ extends Node2D -var CardScene = preload("res://scenes/game/card.tscn") - var card_list: Array func _ready() -> void: init() + GameLoopManager.start_game() var card = create_card("Oxygen") card.show() card.set_pos(300, 300) print(card.get_pos()) + func init() -> void: + # 设置 UI 展示文本 if multiplayer.is_server(): $IsServerLabel.text = "GAMEUI_URHOST" else: $IsServerLabel.text = "GAMEUI_URGUEST" - var addresses: PackedStringArray = IP.get_local_addresses() var ipaddress: String = "" for address in addresses: @@ -26,8 +26,9 @@ func init() -> void: $IPLabel.text = ipaddress $Player1/Username.text = GameManager.username + func create_card(card_name: String): - var card = CardScene.instantiate() + var card = SceneManager.Card.instantiate() add_child(card) card.set_card(card_name) card_list.append(card) diff --git a/scripts/main_menu/create_game_ui.gd b/scripts/main_menu/create_game_ui.gd index e56477b..aeec451 100644 --- a/scripts/main_menu/create_game_ui.gd +++ b/scripts/main_menu/create_game_ui.gd @@ -1,9 +1,9 @@ extends Node2D func _on_create_game_button_pressed() -> void: - var player_num = int($CreateGameEdit.text) + var player_num: int = int($CreateGameEdit.text) if 2 <= player_num and player_num <= 4: - MultiGame.create_server(int(player_num)) + GameLoopManager.create_server(int(player_num)) $".".hide() SceneManager.goto_scene("game/game") else: diff --git a/scripts/main_menu/join_game_ui.gd b/scripts/main_menu/join_game_ui.gd index 7b78a49..efdc016 100644 --- a/scripts/main_menu/join_game_ui.gd +++ b/scripts/main_menu/join_game_ui.gd @@ -3,6 +3,6 @@ extends Node2D func _on_join_game_button_pressed() -> void: var ip: String = $JoinGameEdit.text - MultiGame.create_client(ip) + GameLoopManager.create_client(ip) $".".hide() SceneManager.goto_scene("game/game") diff --git a/scripts/main_menu/main_menu.gd b/scripts/main_menu/main_menu.gd index 8978e02..1ba7bf1 100644 --- a/scripts/main_menu/main_menu.gd +++ b/scripts/main_menu/main_menu.gd @@ -4,11 +4,14 @@ extends Node2D func _on_join_game_pressed() -> void: $JoinGameUI.show() + func _on_start_game_pressed() -> void: $CreateGameUI.show() + func _on_setting_button_pressed() -> void: SceneManager.goto_scene("menus/settings") + func _on_quit_game_pressed() -> void: get_tree().quit() diff --git a/scripts/settings/settings.gd b/scripts/settings/settings.gd index b1c7b0e..9f92fe9 100644 --- a/scripts/settings/settings.gd +++ b/scripts/settings/settings.gd @@ -1,20 +1,24 @@ extends Node2D + func _ready() -> void: init_sources() init_text() + func init_text() -> void: $DataSetting/LineEdit.text = GameManager.data_origin $IPBeginSetting/LineEdit.text = GameManager.ip_begin $UsernameSetting/LineEdit.text = GameManager.username $LoadSource/ChooseSource.select(GameManager.source) + func init_sources() -> void: DownloadManager.get_sources() for source_name in GameManager.sources: $LoadSource/ChooseSource.add_item(source_name) + func _on_save_button_pressed() -> void: GameManager.data_origin = $DataSetting/LineEdit.text GameManager.ip_begin = $IPBeginSetting/LineEdit.text @@ -42,7 +46,6 @@ func _on_download_button_pressed() -> void: $Tips.text = "SETTINGS_TIP_LOADED" - func _on_load_button_pressed() -> void: if GameManager.sources.size() == 0 or GameManager.source == -1: $Tips.text = "SETTINGS_TIP_NOLOCALSOURCE"