I am fairly new to programming and would like to know how I can get my program to subtract 30 from 100 every time I click a button. This is what I have but can't seem to find the correct formula.
int hpLevel = 100;
int hpDrop = 30;
if (hpLevel > 0)
{
lblHpLevel.Text = Convert.ToString(hpLevel - hpDrop);
}
else
{
lblHpLevel.Text = Convert.ToString(hpLevel);
}
The code declares a new hpLevel variable every time the button is clicked. You want that variable defined outside of the method, at the class level, so that the value will be retained between clicks.
Additionally, the code never assigns the result back to the hpLevel variable. It assigns it directly to the TextBox, while hpLevel is never changed. You need to assign the results to hpLevel and then set that value to your textbox.
int hpLevel = 100;
int hpDrop = 30;
void button1_Click( ... )
{
if (hpLevel > 0)
{
hpLevel -= hpDrop;
}
lblHpLevel.Text = Convert.ToString(hpLevel);
}
You must declare int hpLevel = 100 out of the scope of the method that is handling the click event. If int hpLevel = 100 is part of the aformentioned method then you are instantiating an intvariable with name hpLevel and assigning it the value 100 every time you click the button.
You can learn about scopes here
Related
I am generally pretty new to C# and coding in general.
Basically, this is what I have.
public bool TimeLeft;
public void Process()
{
int B = (int)Game.LocalPlayer.Character.TravelDistanceTo(spawnPoint) * 3; // An integer based on the distance of the character to a Vector3(spawnPoint).
while (TimeLeft)
{
int A = Game.GameTime / 1000; //GameTime is time lapsed in game in milliseconds.
}
}
But this is where my brain fries. Let's assume int B is 150.
How would I go about do reduce int B by 1 every time int A increases by 1? This happens within a loop.
I declare int B outside of the loop, and A inside because it needs to update every tick. TimeLeft is set somewhere else.
You have to keep track of the value of A. When you poll A anew you store the value in another variable. Then you can compute the difference and decrease B by this difference. Pseudocode:
int A = ...
int B = ...
while(...)
{
int A_new = ...
B -= A_new - A;
}
You need to define the values outside of the loop, inside the loop should only be the processing taking place. (Like Adok has mentioned)
I'd also say that while (true) is not a good practise of a general processing loop, unless you're making sure the whole program is defined within that loop.
Some game studios have a certain "Init" function, and an "Update" function, the init will happen when the game starts up the first time, and update will always be repeated like a loop after the init has been triggered. The benefit of using Update over a personal while loop is that it won't miss out out on other looping functions like Drawing
With understanding the difference between initialising and updating, It would be easier to understand a countdown like this:
In Init:
//defining 2 values to count down, one that decreases, and one that sets the value back to default.
int A = 150;
int Amax = A;
In Update:
if (A > 0)
{
A -= 1; //decrease the value if it's not at 0
}
else
{
//trigger an activity that happens when A reaches 0
//reset the timer
A = Amax;
}
I need to show a progress bar that have negative values, but when i try to modify the value to a negative number, the c# gets an error (invalid property error). Does anyone knows any method to create a negative value progress bar?
HPHeroi.Maximum = CriacaoDePersonagem.protagonista.status.Vida;
HPHeroi.Minimum = -20;
Does anyone knows any method to create a negative value progress bar?
You cannot. From the documentation:
Exceptions
ArgumentException
The value specified for the property is less than 0.
Instead, what you need to do is offset the entire range of the progress bar to account for the negative value. E.g.:
HPHeroi.Maximum = CriacaoDePersonagem.protagonista.status.Vida + 20;
HPHeroi.Minimum = 0;
Then you need to also account for that when you set the current value of the ProgressBar, e.g.:
HPHeroi.Value = CriacaoDePersonagem.protagonista.status.ActualVida + 20;
The above strategy can be encapsulated in a UserControl that wraps a ProgressBar, exposing the various value-related properties but using an offset to ensure that the actual ProgressBar object doesn't see negative values.
For example:
public partial class ProgressBarWithNegativeValues : UserControl, INotifyPropertyChanged
{
private int _offset;
public ProgressBarWithNegativeValues()
{
InitializeComponent();
}
public int Minimum
{
get => progressBar1.Minimum + _offset;
set
{
int offsetChange = value - _offset;
_offset = value;
progressBar1.Maximum -= offsetChange;
_RaisePropertyChanged();
}
}
public int Maximum
{
get => progressBar1.Maximum + _offset;
set
{
progressBar1.Maximum = value - _offset;
_RaisePropertyChanged();
}
}
public int Value
{
get => progressBar1.Value + _offset;
set
{
progressBar1.Value = value - _offset;
_RaisePropertyChanged();
}
}
public int Step
{
get => progressBar1.Step;
set
{
progressBar1.Step = value;
_RaisePropertyChanged();
}
}
public void Increment(int step) => progressBar1.Increment(step);
public void PerformStep() => progressBar1.PerformStep();
public event PropertyChangedEventHandler PropertyChanged;
private void _RaisePropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
I've omitted the *.Designer.cs code because that's just a single ProgressBar object dropped onto the UserControl with its Dock property set to Fill.
Note in the above that the ProgressBar.Minimum property is always left at 0, and the other properties offset accordingly, whether the minimum value is negative or positive. This keeps the code nice and simple instead of trying to deal with the negative and positive cases separately.
As Peter have stated, a progress bar can not hold a negative number. Therefore you can not use a Progress bar for this.
What I suggest, is instead of using a progress bar, use a track bar and disable it (set it's Enabled property to false).
Therefore, Imagine HPHeroi is a TrackBar object:
HPHeroi.Maximum = CriacaoDePersonagem.protagonista.status.Vida;
HPHeroi.Minimum = -20;
The code above will not result in a runtime error.
Keep in mind, there might be 2 more runtime errors that will occur when you reach the Maximum and Minimum values. To overcome them, add an if statement before each subtraction and addition of the HPHeroi's value (remember, it is a TrackBar now).
If statement example for subtraction:
if (HPHeroi.Value > HPHeroi.Minimum)
HPHeroi.Value--;
If statement example for addition:
if (HPHeroi.Value < HPHeroi.Maximum)
HPHeroi.Value++;
P.S. If you want, you can add a lable with "0" as content and put it under the line of the value of 0 in the track bar so that the user will know when the value is positive and when it is negative.
ProgressBar has a minimum value of 0, but the maximum can be quite high.
If you need it to represent a negative value, just use an offset.
int Offset = 20;
HPHeroi.Maximum = CriacaoDePersonagem.protagonista.status.Vida + Offset;
HPHeroi.Minimum = 0;
When you set the value of HPHeroi, simply add Offset to the new value
HPHeroi.Value = newvalue + Offset
newvalue can therefore be anything from -20 to CriacaoDePersonagem.protagonista.status.Vida, the range you are trying to specify, and your ProgressBar will show that.
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
This is my first post. So..critique is always welcomed.
My question is straight forward just by looking at the title.
How can I use a loop to insert values to different labels by using their reference (get,set methods are in a different form)
What I've tried is to create an array with the references of the labels. The thing is.. it assigns the new values to the array rather than changing the reference which will change the label.
I find it a bit difficult to explain it further than that.
If you have any questions, I will try to answer them best to my knowledge
private void button1_Click(object sender, EventArgs e)
{
int numOfPeriods = Convert.ToInt32(cmbPeriods.Text)-1;
string initialString = cmbStartTime.Text; //Gets the input from combo box "cmbStartTime".
string newTime;
decimal dec = Convert.ToDecimal(TimeSpan.Parse(initialString).TotalHours); //Converts the set by user Lesson start time to a decimal value.
decimal dec2;
decimal lessonLength = 1; // Default lesson length is set to 1 hour.
TimeSpan time;
Test FormOpen = new Test();
string[] periodStartTimes = new string[9] //Loop referencing the labels on Form TEST
{
FormOpen.startTime,FormOpen.startTime2, FormOpen.startTime3, FormOpen.startTime4,
FormOpen.startTime5, FormOpen.startTime6, FormOpen.startTime7, FormOpen.startTime8,
FormOpen.startTime9
};
if (cmbLessonLength.Text != "") //If the combo box "cmbLessonLength" is not empty, use that value instead of the default lesson lenght.
{
lessonLength = Convert.ToDecimal(cmbLessonLength.Text)/60; //Converts minutes to hours.
}
dec2 = dec + lessonLength;
time = TimeSpan.FromHours(Double.Parse(dec2.ToString()));
newTime = time.ToString();
if (newTime[0] == '0')
{
FormOpen.startTime = initialString + " - " + newTime.Remove(5).Remove(0, 1);
}
else
{
FormOpen.startTime = initialString + " - " + newTime.Remove(5);
}
for (int x = 1; x <= numOfPeriods; x++) //LOOP THAT ASSIGNS VALUES TO THE ARRAY AND NOT THE REFERENCE INSIDE IT
{
decimal workingNumber = lessonLength*x;
decimal Convert0 = dec + workingNumber;
TimeSpan Convert1 = TimeSpan.FromHours(Double.Parse(Convert0.ToString()));
string Convert2 = Convert1.ToString().Remove(5);
periodStartTimes[x] = Convert2;
}
FormOpen.subjectName = cmbSubjects.Text;
FormOpen.startTime2 = periodStartTimes[1]; //IT DOES WORK LIKE THIS
FormOpen.startTime3 = periodStartTimes[2];
FormOpen.ShowDialog();
}
I have provided the whole code, so it's clearer and if there's a more efficient way of coding this I would be really thankful if someone could give me a few tips.
Your code cannot work using that array periodStartTimes This is an array of strings and when you initialize it you get the value of the property (IE the current text of the labels) not a reference to a property that you can use to change the labels.
In any case it is a bad practice to allow a different class instance change the internal values of another class. It is better to provide a public method used by the external classes to change the internal properties.
So for example your Test form class could have a public method named as SetTextLabel
public class Test : Form
{
....
public void SetLabelText(string name, string value)
{
switch(name)
{
case "startTime":
this.labelForStartTime.Text = value;
break;
case "label1":
this.firstLabelToUpdate.Text = value;
break;
...
// and so on for all other labels
}
}
}
In this way the code that changes the label is inside the Test class and you can add all the checks and validations required with full access to all the internal variables of the Test class.
Now your loop can be rewritten as
for (int x = 1; x <= numOfPeriods; x++)
{
decimal workingNumber = lessonLength*x;
decimal Convert0 = dec + workingNumber;
TimeSpan Convert1 = TimeSpan.FromHours(Double.Parse(Convert0.ToString()));
string Convert2 = Convert1.ToString().Remove(5);
FormOpen.SetLabelText("label" + x.ToString, Convert2;
}
Of course now you don't need anymore the array, and this will probably remove another error present in your actual code. The array is fixed at 9 elements but you loop for numOfPeriods starting from 1 (thus skipping the first element) and if numOfPeriods is bigger than 8 your code will crash with IndexOutOfRange exception
I have 3 NumericUpDown elements in my form. This elements is synchronized by their sum. For example sum is 9 elements values is 3,3,3 and increment is 2. When user is changed first element up from 3 to 5 we must get 5,2,2.
For synchronized I had tried to use events ValueChanged and VisibleChanged, but they working when we have a programmatic modification or user interaction.
I used this method for every element, but for this events this method starts changing again, when result values other elements is changing in a code.
private void numericUpDown1Change(object sender, EventArgs e)
{
int oldValue = Sum - (int)numericUpDown2.Value - (int)numericUpDown3.Value;
int average;
if ((int)numericUpDown1.Value - oldValue > 0)
{
average = ((int)numericUpDown1.Value - oldValue) / 2;
numericUpDown2.Value = numericUpDown2.Value - average;
numericUpDown3.Value = numericUpDown3.Value - average;
}
else
{
average = (oldValue - (int)numericUpDown1.Value) / 2;
numericUpDown2.Value = numericUpDown2.Value + average;
numericUpDown3.Value = numericUpDown3.Value + average;
}
}
I want to use event, what worked just when user clicking the up or down button, or by the user entering a new value.
What event I must choose for it?
Use the ValueChanged event, but keep a flag telling you if the change is done by code or by user.
For a single control you can keep a Boolean variable at the class level (I would probably call it IsValueChangedByCode) and set it to false. Inside your methods, right before you change the value, set it to true and right after that back to false. Inside the event handler check that flag is true or false, and decide if you want to execute the code or not.
For 3 controls the logic is the same, but instead of using a boolean flag, you need 2 different booleans, or you can use an integer or flags enum.