I am trying to create a bingo caller so I have a list of numbers 1-90 and it randomly picks one, moves it from the 'TobeCalled' List and into 'DeadNumbers' List, this all works fine. The problem I have is that I want to print the list as an object on the screen, so convert it to a string and print it using text apart form I get the error.
Assets\Random_Number.cs(41,17): error CS0103: The name 'String' does not exist in the current context
Here is the code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class Random_Number : MonoBehaviour
{
public List <int> ListofNumbers = new List<int>(); // List of the numbers being called
public List <string> DeadNumbers = new List<string>(); // List of numbers that have been called
public Text text_to_be_Printed; // Text Element
private int numberSelected;
private string numberSelected_str;
public string DeadNumbers_str;
void Start() {
text_to_be_Printed = GetComponent<Text>();
for(int i = 1; i <= 90; i++){
ListofNumbers.Add(i); // Makes a list of all the numbers
}
}
void Update()
{
if (Input.GetKeyDown("space")){ // If space is pressed -text
numberSelected = ListofNumbers[Random.Range (0, ListofNumbers.Count)]; // Get a random number text
numberSelected_str = numberSelected.ToString();
text_to_be_Printed.text = numberSelected_str;
DeadNumbers.Add(numberSelected_str);
ListofNumbers.Remove(numberSelected);
Debug.Log(String.Join(", ", DeadNumbers));
// DeadNumbers_str = String.Join(",", DeadNumbers);
// Debug.Log(DeadNumbers_str);
}
}
}
I have tried uning String.Join but i get the error above, I'm pertty new to Unity and c# so any help would be appricated
You are missing using System; at the top of your file. String class is located at System namespace.
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class Random_Number : MonoBehaviour
{
public List <int> ListofNumbers = new List<int>(); // List of the numbers being called
public List <string> DeadNumbers = new List<string>(); // List of numbers that have been called
public Text text_to_be_Printed; // Text Element
private int numberSelected;
private string numberSelected_str;
public string DeadNumbers_str;
void Start() {
text_to_be_Printed = GetComponent<Text>();
for(int i = 1; i <= 90; i++){
ListofNumbers.Add(i); // Makes a list of all the numbers
}
}
void Update()
{
if (Input.GetKeyDown("space")){ // If space is pressed -text
numberSelected = ListofNumbers[Random.Range (0, ListofNumbers.Count)]; // Get a random number text
numberSelected_str = numberSelected.ToString();
text_to_be_Printed.text = numberSelected_str;
DeadNumbers.Add(numberSelected_str);
ListofNumbers.Remove(numberSelected);
Debug.Log(String.Join(", ", DeadNumbers));
// DeadNumbers_str = String.Join(",", DeadNumbers);
// Debug.Log(DeadNumbers_str);
}
}
}
Adding to foobar's answer
string (small s) as type keyword is the same as System.String so you could also simply use string.Join instead then you don't need the using System;
Related
I'm building my game and after like 4 seconds there is an error that says:
Assets\PlayerInventory.cs(228,37): error CS0103: The name 'ObjectNames' does not exist in the current context I'm using the function so that the objects don't all have the same name, but I can't build because of it. I'm using it like this:
string uniqueName = ObjectNames.GetUniqueName(names, "");
this is just adding a number on the end so it would be
Object
Object (1)
Object (2)
and so on...
Why is it not letting me build?
EDIT:
Code snippet:
using System.Collections;
using System.IO;
using System.Collections.Generic;
using UnityEngine;
using System;
using System.Linq;
using UnityEditor;
using Photon.Pun;
using UnityEngine.UI;
public class PlayerInventory : MonoBehaviour
{
// Names taken
public string[] names = new string[] { "Object" };
void Start()
{
string uniqueName = ObjectNames.GetUniqueName(names, "");
}
}
Some of the using are not needed for this snippet.
Because ObjectNames is part of the namespace UnityEditor which only exists within the Unity editor itself and is completely stripped of during the build process.
=> You can't use any of it in the actual released application, it is only for doing stuff within the editor itself.
Unfortunately the exact content of GetUniqueName is also not public in the source code but you can implement something similar yourself.
There might be better and more efficient ways but I would go with e.g.
public static class StringExtensions
{
// Regex Matches a trailing indexer
// e.g. "Example (1)"
private const string k_IndexMatch = " \\(([0-9]+)\\)$";
private static bool HasIndexer(string name, out int? index, out string nameWithoutIndex)
{
var matches = Regex.Matches(name, k_IndexMatch);
var nameIndexMatch = matches.LastOrDefault();
// or in case of older Unity/c# version without Linq
//var nameIndexMatch = matches.Count == 0 ? null : matches[matches.Count - 1];
if (nameIndexMatch == null)
{
index = null;
nameWithoutIndex = name;
return false;
}
// First group is always entire match, we want only the numeric value which is the second group
var group = nameIndexMatch.Groups[1];
index = int.Parse(group.Value);
nameWithoutIndex = name.Substring(0, name.Length - nameIndexMatch.Value.Length);
return true;
}
public static string GetUniqueName(this string name, IEnumerable<string> existingNames)
{
HasIndexer(name, out var index, out var nameWithoutIndex);
foreach (var existingName in existingNames)
{
if (existingName == nameWithoutIndex)
{
// Exact match (without index)
// in this case either keep your index or if there is none use 1
if (index == null)
{
index = 1;
}
continue;
}
if (HasIndexer(existingName, out var existingIndex, out var existingNameWithoutIndex))
{
if (existingNameWithoutIndex == nameWithoutIndex)
{
index = index == null ? existingIndex + 1 : Math.Max(index.Value, existingIndex.Value + 1);
}
}
}
return nameWithoutIndex + (index == null ? "" : $" ({index})");
}
}
See also .NetFiddle (older c#)
Example usage
var uniqueName = "Example".GetUniqueName(new []{"Example 0", "Example (1)", "Nope", "Example", "Example (2)"});
=>
Example (3)
since only "Example (1)", "Example", "Example (2)" are overlapping matches and highest free index is 3.
I am a beginner C# programmer in general, attempting to create a Japanese falling word typing game in Unity where the word / letter shown on screen will be in Hiragana, but the requested input is in Romaji (alphabetical) letters.
Currently, I am stuck in a rut attempting to figure out how to generate a random number once per words.Add (word) is executed. For instance, when a Word object is created, generate a random number. Then, that random number is used on classes that depend on it, such as getWord_Hiragana, and getWord_Romaji. Most typing games existing on the internet are shown only a single object (English), so I couldn't find what I need.
// WordManager.cs
public class WordManager : MonoBehaviour {
public List<Word> words;
public WordSpawner wordSpawner;
public void AddWord ()
{
Word word = new Word (WordGenerator.GetWord_Romaji(), wordSpawner.SpawnWord());
words.Add (word);
}
}
// WordGenerator.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class WordGenerator : MonoBehaviour {
public static string[] wordList_Hiragana = { "あ", "い", "う", "え", "お" };
public static string[] wordList_Katakana = { "ア", "イ", "ウ", "エ", "オ" };
public static string[] wordList_Romaji = { "a", "i", "u", "e", "o" };
public static int GetIndex ()
{
int index = Random.Range (0, wordList_Romaji.Length - 1); // Get Random number which has the same index for Hiragana, Katakana, and Romaji arrays
Debug.Log ("Index #" + index + ": " + wordList_Hiragana[index] + " " + wordList_Katakana[index] + " " + wordList_Romaji[index]); // Debug Log
return index; // Returns the result of the random as a guidance.
}
public static string GetWord_Hiragana () // A function to return the result of GetIndex as Hiragana word to be used on WordManager and in turn, displays that Hiragana.
{
int index = GetIndex ();
string getWord_Hiragana = wordList_Hiragana [index];
return getWord_Hiragana;
}
public static string GetWord_Romaji ()
{
int index = GetIndex ();
string getWord_Romaji = wordList_Romaji [index];
return getWord_Romaji;
}
}
// Word.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[System.Serializable]
public class Word {
public string word;
private int typeIndex; // Checks for current letter
WordDisplay display;
public Word (string _word, WordDisplay _display) // Displays the word as Hiragana / Katakana
{
word = _word;
display = _display;
display.SetWord (word);
}
public char GetNextLetter ()
{
return word[typeIndex]; // Gets the next letter of the Romaji array
}
public void TypeLetter ()
{
typeIndex++;
}
public bool WordTyped ()
{
bool wordTyped = (typeIndex >= word.Length); // Checks if the whole word has been typed
if (wordTyped)
{
display.RemoveWord (); // Remove the whole object on screen
}
return wordTyped;
}
}
The expected result is for GetIndex to roll a random number once per Word object. When getWord_Romaji is executed, it grabs the return value of GetIndex. The same goes when getWord_Hiragana is executed. Right now, GetIndex is executed twice and generates a random number twice in each Word object, causing the word that appeared on Debug to be different compared to what appears on the game screen. How do I make this work?
If the code above is not enough to solve the problem, the project is posted here.
I would change your Word class constructor to the below:
public class Word
{
public string word;
private int typeIndex; // Checks for current letter
private int wordIndex; // index of word used from WordGenerator
WordDisplay display;
public Word(WordDisplay _display) // Displays the word as Hiragana / Katakana
{
wordIndex = WordGenerator.GetIndex(); // now it will only be called ONCE per instance
word = _WordGenerator.wordList_Romaji[wordIndex];
// you can get the equivalent? letters similarly...with something like:
word = _WordGenerator.wordList_Hiragana[wordIndex];
display = _display;
display.SetWord(word);
}
// ... other existing code ...
}
Note that I've added another field to store the index selected for that particular word instance.
Without seeing the implementation of Word I'ld say from your example it actually does call GetIndex() only exactly once ... namely for GetWord_Romaji() ...
Anyway a quick simple fix could be
private static int randomizedIndex;
public static void NewRandomIndex()
{
randomizedIndex = Random.Range (0, wordList_Romaji.Length - 1);
Debug.Log("Index #" + randomizedIndex + ": " + wordList_Hiragana[randomizedIndex] + " " + wordList_Katakana[randomizedIndex] + " " + wordList_Romaji[randomizedIndex]);
}
public static string GetWord_Hiragana()
{
return wordList_Hiragana[randomizedIndex];
}
public static string GetWord_Romaji ()
{
return wordList_Romaji[randomizedIndex];
}
and call it
public void AddWord ()
{
WordGenerator.NewRandomIndex();
Word word = new Word(WordGenerator.GetWord_Romaji(), wordSpawner.SpawnWord());
words.Add (word);
}
If you rather want to be able to later "translate" the words between those arrays then you should in Word instead of retrieved string rather store the used randomizedIndex and get the string value for it "on the fly".
I have a quiz game and at the end of the game I want to display a leaderboard of the top 10 people with their names and score for example: Ioue 500.
Right now I'm adding score every time user scores, and I'm checking the high score. However I'm not sure how to do the leaderboard. can someone guide me?
This script is where the user registers, it's a different scene.
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
using System.Linq;
using System.Text.RegularExpressions;
using System.IO;
using System;
public class Registration : MonoBehaviour
{
public Text name;
public static Registration _instace;
private void Awake()
{
_instace = this;
}
/// <summary>
/// Performs data validation and registers user
/// </summary>
public void Register()
{
string data;
string currentUser = string.Empty;
string userName;
data = GetData(name);
if (data == null || string.IsNullOrEmpty(data))
{
Recolor(name, errorColor);
return;
}
else
{
userName = data;
currentUser += data + ";";
}
string previousDirectory = Directory.GetCurrentDirectory();
Directory.SetCurrentDirectory(Application.persistentDataPath);
if (File.Exists("Users.csv"))
{
string[] users = File.ReadAllLines("Users.csv");
foreach (string user in users)
{
string[] parts = user.Split(";".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
}
}
File.AppendAllText("Users.csv", currentUser + Environment.NewLine);
Directory.SetCurrentDirectory(previousDirectory);
SceneManager.LoadScene(nextScene);
}
// Gets input data from control group provided
string GetData(Graphic group)
{
InputField inputField = group.GetComponentInChildren<InputField>();
if (inputField != null)
{
return inputField.text;
}
return null;
}
// Gets input data from control group provided
string GetDataD(Graphic group)
{
Dropdown inputField = group.GetComponentInChildren<Dropdown>();
if (inputField != null)
{
return inputField.captionText.text;
}
return null;
}
}
Where i add score is when player get's the right answer
if (isCorrect)
{
theAnswerIsCorrect = true;
playerScore += 20;
scoreDisplayText.text = "Score: " + playerScore.ToString();
}
This is where I compare the old and new score:
public void submitNewPlayerScore(int newScore)
{
if (newScore > playerProgress.highestScore)
{
playerProgress.highestScore = newScore;
SavePlayerProgress();
}
}
Now what I need is I will have many users playing, I just want to display the top 10 users with their names and high scores. Thank you!
Okay first thing : Why do you even need registration when it's offline?
You can omit the registration and just ask for a player name after quiz ends ( if you want to make offline highscores ).
Since you already have kind of highestScore you can just order it using Linq. I assume your code has access to all players ( because it's in csv file ) so I can recommend doing something like this :
List<Player> playerList = new List<Player>();
foreach(string user in File.ReadAllLines("Users.csv"))
{
playersList.Add(Player.Parse(user)); // If you have such method...
}
Now since you have all Players in one list you can use Linq to order it and take only x to display :
int x = 10; // how many records to take
IEnumerable<Player> highestX = playerList.OrderBy(player => player.highestScore).Take(x);
highestX is now holding 10 records with the highest score. You can just iterate through them and display details like highestX.ElementAt(0).Name or something like this.
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);
}
}
}
New to C# Just wondering what the error is, can't understand the error. No need to correct, just want to know the mistake.
ERROR:
The best overloaded method match for 'Systems.Collections.Generic.List.BinarySearch(int,System.Collections.Generic.Icomparer)' has some invalid arguments
Argument1: Cannot convert from system.collections.generic.list to int
Argument2: Cannot convert from int to system.collections.generic.icomparer
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;enter code here
using System.Windows.Forms;
namespace LotoNumbers
{
public partial class FrmLotto : Form
{
// declare class level variables
List<int> player = new List<int>(7);
List<int> computer = new List<int>(6);
public FrmLotto()
{
InitializeComponent();
}
// event method to generate player's numbers
private void btnPlayer_Click(object sender, EventArgs e)
{
// declare and initalize local variables
string display = "";
// reset the winning number label before generating the player's numbers
lblComputerNumber.Text = "00 00 00 00 00 00";
// generate unique random numbers
GenerateRandomNumbers(player);
player.Sort();
// build display string
display = BuildDisplayString(player);
// display winning number in label
lblPlayerNumber.Text = display;
}
// method to generate computer's random numbers (the 'winning numbers')
// and determine how many winning numbers
private void btnComputer_Click(object sender, EventArgs e)
{
// declare and initalize local variables
int winCount = 0;
string display = "";
// generate unique random numbers
GenerateRandomNumbers(computer);
// sort the array in ascending order
computer.Sort();
// build display string
display = BuildDisplayString(computer);
// display winning number in label
lblComputerNumber.Text = display;
// determine if this number matches any of the players numbers
winCount = CompareTwoList(player, computer);
// display the total winning numbers
lblMatching.Text = winCount.ToString("D2");
}
private void GenerateRandomNumbers(List<int> numberList)
{
Random lucky = new Random();
// generate unique random numbers
for (int index = 0; index < numberList.Capacity; index++)
{
int temp = lucky.Next(1, 50);
if (numberList.IndexOf(temp) < 0)
{
numberList.Add(temp);
}
else
{
index--;
}
}
}
private string BuildDisplayString(List<int> numberList)
{
// declare method variable
string display = " ";
// loop through the array and build a display string
foreach (int number in numberList)
display += number.ToString("D2") + " ";
// return display string
return display;
}
private int CompareTwoList(List<int> list1, List<int> list2)
{
// declare method variable
int numberMatching = 0;
// loop through each element in the first array looking for a match in the second array
foreach (int value in list1)
{
if (player.BinarySearch(list2, value) >= 0)
numberMatching++; // a matching value is found
}
return numberMatching;
}
}
}
It looks like you want:
if (list2.BinarySearch(value) >= 0)
numberMatching++; // a matching value is found
You are calling List<int>.BinarySearch(int, IComparer<int>) at the moment. Since value is an int you are getting a type error.
Note you can also do:
int numberMatching = list2.Intersect(list1).Count();
There is no overload for List<int>.BinarySearch() which accepts a List<int> and int as the parameters. See MSDN
You need to use player.BinarySearch(value)