提问人:donbonbon 提问时间:10/30/2023 更新时间:10/30/2023 访问量:34
Unity 中的 TurnManager 逻辑同时执行 if 和 else 条件
TurnManager logic in Unity executes both if and else conditions
问:
在我的 unity 项目中,当玩家做出正确的“猜测”时,turnManager 会执行一个错误的循环。我很难找出问题所在,并希望得到任何回报。 据我所知,这似乎是一个游戏逻辑问题。
在游戏逻辑方面,回合管理器被设计为检查一个条件(如果给定的玩家有一张给定的牌)。事实上,在执行循环的 if 部分(正确/true 条件)后,它也会自动执行 else 部分(条件为 false)。这结束了玩家的回合......与其向 currentPlayer(回合玩家)提供另一个尝试“猜牌”。
我怀疑这是转机代码的问题,而不是 Unity 的设置等。我的假设是基于我可以反驳其他问题,即以下问题:
多次点击 - 这是因为当“猜测”错误时,触发猜测/条件验证的点击按预期工作,当“猜测”错误时按预期执行。
其他脚本对 false 方法的调用:由错误/错误的“猜测”验证调用的方法仅由 turnmanager 调用或出现在 turnmanager 中。没有其他类或脚本调用这些方法(DrawCardFromDeck 和 EndTurn)。
错误的方法调用:换句话说,如果调用猜测验证的方法为 ( OnEventGuessClick ),则问题相同,是基于触发事件 m 或直接依赖调用。
在 debug.logs 之后,似乎 Else 代码片段是在 PlayerController 更新后执行的,它应该是,即表示当前玩家的手牌、四重奏和要猜测的牌。可能是 UI 更新中的某些元素触发了另一个 OnEventGuessClick。然而,这只是一个猜测,因为我无法证实它。
我想,主要问题是代码似乎是正确的,而事实并非如此。即我找不到我应该解决的问题。
任何帮助将不胜感激。
以下是脚本。我只排除了我绝对可以排除的部分,这使得它有点长。下面附上一些脚本的注释:
一个。除了上述问题外,该项目在播放模式下按预期运行。
b.TurnManager 是通过 GameFlowManager.StartTurnManager 调用的,而不是在游戏开始时调用的。
c. 为了分离游戏逻辑和 UI 逻辑,player.cs 是唯一将数据传递给 PlayerController 的项目。
using System.Collections.Generic;
using UnityEngine;
using System.Linq;
public class Player : MonoBehaviour
{
// Existing attributes
public int ID;
public string playerName; // Renamed 'name' to 'playerName' to avoid conflict
public int score;
public int result = 0;
public bool isWinner;
private bool _hasTurn;
public bool hasTurn
{
get { return _hasTurn; }
set
{
_hasTurn = value; // Simply set the value
Debug.Log($"{playerName}: from player script hasTurn is set to {hasTurn}");
// Notify listeners about attribute changes
OnPlayerAttributesChanged?.Invoke(this);
}
}
// Properties for the player's cards, hand, quartets, and score text
public List<Card> HandCards { get; set; }
public List<Card> CardsPlayerCanAsk { get; private set; }
public Transform PlayerHand { get; set; }
public Transform PlayerQuartets { get; set; }
public TMPro.TextMeshProUGUI ScoreText { get; set; }
public TMPro.TextMeshProUGUI ResultText { get; set; }
// Property to display other players' names excluding the current player
public List<Player> PlayerToAsk { get; private set; } = new List<Player>();
private List<Card> _previousCards; // Store the previous state of Cards
private CardManager cardManager;
// Event to notify listeners when player attributes change
public event System.Action<Player> OnPlayerAttributesChanged;
private void Awake()
{
GameObject managersGameObject = GameObject.Find("Managers");
if (managersGameObject != null)
{
// Get the CardManager component from the Managers GameObject
cardManager = managersGameObject.GetComponent<CardManager>();
if (cardManager == null)
{
Debug.LogError("CardManager component not found on the Managers GameObject.");
}
}
else
{
Debug.LogError("Managers GameObject not found in the scene.");
}
HandCards = new List<Card>();
CardsPlayerCanAsk = new List<Card>();
}
// Constructor to initialize the player with the initial turn status
public Player(bool initialTurn)
{
_hasTurn = initialTurn;
OnPlayerAttributesChanged?.Invoke(this);
}
public void SetPlayerToAsk(List<Player> playersToAsk)
{
PlayerToAsk = playersToAsk;
}
// Player.cs
public void AddCardToHand(Card card)
{
HandCards.Add(card);
// Set the card's parent to the player's hand
card.gameObject.transform.SetParent(PlayerHand);
Debug.Log($"Card added to Hand. Total cards in HandCards: {HandCards.Count}");
CheckForQuartets();
UpdateCardsPlayerCanAsk();
// Notify listeners about attribute changes
OnPlayerAttributesChanged?.Invoke(this);
}
public void RemoveCardFromHand(Card card)
{
HandCards.Remove(card);
Debug.Log($"Card added to Hand. Total cards in HandCards: {HandCards.Count}");
CheckForQuartets();
UpdateCardsPlayerCanAsk();
// Notify listeners about attribute changes
OnPlayerAttributesChanged?.Invoke(this);
}
public void UpdateCardsPlayerCanAsk()
{
CardsPlayerCanAsk.Clear();
foreach (Card card in cardManager.AllCards)
{
if (HandCards.Any(playerCard => playerCard.rank == card.rank) && !HandCards.Contains(card))
{
CardsPlayerCanAsk.Add(card);
}
}
OnPlayerAttributesChanged?.Invoke(this);
}
public void CheckForQuartets()
{
var groupedCards = HandCards.GroupBy(card => card.rank);
foreach (var group in groupedCards)
{
if (group.Count() >= 4)
{
MoveCardsToQuartetsArea(group.ToList());
}
}
}
public void MoveCardsToQuartetsArea(List<Card> quartetCards)
{
//...
}
// Check if the player's hand is empty
public bool IsHandEmpty()
{
return HandCards.Count == 0;
}
}
using UnityEngine;
using TMPro;
using UnityEngine.UI;
using System.Linq;
using System.Collections.Generic;
public class PlayerController : MonoBehaviour
{
public TMP_Text playerNameText;
public TMP_Text playerScoreText;
public TMP_Text playerTurnText;
public Transform PlayerHand;
public Transform PlayerQuartetsArea;
public TMP_Dropdown cardsDropdown; // Dropdown for cards player can ask
public TMP_Dropdown playersDropdown; // Dropdown for active players
public Button guessButton; // Button for guess request
public delegate void GuessButtonClickHandler(Card selectedCard, Player selectedPlayer);
public static event GuessButtonClickHandler OnGuessButtonClick;
private List<Card> CardsPlayerCanAsk;
private List<Player> PlayerToAsk;
private List<Card> InitialCards; // Placeholder for cards dropdow
private List<int> playerIDs = new List<int>();
private List<int> cardIDs = new List<int>();
private CardManager cardManager;
public Player AssociatedPlayer { get; set; } // Add this field
public void SetPlayerData(Player player)
{
AssociatedPlayer = player;
player.OnPlayerAttributesChanged += OnPlayerAttributesChanged;
CardsPlayerCanAsk = player.CardsPlayerCanAsk;
PlayerToAsk = player.PlayerToAsk;
playerNameText.text = player.playerName; // Use playerName instead of name
playerScoreText.text = "Score: " + player.score;
playerTurnText.text = player.hasTurn ? "Turn: Yes" : "Turn: No";
// Populate the playersDropdown with active players (excluding the current player)
UpdatePlayersDropdown(AssociatedPlayer.PlayerToAsk); // Pass the list of player names
// Update the cardsDropdown with cards that the player can ask
UpdateCardsDropdown(AssociatedPlayer.CardsPlayerCanAsk);
// Deactivate the turn UI objects for players without turn
if (!player.hasTurn)
{
cardsDropdown.gameObject.SetActive(false);
playersDropdown.gameObject.SetActive(false);
guessButton.gameObject.SetActive(false);
}
else
{
cardsDropdown.gameObject.SetActive(true);
playersDropdown.gameObject.SetActive(true);
guessButton.gameObject.SetActive(true);
}
}
private void OnPlayerAttributesChanged(Player player)
{
// Update the score text when the attributes change
playerNameText.text = player.playerName;
playerScoreText.text = "Score: " + player.score;
playerTurnText.text = player.hasTurn ? "Turn: Yes" : "Turn: No";
Debug.Log("OnPlayerAttributesChanged is called");
foreach (Card card in player.HandCards)
{
card.gameObject.transform.SetParent(PlayerHand);
}
UpdatePlayersDropdown(player.PlayerToAsk);
UpdateCardsDropdown(player.CardsPlayerCanAsk);
// Update the UI activation
ActivatePlayerTurnUI(player.hasTurn);
if (player.hasTurn)
{
// Activate the turn UI objects for the player with the current turn
cardsDropdown.gameObject.SetActive(true);
playersDropdown.gameObject.SetActive(true);
guessButton.gameObject.SetActive(true);
}
else
{
// Deactivate the turn UI objects for the player whose turn has ended
cardsDropdown.gameObject.SetActive(false);
playersDropdown.gameObject.SetActive(false);
guessButton.gameObject.SetActive(false);
}
}
public void UpdatePlayersDropdown(List<Player> updatedPlayersToAsk)
{
Debug.Log("UpdatePlayersDropdown is called");
if (updatedPlayersToAsk != null && updatedPlayersToAsk.Count > 0)
{
// Clear the current dropdown options and lists
playersDropdown.ClearOptions();
playerIDs.Clear();
// Add the player names to the dropdown and store their IDs
List<string> playerNames = updatedPlayersToAsk.Select(player =>
{
playerIDs.Add(player.ID);
return player.playerName;
}).ToList();
playersDropdown.AddOptions(playerNames);
}
else
{
Debug.LogWarning("Updated players list is null or empty.");
}
}
public void UpdateCardsDropdown(List<Card> cards)
{
if (cardsDropdown != null)
{
cardsDropdown.ClearOptions();
cardIDs.Clear();
if (cards != null)
{
List<string> cardNames = new List<string>();
foreach (Card card in cards)
{
cardIDs.Add(card.ID);
cardNames.Add(formattedCardEntry);
}
cardsDropdown.AddOptions(cardNames);
}
else
{
Debug.LogWarning("UpdateCardsDropdown - cards is null");
}
}
}
public void HandleGuessButtonClick()
{
// Disable the button to prevent multiple clicks
guessButton.interactable = false;
Debug.Log("HandleGuessButtonClick called");
// Get the selected index from the dropdowns
int selectedPlayerIndex = playersDropdown.value;
int selectedCardIndex = cardsDropdown.value;
// Use the selected index to access the corresponding IDs
int selectedPlayerID = playerIDs[selectedPlayerIndex];
int selectedCardID = cardIDs[selectedCardIndex];
// Find the corresponding Card and Player objects based on IDs
Card selectedCard = CardsPlayerCanAsk.Find(card => card.ID == selectedCardID);
Player selectedPlayer = PlayerToAsk.Find(player => player.ID == selectedPlayerID);
Debug.Log($"Selected Card ID: {selectedCardID}, Selected Player ID: {selectedPlayerID}");
Debug.Log($"Selected Card: {selectedCard.cardName}");
Debug.Log($"Selected Player: {selectedPlayer.playerName}");
// Directly call the HandlePlayerTurn method in TurnManager
TurnManager turnManager = GameObject.Find("Managers").GetComponent<TurnManager>();
if (turnManager != null)
{
turnManager.OnGuessButtonClick(selectedCard, selectedPlayer);
}
else
{
Debug.LogError("TurnManager not found.");
}
// Re-enable the button after the method is called
guessButton.interactable = true;
Debug.Log("HandleGuessButtonClick finished");
}
public void ActivatePlayerTurnUI(bool isActive)
{
cardsDropdown.gameObject.SetActive(isActive);
playersDropdown.gameObject.SetActive(isActive);
guessButton.gameObject.SetActive(isActive);
}
}
using System.Collections.Generic;
using UnityEngine;
public class TurnManager : MonoBehaviour
{
public PlayerManager playerManager;
public CardManager cardManager;
private List<Card> deckCards;
private bool isInitialized = false;
private Card selectedCard;
private Player selectedPlayer;
private Player currentPlayer;
private bool isPlayerUIEnabled = true;
private bool isDrawingCard = false;
private bool hasHandledCurrentPlayer = false;
private void Awake()
{
PlayerController.OnGuessButtonClick += OnGuessButtonClick;
}
private void OnDestroy()
{
PlayerController.OnGuessButtonClick -= OnGuessButtonClick;
}
private void Start()
{
StartTurnManager();
}
public void StartTurnManager()
{
if (!isInitialized)
{
if (cardManager != null)
{
deckCards = cardManager.GetDeckCards();
Debug.Log($"Total number of cards in turn manager deckCards are: {deckCards.Count}");
isInitialized = true;
}
else
{
Debug.LogError($"{Time.time}: CardManager reference is not assigned.");
}
currentPlayer = playerManager.Players.Find(player => player.hasTurn);
if (currentPlayer != null)
{
StartCoroutine(TurnLoop());
}
else
{
Debug.LogError("No initial player with hasTurn == true found.");
}
}
}
public void OnGuessButtonClick(Card selectedCard, Player selectedPlayer)
{
Debug.Log($"OnGuessButtonClick - Selected Card: {selectedCard}, Selected Player: {selectedPlayer}");
this.selectedCard = selectedCard;
this.selectedPlayer = selectedPlayer;
if (currentPlayer != null && !isDrawingCard)
{
HandlePlayerTurn(currentPlayer); // Moved to HandlePlayerTurn
}
else
{
Debug.LogWarning($"{Time.time}: Invalid player turn.");
}
}
private System.Collections.IEnumerator TurnLoop()
{
while (true)
{
if (currentPlayer.hasTurn)
{
if (!hasHandledCurrentPlayer)
{
HandlePlayerTurn(currentPlayer);
hasHandledCurrentPlayer = true;
}
}
if (!currentPlayer.hasTurn)
{
hasHandledCurrentPlayer = false;
NextCurrentPlayer();
}
yield return null;
}
}
private void HandlePlayerTurn(Player currentPlayer)
{
if (selectedCard == null && selectedPlayer == null)
{
MakeGuess();
}
else
{
AskForCard(selectedCard, selectedPlayer);
}
}
private void MakeGuess()
{
//this method will Enable, disable the turn UI, currently not developed.
Debug.Log("MakeGuess method is called");
}
private void AskForCard(Card selectedCard, Player selectedPlayer)
{
if (selectedPlayer != null && selectedCard != null)
{
if (selectedPlayer.HandCards.Contains(selectedCard))
{
Debug.Log("AskForCar guess is correct");
TransferCard(selectedCard, currentPlayer);
CheckForQuartets();
// If the guess is correct and the player's hand isn't empty, allow another guess.
if (!IsPlayerHandEmpty(currentPlayer))
{
// Allow the player to make another guess without drawing a card or ending the turn.
HandlePlayerTurn(currentPlayer);
}
else if (deckCards.Count > 0)
{
// If the player's hand is empty but the deck isn't, draw a card from the deck.
DrawCardFromDeck();
// After drawing a card, re-evaluate the hand.
if (!IsPlayerHandEmpty(currentPlayer))
{
// Allow the player to make another guess.
// Remove the EndTurn() call from here.
HandlePlayerTurn(currentPlayer);
}
}
// No need to check for the deck being empty here, as we've already handled that case.
}
else
{
// If the guess is wrong, draw a card from the deck and end the turn.
DisplayMessage($"{selectedPlayer.playerName} does not have {selectedCard.cardName}.");
DrawCardFromDeck();
EndTurn(); // This is the correct place to call EndTurn for an incorrect guess.
}
}
}
private void TransferCard(Card selectedCard, Player curPlayer)
{
selectedPlayer.RemoveCardFromHand(selectedCard);
currentPlayer.AddCardToHand(selectedCard);
}
private bool IsPlayerHandEmpty(Player currentPlayer)
{
return currentPlayer.IsHandEmpty();
}
private void EndTurn()
{
NextCurrentPlayer();
}
private void NextCurrentPlayer()
{
int currentIndex = playerManager.Players.IndexOf(currentPlayer);
int nextIndex = (currentIndex + 1) % playerManager.Players.Count;
currentPlayer.hasTurn = false;
Player nextPlayer = playerManager.Players[nextIndex];
nextPlayer.hasTurn = true;
currentPlayer = nextPlayer;
}
private void CheckForQuartets()
{
currentPlayer.CheckForQuartets(); // Implement your quartet-checking logic here
}
private void DisplayMessage(string message)
{
Debug.Log("Display Message: " + message);
}
public void DrawCardFromDeck()
{
if (cardManager != null && currentPlayer != null)
{
cardManager.DrawCardFromDeck(currentPlayer);
}
else
{
Debug.LogError($"{Time.time}: CardManager reference or current player or selected card is not assigned.");
}
}
private void CheckGameEnd()
{
//...
}
private void GameEnd()
{
Debug.Log($"{Time.time}: Game Ended");
}
}
答:
您可以尝试重命名在 UI 中按钮的 onclick 上映射的函数,以便最终中断调用该方法的任何按钮或 UI。之后,通过添加 Button 字段并将按钮拖入其中,直接添加您自己的 OnClick 处理程序:
[SerializeField] Button buttonToBeClicked;
void Awake(){
buttonToBeClicked.onClick.AddListener( () => { OnEventGuessClickRenamed(); });
}
重命名函数将确保没有其他任何意外调用它,并排除 UI 问题。通过代码在唤醒中添加 OnClick 处理程序,然后确保它是您添加它的唯一位置。 如果仍然出现问题,请在调试器中单步执行,并添加更多日志输出。
评论