Console log
My list is adding the sprite name and converting it to an integer to add to a list, then I created a function to show the list but whenever I show the list in the update loop, it alternates between showing just 0's
and actual values. and when I don't put it in an update loop it only shows 0's
public class ballMove : MonoBehaviour {
int[] BallOrder = new int[5]; // me initializing the variable in the
beginning of the program
// int[] BallOrder = {4,6,3,2,7}; if I do this instead of showing 0's it
shows 4,6,3,2,7 when I click the mouse down.
void CreateBalls(int HowMany) {
// makes balls with a unique picture size and position
for (int i = 0; i < HowMany; i++) {
BallClone = Instantiate(Ball);
BallPic = BallClone.GetComponent<SpriteRenderer>();
// give each ball a random image, each image is a number
RandImg();
// just using i for testing purposes.
BallOrder[i] = i;
//array should just be 1,2,3,4,5
}
}
void ShowList()
{
System.Array.Sort(BallOrder);
string text = "";
for (int i = 0; i < BallOrder.Length; i++)
{
text = (text + " " + BallOrder[i]);
}
print(text);
}
void Update()
{
// here it shows the array correctly 1,2,3,4,5
ShowList();
}
void OnMouseDown() {
string BallNum = ConvertSprite(GetComponent<SpriteRenderer>().sprite);
int test = int.Parse(BallNum);
ShowList(); // here when I show list it just shows 0,0,0,0,0
Destroy(gameObject);
}
}
Just to give an answer to the question that is not in comments, the issue was that the console was printing out what could be considered bad data.
By alternating between what was expected (6 random numbers) and not expected (6 zeroes), clearly, the function was being called twice, but from further additions of code snippets, there was no reason as to why the function would be called multiple times.
From the initialization of the array data, the only way for there to be 6 zeroes instead of data was that the data was being overwritten or that it was never initialized. As the array is never written to again after the initialization, it must have meant that it was initialized incorrectly.
The only way for this to have occurred is by having the script attached to two objects in the scene where one is properly initializing the data and the other is not as the initialization occurred in Start.
The solution is to remove the unused script from one of the two objects in the scene.
Related
I have this code but looks like the random is activating the same gameobject. How can I be sure that not the same will be activated? For example, this code activate 2 gameobjects but sometimes just only one, because the random picked the same gameobjects twice.
for (int i = 0; i < 2; i++)
{
int index = Random.Range(0, EyeButtonArray.Length);
EyeButtonArray[index].SetActive(true);
}
You can shuffle your container randomly and pick the first two elements.
int wanted = 2;
int[] nums = System.Linq.Enumerable.Range(0, EyeButtonArray.Length).ToArray();
System.Random rnd = new System.Random();
nums = nums.OrderBy(x => rnd.Next()).ToArray();
for(int x = 0; x < 2; ++x)
EyeButtonArray[nums[x]].SetActive(true);
Another solution using a HashSet is to keep track of the elements you have picked and keep generating until you pick a unique one.
HashSet<int> RandomElementIdx = new HashSet<int>();
int picked = 0;
int wanted = 2;
while(picked < wanted)
{
int index = Random.Range(0, EyeButtonArray.Length);
if(RandomElementIdx.Contains(index))
continue;
RandomElementIdx.Add(index);
EyeButtonArray[index].SetActive(true);
++picked;
}
The above snippet is assuming your list is greater than or equal to wanted. If it is less, it will result in an infinite loop. It is also not exactly efficient as it will continually try to spawn new numbers until it randomly hits one not used.
It sounds like what you want is
You have a list/array of objects
You want to enable the next two random ones of them
(optionally - not sure on this) you want to disable the two current ones
You could simply "shuffle" your array and then enable the two first of the now shuffled items like e.g.
using System.Linq;
...
// OPTIONAL (but I thought makes sense)
// store the currently enabled objects to also be able to disable them later
// when you enable the next pair
private GameObject[] _currentEnabled;
public void EnableTwoRandom()
{
// OPTIONAL (but I thought makes sense)
// if exists first disable the last selected two buttons
if(_currentEnabled!=null)
{
foreach(var item in _currentEnabled)
{
item.SetActive(false);
}
}
// Pick two random buttons
// This first "shuffles" the buttons and then simply takes the
// first two random elements
_currentEnabled = EyeButtonArray.OrderBy(i => Random.value).Take(2).ToArray();
// enable the new two random buttons
foreach(var item in toEnable)
{
item.SetActive(true);
}
}
See
IEnumerable.OrderBy
Random.value
IEnumerable.Take
if additionally you want to be sure that the new selected buttons are also not equal to the previous ones you could add
// Pick two random buttons
if(_currentEnabled != null)
{
// if there already exists a previous selection
// then exclude this selection from the available options first
_currentEnabled = EyeButtonArray.Except(_currentEnabled).OrderBy(i => Random.value).Take(2).ToArray();
}
else
{
_currentEnabled = EyeButtonArray.OrderBy(i => Random.value).Take(2).ToArray();
}
See
IEnumerable.Except
I need some help in programming. I have a list that holds int numbers and I need to convert them to an array of strings and print them one by one all the elements. My code is all in the Update function and if I print an array in the Update function, it will run many times and will print many values. So I just need to somehow call a function that prints an array after a value has been stored or print all the values stored in the array at once.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PrintData: MonoBehaviour
{
float tmp = 0;
public List<int> CheckKeyPress = new List<int>(); //this is list that will
//have only 0 if user pressed key Z and only 1 if user presses key X. It will
//store in list 20 values (of 0 or 1).
void Update()
{
// Here I check what did the user press after they hear some sound.
tmp += Time.deltaTime;
if ((Input.GetKey(KeyCode.Z)))
{
if (tmp >= 1) //I do this following someone's advice. Otherwise all
//this code wouldn't work in update function
{
CheckKeyPress.Add(0);
}
tmp = 0;
}
else if (Input.GetKey(KeyCode.X))
{
if (tmp >= 1)
{
CheckKeyPress.Add(1);
}
tmp = 0;
}
//Here I want to make the array of strings from the list called
//"CheckKeyPress ",and print all elements one by one.
}
}
I would like either to print the elements of array one by one (at the time they get store in lists) or to print them all after the list gets the all 20 elements.
You could use string.Join() to join all items from your List<int>, separating them by the specified separator:
Debug.Log(string.Join(",", CheckKeyPress.ConvertAll(x => x.ToString()).ToArray()));
I'm working on something for school, just a basic score calculator. I know it's not the prettiest code, but it works and that's more what the class is focused on here at the beginning.
The only issue that I have is that whenever I click "Display" it prints out 20 0s. 20 is the length of the array. Everything else is working. It adds the number I input into the array and replaces the 0s. But I don't want it to have 0s at all unless I specifically type them in.
Any help is appreciated.
Full code:
// Creates the list that displays the score
List<string> scoreList = new List<string>();
// Array to store up to 20 scores
int[] scoreArray = new int[20];
// class level variable to store current open slot in the array
int openSlot = 0;
public Form1()
{
InitializeComponent();
}
// Initializes variables that hold our math total and count of numbers entered
int total = 0;
int count = 0;
private void btnExit_Click(object sender, System.EventArgs e)
{
this.Close();
}
private void btnAdd_Click(object sender, System.EventArgs e)
{
if (openSlot <= scoreArray.GetUpperBound(0))
{
try
{
// Basic math for conversion of entered number and calculating total numbers entered
// and the averages of those numbers
int score = Convert.ToInt32(txtScore.Text);
total += score;
count += 1;
int average = total / count;
txtScoreTotal.Text = total.ToString();
txtScoreCount.Text = count.ToString();
txtAverage.Text = average.ToString();
txtScore.Focus();
}
catch(System.FormatException) // Makes sure that the user enters valid character into box
{
MessageBox.Show("Please enter valid number into box");
return;
}
// Adds the most recent entered number to the Score List
scoreList.Add(txtScore.Text);
}
// if statement to make sure that there is still room in the array to store the
// new entry
if (openSlot > scoreArray.GetUpperBound(0)) // GetUpperBound(0) returns the index of the last element in the first dimension
{
MessageBox.Show("The array is full! The most recent number was not added.");
txtScore.SelectAll();
txtScore.Focus();
return;
}
// Assigns a variable as an integer from the score text box
// to allow us to numerically sort the numbers in the scoreArray
int scoreParse = Int32.Parse(txtScore.Text);
// move the most recent number to the current open slot in the score array
scoreArray[openSlot] = scoreParse;
// add 1 to openSlot
openSlot += 1;
}
private void btnClear_Click(object sender, EventArgs e)
{
// Clears all input fields and resets variables to 0
openSlot = 0;
total = 0;
count = 0;
txtScore.Text = "";
txtScoreTotal.Text = "";
txtScoreCount.Text = "";
txtAverage.Text = "";
txtScore.Focus();
// Clears the array and list
int[] clearScoreArray = new int[20];
scoreArray = clearScoreArray;
List<string> clearScoreList = new List<string>();
scoreList = clearScoreList;
}
private void btnDisplay_Click(object sender, EventArgs e)
{
// If array has no stored values, display a MessageBox that informs user
if (scoreArray == null || scoreArray.Length == 0)
{
MessageBox.Show("There are no numbers to display");
return;
}
//move focus to the code textbox
txtScore.Focus();
// Creates a blank string variable named scr to input the scores into
// for the MessageBox
string scr = "";
foreach (var scoreAdded in scoreArray)
{
// Adds variable scr as the string to display
scr += scoreAdded + "\n";
}
// Sorts the array from lowest to highest number
Array.Sort(scoreArray);
// Displays a message box with the scores that were added
MessageBox.Show(scr);
}
}
When you declare a set amount of arrays (In your place it's 20), they get some sort of value, normally it's 0. Keep this is mind when you are using myArrayHere.length, cause it will check how many arrays have been declared (int[] array) and initialized (... = new array[]), not how many have been modified (given a value).
Best solution, IMO is creating a function, that would know how many elements in an array you will need or how many of them you are using (just have a function, that returns the amount of used variables, by checking it with a loop, and then modifying it later on... but that is one way to fix this issue, and there are better fixes than these I pointed out, but as I see you are newer to C# (prob.) fixing your issues with ok'ish code is good, as your first project should be meant for learning, later on, you can improve it and heck, if you are looking to become a pro, take some Programming courses on how to improve your code in general).
Good luck!
-Normantas
You can use nullable if you dont want zero as default value.
int? [] array = new int?[20] ;
Welcome to SO!
When an object is initially declared there is a default initialization value. In this case, 0 is the default value for an int in C#. The default value can often be changed at the initialization of the object if there's a supporting constructor.
When the int[] scoreArray = new int[20]; is declared, all 20 variables are assigned the value of 0. This is because C# does not allow uninitialized variables.
This link shows all default initialization values for C#.
https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/default-values-table
I have a list that contains file names like f1, f2, f3,...,f6. my
program needs to output a list with file names appearing in
random order such as f4,f1,f6,f2,f3,f5.
I want to swap or shift string correctly inside a list I have a list of
size 6 named fileName already containing 6 different file names I
am swapping file names inside of a list fileName as follows and fil
is also a string for remembering current string or file name.
temp =-1;
foreach (Control control in tableLayoutPanel1.Controls) // run loop untill every control inside tablelayoutpanel1.Controls is check or read
{
Button btns = control as Button; // btn sotre the
current button in table.contr
if (btns != null) // check btn got a button from
the panel then
{
temp++;
int randomNumber = 0;
randomNumber = theArray[temp]; //this pic the random number from 0 index then 1 so on theArray already contains random number from 0 to 5 without any repitition and also tested
fil = fileName[randomNumber]; //fil for holding string
fileName[temp] = fileName[randomNumber]; // at filname[0]
swap or shift filename[randomNumber] random are between 0 to
5 and without repitition
fileName[randomNumber] = fil; // this line isnt even necessary
but to be safe i wrot
btns.BackgroundImage = images[randomNumber]; // change
btn image to current random image
copyImages.Add(images[randomNumber]);
btns.BackgroundImage = null; // i purposely doing this :)
}
Using that code I am able to swap string but I cant swap them
correctly as it only run for 6 times so it should swap 6 strings
(each with different name) inside the list on 6 different location
inside the list fileName but its not happening some strings are
showing twice or thrice, hoping someone can point out what I am
doing wrong and theres no index out of range or exception error
I tested it for like hundred time please help thanks and any idea
suggestion or piece of code will be helpful and fil just storing the string at the location of fileName[temp] :) and temp just going from 0 to 5 in a loop
i dont want to shuffle them i just want to swap them according to given index which i am doing in my code but cant to it properly theArray already contains the suffle index i just want to assign the fileName[0] index to theArray[temp] i can send you my proj if you want to have a look just send me hi to my id which show in my profile
So given you have a List of length 6 and an int[6] containing 0 to five in random order
List<String> newList = newList<String>();
foreach(int position in theArray)
{
newList.Add(filename[pos]);
}
filename.Clear();
fileName.AddRange(newList);
would be one way.
or you could simply do filename = newList and not bother with the Clear and AddRange.
You stored the wrong String in your temporary variable.
fil = fileName[temp]; // index changed here
fileName[temp] = fileName[randomNumber];
fileName[randomNumber] = fil;
This is a simple way to shuffle elements in an array. Basicly you go through the array from one end to the middle, swapping each element with one selected at random. Since each swap operation results in two elements being randomly placed, when we reach the middle, the whole array is shuffled.
void Main()
{
var arr = new string[] {"a","b","c"};
Shuffle(arr);
// arr is now shuffled
}
public static void Shuffle<T>(T[] arr)
{
Random r = new Random();
for(int i = arr.Length; i > arr.Length / 2; i--)
{
Swap(arr, r.Next(i), i -1);
}
}
private static void Swap<T>(T[] arr, int first, int second)
{
T temp = arr[first];
arr[first] = arr[second];
arr[second] = temp;
}
I'll start by saying I am very much a beginner programmer, this is essentially my first real project outside of using learning material. I've been making a 'Simon Says' style game (the game where you repeat the pattern generated by the computer) using C# and XNA, the actual game is complete and working fine but while creating it, I wanted to also create a 'top 10' scoreboard. The scoreboard would record player name, level (how many 'rounds' they've completed) and combo (how many buttons presses they got correct), the scoreboard would then be sorted by combo score. This led me to XML, the first time using it, and I eventually got to the point of having an XML file that recorded the top 10 scores. The XML file is managed within a scoreboard class, which is also responsible for adding new scores and sorting scores. Which gets me to the point... I'd like some feedback on the way I've gone about sorting the score list and how I could have done it better, I have no other way to gain feedback =(. I know .NET features Array.Sort() but I wasn't too sure of how to use it as it's not just a single array that needs to be sorted. When a new score needs to be entered into the scoreboard, the player name and level also have to be added. These are stored within an 'array of arrays' (10 = for 'top 10' scores)
scoreboardComboData = new int[10]; // Combo
scoreboardTextData = new string[2][];
scoreboardTextData[0] = new string[10]; // Name
scoreboardTextData[1] = new string[10]; // Level as string
The scoreboard class works as follows:
- Checks to see if 'scoreboard.xml' exists, if not it creates it
- Initialises above arrays and adds any player data from scoreboard.xml, from previous run
- when AddScore(name, level, combo) is called the sort begins
- Another method can also be called that populates the XML file with above array data
The sort checks to see if the new score (combo) is less than or equal to any recorded scores within the scoreboardComboData array (if it's greater than a score, it moves onto the next element). If so, it moves all scores below the score it is less than or equal to down one element, essentially removing the last score and then places the new score within the element below the score it is less than or equal to. If the score is greater than all recorded scores, it moves all scores down one and inserts the new score within the first element. If it's the only score, it simply adds it to the first element. When a new score is added, the Name and Level data is also added to their relevant arrays, in the same way. What a tongue twister. Below is the AddScore method, I've added comments in the hope that it makes things clearer O_o. You can get the actual source file HERE. Below the method is an example of the quickest way to add a score to follow through with a debugger.
public static void AddScore(string name, string level, int combo)
{
// If the scoreboard has not yet been filled, this adds another 'active'
// array element each time a new score is added. The actual array size is
// defined within PopulateScoreBoard() (set to 10 - for 'top 10'
if (totalScores < scoreboardComboData.Length)
totalScores++;
// Does the scoreboard even need sorting?
if (totalScores > 1)
{
for (int i = totalScores - 1; i > - 1; i--)
{
// Check to see if score (combo) is greater than score stored in
// array
if (combo > scoreboardComboData[i] && i != 0)
{
// If so continue to next element
continue;
}
// Check to see if score (combo) is less or equal to element 'i'
// score && that the element is not the last in the
// array, if so the score does not need to be added to the scoreboard
else if (combo <= scoreboardComboData[i] && i != scoreboardComboData.Length - 1)
{
// If the score is lower than element 'i' and greater than the last
// element within the array, it needs to be added to the scoreboard. This is achieved
// by moving each element under element 'i' down an element. The new score is then inserted
// into the array under element 'i'
for (int j = totalScores - 1; j > i; j--)
{
// Name and level data are moved down in their relevant arrays
scoreboardTextData[0][j] = scoreboardTextData[0][j - 1];
scoreboardTextData[1][j] = scoreboardTextData[1][j - 1];
// Score (combo) data is moved down in relevant array
scoreboardComboData[j] = scoreboardComboData[j - 1];
}
// The new Name, level and score (combo) data is inserted into the relevant array under element 'i'
scoreboardTextData[0][i + 1] = name;
scoreboardTextData[1][i + 1] = level;
scoreboardComboData[i + 1] = combo;
break;
}
// If the method gets the this point, it means that the score is greater than all scores within
// the array and therefore cannot be added in the above way. As it is not less than any score within
// the array.
else if (i == 0)
{
// All Names, levels and scores are moved down within their relevant arrays
for (int j = totalScores - 1; j != 0; j--)
{
scoreboardTextData[0][j] = scoreboardTextData[0][j - 1];
scoreboardTextData[1][j] = scoreboardTextData[1][j - 1];
scoreboardComboData[j] = scoreboardComboData[j - 1];
}
// The new number 1 top name, level and score, are added into the first element
// within each of their relevant arrays.
scoreboardTextData[0][0] = name;
scoreboardTextData[1][0] = level;
scoreboardComboData[0] = combo;
break;
}
// If the methods get to this point, the combo score is not high enough
// to be on the top10 score list and therefore needs to break
break;
}
}
// As totalScores < 1, the current score is the first to be added. Therefore no checks need to be made
// and the Name, Level and combo data can be entered directly into the first element of their relevant
// array.
else
{
scoreboardTextData[0][0] = name;
scoreboardTextData[1][0] = level;
scoreboardComboData[0] = combo;
}
}
}
Example for adding score:
private static void Initialize()
{
scoreboardDoc = new XmlDocument();
if (!File.Exists("Scoreboard.xml"))
GenerateXML("Scoreboard.xml");
PopulateScoreBoard("Scoreboard.xml");
// ADD TEST SCORES HERE!
AddScore("EXAMPLE", "10", 100);
AddScore("EXAMPLE2", "24", 999);
PopulateXML("Scoreboard.xml");
}
In it's current state the source file is just used for testing, initialize is called within main and PopulateScoreBoard handles the majority of other initialising, so nothing else is needed, except to add a test score.
I thank you for your time!
As a programming tip, you should replace the 3 different arrays with a single array of Score Objects, each of these objects would have all 3 properties you mentioned (Name, Level and Score). You can then create a comparator-like function (based on the score attribute) for it which can be used to sort it via the Arrays.Sort() method.
If you want to keep you current 3 arrays then you can look up sorting algorithms here: http://en.wikipedia.org/wiki/Sorting_algorithm#Comparison_of_algorithms and just make it so that any changes are done to the 3 arrays simultaneously instead of one by one (since you keep the data in them synchronized by index).
You can consider placing your user name, level, and score in a separate class (let's call it ScoreBoardEntry) that inherits from IComparable and then write a comparator. This will allow you to use the built in sort function of List and will be a neater solution than just writing your own.
Your code should look something like this:
1) Create/load a List < ScoreBoardEntry> with all the previous scores
2) push the new score into it
3) Sort List
4) Print only first 10 entries
I wrote some code for you. I've been learning some new-ish type C# stuff like linq, IEnumerable, and yield and kind of wanted to put them together, so hopefully it helps.
you might like the snippet editor i used - linqpad - it's good for learning/experimenting
void Main()
{
string [] playerNames = {"Aaron", "Rick", "Josie"};
var sim = new GameSimulator(playerNames, 1000000, 5000);
var scores = sim.GetScores(5);
var sorted = scores.OrderBy(c=>c.Score).Reverse();
var top = sorted.Take(2);
// uncomment if using linq pad
//scores.Dump("scores");
//sorted.Dump("sorted");
//top.Dump("top");
}
class GameSimulator
{
public GameSimulator(string [] playerNames, int maxScore, int maxLevel)
{
this.playerNames = playerNames;
this.maxScore = maxScore;
this.maxLevel = maxLevel;
}
private string [] playerNames;
private int maxScore;
private int maxLevel;
public IEnumerable<ScoreBoardEntry> GetScores(int numGames)
{
for (int i = 0; i < numGames; i++)
{
string randomName = playerNames[random.Next(0, playerNames.Length-1)];
int randomScore = random.Next(1, maxScore);
int randomLevel = random.Next(1, maxLevel);
yield return new ScoreBoardEntry(randomName, randomLevel, randomScore);
}
}
static private Random random = new Random();
}
class ScoreBoardEntry
{
public ScoreBoardEntry(string playerName, int levenNumber, int score)
{
PlayerName = playerName;
LevelNumber = levenNumber;
Score = score;
}
public string PlayerName { set; get; }
public int LevelNumber { set; get; }
public int Score { set; get; }
}