- Home /
Roles randomly distributed to Players?
Hey, so I already searched for it but I didn't find anything so now I'm here. I want to make a game where everyone gets a role at the beginning of the game. There are two roles, i will just call them A and B now. Role A has to kill role B and of course the other way around as well. Role A doesn't know what roles the other players have but role B knows who else has role B. So of course there have to be more of role A to make the game fair: 5 Player = 2 role B | 6 Player = 2 role B | 7 Player = 3 role B | 8 Player = 3 role B | 9 Player = 4 role B and so on..
So my question is how do I make it happen? I have no idea where to start so I would be happy if you could help me!
Answer by ElijahShadbolt · Feb 23, 2018 at 11:56 PM
Here's one solution. It works like so:
Calculate how many of each role there should be.
Create a list (like a deck of cards) of all the roles, with the right number of role instances for each role type.
Shuffle/randomize the list.
Give each player their corresponding role from the list.
Player.cs
using UnityEngine;
public class Player : MonoBehaviour
{
public PlayerRole role;
}
PlayersManager.cs
using System.Collections.Generic;
using UnityEngine;
public enum PlayerRole
{
RoleA, // default role
RoleB,
RoleC,
}
public class PlayersManager : MonoBehaviour
{
// list of players in the game
private Player[] players;
// initializes the script.
void Awake()
{
players = FindObjectsOfType<Player>();
}
// called just before the game starts.
void Start()
{
RandomizeRoles();
foreach (Player player in players)
{
if (player == null)
continue;
Debug.Log("Player: " + player.name + ", Role: " + player.role);
}
}
// randomizes player roles.
private void RandomizeRoles()
{
int playerCount = players.Length;
// get number of players who should be each role
int roleBCount = 2;
int roleCCount = 0;
if (playerCount < 5)
{
Debug.LogError("Not enough players.");
return;
}
else if (playerCount >= 5 && playerCount <= 6)
{
roleBCount = 2;
}
else if (playerCount >= 7 && playerCount <= 8)
{
roleBCount = 3;
}
else if (playerCount >= 9 && playerCount <= 10)
{
roleBCount = 4;
roleCCount = 1;
}
else // more than 10 players
{
// 2/5 of players, rounded down
roleBCount = Mathf.FloorToInt(playerCount * 0.4f);
// 1/10 of players, rounded down
roleCCount = Mathf.FloorToInt(playerCount * 0.1f);
}
// initialize list of roles
// prepare list of available roles (like a deck of cards)
PlayerRole[] roles = new PlayerRole[playerCount];
int index = 0;
// add RoleB's
while (roleBCount > 0 && index < playerCount)
{
roles[index] = PlayerRole.RoleB;
--roleBCount;
++index;
}
// add RoleC's
while (roleCCount > 0 && index < playerCount)
{
roles[index] = PlayerRole.RoleC;
--roleCCount;
++index;
}
// add default RoleA's
while (index < playerCount)
{
roles[index] = PlayerRole.RoleA;
++index;
}
// shuffle (randomize) the roles
ShuffleArray(roles);
// assign the roles to each player
for (int i = 0; i < playerCount; ++i)
{
Player player = players[i];
if (player == null)
continue;
player.role = roles[i];
}
}
// randomizes the order of elements in an array.
public static void ShuffleArray<T>(T[] array)
{
T[] newArray = new T[array.Length];
int j = 0;
List<int> availableIndices = new List<int>();
for (int i = 0; i < array.Length; ++i)
{
availableIndices.Add(i);
}
while (availableIndices.Count > 0)
{
int t = UnityEngine.Random.Range(0, availableIndices.Count);
int index = availableIndices[t];
availableIndices.RemoveAt(t);
newArray[j++] = array[index];
}
System.Array.Copy(newArray, array, array.Length);
}
}
You could make it more succinct by replacing lines 75-110 with the following, and removing the ShuffleArray function.
// prepare list of available roles (like a deck of cards)
List<PlayerRole> roles = new List<PlayerRole>();
// add RoleB's
while (roleBCount > 0 && roles.Count < playerCount)
{
roles.Add(PlayerRole.RoleB);
--roleBCount;
}
// add RoleC's
while (roleCCount > 0 && roles.Count < playerCount)
{
roles.Add(PlayerRole.RoleC);
--roleCCount;
}
// add default RoleA's
while (roles.Count < playerCount)
{
roles.Add(PlayerRole.RoleA);
}
// assign random roles to each player
foreach (Player player in players)
{
int i = UnityEngine.Random.Range(0, roles.Count);
player.role = roles[i];
roles.RemoveAt(i);
}
This one looks good thank you very much, I will try it out tomorrow.
Answer by Bunny83 · Feb 23, 2018 at 11:19 PM
Uhm the easiest way is to first determine how many players will go in which "team" / role. The examples you've provided looks like this should work:
static int GetNumberOgBRole(int aTotelPlayers)
{
return Mathf.FloorToInt((aTotalPlayers-0.25f)*0.5f);
}
So when passing "7" it returns "3". When passing 5 it will return 2. When passing "20" it will return "9". So always at least one less than the average half. So role B will always have 1 or 2 players less than role A
Once you know how many of each role you need you can simply distribute them. One way is to simply adding all roles into a List and iterating linearly through all players. Pick a random element from the list and remove it from the list. Another way is to simply scramble the List and give out the roles one-to-one. If you need an array shuffling method, here's a Fisher-Yates implementation (make sure you use Oliphant's version)