Simulating snowfall in Windows Forms C# - c#

I'm quite new in C# and I want to creating something like falling snow (dots) in C# using Windows Forms.
I was already able to create the snowflakes at the top of the screen (I want to create new dot every 0,1s, at random x-position of Form and write down every snowflake's position into the List(Point) and with every Tick of timer (0,1s) I want the snowflake to change its position by 3px down and 1-3px right)
But I have the problem with refreshing the snowflakes positions. I don't know how to acces each snowflake in the List to Randomize its new position.
I tried foreach, but it gives me error, that says I cannot change variable in foreach.
Example:
foreach (var snowflake in snowflakeList)
{
snowflake.Y += 3;
snowflake.X += moveRandom.Next(1, 4);
}
Can anyone please tell me how can I divide List(Point) of snowflakes into invdividual snowflakes, so I could change position of every single dot separately?
Thank you :-)

The simplest way is just to use the index of the collection:
for (int i = 0; i < snowflakeList.Count; i++)
{
var snowflake = snowflakeList[i];
snowflake.Y += 3;
snowflake.X += moveRandom.Next(1, 4);
snowflakeList[i] = snowflake;
}

As Andrews answer use a for loop, but as the list is of Points (a value type) you would need to reference the Point in the list directly rather than make a copy of it:
for (int i = 0; i < snowflakeList.Count; i++)
{
snowflakeList[i].Y += 3;
snowflakeList[i].X += moveRandom.Next(1, 4);
}

Related

How to make this code more functional or 'prettier'

I've been working on a project where I need on a button press that this line gets executed.
if (listView1.SelectedItems[0].SubItems[3].Text == "0") //Checks to see Value
{
listView1.SelectedItems[0].SubItems[3].Text = "1";// If Value is Greater, Increase and Change ListView
questionNumberLabel.Text = listView1.SelectedItems[0].SubItems[3].Text;// Increase and Change Label
}
Now I have this repeated about 10 times with each value increasing by one. But I know that this is ugly, and dysfunctional. As well as conflates the file size. I've tried a few things. Primarily this method.
if (listView1.SelectedItems[0].SubItems[3].Text == "0")
{
for (var i = 1; i < 100;)
{
if (!Int32.TryParse(listView1.SelectedItems[0].SubItems[3].Text, out i))
{
i = 0;
}
i++;
listView1.SelectedItems[0].SubItems[3].Text = i.ToString();
Console.WriteLine(i);
}
}
But instead of just adding one, it does the 100 instances and ends. The reason this is becoming a pain in the *** is because the
listView1.SelectedItems[0].SubItems[3].Text
is just that - it's a string, not an int. That's why I parsed it and tried to run it like that. But it still isn't having the out come I want.
I've also tried this
string listViewItemToChange = listView1.SelectedItems[0].SubItems[3].Text;
Then parsing the string, to make it prettier. It worked like it did before, but still hasn't given me the outcome I want. Which to reiterate is, I'm wanting the String taken from the list view to be changed into an int, used in the for loop, add 1, then restring it and output it on my listView.
Please help :(
You say you want the text from a listview subitem converted to an int which is then used in a loop
so - first your creating your loop variable, i, then in your loop you're assigning to it potentially 3 different values 2 of which are negated by the, i++. None of it makes sense and you shouldn't be manipulating your loop variable like that (unless understand what you're doing).
if you move statements around a little..
int itemsToCheck = 10; // "Now I have this repeated about 10 times "
for (var item = 0; item < itemsToCheck; item++)
{
int i;
if (!Int32.TryParse(listView1.SelectedItems[item].SubItems[3].Text, out i))
{
i = 0;
}
i++;
listView1.SelectedItems[item].SubItems[3].Text = i.ToString();
Console.WriteLine(i);
}
Something along those lines is what you're looking for. I haven't changed what your code does with i, just added a loop count itemsToCheck and used a different loop variable so your loop variable and parsed value are not one in the same which will likely be buggy.
Maybe this give you an idea. You can start using this syntax from C# 7.0
var s = listView1.SelectedItems[0].SubItems[3].Text;
var isNumeric = int.TryParse(s, out int n);
if(isNumeric is true && n > 0){
questionNumberLabel.Text = s;
}
to shortcut more
var s = listView1.SelectedItems[0].SubItems[3].Text;
if(int.TryParse(s, out int n) && n > 0){
questionNumberLabel.Text = s;
}

A for loop somehow overrides an entire array, even though I can see no reason for that

So, been looking at this code for a good while now, and I am lost.
The point is to run a for loop that adds classes to an array, and then for each class runs through an array of points inside of that class, and add variations to it.
This then shows as a bunch of dots on a form, which are supposed to move independently of each other, but now follows each other completely.
It does not matter how much variation there is or anything, it's just 99 dots with the exact same acceleration, velocity, and location, and path.
The code is here, the method isn't touched by any other code, and the problem arises before it returns.
//Point of the method is to put variations of Baby into an array, and return that array
Dot.Class[] MutateAndListBaby(Dot.Class Baby)
{
//Making the empty array
Dot.Class[] BabyList = new Dot.Class[dots.Length];
//For loop that goes through through the whole array
for (int i = 1; i < BabyList.Length; i++)
{
//For each itteration the for loop adds the class reference to the index, then puts the standard directions into that reference, and then sets a value preventing it from being changed in another code
BabyList[i] = new Dot.Class();
BabyList[i].Directions = Baby.Directions;
BabyList[i].StartupComplete = true;
//The zero index variation when made like this, allows it to not be overriden, which would lead one to believe that how the directions are copied is he problem
//But it shouldn't be, BabyList[i].Directions = Baby.Directions; should be fire and forget, it should just add the Directions to the array and then leave it
BabyList[0] = new Dot.Class();
BabyList[0].Directions = new PointF[100];
for (int b = 0; b < BabyList[0].Directions.Length; b++)
{
BabyList[0].Directions[b] = new Point (5, 10);
}
BabyList[0].StartupComplete = true;
//The for loop that shuld add variation, but it seems like it somehow overrides it self, somehow
for (int b = 0; b < BabyList[i].Directions.Length; b++)
{
if (rand.Next(0, 101) >= 100)
{
int rando = rand.Next(-50, 51);
float mod = (float)rando / 50;
float x = BabyList[i].Directions[b].X;
x = x + mod;
BabyList[i].Directions[b].X = rand.Next(-5, 6);
}
if (rand.Next(0, 101) >= 100)
{
int rando = rand.Next(-50, 51);
float mod = (float)rando / 50;
float y = BabyList[i].Directions[b].Y;
y = y * mod;
BabyList[i].Directions[b].Y = rand.Next(-5, 6);
}
}
//Now one would assume this would create a unique dot that would move 100% independently right? Since it's at the end of the for loop, so nothin should change it
// Nope, somehow it makes every other dot copy its directions...
if (i == 5)
{
for (int b = 0; b < BabyList[5].Directions.Length; b++)
{
BabyList[5].Directions[b] = new PointF(-5f, -5f);
}
}
}
return BabyList;
}
}
}
With the code there, what I get is the 0 index dot going its own way, while the other 99 dots for some reason follow the 5th index's Directions, even though they should get their own variations later on in the code.
Any help would be much appreciated, it probarbly something obvious, but trust me, been looking at this thing for quite a while, can't see anything.
If I understand you correctly, this might be the issue:
BabyList[i].Directions = Baby.Directions;
Directions is of type array of PointF - a reference. The line above does not copy the array. Is that what you assume? If I'm not misreading the code you're presenting, you're creating one Dot.Class with its own array of PointF at index 0 and fill the rest of your Dot.Class array with instances that share one single array.
Directions is array, which is a reference type. When you're making assigment of a variable of this type
BabyList[i].Directions = Baby.Directions;
no new instance is created and reference us just being copied into new variable which still references original instance. Essentially in your loop only very first item gets a new instance of Directions as it's explicitly constructed. The rest share the instance which comes as a member of parameter passed to the method.
You probably want to change your if conditions:
(rand.Next(0, 101) >= 100
to
(rand.Next(0, 100) < 99
This will run an average of 99 times out of 100, whereas your current condition runs 1 out of 101 times (on average)
Oh, and Benjamin Podszun's answer about assigning the same array (not a copy of the same array) to Directions apply as well!
(Assuming that Directions isn't a getter that you created to return a copy of an array instead of a reference!)

Pass array number of object to event handler

I have an array of PictureBoxes.
for(int i = 0; i<10; i++)
{
this.elevatorDoors[i] = new System.Windows.Forms.PictureBox();
}
I would like to pass to the click event of one object,the array number that the particular object has.
this.elevatorDoors[i].Click +=
new System.EventHandler((sender,e)=>this.elevatorDoor_Click(sender,e, i));
But all I get when the event fires up is the number 10. I would like to get for example the number 4 when I click on the 4th PictureBox.
var tempValue = i;
this.elevatorDoors[i].Click +=
new System.EventHandler((sender,e)=> this.elevatorDoor_Click(sender,e, tempValue));
This will fix it. So you must pretty much ensure that when you are Invoking the event you are taking the current value of your loop iteration. After leaving the loop the value will always equal to last value. So you introduce tempValue which stores the current iteration.
I am assuming that this is more like a local scope problem. Just create a new function where you assign the clickhandler
private void AssignCallback(PictureBox pb, int index) {
pb.Click += new System.EventHandler((sender,e)=>this.elevatorDoor_Click(sender,e, index));
}
An alternative method would be to use the Tag property on the picturebox and read the value of the tag in your callback like so
this.elevatorDoors[i].Tag = i;
this.elevatorDoors[i].Click +=
new System.EventHandler((sender,e)=>this.elevatorDoor_Click(sender,e, Convert.ToInt32(((Control)i).Tag))-;

Custom Queue Class Iteration and Data Retrieval C#

So I'm working in Visual Studio 2015 with a few custom classes. One of which is called MinPriorityQueue, and it is a priority queue that, in this situation, allows me to retrieve the object of MinimumPriority in the queue via a property MinimumPriority. There is also a method called RemoveMinimumPriority, which is self-explanatory.
I am not allowed to modify this method, it was pre-made for us for this assignment, otherwise I would have already found a simple solution.
My program is meant to compare two text files, and return a value based off a certain equation which isn't important as far as this post goes. The problem I am having is within my UserInterface code. Here is my click event for the 'Analyze' button on my GUI.
private void uxAnalyze_Click(object sender, EventArgs e)
{
Dictionary<string, StoreWord> dictionary = new Dictionary<string, StoreWord>();
const int _numFiles = 2;
MinPriorityQueue<float, StoreInfo> minQueue = new MinPriorityQueue<float, StoreInfo>();
int numWords1 = 0;
int numWords2 = 0;
//Process Both Input Files
using (StreamReader sr = new StreamReader(uxTextBox1.Text))
{
for (int i = 0; i < _numFiles; i++)
{
if (i == 0)
{
dictionary = ReadFile(dictionary, uxTextBox1.Text, i, out numWords1);
}
if (i == 1)
{
dictionary = ReadFile(dictionary, uxTextBox2.Text, i, out numWords2);
}
}
}
int[] numWords = new int[2];
numWords[0] = numWords1;
numWords[1] = numWords2;
//Get 50 Words with Highest Combined Frequencies
foreach(var entry in dictionary.Values)
{
StoreInfo freq = new StoreInfo(entry, numWords);
minQueue.Add(freq, Convert.ToSingle(entry[0] + entry[1]));
if(minQueue.Count > 50)
{
minQueue.RemoveMinimumPriority();
}
}
//Compute and Display the Difference Measure
float diffMeasure = 0;
float temp = 0;
foreach( x in minQueue)
for (int i = 0; i < minQueue.Count; i++)
{
temp += minQueue.????; //This is where my problem stems
}
diffMeasure = (float)(100 * Math.Sqrt(temp));
}
A few lines from the end you will see a comment showing where my problem is located. The MinPriorityQueue (minQueue) has two parameters, a Priority, and a Value, where the Priority is a Float, and the Value is another class called StoreInfo. This class has an Indexer, which will return information from a different file depending on what the index is. In this case, there are only two files. For example: StoreInfo[i] returns the frequency of a word in the ith text file.
Ideally, my code would look like this:
for (int i = 0; i < minQueue.Count; i++)
{
temp += (minQueue.minimumValue[0] - minQueue.minimumValue[1])*(minQueue.minimumValue[0] - minQueue.minimumValue[1]);
}
diffMeasure = (float)(100 * Math.Sqrt(temp));
Problem is, that would require a minimumValue property, which I don't have access to. All I have is minimumPriority.
As far as I can see, there is no other way for me to get the Values that I need in order to get the frequencies that I need to get from the indexer and put into the equation.
Help is much appreciated.
Alright guys, I've been thinking at this for far too long, and it doesn't seem like anyone else sees another solution either.
At this point, I'm just going to go with the logical solution and add another property into the MinPriorityQueue class, even though it is against my professor's wishes.
Thank you all anyway.

C# Edit a variable of arraylist index

I got an arraylist of rectangles and I want to edit the X & Y values of all of them.
I tried using a foreach loop
foreach (Rectangle rect in rectangles)
rect.X += 1;
But this wouldn't work as it's read-only, so I tried a regular for loop
for (int i = 0; i < rectangles.Count; i++)
rectangles[i].X += 1;
And for some reason this wouldn't work either, because rectangles[i] just doesn't have any of rectangle's methods.
Then I stumbled across a post somewhere on stackoverflow about how to call methods of elements of an arraylist. And I haven't been able to find examples of this, so I hope someone can clear this up.
(Unit.unitArray[selectedUnit] as MyClass).DisplayUnitAttributes()
But I have no idea how to put this to use, I don't understand what Unit is supposed to be replaced with, and I'm guessing MyClass would be Rectangle...
Any help is appreciated!
TLDR: I want to iterate over an arraylist with rectangles, and edit the X & Y values of them.
According to the error you have got. "Return value is not a variable"
Rectangle is not a class. its an struct which is not reference type so you have to assign new value into it.
List<Rectangle> rectangles = new List<Rectangle>();
// rectangles.Add(x); make your list here
for (int index = 0; index < rectangles.Count; index++)
{
Rectangle r = rectangles[index];
r.x += 1;
rectangles[index] = r;
}
It's act like this because ArrayList is not typed. It's better to use a List<T> instead (where T is your class, in your example it will be a Rectangle). Here is MSDN link.
You can't modify object this way in the foreach loop. More info on this SO question.
About this example: (Unit.unitArray[selectedUnit] as MyClass).DisplayUnitAttributes()
It's called casting. You can read more about this on this SO question. So in your code it should looks like this: (rectangles[i] as Rectangle).X += 1;. You also should check if result of this casting is not null etc. But better read previous link to understand this.

Categories

Resources