C# 'KeyCode' does not contain a definition for 'numberKey' - c#

I'm trying to make a shortcut from making several different "if statements". Instead I only change one value that is given by a for loop.
"KeyCode.Alpha1" suggests that I press the "1" key on the top of the keyboard and so on.
So the "numberKey" variable has a string stored "Alpha1" but it's reading it as just "numberKey". Then i get a error message saying 'KeyCode' does not contain a definition for 'numberKey'. Help
private void Inventory()
{
for (int i = 1; i <= items.Count; i++)
{
string numberKey = "Alpha" + i.ToString();
if (Input.GetKeyDown(KeyCode.numberKey))
{
items[currentItem].gameObject.SetActive(false);
currentItem = i--;
items[currentItem].gameObject.SetActive(true);
}
}
}

KeyCode is an enum so you can't just dynamically build a string with the same name as an enum and expect it to work. Instead use Enum.Parse:
Input.GetKeyDown(Enum.Parse(typeof(KeyCode), numberKey, true));
Enum.Parse takes the text representation of an Enum and makes the enum from it. So it's basically saying "Return the KeyCode enum entry where the name is equal to numberKey" The boolean at the end tells it not to be case sensitive.

You might try casting between enum and int:
int Alpha0Key = (int)KeyCode.Alpha0;
for (int i = 0; i < items.Count; i++)
{
if (Input.GetKeyDown((KeyCode)(Alpha0Key+i))
{
items[currentItem].gameObject.SetActive(false);
currentItem = i;
items[currentItem].gameObject.SetActive(true);
}
}

Related

The index not what i expected C# unity3d

I found a problem about the index on my script, why my index on method ChooseItem become 1 not 0?
here the script
public void AddBtn()
{
RemoveButton();
for (int i = 0; i < items.Count; i++)
{
indexer = i;
ShopItem activeOne = items[indexer];
go = Instantiate(prefabBtn, parentBtn);
btn = go.GetComponent<_button>();
btn.indexer = indexer;
btn.TheItems.sprite = items[indexer].theitem;
btn.button.onClick.AddListener(() =>chooseItem(indexer));
}
}
public void chooseItem(int index)
{
Debug.Log(index);
}
I don't know the problem, can anyone explain to me why? here the pict
Quite typical mistake when using lambdas!
You overwrite a field value
indexer = i;
Then this line
btn.button.onClick.AddListener(() =>chooseItem(indexer));
or better said the listener lambda expression
()=>chooseItem(indexer);
is executed lazy/delayed using the indexer field reference, not the current value! It will always use the latest value of the field indexer which in your case is 1 if there are two buttons in total.
This is called capture of outer variables:
Lambdas can refer to outer variables. These are the variables that are in scope in the method that defines the lambda expression, or in scope in the type that contains the lambda expression. Variables that are captured in this manner are stored for use in the lambda expression even if the variables would otherwise go out of scope and be garbage collected.
Same would happen btw if you directly used i.
What you need to do is assign the value to a local variable and use that one instead like
var currentIndex = i;
...
btn.button.onClick.AddListener(() =>chooseItem(currentIndex));
Or alternatively if you assign the value anyway to btn.indexer you probably could directly go
btn.button.onClick.AddListener(() => chooseItem(btn.indexer));
You need this code:
public void AddBtn()
{
RemoveButton();
for (int i = 0; i < items.Count; i++)
{
indexer = i;
ShopItem activeOne = items[indexer];
go = Instantiate(prefabBtn, parentBtn);
btn = go.GetComponent<_button>();
btn.indexer = indexer;
btn.TheItems.sprite = items[indexer].theitem;
btn.button.onClick.AddListener(() =>chooseItem(btn));
}
}
public void chooseItem(_button_ btn)
{
Debug.Log(btn.indexer);
}

Convert user entered string into an object in c#

I have a battleship like terminal game, the user enters a coordinate like e2, and the program checks one of the instance variables of my object Box, it checks whether hasShip is true, if its true then it will make the coordinate e2 false, and give the output "Ship destroyed"
The problem is that all my objects are called a1,a2,a3,a4,a5,b1,b2 and so on.
I have created 25 instances of the Box class. All names as such.
Once the program gets input, either e4 ,e5 etc. I want to convert that string into an object.
For example( I want to do something like this )
target = Console.ReadLine();
target.hasShip == true;
I want to convert target into an object, then use target to use the methods of the Box class.
Because the other approach requires me to make loads of if statements, which isn't clean code, doesn't look good, and is a waste if you ask me.
Thanks in advance,
New Answer: use an Array
I am slow. I did not pay attention that you are making a battleship-like game, and that we know that the "boxes" make a rectangle. We can store this efficiently in an array.
Why I did not catch up to this fact earlier? I guess I need to wake up properly.
So, use an array:
var board = new Box[5, 5];
Now, to populate it, we can do a double for loop:
for(var indexRow = 0; indexRow < 5; indexRow++)
{
for(var indexCol = 0; indexCol < 5; indexCol++)
{
board[indexRow, indexCol] = new Box();
}
}
Note: pay attention that the indexes go from 0 to 4. For a total of 5 values: {0, 1, 2, 3, 5}.
And to query from it, we will need the indexes...
Addendum on populating the array
In comments, OP has said that each Box has an id and the ship positions are picked at random.
We can give the id in the loop:
for(var indexRow = 0; indexRow < 5; indexRow++)
{
for(var indexCol = 0; indexCol < 5; indexCol++)
{
var box = new Box();
box.vhID = (((char)(((int)'a') + indexRow))).ToString() + ((char)(((int)'1') + indexCol)).ToString();
board[indexRow, indexCol] = box;
}
}
What I am doing here is constructing the id from the indexes. Basically taking the value of 'a' and adding the indexRow will give us 'a' when indexRow is 0, 'b' when it is 1 and so on. Similarly, we get the digit that represents the column.
Note: We convert the char to int, do the addition, then convert back to char... and then from char to string. Once we have string, we can concatenate them.
I do not think we need this id. But, hey, you can do it like this.
OP also mentions that he will pick 4 ship positions at random. Fair enough:
var random = new Random();
for (var ships = 0; ships < 4; ships++)
{
board[random.Next(0, 4), random.Next(0, 4)].hasShip = true;
}
Since the user inputs an string, I suggest to create a function to convert it to the index pair:
var input = Console.ReadLine();
if (TryGetCoordinates(input, out int irow, out int icol))
{
var target = board[irow, icol];
}
else
{
Console.WriteLine("The cell {0} does not exist.", input);
}
// ...
bool TryGetCoordinates(string cell, out int indexRow, out int indexCol)
{
// ...
}
Start by validating null:
bool TryGetCoordinates(string cell, out int indexRow, out int indexCol)
{
indexRow = -1;
indexCol = -1;
if (cell == null)
{
return false;
}
// ...
}
Note: Feel free to use Trim, ToUpper or ToUpperInvariant.
We know that must be a letter followed by a digit, we can validate the length:
bool TryGetCoordinates(string cell, out int indexRow, out int indexCol)
{
indexRow = -1;
indexCol = -1;
if (cell == null)
{
return false;
}
if (cell.Length != 2)
{
return false;
}
// ...
}
We extract the characters and from them the coordinates. Noting that the first one is a letter, and the other a digit. We can also validate they are withing bounds.
bool TryGetCoordinates(string cell, out int indexRow, out int indexCol)
{
indexRow = -1;
indexCol = -1;
if (cell == null)
{
return false;
}
if (cell.Length != 2)
{
return false;
}
indexRow = (int)cell[0] - (int)'a';
indexCol = (int)cell[1] - (int)'1';
return indexRow < 5 && indexRow >= 0 && indexCol < 5 && indexCol >= 0;
}
And of course, you can do a loop of the validation similar to what was explained in the old answer.
Note: the issue with value types I describe in the old answer still applies with the array.
Old Answer: Use a Dictionary
I believe you do not want to convert the string to an object (the string is an object by the way), you want to pick the Box object you previously created based on the string. And you want to do it without using if statements. What you need is a dictionary.
So, you would have Dictionary<string, Box> meaning that it is a dictionary that you can query by string and stores Box.
Addendums:
In this case, string is the key type, by which we will access the dictionary. When we add an object to the dictionary we identify it with a key, and when we retrieve it, we also use the key. The key does not have to be string, you can choose a different type. string is convenient in this case because it is what you get from Console.ReadLine().
You can create the dictionary to store whatever type you need. If you do not need Box, you can create a dictionary that stores something else.
Creating and populating the Dictionary
Then, you add to the Dictionary all your Box objects, like this:
var dict = new Dictionary<string, Box>();
// ...
dict.Add("a1", CreateBoxA1());
Where CreateBoxA1 represents whatever means you have to create the object. No, you do not need to create a method for each Box... you can do it like this:
dict.Add("a1", new Box());
Or whatever. I do not know how you create them, so consider that a placeholder, ok? ok.
Querying and retrieving values from the Dictionary
Once you have all your Box instances in your dictionary, you can get the one you need using the string:
Console.WriteLine("Enter the name of the Box:");
var name = Console.ReadLine();
var target = dict[name];
Addendum: The value you get from dict[name] is the value that you added to the dictionary with that key. So, if the user typed "a1" it dict[name] will be the value that we added with "a1" (dict.Add("a1", new Box());). Again, if what you need is not Box you can create a dictionary to store a different type.
Input validation
You can also use the Dictionary to validate if the string corresponds to a Box that exists, for example:
Console.WriteLine("Enter the name of the Box:");
var name = Console.ReadLine();
if (dict.KeyExists(name))
{
var target = dict[name];
// ...
}
else
{
Console.WriteLine("The Box {0} does not exist", name);
}
It goes without saying, but... you can make a loop based on that, for example:
Box target = null;
while(true)
{
Console.WriteLine("Enter the name of the Box:");
var name = Console.ReadLine();
if (dict.KeyExists(name))
{
target = dict[name];
break;
}
Console.WriteLine("The Box {0} does not exist", name);
}
Also, it goes without saying, but... you can add your own validations and sanitation steps. For example using ToUpper, ToUpperInvariant or Trim. And I would remind you that changing strings to lower or upper case is culture sensitive.
See also: Best Practices for Using Strings in .NET.
Editing an removing objects from the dictionary
Once you have the object you retrieved from the Dictionary...
var target = dict[name];
We can use it, and even modify it:
var target = dict[name];
if (target.hasShip) // no need for "== true" if hasShip bool
{
target.hasShip = false;
Console.WriteLine("Ship Destroyed");
}
An special note must be done if Box is value type. For a custom type that means that it is not a class but a struct. The problem with value types is that they are copied on assignment, meaning that when you do var target = dict[name]; with a value type, you get a copy. You must then update the dictionary once you manipulated it:
var target = dict[name];
if (target.hasShip) // no need for "== true" if hasShip bool
{
target.hasShip = false;
dict[name] = target;
Console.WriteLine("Ship Destroyed");
}
Note: As I said above, this is only needed for value types.
And you can even remove the Box from the dictionary if that is necesary:
dict.Remove(name);

Retrieve the Textbox field as integer which can be used in <for> loop

In aspx page i have a textbox
<asp:TextBox ID="txtrandom" runat="server"></asp:TextBox>
In .cs page i am retrieving te value from that text box and converting it into int so that it can be used in for loop.
In .cs page
int random;
random = Convert.ToInt16(txtrandom.Text);
for (int i = 0; i < random; i++)
{
//other code
}
But When i am executin it will give error as Input string was not in correct format.How to convert it into int?
Plz try below code
int random=0;
bool isValidInt = int.TryParse(txtrandom.Text, out random);
if (isValidInt)
{
for (int i = 0; i < random; i++)
{
//other code
}
}
else
{
Response.Write("Please enter valid int value in textbox.");
txtrandom.Focus();
}
Thanks
First of all you need to understand that "Converting a value to integer must needed the converted value to be an int type". The value entered in the textbox is a type of string so it may be any type.
So first you need to check for a valid INT value. For that you need to do like this
int random = 0;
bool isValidInt = int.TryParse(txtrandom.Text, out random);
If conversion is successful then you can use the valid integer value which is now in random
And the code will look like (Ref: Hitesh's answer)
if (isValidInt)
{
for (int i = 0; i < random; i++)
{
//other code
}
}
else
{
Response.Write("Please enter valid int value in textbox.");
txtrandom.Focus();
}
You should use text box as number type and for Int conversion you can use
int someInt;
int.TryParse(s, out someInt);
so return value indiacate whether the conversion Int32 succeeded or not.
These are the recommended methods..
int anInteger;
anInteger = Convert.ToInt32(textBox1.Text);
anInteger = int.Parse(textBox1.Text);
Firstly you need to make sure that only numbers are entered into that text box. so that you are not facing any exception while converting it to an integer value.
Use a regular expression validator to make sure that only Integers are entered into that Textbox with validation expression ^[0-9]+$
Also You need to be consistent on what datatype you are using. Use Int32
then
if(!Textbox1.Text.Equals("")) // you can take care of "" by using required field validator
{
Int32 random = Convert.ToInt32(Textbox1.Text);
}
Now use this value accordingly.

text1.Text as inputfield visual basic

Hello i have an inputtextfield were i want to put figures for example 100 to have a script loop for 100 times, but im getting an error all the time. When putting a number at the place it does run normal, i'm trying to feed it with a number from the textbox.
for (var i = 0; i < (textBox2.Text); i++)
{
code in here
}
Here's the error : Error 1 Operator '<' cannot be applied to operands of type 'int' and 'string'
What am i doing wrong? Can someone help me??
You give textBox2.Text although it would have number but it has type string and you need integer.
int result = int.Parse(textBox2.Text);
for (var i = 0; i <result ; i++)
{
//Your code
}
Check if the text can be Parsed to an int first and then proceed. Following int.TryParse() method will return true if textBox2.Text.Trim() is an int
int limit;
if( int.TryParse(textBox2.Text.Trim(), out limit))
{
for (var i = 0; i < limit ; i++)
{
//code in here
}
}
The error message is quite clear, you're trying to compare an integer to a string value. That obviously won't work. You need first to cast the value from the textbox to integer type, than you can apply the condition for the for-loop.
Use Int.Parse(txtFirst.Text);
One thing, you seem to be a beginner, I want you to follow naming conventions in coding like txt prepended to the name of textbox, lbl for label and you can find more in your study material...
You need to parse the textBox2.Text String to get an int. For instance:
int x = int.Parse(textBox2.Text);
for (var i = 0; i < x; i++)
As others have mentioned, textbox2.text is a string and must be converted to a #n integer
for (var i = 0; i < int.Parse(textBox2.Text); i++)
{
//code in here
}
However, i wound recommend you use a more appropriate control, such as a numeric Up Down:
for (var i = 0; i < Convert.ToInt32(numericUpDown1.Value); i++)
{
code in here
}
The value in textBox2.Text is of type string , you need to cast it to int.
This is done by cint() function
cint(textBox2.Text)
or Parse() method
Int32.Parse(textBox2.Text);
THe above two methods will work if you are sure the input string is valid that contains something like "123" rather than "absjsdfd".
for (var i = 0; i < Int32.Parse(textBox2.Text); i++)
{
//your code in here
}
To avoid throwing exception if invalid input is entered in textbox use a more robust function Integer.TryParse()
int limit;
bool valid = int.TryParse(textbox2.Text, out limit);
if(valid)
for (var i = 0; i < limit; i++)
{
//your code in here
}
You need to use the Int32.Parse() method to convert the text in the textbox to an integer. The Text field is only an string and the compiler cannot figure out what you are trying to do.

Check if array is null or empty?

I have some problem with this line of code:
if(String.IsNullOrEmpty(m_nameList[index]))
What have I done wrong?
EDIT: The m_nameList is underlined with red color in VisualStudio, and it says "the name 'm_nameList' does not exist in the current context"??
EDIT 2: I added some more code
class SeatManager
{
// Fields
private readonly int m_totNumOfSeats;
// Constructor
public SeatManager(int maxNumOfSeats)
{
m_totNumOfSeats = maxNumOfSeats;
// Create arrays for name and price
string[] m_nameList = new string[m_totNumOfSeats];
double[] m_priceList = new double[m_totNumOfSeats];
}
public int GetNumReserved()
{
int totalAmountReserved = 0;
for (int index = 0; index <= m_totNumOfSeats; index++)
{
if (String.IsNullOrEmpty(m_nameList[index]))
{
totalAmountReserved++;
}
}
return totalAmountReserved;
}
}
}
If m_nameList is null, that will still blow up, because it will try to find the element to pass to String.IsNullOrEmpty. You'd want:
if (m_nameList == null || String.IsNullOrEmpty(m_nameList[index]))
That's also assuming that index is going to be valid if m_nameList is non-null.
Of course, this is checking if the element of an array is null or empty, or if the array reference itself is null. If you just want to check the array itself (as your title suggests) you want:
if (m_nameList == null || m_nameList.Length == 0)
EDIT: Now we can see your code, there are two problems:
As Henk showed in his answer, you're trying to use a local variable when you need a field
You're also going to get an ArrayIndexOutOfBoundsException (once you've used a field) due to this:
for (int index = 0; index <= m_totNumOfSeats; index++)
That will perform m_totNumOfSeats + 1 iterations because of your bound. You want:
for (int index = 0; index < m_totNumOfSeats; index++)
Note that m_nameList[m_totNumOfSeats] is not valid, because array indexes
start at 0 in C#. So for an array of 5 elements, the valid indexes are 0, 1, 2, 3, 4.
Another option for your GetNumReserved method would be to use:
int count = 0;
foreach (string name in m_nameList)
{
if (string.IsNullOrEmpty(name))
{
count++;
}
}
return count;
Or using LINQ, it's a one-liner:
return m_nameList.Count(string.IsNullOrEmpty);
(Are you sure you haven't got it the wrong way round though? I would have thought reservations would be the ones where the name isn't null or empty, not the ones where it is null or empty.)
If it's the wrong way round, it would be this instead in LINQ:
return m_nameList.Count(name => !string.IsNullOrEmpty(name));
After Edit2:
You are defining m_nameList as a local variable of the constructor.
The rest of your code needs it as a field:
class SeatManager
{
// Fields
private readonly int m_totNumOfSeats;
private string[] m_nameList;
private double[] m_priceList;
// Constructor
public SeatManager(int maxNumOfSeats)
{
m_totNumOfSeats = maxNumOfSeats;
// Create arrays for name and price
m_nameList = new string[m_totNumOfSeats];
m_priceList = new double[m_totNumOfSeats];
}
....
}
To avoid the error you can perform some pre conditions in the if, like these :
if(m_nameList == null || index < 0 || m_nameList.Length < index || String.IsNullOrEmpty(m_nameList[index]))
This should works fine(without causing error) in almost any conditions ...

Categories

Resources