SimpleSpriteSequence and getRandom - c#

I have an Gameobject that contains several prefabs, As in the picture below
public SimpleSpriteSequence birds;
Randomizer setBirds;
setBirds = new Randomizer(birds.sprites);
int index = setBirds.getRandom();
birds.setCurrentSpriteIndex(index);
In the image below we see the population of the array
Invoke("Interface", 1f);
Now with the help of the random I get a random bird from the array. But the problem is that the bird can be repeated. All I want is that at least 6 times in a row when the Invoke("Interface", 1f); function does not repeat the bird.So in principle I have to do so 6 times the bird does not repeat itself. To be a random of these birds but 6 times to be different birds. No I know if I explained it properly, but I hope you understand the idea.

Here is code but it is written in console application since i do not have your code and it is writen with custom class of Birds but you will adapt it to your code. If you need help with it i will help you.
class Birds
{
public int birdID;
public string birdName;
//public Sprite birdSprite;
}
class Program
{
static Random rnd = new Random();
static Birds[] birds = new Birds[10];
static int nBirdsSpawned = 0;
static List<int> spawnedBirds = new List<int>();
static void Main(string[] args)
{
//Database of my birds ;)
birds[0] = new Birds();
birds[1] = new Birds();
birds[2] = new Birds();
birds[3] = new Birds();
birds[4] = new Birds();
birds[5] = new Birds();
birds[6] = new Birds();
birds[7] = new Birds();
birds[8] = new Birds();
birds[9] = new Birds();
birds[0].birdID = 0;
birds[0].birdName = "Bird 1";
birds[1].birdID = 1;
birds[1].birdName = "Bird 2";
birds[2].birdID = 2;
birds[2].birdName = "Bird 3";
birds[3].birdID = 3;
birds[3].birdName = "Bird 4";
birds[4].birdID = 4;
birds[4].birdName = "Bird 5";
birds[5].birdID = 5;
birds[5].birdName = "Bird 6";
birds[6].birdID = 6;
birds[6].birdName = "Bird 7";
birds[7].birdID = 7;
birds[7].birdName = "Bird 8";
birds[8].birdID = 8;
birds[8].birdName = "Bird 9";
birds[9].birdID = 9;
birds[9].birdName = "Bird 10";
int i = 0;
while (i < 100)
{
RandomSpawn();
i++;
}
Console.Write("Finished");
Console.ReadKey();
}
static void CheckForBirdSpawn(int birdID)
{
if (nBirdsSpawned <= 6)
{
if (!spawnedBirds.Contains(birdID))
{
spawnedBirds.Add(birdID);
SpawnBird(birdID);
}
else
{
Console.WriteLine("Bird " + birds[birdID].birdName + " is already spawned!");
}
}
else
{
SpawnBird(birdID);
}
}
static void SpawnBird(int birdID)
{
Console.WriteLine(birds[birdID].birdName);
nBirdsSpawned++;
}
static void RandomSpawn()
{
int r = rnd.Next(0, 10);
CheckForBirdSpawn(r);
}
}
Until first 6 birds are spawned it check if bird is already spawned and if it is it doesn't allow it's spawning. After 6 birds are spawned it allows every bird to be spawned.
Here is output in console app:

I know this is a mainly code reply but how about you try something a little like this?
Populate a list of the bird indexes.
Pick a random index within that list.
Decrease all already spawned birds' Values.
If any reach zero, re-add the birds index into the availableBird list.
Spawn the bird, while adding it's index as Key and the amount of spawning delay needed until it can be spawned again as the Value.
Remove the birds index from the list.
Do the spawn whenever necessary, this will spawn every frame since it is found in a Coroutine which has an infinite while loop.
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class burd : MonoBehaviour {
public bool spawning;
private System.Random rnd = new System.Random();
private Dictionary<int, int> spawnedBurdies = new Dictionary<int, int>();
private List<int> availableBurdies = new List<int>();
// Use this for initialization
void Start () {
for (int index = 0; index < 10; index++)
{
availableBurdies.Add(index);
}
StartCoroutine(SpawnBurdies());
}
private IEnumerator SpawnBurdies()
{
while (true)
{
if (spawning)
{
int burdIndex = rnd.Next(availableBurdies.Count);
spawnBurd(availableBurdies[burdIndex]);
availableBurdies.RemoveAt(burdIndex);
}
yield return new WaitForFixedUpdate();
}
}
private void spawnBurd(int burdIndex)
{
Debug.Log("Spawned burd #" + burdIndex);
List<int> burdieKeys = new List<int>();
foreach (var burdie in spawnedBurdies) { burdieKeys.Add(burdie.Key); }
foreach (var burdieKey in burdieKeys)
{
spawnedBurdies[burdieKey]--;
if(spawnedBurdies[burdieKey] <= 0)
{
spawnedBurdies.Remove(burdieKey);
availableBurdies.Add(burdieKey);
}
}
spawnedBurdies.Add(burdIndex, 6);
}
}
This solution would save you from attempting to spawn birds that can't be spawned; but if there are less birds than the minimum spawns to wait for, an Argument out of range error would be thrown.

Related

Random.Next - Am I silently creating new instances?

Random.Next() randomness failures are almost always caused by creating and then using multiple instances of System.Random with the same seed, either with a time seed or a manual one. However, this is the only instance creation code in my class:
System.Random rNG;
if (string.IsNullOrEmpty(Map.Seed))
{
rNG = new System.Random();
}
else
{
rNG = new System.Random(Map.Seed.GetHashCode());
}
Looping through this second attempt code correctly creates random numbers:
var resourceRoll = rNG.Next(0, this.ResourceByRoll.Count);
var resourceRow = from row in this.ProcGenResourceTable.AsEnumerable()
.Where(row => row["Resource"].Equals(
this.ResourceByRoll[resourceRoll]
))
Looping through this original attempt code often creates the same number twice in a row:
var resourceRow = from row in this.ProcGenResourceTable.AsEnumerable()
.Where(row => row["Resource"].Equals(
this.ResourceByRoll[rNG.Next(0, this.ResourceByRoll.Count)]
))
Am I somehow silently creating a new instance of System.Random when using a Random.Next call as a dictionary index? Why does my original code often return the same number twice in a row?
If it matters:
This class is a Unity script
I am using System.Random, not UnityEngine.Random
My complete class is below:
using Assets.Code.Tools;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using UnityEngine;
public class Map : MonoBehaviour
{
public static int Length { get; set; }
public static int Width { get; set; }
public static int ResourceChanceDenominator { get; set; }
public static string Seed { get; set; }
private static int[,] objectGrid;
private DataTable ProcGenResourceTable { get; set; }
private Dictionary<int, string> ResourceByRoll { get; set; }
private List<GameObject> prefabTrees;
private List<GameObject> prefabStones;
private void Start()
{
this.prefabTrees = GeneralTools.GetPrefabsWithTag("Tree");
this.prefabStones = GeneralTools.GetPrefabsWithTag("Stone");
GenerateMap();
}
public void GenerateMap()
{
var procGenResourceTable = Resources.Load("ProcGenResourceTable") as TextAsset;
if (procGenResourceTable != null)
{
this.ProcGenResourceTable = GeneralTools.GetDataTableFromCSV(procGenResourceTable, "|", true, false);
}
else
{
Console.WriteLine("ProcGenResourceTable could not be found");
return;
}
Map.objectGrid = new int[Map.Width, Map.Length];
this.ResourceByRoll = GetPopulatedResourceByRollDictionary();
System.Random rNG;
if (string.IsNullOrEmpty(Map.Seed))
{
rNG = new System.Random();
}
else
{
rNG = new System.Random(Map.Seed.GetHashCode());
}
for (var i = 0; i < Map.Length; i++)
{
for (var j = 0; j < Map.Width; j++)
{
var roll = rNG.Next(Map.ResourceChanceDenominator);
if (roll == 1)
{
// var resourceRoll = rNG.Next(0, this.ResourceByRoll.Count);
var resourceRow = from row in this.ProcGenResourceTable.AsEnumerable()
.Where(row => row["Resource"].Equals(
this.ResourceByRoll[rNG.Next(0, this.ResourceByRoll.Count)]
))
select new
{
ModelFamily = row["Model Family"],
Tags = row["Tags"]
};
foreach (var row in resourceRow)
{
GameObject resource = null;
switch (row.ModelFamily)
{
case "Tree":
resource = Instantiate(this.prefabTrees[rNG.Next(this.prefabTrees.Count - 1)], new Vector3(i, 0, j), new Quaternion());
break;
case "Stone":
resource = Instantiate(this.prefabStones[rNG.Next(this.prefabStones.Count - 1)], new Vector3(i, 0, j), new Quaternion());
break;
default:
resource = Instantiate(this.prefabTrees[rNG.Next(this.prefabTrees.Count - 1)], new Vector3(i, 0, j), new Quaternion());
break;
}
var tagsListForResource = row.Tags.ToString().Split(new char[] { '|' }).ToList();
if (tagsListForResource.Contains("Resource"))
{
resource.tag = "Resource";
}
}
}
}
}
}
private Dictionary<int, string> GetPopulatedResourceByRollDictionary()
{
var resourceByRoll = new Dictionary<int, string>();
foreach (DataRow row in this.ProcGenResourceTable.Rows)
{
if (!string.IsNullOrEmpty(row["Weight"].ToString()))
{
for (var i = 0; i < Convert.ToInt32(row["Weight"]); i++)
{
resourceByRoll.Add(resourceByRoll.Count, row["Resource"].ToString());
}
}
}
return resourceByRoll;
}
}
I misunderstood what was going on - this is not related to repeated random numbers.
The answer to Michael Welch's question is that I am seeing trees and rocks generate on the same coordinates.
I expected this code to only generate one row of results:
var resourceRow = from row in this.ProcGenResourceTable.AsEnumerable()
.Where(row => row["Resource"].Equals(
this.ResourceByRoll[rNG.Next(0, this.ResourceByRoll.Count)]
))
However, it is sometimes returns more, because .Where() does some looping of its own that re-rolls the number each time.
Having multiple rows returned causes the foreach block to generate multiple prefabs at the coordinate instead of just one.

How to initilize a list using Vars

I have a class called Players that holds various player attributes. I want to use a loop to initialize a list of Players based on certain user input. I will then use the list to play a card game with each of the players. I guess the List needs to be global in scope.
I can't figure out how to initialize the list since I can't seem to user a var
in the name field when trying to create a new Player.
Thanks
class Players
{
public string name;
public double bank;
public Hands playerHands; //A List of hands played
public Players ()
{
name = "Unknown";
bank = 0.0;
playerHands = null;
}
public Players(string name, double bank, Hands playerHands)
{
this.name = name;
this.bank = bank;
this.playerHands = playerHands;
}
}
class Program
{
private static int numOfPlayers;
private static int numOfDecks;
private static List<Cards> shoe;
public static void Main()
{
Console.OutputEncoding = Encoding.UTF8; //required to display special characters
Hands playerHands = new Hands();
Hands dealerHands = new Hands();
SetUpTable();
//Initilize Players
Players player = new Players("Ken", 100.00, playerHands);
Players dealer = new Players("Dealer", 0.0, dealerHands);
int dealerScore = 0, playerScore = 0;
//Deal initial cards
//The deal starts with the dealer who gets the first card face down
Cards dealerUpCard = null;
Hand dealerHand = new Hand();
Hand playerHand = new Hand();
dealer.playerHands.addHand(dealerHand);
player.playerHands.addHand(playerHand);
for (int iii = 1; iii < 3; iii++)
{
//Deal dealer's hand
dealerHand.addCard(shoe[0]);
dealerScore += shoe[0].value;
if (iii == 2) { dealerUpCard = shoe[0]; }
shoe.RemoveAt(0);
//Deal Player's aHand
playerHand.addCard(shoe[0]);
playerScore += shoe[0].value;
shoe.RemoveAt(0);
}
//Print out the test hands
displayHand(dealer);
displayHand(player);
Console.Read();
}
static void displayHand(Players player)
{
//Print out the test hands
for (int i = 0; i < player.playerHands.hands.Count; i++)
{
Console.Write("{0}'s hand: ", player.name);
for (int j = 0; j < player.playerHands.hands[i].hand.Count; j++)
{
Console.Write(" {0}{1} ", player.playerHands.hands[i].hand[j].rank, (char)player.playerHands.hands[i].hand[j].suit);
}
Console.WriteLine();
}
}
static void SetUpTable()
{
//Create players
numOfPlayers = validateUserInput("How many players (1-6)?",1,6);
for (int i = 0; i<numOfPlayers; i++)
{ //get player elements
//initiliz a new unique player in the Players list
//ie: Players player = new Players("Ken", 100.00, playerHands);
}
//Create shoe of cards
numOfDecks = validateUserInput("How many decks of cards (1-8)?", 1, 8);
shoe = Deck.createDeck(numOfDecks);
Deck.shuffleDeck(shoe, numOfDecks);
}
}
public List<Players> ListOfPlayers=new List<Players>();
static void SetUpTable()
{
//Create players
numOfPlayers = 6;
for (int i = 0; i<numOfPlayers; i++)
{
ListOfPlayers.Add(new Players());
//or with initial values with ctor:
ListOfPlayers.Add(new Players("Ken", 100.00, playerHands));
//or
ListOfPlayers.Add(new Players(){name="Ken", bank=100.00, playerHands=_playerHands});
//ie: Players player = new Players("Ken", 100.00, playerHands);
}
}

Filling array with random "cards" of enum

Classic deck of cards/poker game issue. I have classes for each card (CardClubs, CardDiamond, etc). I have an enum for Rank (Deuce = 2, etc). In my CardSet class, I have the constructor:
public SuperCard[] cardArray;
public Random myRandom = new Random();
#region Constructor
public CardSet()
{
cardArray = new SuperCard[52];
for (int i = 0; i < 13; i++)
{
cardArray[i] = new CardClubs((Rank)i + 1);
cardArray[i + 13] = new CardDiamond((Rank)i+1);
cardArray[i + 26] = new CardHeart((Rank)i + 1); ;
cardArray[i + 39] = new CardSpades((Rank)i + 1); ;
}
}
#endregion
And I have the method GetCards, which passes in the number of cards to get. I created the public random up top. GetCards is called in the Program.cs, as such:
int howManyCards = 5; // can be whatever. used this instead of # for debug purposes
SuperCard[] computerHand = myDeck.GetCards(howManyCards); // create two hands, user/comp
SuperCard[] myHand = myDeck.GetCards(howManyCards);
I am not understanding how to use random to generate the random card. here is my current GetCard method (which isn't working) also from the CardSet class. For now, its okay if it generates the same card, just want to understand the basics of random selection.
public SuperCard[] GetCards(int number)
{
SuperCard[] hand = new SuperCard[number];
for (int i = 0; i < number; i++)
{
hand[i] = cardArray[myRandom]((Rank)i + 1);
}
return hand;
}
Use the Random class (http://msdn.microsoft.com/en-us/library/system.random.aspx)
var r = new Random();
r.Next(min,max);

My first c# app and first null object exception

Total noob here. This is my first c# attempt, its a console application that simulates a drinking game called 'Left Right Center'. In the console I receive the following:
CONSOLE
Unhandled Exception: System.NullReferenceException: Object reference not set to an instance of an object
at LeftRightCenter.MainClass.Main (System.String[] args) [0x00038] in /Users/apple/Projects/LearningC/LearningC/Main.cs:80
[ERROR] FATAL UNHANDLED EXCEPTION: System.NullReferenceException: Object reference not set to an instance of an object
at LeftRightCenter.MainClass.Main (System.String[] args) [0x00038] in /Users/apple/Projects/LearningC/LearningC/Main.cs:80
C#
using System;
namespace LeftRightCenter
{
class Player
{
//fields
private int _quarters = 4;
public int Quarters {
get{ return _quarters; }
set{ _quarters += value; }
}
public Player (string name)
{
}
}
class Dice
{
Random random = new Random();
public int Roll ()
{
random = new Random ();
int diceSide;
diceSide = random.Next (0, 6);
diceSide = (diceSide > 2) ? 3 : diceSide;
return diceSide;
}
}
class MainClass
{
static int activePlayer = 0;
static int theCup = 0;
static Player[] thePlayers = {
new Player ("Jessica"),
new Player ("Isaac"),
new Player ("Ed"),
new Player ("Bella"),
new Player ("Elisa"),
new Player ("Fake RedHead"),
new Player ("Linda"),
new Player ("MJ"),
new Player ("Irene"),
new Player("Devin")
};
static Dice[] theDice = new Dice[2];
private static void MoveQuarter (int direction)
{
int numberOfPlayers = thePlayers.Length - 1;
switch (direction) {
case 0:
thePlayers [activePlayer].Quarters = -1;
theCup++;
break;
case 1:
thePlayers [activePlayer].Quarters = -1;
int leftPlayer = (activePlayer == 0) ? numberOfPlayers : activePlayer - 1;
thePlayers [leftPlayer].Quarters = +1;
break;
case 2:
thePlayers [activePlayer].Quarters = -1;
int rightPlayer = (activePlayer == numberOfPlayers) ? 0 : activePlayer + 1;
thePlayers [rightPlayer].Quarters = +1;
break;
}
}
public static void Main (string[] args)
{
int cupEndPoint = thePlayers.Length * 4 - 1;
while (theCup < cupEndPoint) {
foreach (Dice rattle in theDice) {
if (thePlayers [activePlayer].Quarters > 0) {
MoveQuarter (rattle.Roll ()); // this line seems to be the problem
}
}
Console.WriteLine ("{0} Quarters In the Cup", theCup);
}
}
}
}
I have no idea what the problem is or why, and my googling have proven more use confusing than helpful.
For those who are curious, I have little experiment working now
http://pastebin.com/jxCCW2cd
This line
static Dice[] theDice = new Dice[2];
declares an array that allows the storage of 2 objects of the Dice class, but each value in this array is still null.
You need to create a Dice on each slot of the array before using it in the foreach loop inside the Main method.
theDice[0] = new Dice();
theDice[1] = new Dice();
if you stop the debugger on the line
MoveQuarter (rattle.Roll ());
you will see that the rattle Dice is null.
EDIT: Looking at your code I have found a problematic situations
In the Roll method, you recreate the Random generator and this is no good for randomness. (See the accepted answer in this question)
Last, theDice array could be created and initialized in the same way you already do for thePlayers array
static Dice[] theDice = new Dice[2] {new Dice(), new Dice()};
This is a complete revision of your Dice class
class Dice
{
private static Random random;
public Dice()
{
// create the static random generator only on the first instance
if(random == null) random = new Random();
}
public int Roll ()
{
int diceSide;
diceSide = random.Next (1, 7);
diceSide = (diceSide > 2) ? 3 : diceSide;
return diceSide;
}
}

XNA sorting score from array

I want to create a highscore board for my game.
the score board contain the top 5 scores in the text file
the text file are something like this:
alpha, 3500
beta, 3600
gamma, 2200
delta, 3400
epsilon, 2000
and this is my codes :
[Serializable]
public struct HighScoreData
{
public string[] PlayerName;
public int[] Score;
public int Count;
public HighScoreData(int count)
{
PlayerName = new string[count];
Score = new int[count];
Count = count;
}
}
static HighScoreData highScores;
this codes for reading data from text file and already add sorting in it:
try
{
using (StreamReader sr = new StreamReader("highscore.txt"))
{
string line;
int i = 0;
//file = new StreamReader(filePath);
while ((line = sr.ReadLine()) != null)
{
string[] parts = line.Split(',');
highScores.PlayerName[i] = parts[0].Trim();
highScores.Score[i] = Int32.Parse(parts[1].Trim());
i++;
Array.Sort(highScores.Score);
}
}
}
this is how I draw it :
for (int i = 0; i < 5; i++)
{
spriteBatch.DrawString(spriteFont, i + 1 + ". " + highScores.PlayerName[i].ToString()
, new Vector2(200, 150 + 50 * (i)), Color.Red);
spriteBatch.DrawString(spriteFont, highScores.Score[i].ToString(),
new Vector2(550, 150 + 50 * (i)), Color.Red);
}
the problem is when I run the game, it only sorting the scores and not the player name. and also, the first and secod scores in text file are identified as "0". it displayed like this :
alpha 0
beta 0
gamma 2000
delta 2200
epsilon 3400
what must I do, so the program can sorting all the data in the text file, not only the score...?
Another option without comparers using LINQ based on Blau's sample:
struct PlayerScore
{
public string Player;
public int Score;
public int DataYouWant;
}
then a sample of populating the list and sorting it:
List<PlayerScore> scores = new List<PlayerScore>();
Random rand = new Random();
for (int i = 0; i < 10; i++)
{
scores.Add(new PlayerScore()
{
Player = "Player" + i,
Score = rand.Next(1,1000)
});
}
scores = (from s in scores orderby s.Score descending select s).ToList();
foreach (var score in scores)
{
Debug.WriteLine("Player: {0}, Score: {1}", score.Player, score.Score);
}
Make a struct named PlayerScore
struct PlayerScore
{
public string Player;
public int Score;
public int DataYouWant;
public static int Compare(PlayerScore A, PlayerScore B)
{
return A.Score - B.Score;
}
}
and then to Sort call only one time, (outside the while) to the sort method this way:
Array.Sort<PlayerScore>( yourArray, PlayerScore.Compare );
Do you really need to have more than HighScoreData instance? I think that no.. so you store your highscores this way:
static PlayerScore[] highScores = new PlayerScore[MaxHighScorePlayers];

Categories

Resources