Index was out of range using 2 picturebox lists - arrays

I'm making a little game involving 2 picturebox lists and collision detection.
What I have is:
List<PictureBox> spells = new List<PictureBox>();
List<PictureBox> enemy = new List<PictureBox>();
I then use functions to dynamically create new pictureboxes for each of these lists with their appropriate images.
Then the collision detection using a timer:
private void timer1_Tick(object sender, EventArgs e)
{for (int i = 0; i <= spells.Count-1 ; i++)
{
for (int j = 0; j <= enemy.Count-1 ; j++)
{
if (spells[i].Top == enemy[j].Top &&
spells[i].Right > enemy[j].Left &&
spells[i].Tag.ToString()=="Fire" && enemy[j].Tag.ToString()=="Frostenemy")
{
Controls.Remove(enemy[j]);
enemy[j].Dispose();
enemy.Remove(enemy[j]);
Controls.Remove(spells[i]);
spells[i].Dispose();
spells.Remove(spells[i]);
}
And repeat for the other types of picutreboxes. This works OK if there are less than 3 pictureboxes from the "enemy" list, which are generated by another timer, but as soon as there are more than 3 on the screen and I try to create a picturebox from the "spells" list, I get the following error:
"Index was out of range. Must be non-negative and less than the size of the collection."
I have looked up other solutions to this problem but I haven't really had any luck so far.

As an experiment, try making your timer longer (slower, fewer ticks per minute) to see if the problem improves, but doesn't go away.
The timer may be firing off simultaneous runs of your function there -- which could cause all sorts of logical problems.

Related

How to force WinForms into ->Show()

The following code fragment uses a WinForms instance with a button to start a countdown and a textbox to follow it. To simulate a calculation process of any duration, a Fibonacci number is calculated within each count. Regardless of how much time the form element has to react, the countdown is not displayed. Only when everything is finished, the result alone is displayed.
Put simply, I wonder where the event handler gets the idea that it has to wait for the whole process to finish. The calculation has nothing to do with the form element. Actually, it would make more sense to get the calculation 'politely' wait for the UI element, if it lacks the time to display the desired intermediate steps and thus pauses for a moment. Is there any other methode than ->Show() to force a Form window refresh or is this waiting direction perhaps 'default' and can be optionally reversed?
main.cpp
---
form1.h / form1.cpp
---
// sub.cpp ...
void App1::Form1::button1_Click(System::Object^ sender, System::EventArgs^ e) {
unsigned res,dur=40;
System::String^ s;
Form^ fo = Form::ActiveForm;
for(int i = 10;i >= 0;i--) {
res = fibo(dur); // Loop: dur 5|80 ~ instantan|endless
s = i.ToString();
fo->Controls[1]->Text = s;
if(1) fo->Show(); } /// 0|1 no difference ??
s = res.ToString();
fo->Controls[1]->Text = s; }
unsigned fibo(unsigned n) { // time consuming calculation placeholder
long result = 0;
if (n == 0) return 0;
else if (n < 2) result = 1;
else result = fibo(n - 1) + fibo(n - 2);
return result; }
On my way to this question I found articles dealing with 'backgraoundWorker', hence the Fibonacci numbers. But what if the 100% is not known? This complicity all just to show that the process is still alive seems to me a bit break a fly on the wheel. Isn't that done more simple?

How can i cooldown a loop in wpf ? Forest Fire Simulation

As a personnal work, i have to do a forest fire simulation in WPF.
I created all the map with a grid, and using an array.
The Fire is added through a random number ( in the array when ex : case = " Forest ").
The Fire is burning all the " forest case " and it depends on the wind ( N S E W, etc. ). Everything is working fine !
But i encounter a minor problem through the "fire loop". I mean, when i click on my button ' fire progress " ( which does the fire expansion ) all the forest case burns in a simultaneous way. ( the direction is correct, only the case with the right direction burns, the problem is not here ).
I wanted to cooldown this loop as each case after case will be burned, such as :
Case forest burns. Wait. Case forest 2 burns. And so on. And not all the cases in the right directions ( of the wind ).
I tried to use a dispatcher timer (TimeSpan ). But with no success. The only thing's working is the results of the loop is slowdown ( in seconds, milliseconds, days, whatever ). BUT all the cases changes in a same time. And not one by one.
Apologies if my english is not grammatically correct !
Here is my code :
private void DeclencherLeFeu()
{
TempsDuJeu = new DispatcherTimer();
TempsDuJeu.Interval = TimeSpan.FromSeconds(1);
TempsDuJeu.Tick += new EventHandler(OnTimerGameEvent);
TempsDuJeu.Start();
TempsQueMetLeFeuPourBrulerLaForet = new DispatcherTimer();
TempsQueMetLeFeuPourBrulerLaForet.Interval = TimeSpan.FromSeconds(8);
TempsQueMetLeFeuPourBrulerLaForet.Tick += new EventHandler(LesArbresSontCalcines);
TempsQueMetLeFeuPourBrulerLaForet.Start();
}
Note : LesArbresSontCalcines means in english that the trees are burned. It calls a function just as below :
private void LesArbresSontCalcines(object sender, EventArgs e)
{
for (int i = 0; i < 7; i++)
{
for (int j = 1; j < 10; j++)
{
if (MonTableau[i, j].Name == "Feu")
{
MonTableau[i, j].Source = new BitmapImage(new Uri(#"E:\tp999\wpfapplication13\wpfapplication13\ArbreMort1.gif", UriKind.RelativeOrAbsolute));
ImageBehavior.SetAnimatedSource(MonTableau[i, j], new BitmapImage(new Uri(#"E:\tp999\wpfapplication13\wpfapplication13\ArbreMort1.gif", UriKind.RelativeOrAbsolute)));
MonTableau[i, j].Name = "Noir";
}
}
}
}
Note : All the burning cases ( i use a fire.gif on the forest case ) are replacing with the ArbreMort1.gif (represents a blacked tree ).
In this part of my code, all the burning cases just change, in a same time, as a dead tree. And Not one by one.
I tried to do that the first burning case will be the first be darked ( with the ArbreMort1.gif) and so on till the ending burning case ( that will be the last to be transformed ).
How should i use this dispatcher timer ?
Thank you for your replies ! :)
You need to re-architect the handler. Create class members int[7] j and int i = 0;
Then inside handler index j array with i value to determine what j index is. Then increment j index then increment i mod 7. So now it will take 560 seconds to complete the sequence.
Thank you for your answers ! I will try to fix it ! :)
Have a nice day !

as3 array of objects - movement with constant speed

Ok, so I have some experience with as3 and some of the basics. But this problem has been stumping me for so long. I tried to do a workaround based on what I currently know about as3. But somehow either i get an error message or it just doesn't do anything at all. Here is the code that i'm trying to solve.
var zombieCount:Array = new Array();
var helltime:Timer = new Timer(1500);
helltime.addEventListener(TimerEvent.TIMER, spawnzombies)
helltime.start();
function spawnzombies(happened:TimerEvent){
var zombie1:Zombie = new Zombie();
zombieCount.push(zombie1);
stage.addChild(zombieCount[zombieCount.length - 1]);
zombie1.x = 135 + (330*Math.random())
zombie1.y = -29
stage.addEventListener(Event.ENTER_FRAME, move_zombie)
function move_zombie(happened:Event){
for(var i:int; i < zombieCount.length; i++){
zombieCount[i].y = zombieCount[i].y + 1;
if(zombieCount[i].hitTestObject(border)){
stage.removeChild(zombieCount[i]);
zombieCount.shift();
trace(zombieCount.length);
}
}
}
}
While this may not be inclusive of everything wrong, here are at least a few of the issues I see.
Inline function issue:
Inside your timer tick handler (spawnZombies), you create an inline function called move_zombie and then add an enter frame handler that calls that function.
The issue here, is that every tick of the timer, will then create a whole new copy of that function, and add ANOTHER enter frame handler. This will create huge problems after a few timer ticks.
Break that move_zombie function OUT OF the spawn function:
eg:
helltime.addEventListener(TimerEvent.TIMER, spawnzombies)
helltime.start();
stage.addEventListener(Event.ENTER_FRAME, move_zombie);
function move_zombie(......
function spawnzombies(.....
Iteration issue:
In your for loop:
for(var i:int; i < zombieCount.length; i++){
zombieCount[i].y = zombieCount[i].y + 1;
if(zombieCount[i].hitTestObject(border)){
stage.removeChild(zombieCount[i]);
zombieCount.shift();
trace(zombieCount.length);
}
}
You are not initializing your i value. While this will default it to 0, it's still a good idea for readability to initialize it.
So your iterating forward from 0 to the end of the array. However, if your hit test succeeds, you then use the shift method of the array. This removes the first item of the array (irrespective of what value i is at the time). This will remove the wrong item, plus mess up what zombieCount[i] refers to (because the amount of items has now changed after doing shift, so the next iteration zombieCount[i] will be a reference to same item as the previous iteration).
Instead of what you're currently doing, use the splice method to remove, and iterate backwards so your index doesn't get out of whack.
for(var i:int=zombieCount.length-1;i >=0;i--){
zombieCount[i].y += 1; //move it down 1 pixel
if(zombieCount[i].hitTestObject(border)){
stage.removeChild(zombieCount[i]);
zombieCount.splice(i,1); //remove the item at the current index (do this instead of shift)
trace(zombieCount.length);
}
}

Changing Child Index of MovieClips based on their Y Position?

I'm writing a game with Flash CS5/AS 3.0 that tries to simulate depth of field by drawing all the relevant Movie Clips based on their Y position in ascending order, i.e. things lower on the stage overlap things higher on the stage. A MovieClip with a Y position of 10 would therefore need to have a lower index compared to a MovieClip with a Y position of 20, so the second one gets drawn on top of the first.
I wrote a quick and dirty function just to test this. During the trace, I've noticed that the truck's index hits 0 when I go near the top of the stage, but if I go too far up it will completely disappear from the stage. Trace then starts generating this error:
ArgumentError: Error #2025: The supplied DisplayObject must be a child of the caller.
at flash.display::DisplayObjectContainer/getChildIndex()
at EICT::Game/ReorganizeDisplayIndexes()
at EICT::Game/loop()
theTruck is a MovieClip of the player controlled vehicle
Enemies, Cones, Rocks are all arrays which contain MovieClips
None of them have event listeners.
private function ReorganizeDisplayIndexes(): void
{
var drawableObjects:Array = new Array();
drawableObjects.push(theTruck);
drawableObjects = drawableObjects.concat(Enemies, Rocks, Bushes);
drawableObjects.sortOn("y", Array.DESCENDING | Array.NUMERIC);
drawableObjects.reverse();
trace(collisionLayer.getChildIndex(theTruck));
for (var a:int = collisionLayer.numChildren - 1; a >= 0; a--)
{
collisionLayer.removeChildAt(a);
}
for (var i:int = 0; i < drawableObjects.length; i++)
{
collisionLayer.addChild(drawableObjects[i]);
}
}
Hint: You don't need to remove the child first. When you use addChild() on an object, it is automatically re-added to the next highest depth.
That said, you'll just need to do something like this:
drawableObjects.sortOn("y");
for each(var i:DisplayObject in drawableObjects)
{
if(i.parent)
i.parent.addChild(i);
}
Use setChildIndex instead of removing and re-adding:
for (var a:int = collisionLayer.numChildren - 1; i >= 0; i--)
{
collisionLayer.setChildIndex(drawableObjects[i], i);
}
Also, it's a bit wasteful to first order the sort in descending and then reversing the array. Sort it ascending to begin with!

How to update silverlight UI while processing

I went through several examples posted online but I cant answer my question.
I have my 'p' variable that is being increased by 1 in the for loop. I want the UI to display the progress of calculation (to show how 'p' is increasing from 0 to 1000000). I do the calculation on the separate thread and the I call dispatcher to update the ResultBox in UI. Example:
int p=0;
...
private void GO(object sender, System.Windows.RoutedEventArgs e)
{
new Thread(delegate()
{
DoWork();
}).Start();
}
void DoWork()
{
for (int i = 0; i < 1000; i++)
{
for (int j = 0; j < 10000; j++)
{
p++;
this.Dispatcher.BeginInvoke(delegate { ResultBox.Text = p.ToString(); });
}
}
}
For some reason this doesn't work. However when I put Thread.Sleep(1) just before this.Dispatcher... it works as intended. Does it mean that the UI update (Dispatcher) is called too frequently therefore it freezes?
Is there any other way to do it?
Thank you
Why not bind a property to your TextBox and the update the property value instead of poking at the textbox directly?
Yes only doing p++ in your loop will not take much of time and inside silverlight, Dispatcher is nothing but a simple queue with delegates, and before silverlight can even update and process its UI, you are pumping too many values on the queue. Imagin what will happen if you keep on adding queue way to faster then the queue is dequeued, then eventually it will hit max limit as well. And eventually it will just stop. If your p++ is replaced with more time consuming task, then you may get good result.
You must know that our eye usually can see only updates of 30 fps, more then 30 updates per second will not be of any use at all, I will suggest your view update should be reduced to max 10 updates per second for best performance.
And for showing progress, I think 1 update per second is also enough. First always display updates very slowly, like
void DoWork()
{
for (int i = 0; i < 1000; i++)
{
for (int j = 0; j < 10000; j++)
{
p++;
if((p % 1000)==0){
this.Dispatcher.BeginInvoke(delegate
{ ResultBox.Text = p.ToString(); });
}
}
}
}
Now you can increaes/decrease 1000 to some suitable multipler of 10 to adjust your visual update.

Resources