fix: resolve 43 GDScript warnings and fix card display

- Rename shadowed variables (round->_round, seed->_seed, is_processing->_is_processing)
- Prefix unused parameters with underscore throughout
- Add @warning_ignore for false positive integer_division warnings
- Fix unused_signal warnings in event_bus.gd
- Fix CardNode display: move setup() after add_child() so @onready works
- Redesign CardNode with Panel background, suit symbols, red/black colors
- Delete unused _current_hint in TrainingController
This commit is contained in:
xiaji
2026-05-30 22:38:52 +08:00
parent bad46b0109
commit cef2cba7a5
14 changed files with 577 additions and 512 deletions

View File

@@ -4,7 +4,7 @@ extends RefCounted
var ai_name: String = "AI" var ai_name: String = "AI"
func decide(hand: Array, table: Array, current_rank: int, config: RuleConfig) -> HandEvaluator.EvaluatedPlay: func decide(_hand: Array, _table: Array, _current_rank: int, _config: RuleConfig) -> HandEvaluator.EvaluatedPlay:
var pass_play := HandEvaluator.EvaluatedPlay.new() var pass_play := HandEvaluator.EvaluatedPlay.new()
pass_play.type = -1 pass_play.type = -1
pass_play.primary_rank = 0 pass_play.primary_rank = 0

View File

@@ -31,7 +31,7 @@ func _score_all(moves: Array, hand_size: int, current_rank: int) -> Array:
results.append({"move": m, "score": score}) results.append({"move": m, "score": score})
return results return results
func _score_move(play: HandEvaluator.EvaluatedPlay, hand_size: int, current_rank: int) -> float: func _score_move(play: HandEvaluator.EvaluatedPlay, hand_size: int, _current_rank: int) -> float:
var score := 0.0 var score := 0.0
var remaining := hand_size - play.cards.size() var remaining := hand_size - play.cards.size()
score += (27.0 - remaining) / 27.0 * 0.3 score += (27.0 - remaining) / 27.0 * 0.3

View File

@@ -25,9 +25,9 @@ class Team:
var score: int = 0 var score: int = 0
var current_level: int = 2 var current_level: int = 2
static func create_team(team_id: int, p1: int, p2: int) -> Team: static func create_team(p_team_id: int, p1: int, p2: int) -> Team:
var t := Team.new() var t := Team.new()
t.team_id = team_id t.team_id = p_team_id
t.player_indices = [p1, p2] t.player_indices = [p1, p2]
return t return t

View File

@@ -16,9 +16,10 @@ static func _rank_for(original_id: int) -> int:
return 15 return 15
if original_id == 53: if original_id == 53:
return 16 return 16
@warning_ignore("integer_division")
return 2 + (original_id / 4) return 2 + (original_id / 4)
static func create(seed: int = -1) -> Deck: static func create(p_seed: int = -1) -> Deck:
var d := Deck.new() var d := Deck.new()
d._cards = [] d._cards = []
for deck_idx in range(2): for deck_idx in range(2):
@@ -29,15 +30,15 @@ static func create(seed: int = -1) -> Deck:
var c := Card.create(orig_id, suit, rank) var c := Card.create(orig_id, suit, rank)
c.card_id = global_id c.card_id = global_id
d._cards.append(c) d._cards.append(c)
if seed >= 0: if p_seed >= 0:
d._shuffle_with_seed(seed) d._shuffle_with_seed(p_seed)
else: else:
d._shuffle_random() d._shuffle_random()
return d return d
func _shuffle_with_seed(seed: int) -> void: func _shuffle_with_seed(p_seed: int) -> void:
var rng := RandomNumberGenerator.new() var rng := RandomNumberGenerator.new()
rng.seed = seed rng.seed = p_seed
for i in range(_cards.size() - 1, 0, -1): for i in range(_cards.size() - 1, 0, -1):
var j := rng.randi_range(0, i) var j := rng.randi_range(0, i)
var tmp := _cards[i] var tmp := _cards[i]

View File

@@ -14,9 +14,9 @@ var teams: Array = []
var player_hands: Array = [[], [], [], []] var player_hands: Array = [[], [], [], []]
var player_names: Array[String] = ["Player", "AI-1", "AI-2", "AI-3"] var player_names: Array[String] = ["Player", "AI-1", "AI-2", "AI-3"]
var player_human: Array[bool] = [true, false, false, false] var player_human: Array[bool] = [true, false, false, false]
var round: Round var _round: Round
var action_log: Array = [] var action_log: Array = []
var seed: int = 0 var _seed: int = 0
var finished_players: Array[int] = [] var finished_players: Array[int] = []
var current_winner_team: int = -1 var current_winner_team: int = -1
var game_end_reason: String = "" var game_end_reason: String = ""
@@ -25,11 +25,11 @@ static func create(config: RuleConfig, seed_: int = -1) -> GameState:
var gs := GameState.new() var gs := GameState.new()
gs.rule_config = config gs.rule_config = config
if seed_ >= 0: if seed_ >= 0:
gs.seed = seed_ gs._seed = seed_
else: else:
gs.seed = Time.get_unix_time_from_system() as int gs._seed = Time.get_unix_time_from_system() as int
gs.teams = [_Actions.Team.create_team(0, 0, 2), _Actions.Team.create_team(1, 1, 3)] gs.teams = [_Actions.Team.create_team(0, 0, 2), _Actions.Team.create_team(1, 1, 3)]
gs.round = Round.new() gs._round = Round.new()
return gs return gs
func get_team(player_idx: int) -> Actions.Team: func get_team(player_idx: int) -> Actions.Team:
@@ -91,7 +91,7 @@ func to_packed_snapshot(for_player: int) -> Dictionary:
"phase": phase, "phase": phase,
"current_rank": current_rank, "current_rank": current_rank,
"own_hand": _pack_hand(player_hands[for_player]), "own_hand": _pack_hand(player_hands[for_player]),
"table": _pack_table(round.table), "table": _pack_table(_round.table),
"finished": finished_players.duplicate(), "finished": finished_players.duplicate(),
"team_scores": [teams[0].score, teams[1].score] "team_scores": [teams[0].score, teams[1].score]
} }

View File

@@ -74,7 +74,7 @@ static func _eval_three(reals: Array[Card], wilds: Array[Card], has_wild: bool)
return _make_result(_C.TYPE_TRIPLE, reals[0].rank(), false, reals + wilds.slice(0, 2)) return _make_result(_C.TYPE_TRIPLE, reals[0].rank(), false, reals + wilds.slice(0, 2))
return null return null
static func _eval_four(reals: Array[Card], wilds: Array[Card], has_wild: bool, current_rank: int, config: RuleConfig) -> EvaluatedPlay: static func _eval_four(reals: Array[Card], wilds: Array[Card], has_wild: bool, _current_rank: int, _config: RuleConfig) -> EvaluatedPlay:
var all_cards := reals + wilds var all_cards := reals + wilds
if not has_wild and reals.size() == 4: if not has_wild and reals.size() == 4:
if _all_same_rank(reals): if _all_same_rank(reals):
@@ -94,7 +94,7 @@ static func _eval_four(reals: Array[Card], wilds: Array[Card], has_wild: bool, c
return _make_result(_C.TYPE_BOMB, reals[0].rank(), false, all_cards) return _make_result(_C.TYPE_BOMB, reals[0].rank(), false, all_cards)
return null return null
static func _eval_multi(reals: Array[Card], wilds: Array[Card], has_wild: bool, current_rank: int, n: int, config: RuleConfig) -> EvaluatedPlay: static func _eval_multi(reals: Array[Card], wilds: Array[Card], has_wild: bool, _current_rank: int, n: int, config: RuleConfig) -> EvaluatedPlay:
if not has_wild: if not has_wild:
return _eval_pure_multiple(reals, n, config) return _eval_pure_multiple(reals, n, config)
if n == 5: if n == 5:
@@ -103,9 +103,11 @@ static func _eval_multi(reals: Array[Card], wilds: Array[Card], has_wild: bool,
result = _eval_straight(reals, wilds, 5, config) result = _eval_straight(reals, wilds, 5, config)
if result != null: return result if result != null: return result
if n >= 6 and n % 2 == 0: if n >= 6 and n % 2 == 0:
@warning_ignore("integer_division")
var result := _eval_consecutive_pairs(reals, wilds, n / 2, config) var result := _eval_consecutive_pairs(reals, wilds, n / 2, config)
if result != null: return result if result != null: return result
if n >= 6 and n % 3 == 0: if n >= 6 and n % 3 == 0:
@warning_ignore("integer_division")
var result := _eval_steel_plate(reals, wilds, n / 3, config) var result := _eval_steel_plate(reals, wilds, n / 3, config)
if result != null: return result if result != null: return result
if n >= 5: if n >= 5:
@@ -116,6 +118,7 @@ static func _eval_multi(reals: Array[Card], wilds: Array[Card], has_wild: bool,
static func _eval_pure_multiple(reals: Array[Card], n: int, config: RuleConfig) -> EvaluatedPlay: static func _eval_pure_multiple(reals: Array[Card], n: int, config: RuleConfig) -> EvaluatedPlay:
if n >= 5 and _is_straight(reals, config): if n >= 5 and _is_straight(reals, config):
return _make_result(_C.TYPE_STRAIGHT, reals[n-1].rank(), true, reals) return _make_result(_C.TYPE_STRAIGHT, reals[n-1].rank(), true, reals)
@warning_ignore("integer_division")
if n >= 6 and n % 2 == 0 and _is_consecutive_pairs(reals, n / 2): if n >= 6 and n % 2 == 0 and _is_consecutive_pairs(reals, n / 2):
return _make_result(_C.TYPE_CONSECUTIVE_PAIRS, reals[n-1].rank(), true, reals) return _make_result(_C.TYPE_CONSECUTIVE_PAIRS, reals[n-1].rank(), true, reals)
if n == 5 and _is_triple_plus_two(reals): if n == 5 and _is_triple_plus_two(reals):
@@ -156,13 +159,13 @@ static func _eval_straight(reals: Array[Card], wilds: Array[Card], n: int, confi
return _make_result(_C.TYPE_STRAIGHT, max_rank, w == 0, reals + wilds) return _make_result(_C.TYPE_STRAIGHT, max_rank, w == 0, reals + wilds)
return null return null
static func _eval_consecutive_pairs(reals: Array[Card], wilds: Array[Card], pair_count: int, config: RuleConfig) -> EvaluatedPlay: static func _eval_consecutive_pairs(reals: Array[Card], wilds: Array[Card], pair_count: int, _config: RuleConfig) -> EvaluatedPlay:
if reals.size() + wilds.size() != pair_count * 2: return null if reals.size() + wilds.size() != pair_count * 2: return null
if wilds.is_empty() and _is_consecutive_pairs(reals, pair_count): if wilds.is_empty() and _is_consecutive_pairs(reals, pair_count):
return _make_result(_C.TYPE_CONSECUTIVE_PAIRS, reals[reals.size()-1].rank(), true, reals) return _make_result(_C.TYPE_CONSECUTIVE_PAIRS, reals[reals.size()-1].rank(), true, reals)
return null return null
static func _eval_steel_plate(reals: Array[Card], wilds: Array[Card], triple_count: int, config: RuleConfig) -> EvaluatedPlay: static func _eval_steel_plate(reals: Array[Card], wilds: Array[Card], triple_count: int, _config: RuleConfig) -> EvaluatedPlay:
if reals.size() + wilds.size() != triple_count * 3: return null if reals.size() + wilds.size() != triple_count * 3: return null
if wilds.is_empty() and _is_steel_plate(reals): if wilds.is_empty() and _is_steel_plate(reals):
return _make_result(_C.TYPE_STEEL_PLATE, reals[reals.size()-1].rank(), true, reals) return _make_result(_C.TYPE_STEEL_PLATE, reals[reals.size()-1].rank(), true, reals)
@@ -180,7 +183,7 @@ static func _is_straight(cards: Array[Card], config: RuleConfig) -> bool:
if not config.straight_extends_to_ace and cards[cards.size()-1].rank() > 14: return false if not config.straight_extends_to_ace and cards[cards.size()-1].rank() > 14: return false
return true return true
static func _is_consecutive_pairs(cards: Array[Card], pair_count: int) -> bool: static func _is_consecutive_pairs(cards: Array[Card], _pair_count: int) -> bool:
for i in range(0, cards.size(), 2): for i in range(0, cards.size(), 2):
if cards[i].rank() != cards[i+1].rank(): return false if cards[i].rank() != cards[i+1].rank(): return false
for i in range(0, cards.size() - 2, 2): for i in range(0, cards.size() - 2, 2):

View File

@@ -11,7 +11,7 @@ var is_cleared: bool = false
func can_pass() -> bool: func can_pass() -> bool:
return not table.is_empty() return not table.is_empty()
func add_play(play: HandEvaluator.EvaluatedPlay, player_idx: int) -> void: func add_play(play: HandEvaluator.EvaluatedPlay, _player_idx: int) -> void:
table.append(play) table.append(play)
if play.type == -1: if play.type == -1:
pass_count += 1 pass_count += 1

View File

@@ -12,7 +12,7 @@ static func can_play(
play: HandEvaluator.EvaluatedPlay, play: HandEvaluator.EvaluatedPlay,
table_history: Array, table_history: Array,
last_player_idx: int, last_player_idx: int,
current_rank: int, _current_rank: int,
config: RuleConfig config: RuleConfig
) -> Dictionary: ) -> Dictionary:
if play.type == -1: if play.type == -1:

View File

@@ -12,7 +12,7 @@ signal game_ended(winner_team: int, reason: String)
var game_state: GameState var game_state: GameState
var ai_players: Dictionary = {} var ai_players: Dictionary = {}
var is_processing: bool = false var _is_processing: bool = false
func start_game(config: RuleConfig, human_idx: int = 0, seed_: int = -1) -> void: func start_game(config: RuleConfig, human_idx: int = 0, seed_: int = -1) -> void:
game_state = GameState.create(config, seed_) game_state = GameState.create(config, seed_)
@@ -20,37 +20,37 @@ func start_game(config: RuleConfig, human_idx: int = 0, seed_: int = -1) -> void
for i in range(4): for i in range(4):
if not game_state.player_human[i]: if not game_state.player_human[i]:
ai_players[i] = L2RuleAI.new() ai_players[i] = L2RuleAI.new()
var deck := Deck.create(game_state.seed) var deck := Deck.create(game_state._seed)
game_state.deal_cards(deck) game_state.deal_cards(deck)
game_state.phase = GameState.Phase.PLAY game_state.phase = GameState.Phase.PLAY
game_state.round.active_player_idx = 0 game_state._round.active_player_idx = 0
state_changed.emit() state_changed.emit()
func handle_human_play(cards: Array) -> Dictionary: func handle_human_play(cards: Array) -> Dictionary:
if is_processing: if _is_processing:
return {"ok": false, "error_code": 1, "data": null} return {"ok": false, "error_code": 1, "data": null}
var hand := game_state.get_hand(game_state.round.active_player_idx) var hand := game_state.get_hand(game_state._round.active_player_idx)
var play := HandEvaluator.evaluate(cards, game_state.current_rank, game_state.rule_config) var play := HandEvaluator.evaluate(cards, game_state.current_rank, game_state.rule_config)
if play == null or play.type == -1: if play == null or play.type == -1:
return {"ok": false, "error_code": 1, "data": null} return {"ok": false, "error_code": 1, "data": null}
var last_idx := game_state.round.last_non_pass_player() var last_idx := game_state._round.last_non_pass_player()
var result := RuleEngine.can_play(hand, play, game_state.round.table, last_idx, game_state.current_rank, game_state.rule_config) var result := RuleEngine.can_play(hand, play, game_state._round.table, last_idx, game_state.current_rank, game_state.rule_config)
if not result.ok: if not result.ok:
return result return result
_apply_play(game_state.round.active_player_idx, play) _apply_play(game_state._round.active_player_idx, play)
_advance_turn() _advance_turn()
return {"ok": true, "error_code": 0, "data": null} return {"ok": true, "error_code": 0, "data": null}
func handle_human_pass() -> Dictionary: func handle_human_pass() -> Dictionary:
if is_processing: if _is_processing:
return {"ok": false, "error_code": 1, "data": null} return {"ok": false, "error_code": 1, "data": null}
var old_last := game_state.round.last_non_pass_player() var old_last := game_state._round.last_non_pass_player()
if old_last >= 0 and old_last == game_state.round.active_player_idx: if old_last >= 0 and old_last == game_state._round.active_player_idx:
return {"ok": false, "error_code": 3, "data": null} return {"ok": false, "error_code": 3, "data": null}
var pass_play := HandEvaluator.EvaluatedPlay.new() var pass_play := HandEvaluator.EvaluatedPlay.new()
pass_play.type = -1 pass_play.type = -1
pass_play.primary_rank = 0 pass_play.primary_rank = 0
_apply_play(game_state.round.active_player_idx, pass_play) _apply_play(game_state._round.active_player_idx, pass_play)
_advance_turn() _advance_turn()
return {"ok": true, "error_code": 0, "data": null} return {"ok": true, "error_code": 0, "data": null}
@@ -61,10 +61,10 @@ func _apply_play(player_idx: int, play: HandEvaluator.EvaluatedPlay) -> void:
action.player_idx = player_idx action.player_idx = player_idx
action.action_type = "PASS" if play.type == -1 else "PLAY" action.action_type = "PASS" if play.type == -1 else "PLAY"
action.cards = play.cards.duplicate(false) action.cards = play.cards.duplicate(false)
action.seq_id = game_state.round.next_seq() action.seq_id = game_state._round.next_seq()
action.timestamp = Time.get_unix_time_from_system() action.timestamp = Time.get_unix_time_from_system() as int
game_state.action_log.append(action) game_state.action_log.append(action)
game_state.round.add_play(play, player_idx) game_state._round.add_play(play, player_idx)
var hand: Array = game_state.get_hand(player_idx) var hand: Array = game_state.get_hand(player_idx)
if hand.is_empty() and not game_state.is_player_finished(player_idx): if hand.is_empty() and not game_state.is_player_finished(player_idx):
game_state.add_finished_player(player_idx) game_state.add_finished_player(player_idx)
@@ -77,19 +77,19 @@ func _apply_play(player_idx: int, play: HandEvaluator.EvaluatedPlay) -> void:
EventBus.bomb_detonated.emit(player_idx, play.primary_rank) EventBus.bomb_detonated.emit(player_idx, play.primary_rank)
func _advance_turn() -> void: func _advance_turn() -> void:
var hand: Array = game_state.get_hand(game_state.round.active_player_idx) var hand: Array = game_state.get_hand(game_state._round.active_player_idx)
if hand.is_empty(): if hand.is_empty():
var partner := game_state.get_partner(game_state.round.active_player_idx) var partner := game_state.get_partner(game_state._round.active_player_idx)
if not game_state.is_player_finished(partner): if not game_state.is_player_finished(partner):
game_state.round.active_player_idx = partner game_state._round.active_player_idx = partner
game_state.round.reset_for_new_round() game_state._round.reset_for_new_round()
else: else:
_next_alive_player() _next_alive_player()
elif game_state.round.is_cleared: elif game_state._round.is_cleared:
game_state.round.reset_for_new_round() game_state._round.reset_for_new_round()
else: else:
_next_alive_player() _next_alive_player()
var current := game_state.round.active_player_idx var current := game_state._round.active_player_idx
turn_ready.emit(current, game_state.player_human[current]) turn_ready.emit(current, game_state.player_human[current])
EventBus.turn_changed.emit(current) EventBus.turn_changed.emit(current)
if not game_state.player_human[current]: if not game_state.player_human[current]:
@@ -97,8 +97,8 @@ func _advance_turn() -> void:
func _next_alive_player() -> void: func _next_alive_player() -> void:
for _i in range(4): for _i in range(4):
game_state.round.active_player_idx = (game_state.round.active_player_idx + 1) % 4 game_state._round.active_player_idx = (game_state._round.active_player_idx + 1) % 4
if not game_state.is_player_finished(game_state.round.active_player_idx): if not game_state.is_player_finished(game_state._round.active_player_idx):
return return
func _trigger_ai(player_idx: int) -> void: func _trigger_ai(player_idx: int) -> void:
@@ -106,7 +106,7 @@ func _trigger_ai(player_idx: int) -> void:
if ai == null: if ai == null:
return return
var hand8: Array = game_state.get_hand(player_idx) var hand8: Array = game_state.get_hand(player_idx)
var decision: HandEvaluator.EvaluatedPlay = ai.decide(hand8, game_state.round.table, game_state.current_rank, game_state.rule_config) var decision: HandEvaluator.EvaluatedPlay = ai.decide(hand8, game_state._round.table, game_state.current_rank, game_state.rule_config)
if decision.type == -1: if decision.type == -1:
_apply_play(player_idx, decision) _apply_play(player_idx, decision)
else: else:

View File

@@ -2,15 +2,13 @@
class_name TrainingController class_name TrainingController
extends GameController extends GameController
var _current_hint: HandEvaluator.EvaluatedPlay = null
func get_hint() -> HandEvaluator.EvaluatedPlay: func get_hint() -> HandEvaluator.EvaluatedPlay:
var hand := game_state.get_hand(game_state.round.active_player_idx) var hand := game_state.get_hand(game_state._round.active_player_idx)
if hand.is_empty(): if hand.is_empty():
return null return null
var ai := L2RuleAI.new() var ai := L2RuleAI.new()
return ai.decide(hand, game_state.round.table, game_state.current_rank, game_state.rule_config) return ai.decide(hand, game_state._round.table, game_state.current_rank, game_state.rule_config)
func get_all_legal_moves() -> Array: func get_all_legal_moves() -> Array:
var hand := game_state.get_hand(game_state.round.active_player_idx) var hand := game_state.get_hand(game_state._round.active_player_idx)
return MoveGenerator.generate(hand, game_state.current_rank, game_state.rule_config) return MoveGenerator.generate(hand, game_state.current_rank, game_state.rule_config)

View File

@@ -7,8 +7,12 @@ signal card_double_clicked(card_node: CardNode)
var card_data: Card = null var card_data: Card = null
var is_selected: bool = false var is_selected: bool = false
@onready var texture_rect: TextureRect = $TextureRect @onready var panel: Panel = $Panel
@onready var label: Label = $Label @onready var rank_label: Label = $Panel/RankLabel
@onready var suit_label: Label = $Panel/SuitLabel
const SUIT_SYMBOLS := ["\u2660", "\u2665", "\u2663", "\u2666", "SJ", "BJ"]
const RANK_NAMES := ["", "", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A", "SJ", "BJ"]
func setup(card: Card) -> void: func setup(card: Card) -> void:
card_data = card card_data = card
@@ -17,17 +21,43 @@ func setup(card: Card) -> void:
func update_display() -> void: func update_display() -> void:
if card_data == null: if card_data == null:
return return
var suits := ["S", "H", "C", "D", "SJ", "BJ"]
var ranks := ["", "", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A", "SJ", "BJ"]
var suit := card_data.suit() var suit := card_data.suit()
var rank := card_data.rank() var rank := card_data.rank()
if rank < ranks.size() and suit < suits.size() and label: var is_red := suit == 1 or suit == 3
label.text = "%s %s" % [suits[suit], ranks[rank]] var color := Color.RED if is_red else Color.BLACK
modulate = Color.WHITE if not is_selected else Color(1.2, 1.2, 0.8)
if rank_label:
rank_label.text = RANK_NAMES[rank]
rank_label.add_theme_color_override("font_color", color)
rank_label.add_theme_font_size_override("font_size", 14)
if suit_label:
suit_label.text = SUIT_SYMBOLS[suit]
suit_label.add_theme_color_override("font_color", color)
suit_label.add_theme_font_size_override("font_size", 24)
_update_panel()
func _update_panel() -> void:
if panel == null:
return
var sbox := StyleBoxFlat.new()
sbox.bg_color = Color.WHITE if not is_selected else Color(1.0, 1.0, 0.6)
sbox.set_corner_radius_all(6)
sbox.border_width_left = 2
sbox.border_width_right = 2
sbox.border_width_top = 2
sbox.border_width_bottom = 2
sbox.border_color = Color(0.3, 0.3, 0.3)
sbox.content_margin_left = 2
sbox.content_margin_right = 2
sbox.content_margin_top = 2
sbox.content_margin_bottom = 2
panel.add_theme_stylebox_override("panel", sbox)
func set_selected(sel: bool) -> void: func set_selected(sel: bool) -> void:
is_selected = sel is_selected = sel
update_display() _update_panel()
func _on_gui_input(event: InputEvent) -> void: func _on_gui_input(event: InputEvent) -> void:
if event is InputEventMouseButton: if event is InputEventMouseButton:

View File

@@ -1,16 +1,40 @@
[gd_scene load_steps=2 format=3 uid="uid://card_node"] [gd_scene load_steps=2 format=3 uid="uid://card_node"]
[ext_resource type="Script" path="res://src/ui/components/card_node.gd" id="1_script"] [ext_resource type="Script" path="res://src/ui/components/card_node.gd" id="1_script"]
[node name="CardNode" type="Control"] [node name="CardNode" type="Control"]
custom_minimum_size = Vector2(80, 120) custom_minimum_size = Vector2(70, 100)
size = Vector2(80, 120) mouse_filter = 1
size = Vector2(70, 100)
script = ExtResource("1_script") script = ExtResource("1_script")
[node name="TextureRect" type="TextureRect" parent="."]
layout_mode = 0 [node name="Panel" type="Panel" parent="."]
offset_right = 80.0 layout_mode = 1
offset_bottom = 120.0 mouse_filter = 2
[node name="Label" type="Label" parent="."] anchors_preset = 15
layout_mode = 0 anchor_right = 1.0
offset_right = 80.0 anchor_bottom = 1.0
offset_bottom = 120.0
[node name="RankLabel" type="Label" parent="Panel"]
layout_mode = 1
anchors_preset = 2
anchor_top = 1.0
anchor_bottom = 1.0
offset_top = -18.0
offset_right = 12.0
offset_bottom = -2.0
text = "A"
horizontal_alignment = 1
[node name="SuitLabel" type="Label" parent="Panel"]
layout_mode = 1
anchors_preset = 8
anchor_left = 0.5
anchor_right = 0.5
anchor_top = 0.5
anchor_bottom = 0.5
offset_left = -20.0
offset_top = -20.0
offset_right = 20.0
offset_bottom = 20.0
horizontal_alignment = 1 horizontal_alignment = 1
vertical_alignment = 1 vertical_alignment = 1

View File

@@ -13,17 +13,22 @@ const CARD_SCENE := preload("res://src/ui/components/card_node.tscn")
var training_controller: TrainingController = null var training_controller: TrainingController = null
func update_hand(hand: Array) -> void: func update_hand(hand: Array) -> void:
print("[DEBUG] HandArea.update_hand called, cards count: ", hand.size())
for cn in card_nodes: for cn in card_nodes:
cn.queue_free() cn.queue_free()
card_nodes.clear() card_nodes.clear()
selected_cards.clear() selected_cards.clear()
for c in hand: for c in hand:
var node := CARD_SCENE.instantiate() as CardNode var node := CARD_SCENE.instantiate() as CardNode
if node == null:
print("[DEBUG] CardNode instantiate returned null!")
continue
add_child(node)
node.setup(c) node.setup(c)
node.card_clicked.connect(_on_card_clicked) node.card_clicked.connect(_on_card_clicked)
node.card_double_clicked.connect(_on_card_double_clicked) node.card_double_clicked.connect(_on_card_double_clicked)
add_child(node)
card_nodes.append(node) card_nodes.append(node)
print("[DEBUG] CardNodes created: ", card_nodes.size())
func _on_card_clicked(card_node: CardNode) -> void: func _on_card_clicked(card_node: CardNode) -> void:
card_node.set_selected(not card_node.is_selected) card_node.set_selected(not card_node.is_selected)

View File

@@ -65,10 +65,14 @@ func _on_hint_pressed() -> void:
hand_area.selected_cards.append(card) hand_area.selected_cards.append(card)
if status_label: status_label.text = "建议牌型: %s (rank=%d)" % [hint.type, hint.primary_rank] if status_label: status_label.text = "建议牌型: %s (rank=%d)" % [hint.type, hint.primary_rank]
func _on_game_ended(winner_team: int, reason: String) -> void: func _on_game_ended(winner_team: int, _reason: String) -> void:
if status_label: status_label.text = "游戏结束! 队伍 %d 获胜" % winner_team if status_label: status_label.text = "游戏结束! 队伍 %d 获胜" % winner_team
if hand_area: hand_area.disable_input() if hand_area: hand_area.disable_input()
func _refresh_ui() -> void: func _refresh_ui() -> void:
if controller and controller.game_state and hand_area: if controller and controller.game_state and hand_area:
hand_area.update_hand(controller.game_state.get_hand(0)) var hand: Array = controller.game_state.get_hand(0)
print("[DEBUG] _refresh_ui: hand size = ", hand.size())
hand_area.update_hand(hand)
else:
print("[DEBUG] _refresh_ui: controller=", controller, " game_state=", controller.game_state if controller else null, " hand_area=", hand_area)