Condensing multiple methods into one - c#

I have this method that I have essentially duplicated and hardcoded three times, but I would like to condense the three into one method and dynamically change the Input.GetKey(). I am just unsure of how to do that.
The main method is:
private void AugmentAbility1(AugmentData augmentData)
{
switch (augmentData.state)
{
case AbilityState.ready:
if (Input.GetKey(ability1Key))
{
augmentIndex = augmentData.index;
augmentList[augmentIndex].augmentSkill.Ability();
augmentData.state = AbilityState.active;
augmentData.activeTime = augmentList[augmentIndex].augmentSkill.activeTime;
}
break;
case AbilityState.active:
if (augmentData.activeTime > 0)
{
augmentData.activeTime -= Time.deltaTime;
}
else
{
augmentData.state = AbilityState.cooldown;
augmentData.cooldownTime = augmentList[augmentIndex].augmentSkill.cooldownTime;
}
break;
case AbilityState.cooldown:
if (augmentData.cooldownTime > 0)
{
augmentData.cooldownTime -= Time.deltaTime;
Debug.Log("TimeLeft: " +augmentData.cooldownTime);
}
else
{
augmentData.state = AbilityState.ready;
Debug.Log("state changed to: " + augmentData.state);
}
break;
}
}
In addition to AugmentAbility1, I have 2 other methods(AugmentAbility2,AugmentAbility3) where I pass in augmentData2 and augmentData3. I know I could easily use a foreach to pass those parameters in. The issue is that each AugmentAbility method has a different ability key.
if (Input.GetKey(abilityXKey))
The separate variables being:
ability1Key = Keycode.Alpha1
ability2Key = Keycode.Alpha2
ability3Key = Keycode.Alpha3
The three methods are currently sitting in my Update() like so, in order to catch the different key inputs.
Update()
{
AugmentAbility1(augmentData1);
AugmentAbility2(augmentData2);
AugmentAbility3(augmentData3);
}

Say hello to C# syntactic sugar in the form of Action and Func
In this case:
private void AugmentAbility(AugmentData augmentData,
KeyCode expectedKeyCode,
Action<AugmentData> completionWhenMatchedKey)
{
switch (augmentData.state)
{
case AbilityState.ready:
if (Input.GetKey(expectedKeyCode))
{
completionWhenMatchedKey(augmentData);
}
break;
case AbilityState.active:
if (augmentData.activeTime > 0)
{
augmentData.activeTime -= Time.deltaTime;
}
else
{
augmentData.state = AbilityState.cooldown;
augmentData.cooldownTime =
augmentList[augmentIndex].augmentSkill.cooldownTime;
}
break;
case AbilityState.cooldown:
if (augmentData.cooldownTime > 0)
{
augmentData.cooldownTime -= Time.deltaTime;
Debug.Log("TimeLeft: " +augmentData.cooldownTime);
}
else
{
augmentData.state = AbilityState.ready;
Debug.Log("state changed to: " + augmentData.state);
}
break;
}
}
// Now to call it:
public void Update() {
AugmentAbility(augmentData1, KeyCode.Alpha1, (augmentData) => {
augmentIndex = augmentData.index;
augmentList[augmentIndex].augmentSkill.Ability();
augmentData.state = AbilityState.active;
augmentData.activeTime = augmentList[augmentIndex].augmentSkill.activeTime;
});
AugmentAbility(augmentData2, KeyCode.Alpha2, (augmentData) => {
// Do sth else
});
AugmentAbility(augmentData3, KeyCode.Alpha3, (augmentData) => {
// Do sth entirely different
});
}

Related

Case/Switch statement not executing part of the code in C#

I have written a Switch/Case statement. The purpose of this statement is to check whether a specific checkbox is selected or not. If the checkbox is selected, the case statements get the true value and the name of the checkbox. For example, if I select Ford in the XAML front end interface, a label gets updated and it adds the value of 10 and if it is unselected, it subtracts 10 as to get the value back. However, I'm just getting the value subtracted. Even when I select the checkbox, I end up with -10, -20 etc values.
I can't figure out where I am going wrong with this.
public static int storage = 0;
public static void StorageRequired(string carName, bool state)
{
switch (carName)
{
case "Ford":
if (state)
{
storage += 10;
}
else
{
storage -= 10;
}
return;
case "Honda":
if (state)
{
storage += 10;
}
else
{
storage -= 10;
}
return;
case "McLaren":
if (state)
{
storage += 10;
}
else
{
storage -= 10;
}
return;
case "Mercedes":
if (state)
{
storage += 10;
}
else
{
storage -= 10;
}
return;
default:
storage = 0;
return;
}
}
Now I have a some checkboxes such as Ford, Honda etc, one for each case. And I am calling them StorageRequired method like this:
private void Single_Checked(object sender, RoutedEventArgs e)
{
if (InstallFord?.IsChecked == true)
{
InstallAE.IsChecked = true;
CarConfigs.StorageRequired("Ford", true);
}
if (InstallFord?.IsChecked == false)
{
InstallAE.IsChecked = false;
CarConfigs.StorageRequired("Ford", false);
}
if (InstallHonda?.IsChecked == true)
{
CarConfigs.StorageRequired("Honda", true);
}
if (InstallHonda?.IsChecked == false)
{
CarConfigs.StorageRequired("Honda", false);
}
if (InstallMcLaren?.IsChecked == true)
{
CarConfigs.StorageRequired("McLaren", true);
}
if (InstallMcLaren?.IsChecked == false)
{
CarConfigs.StorageRequired("McLaren", false);
}
if (InstallMercedesvisitor?.IsChecked == true)
{
CarConfigs.StorageRequired("Mercedes", true);
}
if (InstallMercedesvisitor?.IsChecked == true)
{
CarConfigs.StorageRequired("Mercedes", false);
}
lblRequiredSpace.Content = $"Required space: {CarConfigs.storage} Mb";
}
The problem is that when I click and check a checkbox, for instance Ford, I get -10 instead of 10. And then when I uncheck it again, I get -20. I'd really appreciate some help in figuring out where I am going wrong here. Basically, I should get 10 added if I am checking any of the cars and similarly, 10 subtracted to get back to original value if that car is unchecked.
Note: 10 is just arbitrary here to make things simple.
Here is your problem. Never put return in a switch case, you should use break; instead of return.
I am not really sure what CarConfigs.GetSpaceConsumed is, So I will assume that its a number. So if you are getting a number you should (You don't have to but I reccomend) use return functions.
So this should probably work, however I made the storage to be local variable so it will return number from the switch statement and the whole function in this case would a return function.
public static int StorageRequired(string carName, bool state)
{
int storage = 0;
switch (carName)
{
case "Ford":
if (state){
storage += 10;
}else{
storage -= 10;
}
break;
case "Honda":
if (state){
storage += 10;
}else{
storage -= 10;
}
break;
case "McLaren":
if (state){
storage += 10;
}else{
storage -= 10;
}
break;
case "Mercedes":
if (state){
storage += 10;
}else{
storage -= 10;
}
break;
}
return storage;
}

Weird results in c# app game

For an internship project I'm making an app based on Foley sound effects. I made a game for it. One button generates the effect, one plays the sound and four buttons for possible awnsers.
Somehow, the text displays ('helaas' and 'juist!') aren't consistent. The awnser could be right and it will display 'helaas', but when clicken multiple times, it will display 'juist!'. Can anyone help me with what I am doing wrong here?
int kiesnummer()
{
Random randomSound = new Random();
int theSound = randomSound.Next(1, 4);
return theSound;
}
NewSound.Click += delegate
{
kiesnummer();
if (kiesnummer() == 1)
{
welk.Text = "Open haard";
}
else if (kiesnummer() == 2)
{
welk.Text = "Regen";
}
else if (kiesnummer() == 3)
{
welk.Text = "Hondenpootjes op hout";
}
else if (kiesnummer() == 4)
{
welk.Text = "Paardenhoeven op beton";
}
};
Play.Click += delegate
{
if (kiesnummer() == 1)
{
_chips.Start();
}
else if (kiesnummer() == 2)
{
_rain.Start();
}
else if (kiesnummer() == 3)
{
_doggo.Start();
}
else if(kiesnummer() == 4)
{
_koko.Start();
}
};
//Parameters aan functie koppelen bij klikken op de knop
Aw1.Click += delegate
{
kiesknop(1);
};
Aw2.Click += delegate
{
kiesknop(2);
};
Aw3.Click += delegate
{
kiesknop(3);
};
Aw4.Click += delegate
{
kiesknop(4);
};
//Beoordelen of keuze juist of onjuist is
bool kiesknop(int knop)
{
if (knop == kiesnummer())
{
end.Text = "Juist!";
return true;
}
else
{
end.Text = "Helaas!";
return false;
}
}
(I left the button and media declerations out, since it didn't seem relevant)
Calling kiesnummer(); in every if condition will give you different results as it generates new random value every time.
Call it once and use its value through-out:
int value = kiesnummer();
if (value == 1)
{
welk.Text = "Open haard";
}
else if (value == 2)
{
welk.Text = "Regen";
}
else if (value) == 3)
{
welk.Text = "Hondenpootjes op hout";
}
else if (value == 4)
{
welk.Text = "Paardenhoeven op beton";
}

How to disable more than one NumericUpDown controls using one method?

i have a form with more than one NumericUpDown as controls to input answer. i want every input is true for an operation (multiplication, sum etc), NumericUpDown for that operation will be disable. i have used the code below (just for sum operation), but i think its not efficient because i have to make a method to check every operation.
private void IsSumTrue() {
if (add1 + add2 == sum.Value)
{
sum.Enabled = false;
}
}
private void IsDifferenceTrue()
{
if (add1 - add2 == difference.Value)
{
difference.Enabled = false;
}
}
private void IsProductTrue()
{
if (add1 * add2 == product.Value)
{
product.Enabled = false;
}
}
private void IsQuotientTrue()
{
if (add1 / add2 == quotient.Value)
{
quotient.Enabled = false;
}
}
anyone have idea how to make it more efficient with just a method for all operation?
below is my idea, but to check the value is true for every NumericUpDown i don't know how.
private void DisableIfValueIsTrue()
{
foreach(Control control in this.Controls)
{
NumericUpDown value = control as NumericUpDown;
// if(value [NEED HELP]
}
}
Considering your situtaion, you can set a tag for each NumericUpDown in design mode like this:
sum.Tag=1;
square.Tag=2;
etc
Then define some int variables:
int iSum=add1+add2;
int iSquare= //Whatever you want
etc
And finally loop through your controls this way:
foreach (NumericUpDown control in this.Controls.OfType<NumericUpDown>())
{
int intCondition = Convert.ToInt32(control.Tag) == 1
? iSum
: Convert.ToInt32(control.Tag) == 2
? iSquare
: Convert.ToInt32(control.Tag) == 3
? i3
: i4; //You should extend this for your 8 controls
control.Enabled = intCondition == control.Value;
}
OK! Second way I offer
Since you will have to always check 8 different conditions, you could simply forget about looping through the controls and just change your method like this:
private void DisableIfValueIsTrue()
{
sum.Enabled = add1 + add2 != sum.Value;
difference.Enabled= add1 - add2 != difference.Value;
product.Enabled= add1 * add2 != product.Value;
quotient.Enabled= (add2 !=0) && (add1 / add2 != quotient.Value);
//etc
}
I came across this while doing some research and would like to give my solution I used for my situation and hope it helps people. I needed minimum and maximum numbers for a calculation, so mine are named appropriately and I correlated these with some CheckBoxes. I used null in beginning of minimum and end of maximum to account for empty. I also had to create an event handler SubscribeToEvents() shown below.
In my load event for my form:
SubscribeToEvents();
_checkBoxs = new[] { cbXLight, cbLight, cbMedium, cbHeavy, cbXHeavy, cbXXHeavy, cbXXXHeavy };
_minimumsNumericUpDowns = new[] { null, nLightMin, nMediumMin, nHeavyMin, nXHeavyMin, nXXHeavyMin, nXXXHeavyMin };
_maximumsNumericUpDowns = new[] { nXLightMax, nLightMax, nMediumMax, nHeavyMax, nXHeavyMax, nXXHeavyMax, null };
then I created a method:
private void DisableNumericUpDowns()
{
// disable everything:
foreach (var n in _minimumsNumericUpDowns)
{
if (n != null)
n.Enabled = false;
}
foreach (var n in _maximumsNumericUpDowns)
{
if (n != null)
n.Enabled = false;
}
}
The event handler:
private bool _eventsSubscribed;
private void SubscribeToEvents()
{
if (_eventsSubscribed)
return;
_eventsSubscribed = true;
cbXXHeavy.CheckedChanged += CheckBox_NumericState;
cbXHeavy.CheckedChanged += CheckBox_NumericState;
cbXLight.CheckedChanged += CheckBox_NumericState;
cbHeavy.CheckedChanged += CheckBox_NumericState;
cbLight.CheckedChanged += CheckBox_NumericState;
cbMedium.CheckedChanged += CheckBox_NumericState;
cbXXXHeavy.CheckedChanged += CheckBox_NumericState;
}
Now I can used this to check when they are enabled and if they are greater than or less than 0 if needed in the method CheckBox:
private void CheckBox_NumericState(object sender, EventArgs e)
{
// disable everything
DisableNumericUpDowns();
// see if more than one checkbox is checked:
var numChecked = _checkBoxs.Count((cb) => cb.Checked);
// enable things if more than one item is checked:
if (numChecked <= 1) return;
// find the smallest and enable its max:
var smallest = -1;
for (var i = 0; i < _checkBoxs.Length; i++)
{
if (!_checkBoxs[i].Checked) continue;
if (_maximumsNumericUpDowns[i] != null)
{
_maximumsNumericUpDowns[i].Enabled = true;
}
smallest = i;
break;
}
// find the largest and enable its min:
var largest = -1;
for (var i = _checkBoxs.Length - 1; i >= 0; i--)
{
if (!_checkBoxs[i].Checked) continue;
if (_minimumsNumericUpDowns[i] != null)
{
_minimumsNumericUpDowns[i].Enabled = true;
}
largest = i;
break;
}
// enable both for everything between smallest and largest:
var tempVar = largest - 1;
for (var i = (smallest + 1); i <= tempVar; i++)
{
if (!_checkBoxs[i].Checked) continue;
if (_minimumsNumericUpDowns[i] != null)
{
_minimumsNumericUpDowns[i].Enabled = true;
}
if (_maximumsNumericUpDowns[i] != null)
{
_maximumsNumericUpDowns[i].Enabled = true;
}
}
}
So I can check each state as required:
I want to check if Extra Light is check:
// Extra Light
if (!cbXLight.Checked) return;
if (nXLightMax.Enabled == false)
{
_structCategoryType = XLight;
CheckStructureSheets();
}
else
{
if (nXLightMax.Value > 0)
{
_dMax = nXLightMax.Value;
_structCategoryType = XLight;
CheckStructureSheets();
}
else
{
MessageBox.Show(#"Extra Light Max cannot be zero (0)");
}
}
and next light checks both:
// Light
if (cbLight.Checked)
{
if (nLightMin.Enabled == false && nLightMax.Enabled == false)
{
_structCategoryType = Light;
CheckStructureSheets();
}
else
{
if (nLightMin.Enabled && nLightMin.Value > 0)
{
if (nXLightMax.Enabled && nLightMin.Enabled && nLightMax.Enabled == false)
{
_dMin = nLightMin.Value;
_structCategoryType = Light;
CheckStructureSheets();
}
else
{
if (nLightMax.Value > 0)
{
_dMin = nLightMin.Value;
_dMax = nLightMax.Value;
_structCategoryType = Light;
CheckStructureSheets();
}
else
{
MessageBox.Show(#"Light Max cannot be zero (0)");
return;
}
}
}
else if (nLightMin.Enabled == false && nLightMax.Enabled)
{
if (nLightMax.Value > 0)
{
_dMax = nLightMax.Value;
_structCategoryType = Light;
CheckStructureSheets();
}
else
{
MessageBox.Show(#"Light Max cannot be zero (0)");
}
}
else
{
MessageBox.Show(#"Light Min cannot be zero (0)");
return;
}
}
}
Hope this helps someone.
Tim
thanks for #AlexJoliq and #BrettCaswell. just want to inform that before Alex edited his answer from using "==" to "!=", i (thought) already solved the problem. but i don't know where is the more effective and efficient way, alex's or mine.
below is my code for DisableIfValueIsTrue():
if (add1 + add2 == sum.Value) sum.Enabled = false;
if (add1 - add2 == difference.Value) difference.Enabled = false;
if (add1 * add2 == product.Value) product.Enabled = false;
if (add1 / add2 == quotient.Value) quotient.Enabled = false;

C# List.Remove(object)

I have an object which is a List within a List:
public List<List<MyObject>> Grid { get; set; }
I have noticed that sometimes when I do:
Grid[currentShape.ColumnNumber].Remove(currentShape);
It removes two objects from the array.
The way in which I populate the Grid object is if a certain condition is met, then I basically do:
Grid[newShape.ColumnNumber].Add(newShape);
currentShape = newShape;
currentShape is a class variable which I use to move around the object on the screen. Is it because of a Reference Type that when I sometimes do .Remove(), it deletes more than one object from the array? Do I need to extend the .Remove() somehow?
Any help is highly appreciated.
Update - The entire method:
public void MoveIfPossible(MoveDirection direction)
{
List<Shape> neighbouringShapes = new List<Shape>();
switch (direction)
{
case MoveDirection.Right:
if (currentShape.ColumnNumber == utilities.columns.Count - 1)
return;
neighbouringShapes = GetNeighbouringShapes(currentShape.ColumnNumber);
foreach (var s in neighbouringShapes)
{
if (currentShape.Position.X + 1 < s.Position.X && currentShape.Position.Y + currentShape.Texture.Height >= s.Position.Y)
{
return;
}
}
world.Grid[currentShape.ColumnNumber].Remove(currentShape);
world.Grid[currentShape.ColumnNumber + 1].Add(currentShape);
currentShape.Position.X = utilities.columns[currentShape.ColumnNumber + 1].X;
currentShape.ColumnNumber++;
currentShape.Coordinate.X = currentShape.ColumnNumber;
currentShape.Coordinate.Y = world.Grid[currentShape.ColumnNumber].Count - 1;
break;
case MoveDirection.Left:
if (currentShape.ColumnNumber == 0)
return;
neighbouringShapes = GetNeighbouringShapes(currentShape.ColumnNumber - 1);
foreach (var s in neighbouringShapes)
{
if (currentShape.Position.X - 1 > s.Position.X && currentShape.Position.Y + currentShape.Texture.Height >= s.Position.Y)
{
return;
}
}
world.Grid[currentShape.ColumnNumber].Remove(currentShape);
world.Grid[currentShape.ColumnNumber - 1].Add(currentShape);
currentShape.Position.X = utilities.columns[currentShape.ColumnNumber - 1].X;
currentShape.ColumnNumber--;
currentShape.Coordinate.X = currentShape.ColumnNumber;
currentShape.Coordinate.Y = world.Grid[currentShape.ColumnNumber].Count;
break;
}
}

Form showing then closing when application starts

This is the form code and every time I test some inputs, the application will open and then immediately close and I can't figure out what is causing it.
namespace Assignment2
{
public partial class IsmClassForm : Form
{
public IsmClassForm()
{
InitializeComponent();
}
private void IsmClassForm_Load(object sender, EventArgs e)
{
}
protected Student m_student;
protected Course m_course;
protected IsmClassForm m_next;
protected EnrollmentForm m_home;
public bool TestPrerequisites()
{
if (!m_student.Record.MeetsPrerequisites(m_course.Number))
{
MessageBox.Show("The registrar reports that you don't meet the prerequisites for " + m_course.Prefix + m_course.Number.ToString());
m_student.PridePoints = m_student.PridePoints - 5;
m_student.Record.Remove(m_course);
return false;
}
return true;
}
public string Description
{
get
{
return textDescription.Text;
}
set
{
textDescription.Text = value;
}
}
public string Title
{
get
{
return this.Text;
}
set
{
this.Text = value;
}
}
public string Welcome
{
get
{
return labelWelcome.Text;
}
set
{
labelWelcome.Text = value;
}
}
public bool Initialize(Student student, int course, IsmClassForm next, EnrollmentForm home)
{
if (student == null) return false;
m_student = student;
m_next = next;
m_home = home;
m_course = m_student.Record.FindEnrolled(course);
if (m_course == null)
{
return false;
}
labelCourse.Text = m_course.Prefix + "-" + m_course.Number.ToString();
return TestPrerequisites();
}
public enum DropMode
{
FreeDrop, PayDrop, Withdraw, NoDrop
};
DropMode mState = DropMode.FreeDrop;
public DropMode Drop
{
get
{
return mState;
}
set
{
mState = value;
UpdateDrop();
}
}
public void UpdateDrop()
{
switch (Drop)
{
case DropMode.FreeDrop:
buttonDrop.Text = "Drop";
break;
case DropMode.PayDrop:
buttonDrop.Text = "Drop";
break;
case DropMode.Withdraw:
buttonDrop.Text = "Withdraw";
break;
case DropMode.NoDrop:
buttonDrop.Text = "Done";
break;
}
}
protected void buttonDrop_Click(object sender, EventArgs e)
{
switch (Drop)
{
case DropMode.FreeDrop:
m_student.PridePoints = m_student.PridePoints - 5;
m_student.Record.Remove(m_course);
m_course = null;
break;
case DropMode.PayDrop:
m_student.PridePoints = m_student.PridePoints - 10;
m_student.WealthPoints = m_student.WealthPoints - 500;
m_student.Record.Remove(m_course);
m_course = null;
break;
case DropMode.Withdraw:
m_student.PridePoints = m_student.PridePoints - 50;
m_student.WealthPoints = m_student.WealthPoints - 500;
m_course.Grade = "W";
break;
case DropMode.NoDrop:
m_student.WealthPoints = m_student.WealthPoints - 500;
break;
}
Close();
}
protected void IsmClassForm_FormClosed(object sender, FormClosedEventArgs e)
{
if (e.CloseReason == CloseReason.UserClosing)
{
//The student not having a grade suggest the buttons were ignored
if (m_course != null && m_course.Grade == null)
{
m_course.Grade = "F";
m_student.PridePoints = m_student.PridePoints - 100;
m_student.WealthPoints = m_student.WealthPoints - 500;
}
if (m_next != null) m_next.Show();
else if (m_home != null) m_home.Show();
}
}
And here are some test inputs:
static void TestIsmClassForm()
{
Student tjt1 = new Student("Travis Todd");
tjt1.Record = new Transcript();
tjt1.Record.Add(new Course(1, 3113, "B", false));
tjt1.Record.Add(new Course(1, 3232, "C", false));
tjt1.Record.Add(new Course(2, 3113, "A", true));
tjt1.Record.Add(new Course(2, 3232, null, true));
tjt1.Record.Add(new Course(2, 4220, null, true));
IsmClassForm f4220 = new IsmClassForm();
IsmClassForm f3232 = new IsmClassForm();
IsmClassForm f4212 = new IsmClassForm();
f4212.Initialize(tjt1, 4212, f3232, null);
f3232.Initialize(tjt1, 3232, f4220, null);
f4220.Initialize(tjt1, 4220, null, null);
f4212.Show();
}
This does use some other classes in the project and their forms, but I the other functions all work and these is the only problem I have found so far. Am I missing something glaringly obvious?
Thank you,
Travis
You have two ways to achieve this;
Given your entry method:
public static void Main()
{
TestIsmClassForm();
}
You can use Application.Run or Form.ShowDialog:
static void TestIsmClassForm()
{
...All of your original code...
Application.Run(f4212.Show());
//OR
f4212.ShowDialog()
}
What is happening right now is that Form.Show is non-blocking - the application calls it, continues on out of the method, and closes.
Application.Run will show the form and wait until it closes before exiting the application. Form.ShowDialog() will block the calling method until the form is closed.
Application.Run is preferred because it guarantees the form used as the application host is marshalled in the "Main" or "GUI" thread. ShowDialog() makes no guarantee when run direct from Main()(Application.MessageLoop is false) and it is possible for some surprisingly annoying threading bugs to happen - so the majority of the time Application.Run is the best way to achieve what you are doing.
Make sure there is a Program.cs (that's the default name) file in your project. It should have void Main(string[] args) method, which will construct an instance of the form (namely, form1) and do Application.Run(form1).
Place breakpoints in IsmClassForm_Load and IsmClassForm_FormClosed to catch the moments of the form opening and closing.
The reason the form disappears is that the variable/object that contains the form goes out of scope and is disposed off at the end of your test block.
i.e. As soon as the 'code' reaches the closing '}' all of those form (and the Student) variables will be disposed of.
You could replace the .Show(), with .ShowDialog() which will cause the code to stop until the form is manually closed.
MSDN: ShowDialog
MSDN: Variable and Method Scope

Categories

Resources