C# - Making classes in a for loop - c#

I have this class:
class player
{
public string name;
public int rating;
{
The number of these classes made is dependant on a user specified amount numberOfPlayers. So my first reaction was to create a for loop to do this. i.e:
for (int i = 0; i< numberOfPlayers; i++)
{
//create class here
}
However, I need to be able to access these classes individually when later using their individual data - almost like they've been put into an array. How would I go about making a number of classes of which can be accessed individually?

You use a List<T> variable where T is your class
List<Player> players = new List<Player>();
for (int i = 0; i< numberOfPlayers; i++)
{
Player p = new Player();
p.Name = GetName();
p.rating = GetRating();
players.Add(p);
}
Of course GetName and GetRating should be substituded by your code that retrieves these informations and add them to the single player.
Getting data out of a List<T> is in no way very different from reading from an array
if(players.Count > 0)
{
Player pAtIndex0 = players[0];
....
}
You can read more info at MSDN page on List class

List<Player> players = new List<Player>();
for (int i = 0; i< numberOfPlayers; i++)
{
Player p = new Player();
p.Name = "";
p.rating = "";
players.Add(p);
}
to access it individually you can use...
foreach(Player p in players )
{
}

You've got the right idea. Make a player class that can be re-used over and over, a loop in which to create these players and now we need to store them somewhere. This will probably divide opinion if you get more than one answer but I like dictionaries for this kind of thing as you can access values by unique keys.
// Your player class. I've added 'id' so we can identify them by this later.
class Player
{
public int id;
public string name;
public int rating;
}
// The dictionary. They work like this dictionary<key, value> where key is a unique identifier used to access the stored value.
// Useful since you wanted array type accessibility
// So in our case int represents the player ID, the value is the player themselves
Dictionary<int, Player> players = new Dictionary<int, Player>();
// Create your players
for (int i = 0; i < numberOfPlayers; i++)
{
Player p = new Player()
{
id = i + 1,
name = $"Player{i}",
rating = 5
};
// Add them to dictionary
players.Add(p.id, p);
}
// Now you can access them by the ID:
if (players.ContainsKey(1))
{
Console.WriteLine(players[1].name);
}
The dictionary key can be anything you like so long as it's unique. You could identify them by name if you like.

Related

Changing the player class every turn in a loop

I need some kind of class or structure to hold data for 4 players in a simple game. How can I change the player class in every turn during the loop?
I mean something similar to this, where in every turn of a loop some instructions are chaning the data in the class of each player. Is there any effortless way to do this instead of creating many ifs?
internal class Program
{
private static void Main(string[] args)
{
Player player1 = new Player();
Player player2 = new Player();
Player player3 = new Player();
Player player4 = new Player();
int playerTurn = 1;
while(true)
{
//some instructions to change the data for example
//player(playerTurn).x = 1
}
}
}
class Player
{
public int x = 0;
public int y = 0;
}
Whenever you have numbered variables like this:
Player player1 = new Player();
Player player2 = new Player();
Player player3 = new Player();
Player player4 = new Player();
What you probably want is a collection. For example:
var players = new List<Player>
{
new Player(),
new Player(),
new Player(),
new Player()
};
Then you can loop over the list, change specific elements therein, etc.
In your specific case, it looks like you want to access the specific Player by an index:
//player(playerTurn).x = 1
You can do this with the list index:
players[playerTurn].x = 1;
Though if the list is ever sorted, that index is gone. In this case you might instead use a Dictionary<int, Player>. For example:
var players = new Dictionary<int, Player>
{
{ 1, new Player() },
{ 2, new Player() },
{ 3, new Player() },
{ 4, new Player() }
}
In this case each Player object is always and consistently uniquely identified by that integer value. And the usage is the same:
players[playerTurn].x = 1;
Alternatively, you might create a unique identifier on the Player itself. For example, suppose it has an ID property that you can set:
var players = new List<Player>
{
new Player { ID = 1 },
new Player { ID = 2 },
new Player { ID = 3 },
new Player { ID = 4 }
};
In this case you can still use the more generically versatile List<Player> structure, and query it to find the specific Player:
players.Single(p => p.ID == playerTurn).x = 1;
There are other collection types you can use. You could even take it a step further and create a custom PlayerList object which internally contains a collection, the current "turn", and other information about the list of players. But overall the point is that collection types are useful when you have a series of objects.

Get all materials of parent and its children in an array except for few

I am getting all materials from the parent and its children and storing it in an array. I want to however ignore few gameObjects from the list to be added. Can I add a string as the gameObject's name to be ignored so that except these gameObject, everything gets added?
Another thing is, how do I get all and each material from each gameObject? Few gameObjects have 5 and others have only 1. With the below code, I could only receive only one material from each gameObject.
public Renderer[] allChildRenderers;
public Material[] allMaterials;
public string[] GameObjects_ToIgnore;
void Start () {
allChildRenderers = GetComponentsInChildren<Renderer> ();
allMaterials = new Material[allChildRenderers.Length];
for (int i = 0; i < allChildRenderers.Length; i++) {
allMaterials[i] = allChildRenderers[i].GetComponent<Renderer> ().material;
}
}
}
If you want to ignore some GameObjects, you should use tags, which is a little harder to change than the name of the GameObjects themselves (this means your code may break if you change the name of the GameObject, as for the tag, you won't be changing frequently). Give the objects that should be ignored a new tag to indicate it.
for (int i = 0; i < allChildRenderers.Length; i++) {
if(allChildRenderers[i].gameObject.CompareTag("ignored_tag")) continue;
allMaterials[i] = allChildRenderers[i].material;
}
There is also a little ambiguity in your code:
allMaterials[i] = allChildRenderers[i].GetComponent<Renderer> ().material;
You are calling GetComponent<Renderer> in an object that is already a Renderer (allChildRenderers[i]). You should just call
allMaterials[i] = allChildRenderers[i].material;
As for the multiple materials in the same object, use allChildRenderers[i].materials to get the array of materials the object is using. allChildRenderers[i],material returns just the first material, while allChildRenderers[i].materials return the array with all of the used materials.
Try this:
First, change allMaterials for a list instead of array:
public List<Material> allMaterials = new List<Material>();
Then, try this:
for (int i = 0; i < allChildRenderers.Length; i++) {
if(allChildRenderers[i].gameObject.CompareTag("ignored_tag")) continue;
foreach(Material mat in allChildRenderers[i].materials)
allMaterials.Add(mat);
}
Yes
List<string> excludedNames;
int materialIndex = 0;
for (Renderer currRenderer in allChildRenderers){
if(!exludedNames.Contains(currRenderer.gameObject.name)){
foreach(Material currMaterial in currRenderer.materials){
allMaterials[materialIndex] = currMaterial;
materialindex++;
}
}
}
EDIT if allMaterials is supposed to have an entry per Renderer, it should be Material[][] or Renderer[]
Material[][] allMaterials;
List<string> excludedNames;
int rendererIndex = 0;
for (Renderer currRenderer in allChildRenderers){
if(!exludedNames.Contains(currRenderer.gameObject.name)){
int materialIndex = 0;
foreach(Material currMaterial in currRenderer.materials){
allMaterials[rendererIndex][materialIndex] = currMaterial;
materialindex++;
}
rendererIndex++;
}
}

Need my C# JSON.text file to have Default HighScores if it gets deleted or values are changed (UNITY)

How can I add default int and string name values to a JSON.txt though C#?
I would first create the default collection of HighScore with all of those fake players:
private List<Score> scores = null;
void Start()
{
this.scores = new List<Score>()
{
new Score("Adam", 10000), new Score("Eve",7500); // ...
};
Score[]scores = GetJsonFileWithScore(); // This is where you get the real players score
this.scores.AddRange(scores);
this.scores.OrderBy (s => s.score); // Order it by score
int index = 4;
this.scores.RemoveRange(index, list.Count - index); // keep only the best 5
}

C# Replace String.Split [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 5 years ago.
Improve this question
I have a string with this format "10,2/20,5/50,3"
Those are wins of every player.
"roomPrize,wins/nextRoomPrize,wins" etc
I figured out how to read it but I want to change the amount of wins for some roomPrize. I've come this far.
winsRawData = getStatW.text; //That is the wins string formated as explained above
string[] winSplits = winsRawData.Split('/');
for(int i = 0; i < winSplits.Length; i++)
{
if(winSplits[i].Split(',')[0] == room.ToString()) //room is the roomPrize that i want to affect
{
//newWins is the new win count that I want to update with
//winSplits[i].Split(',')[1] == newWins; <-- I just need to do that
}
}
Thanks
If I understood your question well, you would like to do the following:
winSplits[i].Split(',')[1] = newWins;
In order to achieve this, you would need to split the value, then re-create it (e.g. Join) and put it back in the original array.
The following should do the trick:
winsRawData = getStatW.text; //That is the wins string formated as explained above
string[] winSplits = winsRawData.Split('/');
for (int i = 0; i < winSplits.Length; i++)
{
var dataArray = winSplits[i].Split(',');
if (dataArray[0] == room.ToString()) //room is the roomPrize that i want to affect
{
// sets the new value.
dataArray[0] = newWins;
}
// finalize by recreating the string and push it back to the original array
winSplits[i] = String.Join(",", dataArray);
}
Edit Using the following values:
var winsRawData = "10,2/20,5/50,3";
int room = 10;
int newWins = 100;
And by adding the var output = String.Join("/", winSplits); at the end of the above code, you will get a string output:
"100,2/20,5/50,3"
See the code below for a complete example:
string[] winSplits = winsRawData.Split('/');
for (int i = 0; i < winSplits.Length; i++)
{
var dataArray = winSplits[i].Split(',');
if (dataArray[0] == room.ToString()) //room is the roomPrize that i want to affect
{
// sets the new value.
dataArray[0] = newWins.ToString();
}
// finalize by recreating the string and push it back to the original array
winSplits[i] = String.Join(",", dataArray);
}
var output = String.Join("/", winSplits); // = "100,2/20,5/50,3"
you should first refactor to deserialize the data into some Player objects, change it's wins count and then serialize it back:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
// Raw data
string rawData = "10,2/20,5/50,3";
// First split
string[] playersRaw = rawData.Split('/');
// Initialize a collection for the player objects
var players = new List<Player>();
// Iterates over the splitted players data
foreach (var playerRaw in playersRaw)
{
// Deserialize each player
var playerDeserialized = Player.Deserialize(playerRaw);
// Store the player data into the players collection
if (playerDeserialized != null)
players.Add(playerDeserialized);
}
// Seeks for player with room prize 10
foreach (var player in players)
{
if (player.RoomPrize == 10)
// Increments players data wins count
player.Wins += 1;
}
// Updates the raw data serializing all players back again
rawData = string.Join("/", Array.ConvertAll(players.ToArray(), (p) => p.Serialize()));
Console.WriteLine(rawData);
Console.ReadLine();
}
}
class Player
{
public int RoomPrize { get; set; }
public int Wins { get; set; }
public static Player Deserialize(string data, char separator = ',')
{
Player player = null;
string[] splittedData = new string[] { };
if (!string.IsNullOrEmpty(data) && (splittedData = data.Split(separator)).Length == 2)
{
int roomPrize = 0, wins = 0;
if (int.TryParse(splittedData[0], out roomPrize) && int.TryParse(splittedData[1], out wins))
{
player = new Player();
player.RoomPrize = roomPrize;
player.Wins = wins;
}
}
return player;
}
public string Serialize()
{
return string.Format("{0},{1}", this.RoomPrize, this.Wins);
}
}
}
It's much more code, but is easier to maintain.

LeaderBoard in C# UNITY3D?

I Needed To Develop LeaderBoard For Storing Details(means Scores) of Players in Games.Just Displaying players Scores on LeaderBoard in UNITY3D.so plz help me i dont have any idea. in below code Social Platforms NameSpace is there but i dont know how start and how to implement LeaderBoard in unity3d.
using UnityEngine;
using System.Collections.Generic;
using UnityEngine.SocialPlatforms;
public class LBoard : MonoBehaviour
{
ILeaderboard leaderBoard;
// Use this for initialization
void Start ()
{
leaderBoard = Social.CreateLeaderboard();
}
// Update is called once per frame
void Update ()
{
}
}
You need to create an IComparable class and add details like name and score , compare by score.
public class PlayerScore : IComparable<PlayerScore>
public string name;
public int score;
public int CompareTo(PlayerScore other)
{
return this.score.CompareTo(other.score);
}
You also need a list
public static List<PlayerScore> scoreIndex = new List<PlayerScore>(5);
You need some way of getting input from user to add name.
When adding score, create object of iComparer class and set name, score etc.
PlayerScore a = new PlayerScore();//create instance
a.name = PlayerStats.playerName;//set name
a.score = PlayerStats.score;//and score
scoreIndex.Add(a);
Then add new object to List and sort list, List.Sort();. if you want reversed then add reverse().
scoreIndex.Sort ();
scoreIndex.Reverse ();
Save list to player prefs e.g.
PlayerPrefs.SetString("name0" , scoreIndex[0].name);
PlayerPrefs.SetInt("score0" , scoreIndex[0].score);
PlayerPrefs.SetString("name1" , scoreIndex[1].name);
PlayerPrefs.SetInt("score1" , scoreIndex[1].score);
To display names and scores, create 3dText objects for names/scores and place a script like
public class PlayerNameHS : MonoBehaviour
public int pos;
void Start ()
{
renderer.material.color = Color.black;
TextMesh t = (TextMesh)gameObject.GetComponent(typeof(TextMesh));
t.text = PlayerPrefs.GetString("name" + pos);
}
void Update ()
{
}
}
Set Pos for each object.Do the same for scores with score script.
At the start of the game add player prefs into list or you will get an error when trying to retrieve names/scores. needs to be same amount as list size.
PlayerScore a = new PlayerScore();
a.name = PlayerPrefs.GetString("name0");
a.score = PlayerPrefs.GetInt("score0");
yourScript.scoreIndex.Add(a);
PlayerScore b = new PlayerScore();
b.name = PlayerPrefs.GetString("name1");
b.score = PlayerPrefs.GetInt("score1");
yourScript.scoreIndex.Add(b);
Don't know if I'm explaining this well, but you basically need to add playerprefs to list, add comparable scores to list, sort the list, save the list, display the saved list. I'm new to this so take it easy with criticism ;)
If you mean leaderboard like a local high scores table, you would need two functions: AddScore and a function that gets the high scores. (note this example is in C#)
function AddScore(string name, int score){
int newScore;
string newName;
int oldScore;
string oldName;
newScore = score;
newName = name;
for(int i=0;i<10;i++){
if(PlayerPrefs.HasKey(i+"HScore")){
if(PlayerPrefs.GetInt(i+"HScore")<newScore){
// new score is higher than the stored score
oldScore = PlayerPrefs.GetInt(i+"HScore");
oldName = PlayerPrefs.GetString(i+"HScoreName");
PlayerPrefs.SetInt(i+"HScore",newScore);
PlayerPrefs.SetString(i+"HScoreName",newName);
newScore = oldScore;
newName = oldName;
}
}else{
PlayerPrefs.SetInt(i+"HScore",newScore);
PlayerPrefs.SetString(i+"HScoreName",newName);
newScore = 0;
newName = "";
}
}
}
And then to get the highscores:
void GetHighScores()
{
for(int i = 0; i < 10; i++)
{
Debug.Log(PlayerPrefs.GetString(i + "HScoreName") + " has a score of: " + PlayerPrefs.GetInt(i + "HScore"));
}
}
If you want to create a networked/online leaderboard, you need to use something like GameFly (take a look at that example).

Categories