Issues loading different levels randomly in Unity-3D - c#

I need to create a class (or classes, if need be) that loads levels randomly every time the user clicks on the "Next Button" and once all levels have been loaded, we stop loading and close the application. I got the code set up but I am still not getting the result I am looking for which is:
User clicks on a button.
Load a random level
That levels gets stored in an array list
Once the user is done with that level he/she presses the "Load Next Level" button
Load the next random level
But first, we check if the random level is not the same as before.
If it's not, then we repeat steps 2-5, else we go to step 8
If the levels have all been visited then we quit the application
The problem I am having is that my game loads the same level every time I hit play and it doesn't go to the next scene after I am done with the current one. This is what I have so far:
using UnityEngine;
using System.Collections;
[ExecuteInEditMode]
public class SceneManager : MonoBehaviour
{
public static bool userClickedNextButton; //This flag is raised by the other classes that have the GUI button logic
protected const int MAX = 2;
private ArrayList scenesWereAlreadyLoaded = new ArrayList();
void Update()
{
if (userClickedNextButton)
{
//by default the game starts at 0 so I want to be able to
//randomly call the next two scenes in my game. There will
//be more levels but for now I am just testing two
int sceneToLoad = Random.Range(1, 2);
if (!scenesWereAlreadyLoaded.Contains(sceneToLoad))
{
scenesWereAlreadyLoaded.Add(sceneToLoad);
Application.LoadLevel(sceneToLoad);
}
userClickedNextButton = false;
}
if (scenesWereAlreadyLoaded.Count > MAX) { Application.Quit(); }
}
}

You create a list with your level numbers, then remove the currently loaded level. You repeat that until the list is empty.
Also don't use ArrayList, it's very old and deprecated type, from the ages before .NET/Mono had Generic support. Better use a Generic List<T>, which is type safe and faster than ArrayList.
using UnityEngine;
using System.Collections;
using System.Linq;
using System.Collections;
using System.Collections.Generic;
[ExecuteInEditMode]
public class SceneManager : MonoBehaviour
{
// not best idea to have it static
public static bool userClickedNextButton;
protected const int MAX = 50;
private List<int> scenes = new List<int>();
void Start() {
// Initialize the list with levels
scenes = new List<int>(Enumerable.Range(1,MAX)); // This creates a list with values from 1 to 50
}
void Update()
{
if (userClickedNextButton)
{
if(scenes.Count == 0) {
// No scenes left, quit
Application.Quit();
}
// Get a random index from the list of remaining level
int randomIndex = Random.Range(0, scenes.Count);
int level = scenes[randomIndex];
scenes.RemoveAt(randomIndex); // Removes the level from the list
Application.LoadLevel(level);
userClickedNextButton = false;
}
}
}

As per the Unity3D documentation (http://docs.unity3d.com/Documentation/ScriptReference/Random.Range.html), range returns an integer between min (included) and max (excluded), so, in your case, Random.Range(1,2) will always returns 1.
Try with this
int = sceneToLoad = Random.Range(1,3)

There is an easier way to do so. You can prepare an array with random unique numbers. When you want to load a new level just increment the index of the array.
Here's a code that can help:(Attach this script to an empty gameobject in your first scene)
using UnityEngine;
using System.Collections;
public class MoveToRandomScene : MonoBehaviour {
public Texture nextButtonTexture; // set this in the inspector
public static int[] arrScenes;
public static int index;
void Start () {
index = 0;
arrScenes = GenerateUniqueRandom (10, 0, 10); //assuming you have 10 levels starting from 0.
}
void OnGUI {
// Load the first element of the array
if (GUI.Button(new Rect (0,0,Screen.width/4,Screen.height/4),nextButtonTexture))
{
int level = arrScenes [0] ;
Application.LoadLevel (level);
}
}
//Generate unique numbers (levels) in an array
public int[] GenerateUniqueRandom(int amount, int min, int max)
{
int[] arr = new int[amount];
for (int i = 0; i < amount; i++)
{
bool done = false;
while (!done)
{
int num = Random.Range(min, max);
int j = 0;
for (j = 0; j < i; j++)
{
if (num == arr[j])
{
break;
}
}
if (j == i)
{
arr[i] = num;
done = true;
}
}
}
return arr;
}
}
For the other scenes you just need to create this script and attach it to an empty game object whenever you want to load a new random scene:
void OnGUI {
if (GUI.Button(new Rect (0,0,Screen.width/4,Screen.height/4),nextButtonTexture))
{
if (MoveToRandomScene.index == 9) {
// Load again your first level
Application.LoadLevel(0);
}
// else you continue loading random levels
else {
MoveToRandomScene.index++;
int level = MoveToRandomScene.arrScenes[MoveToRandomScene.index];
Application.LoadLevel(level);
}
}
}

Related

How to activate and deactivate GameObjects with a delay in Untiy

I am working on a game, that has a keypad puzzle. A specific key combination lights up one by one, which the player must repeat to solve that puzzle. I am going to let the player know what the combination is by activating and deactivating some GameObjects systematically, one by one. As it suggests, there is some time delay between the deactivation of one GameObject and the activation of another. The problem is, in my code, all the GameObjects activate simultaneously instead of one by one, after a delay.
Here is the code:
public string Generate(int length, float delay)
{
// Variables for logic
string combination = "";
int prev = -1; int current = 0;
int rnd = 0;
for (int i = 0; i < length; i++)
{
rnd = Random.Range(0, BUTTONS);
while (rnd == prev)
{
rnd = Random.Range(0, BUTTONS);
}
prev = current;
current = rnd;
combination += current.ToString();
// Activation and Deactivation
StartCoroutine(GenerateDelay(delay, current));
}
return combination;
}
IEnumerator GenerateDelay(float delay, int index)
{
ButtonClicks[index].SetActive(true);
yield return new WaitForSeconds(delay);
ButtonClicks[index].SetActive(false);
}
The loop counter specifies the length of the combination. I believe there is something wrong with the Coroutine I made? Since all the objects activate simultaneously.
Here is the result in the game as well:
We can see, only one button should turn green at a time, but all of them do in this case. Any solutions?
You start all your Coroutines parallel so things happen at the same time.
StartCoroutine does not delay the method which calls it (unless it is yielded as well.
You would need to run the entire loop within a Coroutine in order to delay it as well.
You could simply split up the creation of the combination and while you already return it you start the visualization in the background in parallel
public string Generate(int length, float delay, Action<string> onCombination)
{
// Variables for logic
var combination = List<int>();
var prev = -1;
for (var i = 0; i < length; i++)
{
int rnd;
do
{
rnd = Random.Range(0, BUTTONS);
}
while (rnd == prev);
prev = rnd;
combination.Add(rnd);
}
StartCorouine (ShowCombination(combination, delay));
return string.Join("", combination);
}
private IEnumerator ShowCombination (IEnumerable<int> combination, float delay)
{
foreach(var i in combination)
{
ButtonClicks[i].SetActive(true);
yield return new WaitForSeconds(delay);
ButtonClicks[i].SetActive(false);
}
}
something alot easier then a coroutine is invoking a function, basically create a function to activate/deactivate the wanted object and whenever you want to call it do:
Invoke("FUNCTIONNAME", TIME);
and it will run the function specified after the TIME.

for loop with counter not working after adding input

I have this counter programm based on object oriented programming in C# and
the counter has an Increment Method which counts up so like it goes from 0..1...2.. to 30.
The for loop was working perfectly fine but then I decided to add a class with two Methods that either count up in odd or even steps which also works fine. The only problem is that after changing the main class now it doesn't work in a loop anymore until its on 30, so I have to enter every step individually.
This is my main code (I'm pretty sure the problem is due to the Console.ReadLine and input in general but I don't know what exactly is the issue)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Counter
{
class Program
{
static void Main(string[] args)
{
char confirm;
int input;
do
{
//int inNum;
Console.Clear();
ModusCounter b = new ModusCounter(0, 30);
for (; ; )
{
b.Display(19, 7);
Console.Write("do you want (1)odd // (2) even // (0)standard ? ");
input = Convert.ToInt32(Console.ReadLine());
if (input == 1)
{
b.OddCount();
}
else if (input == 2)
{
b.EvenCount();
}
else
b.Increment();
System.Threading.Thread.Sleep(300);
if (Console.KeyAvailable) break;
}
//b.Increment();
b.Display(19, 7);
Console.WriteLine();
Console.WriteLine();
Console.WriteLine("do you want to restart? (J // N) ");
confirm = Convert.ToChar(Console.ReadLine());
}
while (confirm == 'J');
Console.ReadLine();
}
}
}
ModusCounter:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Counter
{
public class ModusCounter:CCounter
{
private int wholenum;
public int Wholenum
{
get => wholenum;
set
{
wholenum = value;
}
}
public ModusCounter(int start, int limit) : base(start, limit)
{ }
public void EvenCount() //2
{
Wholenum = 2;
Level += Wholenum;
if (Level % 2 == 0)
{
Level += Wholenum - 2;
}
else
{
Level += Wholenum -1;
}
if (Level > Limit)
Level = Start;
}
public void OddCount() //1
{
Wholenum = 1;
Level += Wholenum;
if (Level % 2 == 0)
{
Level += Wholenum;
}
else
{
Level += Wholenum + 1;
}
if (Level > Limit)
Level = Start;
}
}
}
base class:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Counter
{
public class CCounter
{
private int start;
private int limit;
private int level;
public int Start
{
get => start;
protected set
{
start = value;
}
}
public int Limit
{
get => limit;
protected set
{
limit = value;
}
}
public int Level
{
get => level;
protected set
{
if (value < Start)
level = Start;
else if (value > Limit)
Level = Limit;
else
level = value;
}
}
public CCounter(int start_, int limit_)
{
Start = start_;
Limit = limit_;
Level = Start;
}
public void Increment()
{
int level = Level + 1;
if (level > Limit9
Level = Start;
else
Level = level;
}
public void Display(int x_, int y_)
{
Console.SetCursorPosition(x_, y_);
Console.Write(Level.ToString("00"));
}
}
}
First, welcome to S/O. Hope you get good info out here during your obvious learning curve into development. A couple things could get simplified, but that will come with learning, so I wont pounce, but you will see as your skills improve over time.
First, your for(;;) loop. That is in-itself causing an infinite loop. The console read line to get input is always waiting for the next option from your prompt asking for odd, even or standard, so it keeps cycling through.
I dont think your Console.KeyAvailable is ever really getting triggered to break out of the for loop to get you to the next prompt of allowing the user to retry J/N option. You have the console.ReadLine which reads the entire buffer until you hit the enter key. By that time, you are incrementing your cycle, displaying the results and giving a 300 millisecond delay from your Thread.Sleep(300) call, of which you are probably not clicking a key in that short span to break the loop. Now, if you changed the Thread.Sleep(2000) you would be giving the user 2 seconds (1 second = 1000 milliseconds) AFTER the display to press any key to break the loop.
Next item/question I have for you. Your incrementing you appear to be ok with that functionality, but what / why do you want to break. When it gets to the limit? If so, then test for that after the increment process has completed such as (before the Thread.Sleep call)
if (b.Level >= b.Limit)
break;
Getting to your CCounter class and looking at its Increment method. You have a check that if the local "level" variable is greater than the limit to set the level = START value. Was that intended, or not. Also, by using a new int value by the same name as a property on your class (int level vs property level) is not a good practice and can add confusion.
public void Increment()
{
int level = Level + 1;
if (level > Limit)
Level = Start;
else
Level = level;
}
It appears you are trying to use a local temporary variable but is not necessary. It could just as easily be done with slight alteration as I have below.
public void Increment()
{
if (Level +1 > Limit)
Level = Start;
else
Level = Level +1;
}
Because I am not ASSIGNING a value to the "Level" public property, it in essence is doing the +1 before its COMPARISON to the LIMIT property. Only in the ELSE condition do I assign.
Also, a shortcut on adding to a variable or subtracting could be seen as
Level++
or
Level--
Hopefully this helps add SOME clarity to what you are looking to get resolution to and can get you further in your development.

When trying to display a hand of cards from a shuffled deck, it fills every hand with the Ace of Clubs

This is my first time using C#. I have to convert an old project from Java. The old project works, but when I attempted to convert it, something went wrong? The Card class sets the default card to the Ace of Spades, but it is displaying Ace of Clubs. Ace and Clubs are each the first listed of the enums so I guess it is not using the default?
Since it is displaying the same card I thought it would be something wrong with my shuffle method..but I am unsure at this point.
There is a Card, Deck, and Hand class. Then Enums for Suit and Face.
UPDATE: I believe the error is in the method directly below? I need to figure out how to use the 'n' in c#. It is needed in a different class.
In Java I had it as:
public Card(int n)
{
face = Face.values()[n % 13];
suit = Suit.values()[n % 4];
} //end Card (int n) method
c#:
public Card(int n) //??
{
var face = (Face) 13;
var suit = (Suit) 4;
}
The code above is in the Card class? I know that is not too helpful, but the only other way it to post ALL of the code here.
//Some of the Deck class
public void Shuffle()
{
Random ran = new Random();
for (int nextCard = 0; nextCard < deck.Length; nextCard++)
{
Card hold = deck[nextCard];
int random = ran.Next(deck.Length);
deck[nextCard] = deck[random];
deck[random] = hold;
}
}
public Card DealACard()
{
if (nextCard > 51)
{
return null;
}
return deck[nextCard++];
}
public Hand DealAHand(int handSize)
{
Hand hand = new Hand(handSize);
for (int i = 0; i < handSize; i++)
{
hand.AddCard(DealACard());
}
return hand;
}
//Some of the Hand Class
public void AddCard(Card card)
{
hand[cardsInHand] = card;
cardsInHand++;
}
public override string ToString()
{
String handToString = ""; //string to hold display format
//for loop to display each card in a hand
for (int n = 0; n < cardsInHand; n++)
{
handToString += hand[n].ToString() + "\n";
}
return handToString;
}
// Driver Class
Deck deck1 = new Deck();
int cardsToGet = 53;
do
{
Console.Write("How many cards are in one hand? ");
int handSize = Convert.ToInt32(Console.ReadLine());
// int handSize = Console.Read();
Console.Write("How many players are playing? ");
int players = Convert.ToInt32(Console.ReadLine());
cardsToGet = handSize * players;
if (cardsToGet < 53) // if to shuffle deck and display players' hands
{
deck1.Shuffle();
for (int i = 0; i < players; i++) // displays each players hand
{
Console.WriteLine("\nPlayer " + (i + 1) + ":");
Console.WriteLine(deck1.DealAHand(handSize));
}
}
else
{
Console.WriteLine("\nThere are not enough cards in the deck to deal " + players + " hands of " + handSize + " cards. Try again.\n");
}
}
while (cardsToGet > 52);
It is suppose to ask for a number of cards per hand and a number of players then displays a hand for each player without duplicating cards. Currently, it fills every players hand with Ace of Clubs. There are no errors showing.
Now that you've updated your question, this is answerable. The mistake is in your Card constructor, which no matter the value of n that you pass in, creates every card with the Face with value 13 and the Suit with value 4. You have the right method for turning an int into a Face or Suit enum (just cast it), so you just need to do the modulo operation like your Java version did:
public Card(int n)
{
var face = (Face) n % 13;
var suit = (Suit) n % 4;
}
Well, almost. The var keyword in C# just creates a local variable that's not visible outside the scope it's declared in: in this case, the constructor. What you meant to do is assign values to instance properties of your Card class. You haven't shown us what those properties are named, but I'm going to assume they're named Face and Suit (with initial uppercase as is C# naming convention); rename as appropriate:
public Card(int n)
{
this.Face = (Face) n % 13;
this.Suit = (Suit) n % 4;
}
And now your cards should all be different, rather than all being the ace of clubs.
Hello TJ and welcome to S/O, coming from other languages can be a learning curve. Same as if I switched to Java. I quickly threw this together to introduce working with lists and classes within C#. Not perfect, but does what you are looking to get at. Hope it helps. I originally wrote this with C# via a WPF application vs Console app, but the core is all the same (only thing that would be different is the "MessageBox.Show()" that shows each hand vs the Console output which I also included.
I am notorious for commenting through my code and hope this all (or most of it) makes sense as you dive into C#...
I'm starting with enums for the card faces and suits.
public enum CardFace
{
Two = 0,
Three = 1,
Four = 2,
Five = 3,
Six = 4,
Seven = 5,
Eight = 6,
Nine = 7,
Ten = 8,
Jack = 9,
Queen = 10,
King = 11,
Ace = 12
}
public enum CardSuit
{
Hearts = 0,
Clubs = 1,
Diamonds = 2,
Spades = 3
}
Next, a class to represent a single card
public class SingleCard
{
public CardFace Face { get; set; }
public CardSuit Suit { get; set; }
// place-holder for randomizing cards
public int RndNumber { get; set; }
// return the name of the card based on it's parts as single string
public string NameOfCard { get { return $"{Face} of {Suit}"; } }
}
Now, the class for building the initial deck of cards, shuffling, dealing and displaying the cards (of the entire deck, or of the individual hands)
public class DeckOfCards
{
public List<SingleCard> SingleDeck { get; private set; } = new List<SingleCard>();
public List<SingleCard> ShuffledDeck { get; private set; }
// create a single random generator ONCE and leave active. This to help prevent
// recreating every time you need to shuffle and getting the same sequences.
// make static in case you want multiple decks, they keep using the same randomizing object
private static Random rndGen = new Random();
public DeckOfCards()
{
// build the deck of cards once...
// Start going through each suit
foreach (CardSuit s in typeof(CardSuit).GetEnumValues())
{
// now go through each card within each suit
foreach (CardFace f in typeof(CardFace).GetEnumValues())
// Now, add a card to the deck of the suite / face card
SingleDeck.Add(new SingleCard { Face = f, Suit = s });
}
// so now you have a master list of all cards in your deck declared once...
}
public void ShuffleDeck()
{
// to shuffle a deck, assign the next random number sequentially to the deck.
// don't just do random of 52 cards, but other to prevent duplicate numbers
// from possibly coming in
foreach (var oneCard in SingleDeck)
oneCard.RndNumber = rndGen.Next(3901); // any number could be used...
// great, now every card has a randomized number assigned.
// return the list sorted by that random number...
ShuffledDeck = SingleDeck.OrderBy( o => o.RndNumber).ToList();
}
public void DisplayTheCards( List<SingleCard> theCards )
{
// show the deck of cards, or a single person's hand of cards
var sb = new StringBuilder();
foreach (var c in theCards)
sb = sb.AppendLine( c.NameOfCard );
MessageBox.Show(sb.ToString());
}
public void ConsoleDisplayTheCards(List<SingleCard> theCards)
{
// show the deck of cards, or a single person's hand of cards
foreach (var c in theCards)
Console.WriteLine(c.NameOfCard);
}
public List<List<SingleCard>> DealHands( int Players, int CardsPerHand )
{
// create a list of how many hands to be dealt...
// each player hand will consist of a list of cards
var Hands = new List<List<SingleCard>>(Players);
// prepare every players hand before dealing cards
for (var curPlayer = 0; curPlayer < Players; curPlayer++)
// each player gets their own list of cards
Hands.Add( new List<SingleCard>());
// prepare card sequence to deal
var nextCard = 0;
// loop for as many cards per hand
for (var oneCard = 0; oneCard < CardsPerHand; oneCard++)
{
// loop every player gets a card at a time vs one player gets all, then next player
for (var curPlayer = 0; curPlayer < Players; curPlayer++)
// add whatever the next card is to each individual's hand
Hands[curPlayer].Add(ShuffledDeck[nextCard++]);
}
return Hands;
}
}
I did not include the input of getting how many players, how many cards as you already had that. I also did not validate total cards to be dealt as you had that too. HTH

Creating a dice that doubles and continues to roll if it lands on a specific number in C#?

I am trying to make a program that I Believe has to make use of recursion. In short: create a program that will throw a Dice. If it lands on a 6, two Dices are created and rolled, and so on until no more 6 are rolled.
The problem is not creating a new or true random object, but the recursive Dices.
The recursion method looks like this:
public static int Recursion(int a)
{
Random m = new Random();
if (a < 6)
{
return a;
}
else
{
a = m.Next(1, 7);
return Recursion(a) * 2;
}
}
Possibly something like this?
public static int Roll() {
return Roll(new Random(), 1);
}
public static int Roll(Random random, int diceCount) {
int sum = 0;
for (int dice = 1; dice <= diceCount; ++dice) {
int rolled = random.Next(1, 7);
if (rolled == 6) {
sum += Roll(random, 2)
}
else
{
sum += rolled;
}
}
return sum;
}
So, first I roll one die/dice. If it is not 6, then I accept its value as the result. If it is six, then I remove that die/dice, and replace it with two other I roll. Then, for each of the new ones I follow the same rule, until all the dice on the table is rolled and none of them is 6. Now I sum all the value of dice. This is what this recursive algorithm does. Note, that - however it has infinitely low chance - you can play this until the end of times, since there is always chance of rolling 6, so you can possibly roll only 6's until you die.
You can make it more object oriented by creating a dice object:
using System;
using System.Collections.Generic;
class Dices
{
public class Dice
{
private static Random roler = new Random();
private int roledNumber;
public int Role()
{
roledNumber = roler.Next(6) + 1 ;
return roledNumber;
}
public int Number
{
get { return roledNumber; }
}
}
static void Main(string[] args)
{
List<Dice> allDices = new List<Dice>();
Dice firstDice = new Dice();
allDices.Add(firstDice);
if (firstDice.Role() == 6) createDices(allDices);
}
static void createDices(List<Dice> dices)
{
Dice first = new Dice();
dices.Add(first);
if (first.Role() == 6) createDices(dices);
Dice second = new Dice();
dices.Add(second);
if (second.Role() == 6) createDices(dices);
}
}

How to prevent same object from being picked from array twice in a row

I am having a bit of a problem figuring out how to randomly get an object out of a list that wasn't picked on the last update of a script. When this randomly instantiated object is spawned and reaches a certain y value, it will set itself to inactive. So when this object is not active, it will go through an array and pick another object at random. However, I do not want to include the previous active object.
example: blue ball was first active. Moves on the Y axis. Becomes inactive. Next object spawn should have no chance of being a blue ball. Any ideas and help will be greatly appreciated.
My code is below
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class ballGeneratorShooter : MonoBehaviour
{
private int ballSelector;
private TagNumber theTagNumber;
public ObjectPooler[] theObjectballPools;//In my inspector, I have 5 prefab gameObjects attached
List<ObjectPooler> changingBalls;
public bool changeBalls;
public GameObject currentBall;
public GameObject newBall;
// Use this for initialization
void Start()
{
changingBalls = new List<ObjectPooler>();
currentBall = newBall;
}
// Update is called once per frame
void Update()
{
if (newBall == null)
{
ballSelector = Random.Range(0, theObjectballPools.Length);
newBall = theObjectballPools[ballSelector].GetPooledObject();
newBall.transform.position = transform.position;
newBall.transform.rotation = transform.rotation;
newBall.SetActive(true);
}
if (newBall.activeInHierarchy == false)
{
if (changeBalls)
{
for (int i = 0; i < theObjectballPools.Length; i++)
{
if (theObjectballPools[i].GetPooledObject().GetComponent<TagNumber>().tag != currentBall.GetComponent<TagNumber>().tag)
{
changingBalls.Add(theObjectballPools[i]);
}
//changingballs.Add(theObjectballPools[i]);
}
ballSelector = Random.Range(0, changingBalls.Count);
newBall = theObjectballPools[ballSelector].GetPooledObject();
Debug.Log(changingBalls.Count);
newBall.transform.position = transform.position;
newBall.transform.rotation = transform.rotation;
newBall.SetActive(true);
currentBall = newBall;
changeBalls = false;
changingBalls.Clear();
}
}
}
}
You need to store the random number to variable (lastRandomNum) each time you generate a random number. Now, use the function below that can generate a random number with exclusion.
int RandomWithExclusion(int min, int max, int exclusion)
{
var result = UnityEngine.Random.Range(min, max - 1);
return (result < exclusion) ? result : result + 1;
}
You pass in 0 to min, then theObjectballPools.Length or changingBalls.Count to the max, then finally, lastRandomNum value to the exclusion parameter.
You also need a boolean variable to determine if this is the first run. If this is the first run, use the Unity's Random.Range function then set the firstRun to false. If it is not the firstRun, use the RandomWithExclusion function from this answer and pass in the lastRandomNum value to exclude it. Also, store the generated random number to the lastRandomNum variable to be used next frame.
Below is a simplified version of what I said above. You have to incorporate that to your code.
GameObject[] yourItem = null;
bool firstRun = true;
int lastRandomNum = 0;
void Update()
{
if (firstRun)
{
firstRun = false;
//First run, use Random.Range
lastRandomNum = UnityEngine.Random.Range(0, yourItem.Length);
}
else
{
//Not First run, use RandomWithExclusion
lastRandomNum = RandomWithExclusion(0, yourItem.Length, lastRandomNum);
}
//Do something with the lastRandomNum value below
newBall = theObjectballPools[lastRandomNum].GetPooledObject();
}
int RandomWithExclusion(int min, int max, int exclusion)
{
var result = UnityEngine.Random.Range(min, max - 1);
return (result < exclusion) ? result : result + 1;
}
Try linq :
public class Ball
{
public static List<Ball> balls = new List<Ball>();
public int value { get; set; }
public Boolean active { get; set; }
public Ball() {}
public Ball(int size)
{
// initial class
Random rand = new Random();
for (int i = 0; i < size; i++)
{
balls.Add(new Ball(){ value = rand.Next(), active = false});
}
}
public Ball GetRandom()
{
Random rand = new Random();
Ball randomBall = balls.Where(x => x.active == false).Select((x) => new { value = x, randX = rand.Next() }).OrderBy(x => x.randX).FirstOrDefault().value;
randomBall.active = true;
return randomBall;
}
}

Categories

Resources