Changes for bot logic.

This commit is contained in:
Ashby Issac 2026-01-27 20:55:55 +05:30
parent a9af5d1d17
commit bfa63f0e8f
3 changed files with 214 additions and 43 deletions

View File

@ -9,8 +9,7 @@ public enum PlayerType
Player1 = 0,
Player2 = 1,
Player3 = 2,
Player4 = 3,
Bot
Player4 = 3
}
[System.Serializable]
@ -20,17 +19,26 @@ public class PlayerGameData
public int startIndex;
public int endIndex;
public Transform playersParent;
public List<PlayerPawn> playerPawnsDict;
public Dictionary<int, PlayerPawn> playerPawnsDict;
public int totalPawnsFinished = 0;
}
[System.Serializable]
public enum MatchType
{
LAN,
PVP,
Bot
}
public enum BotMove
{
FinishingPathMove = 0,
SafeMove = 1,
AttackMove = 2,
NormalMove = 3,
NoMoves = 4
}
public class GameplayManager : MonoBehaviour, IBase, IBootLoader, IDataLoader
{
[SerializeField] private TextMeshProUGUI diceText;
@ -45,13 +53,17 @@ public class GameplayManager : MonoBehaviour, IBase, IBootLoader, IDataLoader
private PlayerType currentPlayerTypeTurn;
private int currentPlayerTurnIndex = 0;
private List<PlayerType> playerTypes = new List<PlayerType>();
private List<PlayerType> allPlayerTypes = new List<PlayerType>();
private List<PlayerType> botTypesInGame = new List<PlayerType>();
public List<PlayerType> PlayerTypesCollection => playerTypes;
public List<PlayerType> PlayerTypesCollection => allPlayerTypes;
// private Dictionary<PlayerTypes, > playerPawnsDict = new Dictionary<PlayerTypes, List<PlayerPawn>>();
private Dictionary<PlayerType, PlayerGameData> playerGameDatasDict = new Dictionary<PlayerType, PlayerGameData>();
// botRuntimeMovementData: where can the bot move if a particular dice value is thrown, and based on the value set the bot move for each using a predictive approach and select based on the the priority
private Dictionary<PlayerType, Dictionary<int, BotMove>> botRuntimeMovementData = new Dictionary<PlayerType, Dictionary<int, BotMove>>();
private TilesManager tilesManager;
private int diceRolledValue;
@ -74,53 +86,119 @@ public class GameplayManager : MonoBehaviour, IBase, IBootLoader, IDataLoader
CanRollDice = true;
// initialize the player list from UI.
InitPlayerTypesForLAN(null);
// InitPlayerTypesForLAN(null);
InitPlayerTypesForBotMatch(PlayerType.Player1, 1);
}
// TODO :: Call when the UI selection is made and game starts
public void InitPlayerTypesForLAN(List<PlayerType> types)
{
// TODO :: 2P, 3P, 4P
playerTypes = new List<PlayerType> { PlayerType.Player1, PlayerType.Player2, PlayerType.Player3, PlayerType.Player4 };
allPlayerTypes = new List<PlayerType> { PlayerType.Player1, PlayerType.Player2, PlayerType.Player3, PlayerType.Player4 };
playerBaseHandler.InitPlayerTypes(playerTypes);
playerBaseHandler.InitPlayerTypes(allPlayerTypes);
InitCurrentGamePlayerInfo();
}
public void InitPlayerTypesForBotMatch(PlayerType selectedPlayerType, int botCount)
{
// test data
botTypesInGame.Clear();
allPlayerTypes.Clear();
AssignBotTypes(selectedPlayerType, botCount);
InitBotRuntimeData();
allPlayerTypes.Add(selectedPlayerType);
allPlayerTypes.AddRange(botTypesInGame);
playerBaseHandler.InitPlayerTypes(allPlayerTypes);
InitCurrentGamePlayerInfo();
AssignPlayerAndBotStates(selectedPlayerType);
}
private void InitBotRuntimeData()
{
botRuntimeMovementData.Clear();
foreach (var botType in botTypesInGame)
{
PlayerGameData playerGameData = playerGameDatasDict[botType];
if (!botRuntimeMovementData.ContainsKey(botType))
{
botRuntimeMovementData.Add(botType, new Dictionary<int, BotMove>());
}
foreach (var pawn in playerGameData.playerPawnsDict)
{
botRuntimeMovementData[botType].Add(pawn.Value.PlayerId, BotMove.SafeMove);
}
}
}
private void AssignPlayerAndBotStates(PlayerType selectedPlayerType)
{
PlayerBase playerBase = playerBaseHandler.GetPlayerBase(selectedPlayerType);
playerBase.AssignBotState(PawnType.User);
foreach (PlayerType playerType in botTypesInGame)
{
playerBase = playerBaseHandler.GetPlayerBase(playerType);
playerBase.AssignBotState(PawnType.Bot);
}
}
private void AssignBotTypes(PlayerType selectedPlayerType, int botCount)
{
int addedBots = 0;
if (botCount == 1)
{
var playerType = (PlayerType)((int)selectedPlayerType + 2 < Enum.GetValues(typeof(PlayerType)).Length ?
(int)selectedPlayerType + 2 : (int)selectedPlayerType - 2);
botTypesInGame.Add(playerType);
}
else if (botCount == 2)
{
foreach (PlayerType enumType in Enum.GetValues(typeof(PlayerType)))
{
if (enumType == selectedPlayerType) continue;
botTypesInGame.Add(enumType);
addedBots++;
if (addedBots == botCount) break;
}
}
else
{
foreach (PlayerType enumType in Enum.GetValues(typeof(PlayerType)))
{
if (enumType == selectedPlayerType) continue;
botTypesInGame.Add(enumType);
}
}
}
// TODO :: Call based on 2P/3P/4P
public void InitCurrentGamePlayerInfo()
{
currentPlayerTypeTurn = playerTypes[currentPlayerTurnIndex];
currentPlayerTypeTurn = allPlayerTypes[currentPlayerTurnIndex];
// initialize the board based on the player types
foreach (PlayerGameData playerGameData in playerGameDatas)
{
if (!playerTypes.Contains(playerGameData.playerType))
if (!allPlayerTypes.Contains(playerGameData.playerType))
continue;
Debug.Log($"playerGameData.playerType: {playerGameData.playerType}");
playerGameDatasDict.Add(playerGameData.playerType, playerGameData);
playerGameDatasDict[playerGameData.playerType].playerPawnsDict = new List<PlayerPawn>();
playerGameDatasDict[playerGameData.playerType].playerPawnsDict = new Dictionary<int, PlayerPawn>();
foreach (Transform playerPawnChild in playerGameData.playersParent)
{
if (!playerPawnChild.gameObject.activeInHierarchy) continue;
playerGameDatasDict[playerGameData.playerType].playerPawnsDict.Add(playerPawnChild.GetComponent<PlayerPawn>());
var pawn = playerPawnChild.GetComponent<PlayerPawn>();
playerGameDatasDict[playerGameData.playerType].playerPawnsDict.Add(pawn.PlayerId, pawn);
}
}
}
@ -129,9 +207,9 @@ public class GameplayManager : MonoBehaviour, IBase, IBootLoader, IDataLoader
{
foreach (var playerPawn in playerGameDatasDict[currentPlayerTypeTurn].playerPawnsDict)
{
if (playerPawn.GetPlayerState() == PlayerState.InFinishingPath) continue;
if (playerPawn.Value.GetPlayerState() == PlayerState.InFinishingPath) continue;
playerPawn.SetPlayerSelectionState(state);
playerPawn.Value.SetPlayerSelectionState(state);
}
}
@ -149,23 +227,9 @@ public class GameplayManager : MonoBehaviour, IBase, IBootLoader, IDataLoader
// provide option to select a pawn from the list
// also play a simple animation before selecting
EnablePlayerSelectionStates(true);
CanRollDiceAgain = true;
bool AreAllPawnsInFinishingPath = false;
foreach (var pawn in playerGameDatasDict[currentPlayerTypeTurn].playerPawnsDict)
{
if (pawn.GetPlayerState() == PlayerState.InFinishingPath && pawn.GetPlayerState() != PlayerState.HasFinished)
{
AreAllPawnsInFinishingPath = true;
continue;
}
AreAllPawnsInFinishingPath = false;
break;
}
if (AreAllPawnsInFinishingPath)
if (AreAllPawnsInFinishingPath())
CanRollDice = true;
pointerMeshRend.material = selectMat;
@ -174,7 +238,7 @@ public class GameplayManager : MonoBehaviour, IBase, IBootLoader, IDataLoader
else // if there are any other pawns that are in safe or moving state
{
// for player's logic
IEnumerable<PlayerPawn> availPlayers = playerGameDatasDict[currentPlayerTypeTurn].playerPawnsDict.Select(pawn => pawn)
IEnumerable<PlayerPawn> availPlayers = playerGameDatasDict[currentPlayerTypeTurn].playerPawnsDict.Values.Select(pawn => pawn)
.Where(pawn => pawn.GetPlayerState() == PlayerState.InSafeZone ||
pawn.GetPlayerState() == PlayerState.Moving ||
pawn.GetPlayerState() == PlayerState.InFinishingPath);
@ -204,6 +268,7 @@ public class GameplayManager : MonoBehaviour, IBase, IBootLoader, IDataLoader
Debug.Log($"CustomAvailablePlayers: {customAvailPlayers}");
if (customAvailPlayers < 1)
{
// TODO :: Switch the player once the dice rolling has completed
SwitchPlayer();
CanRollDice = true;
}
@ -212,6 +277,24 @@ public class GameplayManager : MonoBehaviour, IBase, IBootLoader, IDataLoader
}
}
private bool AreAllPawnsInFinishingPath()
{
bool areAllPawnsInFinishingPath = false;
foreach (var pawn in playerGameDatasDict[currentPlayerTypeTurn].playerPawnsDict)
{
if (pawn.Value.GetPlayerState() == PlayerState.InFinishingPath && pawn.Value.GetPlayerState() != PlayerState.HasFinished)
{
areAllPawnsInFinishingPath = true;
continue;
}
areAllPawnsInFinishingPath = false;
break;
}
return areAllPawnsInFinishingPath;
}
public void OnPawnSelected(PlayerPawn playerPawn)
{
EnablePlayerSelectionStates(false);
@ -294,21 +377,21 @@ public class GameplayManager : MonoBehaviour, IBase, IBootLoader, IDataLoader
Debug.Log($"currentPlayerTurn: {currentPlayerTypeTurn}");
Debug.Log($"currentPlayerTurnIndex: {currentPlayerTurnIndex}");
if (playerTypes.Count == 1)
if (allPlayerTypes.Count == 1)
{
Debug.LogError($"GAME IS OVER");
return;
}
if (currentPlayerTypeTurn == playerTypes[playerTypes.Count - 1])
if (currentPlayerTypeTurn == allPlayerTypes[allPlayerTypes.Count - 1])
{
currentPlayerTurnIndex = 0;
currentPlayerTypeTurn = playerTypes[currentPlayerTurnIndex];
currentPlayerTypeTurn = allPlayerTypes[currentPlayerTurnIndex];
}
else
{
currentPlayerTurnIndex++;
currentPlayerTypeTurn = playerTypes[currentPlayerTurnIndex];
currentPlayerTypeTurn = allPlayerTypes[currentPlayerTurnIndex];
}
diceText.text = $"{0}";
@ -323,6 +406,64 @@ public class GameplayManager : MonoBehaviour, IBase, IBootLoader, IDataLoader
if (playerPawn)
playerPawn.SetPlayerState(tilesManager.RetrieveTileBasedOnIndex(playerPawn.CurrentTileIndex).IsSafeZone ? PlayerState.InSafeZone : PlayerState.Moving);
Debug.Log($"botTypesInGame.Contains(currentPlayerTypeTurn): {botTypesInGame.Contains(currentPlayerTypeTurn)}");
if (!CanRollDiceAgain && botTypesInGame.Contains(currentPlayerTypeTurn)) // TODO :: Double check calling of the function
{
Invoke(nameof(RollDiceForBot), 1f);
}
}
private void RollDiceForBot()
{
Debug.Log($"RollDiceForBot");
OnDiceRolled(UnityEngine.Random.Range(1, Ludo_3D_Constants.Max_Dice_Rolls + 1));
}
// TODO :: Call right after the dice is rolled with the animation
// What happens when you get a 6
private void SelectPawnFromBotBase()
{
var botPawnsDict = botRuntimeMovementData[currentPlayerTypeTurn]; // set the data inside this dict
// check the data from the playerGameDataDict
// change playerPawnsDict to list
// only select the pawns that are active
// if no pawns have left the home select the first pawn inside the base
//
foreach (var keyValuePair in playerGameDatasDict[currentPlayerTypeTurn].playerPawnsDict)
{
var playerPawn = keyValuePair.Value;
var possibleLandingIndex = playerPawn.CurrentTileIndex + diceRolledValue;
if (playerPawn.GetPlayerState() == PlayerState.HasFinished)
{
botPawnsDict.Remove(playerPawn.PlayerId); // TODO :: Double check logic
continue;
}
Tile tileData = tilesManager.RetrieveTileBasedOnIndex(possibleLandingIndex);
if (playerPawn.GetPlayerState() == PlayerState.InFinishingPath || possibleLandingIndex > playerGameDatasDict[currentPlayerTypeTurn].endIndex)
{
botPawnsDict[playerPawn.PlayerId] = BotMove.FinishingPathMove;
continue;
}
else if (tileData.IsSafeZone || playerPawn.GetPlayerState() == PlayerState.InHome)
{
botPawnsDict[playerPawn.PlayerId] = BotMove.SafeMove;
}
else if (tileData.PlayerPawn != null)
{
botPawnsDict[playerPawn.PlayerId] = BotMove.AttackMove;
}
else
{
botPawnsDict[playerPawn.PlayerId] = BotMove.NormalMove;
}
}
}
private void MoveThroughTiles(PlayerPawn playerPawn, int index, int targetIndex)
@ -486,10 +627,10 @@ public class GameplayManager : MonoBehaviour, IBase, IBootLoader, IDataLoader
CanRollDiceAgain = false;
SwitchPlayer();
if (playerTypes.Contains(currentPlayerTypeTurn))
playerTypes.Remove(currentPlayerTypeTurn);
if (allPlayerTypes.Contains(currentPlayerTypeTurn))
allPlayerTypes.Remove(currentPlayerTypeTurn);
Debug.Log($"PlayerTypes: {playerTypes.Count}");
Debug.Log($"PlayerTypes: {allPlayerTypes.Count}");
}
else
{

View File

@ -13,6 +13,11 @@ public class PlayerBase : MonoBehaviour
[SerializeField] private BasePlacementData[] basePlacementDatas;
[SerializeField] private PlayerPawn[] playerPawns;
public bool IsBotBase
{
get; private set;
}
public PlayerType GetPlayerType() => playerType;
public void InitPlayerData()
@ -23,6 +28,15 @@ public class PlayerBase : MonoBehaviour
}
}
public void AssignBotState(PawnType pawnType)
{
IsBotBase = pawnType == PawnType.Bot;
for (int idx = 0; idx < playerPawns.Length; idx++)
{
playerPawns[idx].AssignBotPlayerState(IsBotBase);
}
}
public Transform GetBasePlacementDataPosition(int idx)
{
return basePlacementDatas[idx].placementTransform;

View File

@ -11,6 +11,12 @@ public enum PlayerState
HasFinished
}
public enum PawnType
{
User,
Bot
}
public class PlayerPawn : MonoBehaviour
{
[SerializeField] private PlayerState playerState;
@ -33,6 +39,16 @@ public class PlayerPawn : MonoBehaviour
get; private set;
}
public bool IsBotPlayer
{
get; private set;
}
public void AssignBotPlayerState(bool state)
{
IsBotPlayer = state;
}
public void SetPlayerSelectionState(bool state)
{
canSelectPlayerFromHome = state;
@ -68,7 +84,7 @@ public class PlayerPawn : MonoBehaviour
private void OnMouseDown()
{
if (!canSelectPlayerFromHome) return;
if (IsBotPlayer || !canSelectPlayerFromHome) return;
SetGameplayManager();
gameplayManager.OnPawnSelected(this);