This question already has an answer here:
More organized way to call Coroutines?
(1 answer)
Closed 5 years ago.
I have coroutine that after N seconds clear text and returns it to it's original shape. Problem is that coroutine never continues after first return (wait for seconds).
I had this problem somewhere else and figured it out that is happening because i destroy Gameobject before coroutine finish so i made it return bool but now i am confused and can not use same trick here since i am starting coroutine through script that is not initialized. That script only has static function through which i start coroutine. Here is my code:
void OnMouseDown()
{
bool safeDestroy = false;
IGatherable gather = CharacterCommands.character.GetComponent<IGatherable>();
if(gather != null)
{
switch(itemID)
{
case 3:
Drops[] d = ChestDrop.GetItemFromDropStash(drops, gather, this); //Here is function that is starting function with coroutine PROBLEM
if(d.Length == 0)
{
safeDestroy = true;
}
else
{
drops = d;
}
break;
default:
if(ItemDatabase.GetItem(itemID).maxStackable < Inventory.GetCoins() + amount)
{
Parameters.centerText.text = "Not enough space in your bag!";
safeDestroy = Parameters.clearText(Parameters.centerText, 3, this); //Coroutine i had same problem but done it this way.
}
else
{
gather.GatherItem(itemID, amount);
safeDestroy = true;
}
break;
}
}
if(safeDestroy)
{
Destroy(this.gameObject);
}
}
And here is the function itself:
public static Drops[] GetItemFromDropStash(Drops[] drops, IGatherable gather, MonoBehaviour justToStartCoroutine)
{
foreach(Drops drop in drops)
{
int r = UnityEngine.Random.Range(1, 101);
if(r < drop.chance)
{
if(ItemDatabase.GetItem(drop.itemID).maxStackable > Inventory.GetItemFromInventoryById(drop.itemID).amount + drop.amount)
{
Inventory.AddItemToInventory(drop.itemID, drop.amount);
Parameters.centerText.text = "+" + drop.amount + " " + ItemDatabase.GetItem(drop.itemID).itemName;
switch(ItemDatabase.GetItem(drop.itemID).itemRarity)
{
case ItemRarity.common:
Parameters.centerText.color = Color.gray;
break;
case ItemRarity.normal:
Parameters.centerText.color = new Color(80, 100, 255);
break;
case ItemRarity.rare:
Parameters.centerText.color = new Color(255, 80, 80);
break;
case ItemRarity.special:
Parameters.centerText.color = new Color(200, 0, 220);
break;
case ItemRarity.legacy:
Parameters.centerText.color = new Color(199, 224, 0);
break;
case ItemRarity.legendary:
Parameters.centerText.color = new Color(224, 169, 0);
break;
}
bool t = Parameters.clearText(Parameters.centerText, 3, justToStartCoroutine);
int i = Array.IndexOf(drops, drop);
List<Drops> tmp = new List<Drops>(drops);
tmp.RemoveAt(i);
drops = tmp.ToArray();
}
else if (Inventory.CheckForFreeSpaceInInventory() == true)
{
Inventory.AddItemToInventoryToNewSlot(drop.itemID, drop.amount);
Parameters.centerText.text = "+" + drop.amount + " " + ItemDatabase.GetItem(drop.itemID).itemName;
switch(ItemDatabase.GetItem(drop.itemID).itemRarity)
{
case ItemRarity.common:
Parameters.centerText.color = Color.gray;
break;
case ItemRarity.normal:
Parameters.centerText.color = new Color(80, 100, 255);
break;
case ItemRarity.rare:
Parameters.centerText.color = new Color(255, 80, 80);
break;
case ItemRarity.special:
Parameters.centerText.color = new Color(200, 0, 220);
break;
case ItemRarity.legacy:
Parameters.centerText.color = new Color(199, 224, 0);
break;
case ItemRarity.legendary:
Parameters.centerText.color = new Color(224, 169, 0);
break;
}
bool t = Parameters.clearText(Parameters.centerText, 3, justToStartCoroutine);
int i = Array.IndexOf(drops, drop);
List<Drops> tmp = new List<Drops>(drops);
tmp.RemoveAt(i);
drops = tmp.ToArray();
}
else
{
Parameters.centerText.text = "Not enough space in inventory!";
bool t = Parameters.clearText(Parameters.centerText, 3, justToStartCoroutine);
}
}
}
return drops;
}
How can i achieve so that my item (where OnMouseDown() is) doesn't destroy until coroutine is finished?
If you want to wait for a coroutine to finish...then the method must also be a coroutine.
You have 3 options, depending on your specific scenario:
Move the code that needs to wait into the existing coroutine method (after the last current yield.
You can also pass a delegate into the current coroutine and use it as a callback, then each use of the existing coroutine can supply its own callback delegate. The "wait for finish" code then goes inside this delegate.
Turn the current not-coroutine method into a coroutine.
Create a new coroutine, shove the code that needs to wait for the other coroutine into it, including the call to the existing coroutine, yield on that other coroutine.
Related
So I am trying to create this script which changes the color of the sprite when I execute the method OnMouseDown().
The color change should execute every 2 seconds. In this code provided below the colors only change once for some reason.
I have already tried coroutines. But they didn't work for some reason.
Please help thanks,
public bool startstop = false;
SpriteRenderer m_SpriteRenderer;
IEnumerator Changecolor() {
yield return new WaitForSeconds(3);
int random = Random.Range(1, 4);
if (random == 1) {
this.m_SpriteRenderer = this.GetComponent<SpriteRenderer>();
this.m_SpriteRenderer.color = Color.blue;
} else if (random == 2) {
this.m_SpriteRenderer = this.GetComponent<SpriteRenderer>();
this.m_SpriteRenderer.color = Color.red;
} else if (random == 3) {
this.m_SpriteRenderer = this.GetComponent<SpriteRenderer>();
this.m_SpriteRenderer.color = Color.green;
} else {
this.m_SpriteRenderer = this.GetComponent<SpriteRenderer>();
this.m_SpriteRenderer.color = Color.yellow;
}
this.StartCoroutine("Changecolor", 3f);
}
private void OnMouseDown() {
if (this.startstop) {
this.StartCoroutine("Changecolor", 3f);
this.startstop = !this.startstop;
} else {
this.StopCoroutine("Changecolor");
this.startstop = !this.startstop;
}
}
No errors just doesn't work.
Do you have a Collider on the object? A Collider is needed to have the OnMouseDown event fired.
The code principally works, but is far from quality.
- Only call GetComponent() once, then cache the result. This call is very expensive.
- Initially you have to click two times, as the Coroutine will be stopped at the first click.
Here is the code with some improvements:
public bool m_isRunning = false;
public SpriteRenderer m_spriteRenderer;
private void Start() {
m_spriteRenderer = this.GetComponent<SpriteRenderer>();
}
private IEnumerator Changecolor() {
yield return new WaitForSeconds(3);
int random = Random.Range(1, 4);
if (random == 1) {
m_spriteRenderer.color = Color.blue;
} else if (random == 2) {
m_spriteRenderer.color = Color.red;
} else if (random == 3) {
m_spriteRenderer.color = Color.green;
} else {
m_spriteRenderer.color = Color.yellow;
}
this.StartCoroutine("Changecolor", 3f);
}
private void OnMouseDown() {
m_isRunning = !m_isRunning;
if (m_isRunning) {
StartCoroutine("Changecolor", 3f);
} else {
StopCoroutine("Changecolor");
}
}
Note that the second parameter you pass in (3f)
StartCoroutine ("Changecolor", 3f);
does nothing since your Changecolor does not take any arguments ...
I would actually suggest to not use Coroutine here at all but rather InvokeRepeating and CancelInvoke
void Changecolor()
{
// Either in Awake or as lazy initialization
if(!m_SpriteRenderer) m_SpriteRenderer = GetComponent<SpriteRenderer>();
int random = Random.Range(1, 4);
switch(random)
{
case 1:
m_spriteRenderer.color = Color.blue;
break;
case 2:
m_spriteRenderer.color = Color.red;
break;
case 3:
m_spriteRenderer.color = Color.green;
break;
default:
m_spriteRenderer.color = Color.yellow;
break;
}
}
private void OnMouseDown()
{
startstop = !startstop;
if (this.startstop)
{
InvokeRepeating(nameof(Changecolor), 0f, 2f);
}
else
{
CancelInvoke(nameof(Changecolor));
}
}
The code you provided works just fine, and sins you say the color changes only once, I assume you have a collider on the object that has the script attached, the only thing you should change is the continues call to GetComponent<SpriteRenderer> because it is pretty costly and should only be called in either Start or Awake another thing, which isn't major, and there is nothing wrong with it, but it kind of rubs me the wrong way, is the creation of a new coroutine at the end of the old, why not do something like this:
private Coroutine _colorChanger;
private SpriteRenderer _renderer;
void Start() //Can be Awake, whichever you choose
{
_renderer = GetComponent<SpriteRenderer>();
if (_renderer == null)
{
Debug.Log("No sprite found.");
return;
}
//This is performed if OnMouseDown is implemented, if you implement the Update with Input.GetKeyDown, then this can be removed
var collider = GetComponent<Collider>();
if (collider == null)
{
collider = gameObject.AddComponent<BoxCollider>(); //or BoxCollider2D if you are applying the script to the sprite itself.
}
collider.isTrigger = true;
}
private void OnMouseDown() //this can be swapped out for what Saif wrote, a Update method which checks if the button is down, should be GetKeyDown instead of GetKey, having it that way will eliminate the need for a collider/UI element
{
if (_colorChanger == null)
{
_colorChanger = StartCoroutine(ChangeColor(2f));
}
else
{
StopCoroutine(_colorChanger);
_colorChanger = null;
}
}
IEnumerator ChangeColor(float timeoutSec)
{
while (true)
{
yield return new WaitForSeconds(timeoutSec);
int random = Random.Range(1, 5); //Change max from 4 to 5
if (random == 1)
{
_renderer.color = Color.blue;
}
else if (random == 2)
{
_renderer.color = Color.red;
}
else if (random == 3)
{
_renderer.color = Color.green;
}
else
{
_renderer.color = Color.yellow;
}
}
}
Update: just noticed something that others missed, you should change the Random.Range(1, 4) to Random.Range(1, 5) or else the yellow color will never come into effect.
Your code is right, no issues in it except that the OnMouseDown() function will not be called since you are not clicking on any box triggers or any UI elements. Hence try to use update function as given below:
void Update()
{
if (Input.GetKey(KeyCode.Mouse0))
{
if (startstop == false)
{
StartCoroutine("Changecolor", 3f);
this.startstop = !this.startstop;
}
else
{
StopCoroutine("Changecolor");
this.startstop = !this.startstop;
}
}
}
I am making a snake game as my homework assignment , I've already added a code for making the snake head move depending on the user input (left , right , down , up)
But I am stuck with the timing of it , I used Thread.Sleep in order for the game not to crash and get an exception , but my instructor told me that Thread.Sleep is a horrible idea in programming because it literally adds a delay to your game.
So, I need to somehow make it that there won't be a delay in my game while avoiding Thread.Sleep
class Program
{
static void Main(string[] args)
{
Direction direction = Direction.Down;
Console.CursorVisible = false;
int x=0 , y=0 ;
int xprev = 2, yprev = 2;
char shape = 'o';
x = xprev;
y = yprev;
Console.SetCursorPosition(xprev, yprev);
Console.Write(shape);
UserInput input = new UserInput();
ConsoleKeyInfo? info;
while (true)
{
info = input.GetKey();
if (info.HasValue)
{
switch (info.Value.Key)
{
case ConsoleKey.RightArrow:
direction = Direction.Right;
break;
case ConsoleKey.LeftArrow:
direction = Direction.Left;
break;
case ConsoleKey.UpArrow:
direction = Direction.Up;
break;
case ConsoleKey.DownArrow:
direction = Direction.Down;
break;
}
}
Thread.Sleep(100);
switch (direction)
{
case Direction.Up:
y--;
break;
case Direction.Down:
y++;
break;
case Direction.Left:
x--;
break;
case Direction.Right:
x++;
break;
}
Console.MoveBufferArea(xprev, yprev, 1, 1, x, y);
xprev = x;
yprev = y;
}
As Sohaib Jundi suggests, a timer of some description is a reasonable solution here. Your objective is:
Every 100ms, update where the snake is
Rather than solve this by saying make the application pause for 100ms, then update the snake, using a timer changes it to Have something that triggers every 100ms to update the snake.
For example:
using System;
using System.Threading;
namespace Snake
{
class Program
{
static void Main(string[] args)
{
var snakeTimer = new Timer(updateTheSnake, null, 0, 100);
while(true)
{
var keypress = Console.ReadKey();
if (keypress.Key == ConsoleKey.Escape)
{
break;
}
}
}
static void updateTheSnake(object state)
{
Console.Write("#");
}
}
}
This is a very simple example that just draws a line of # across the screen until the user presses the escape key. In your code, you'd likely want to move everything below the Thread.Sleep into the updateTheSnake method. direction will probably need to be stored into shared state so that you can refer to it from the updateTheSnake method.
What I'm trying to do is this:
I want the 4 pictureBoxes I got in the form to get the faces of card - turn them over I mean. a random card from the 4 will be chosen, turned over and show the face of the card being chosen also randomley.
Once a card is turned over, it cant be turend over again in the next timer interval, and once all cards had been turned over, a messageBox appears and once the user presses ok, it all restarts.
Problem is: the messageBox keeps appearing over and over again, because of the flag positive value. I don't know which variable should I use to prevent that from happening.
Relevant code:
//This function is the timer's function, it starts every time interval:
private void cardsChangingTimer_Tick(object sender, EventArgs e)
{
int chosenImage = rnd.Next(1, 17);
int chosenCard = rnd.Next(0, 4);
if (bucketArr[chosenCard] == 0)
{
bucketArr[chosenCard]++;
switch (chosenCard)
{
case 0:
card1Pic.Image = Image.FromFile("cards\\" + chosenImage + ".png");
break;
case 1:
card2Pic.Image = Image.FromFile("cards\\" + chosenImage + ".png");
break;
case 2:
card3Pic.Image = Image.FromFile("cards\\" + chosenImage + ".png");
break;
case 3:
card4Pic.Image = Image.FromFile("cards\\" + chosenImage + ".png");
break;
}
}
gameEnded = true;
for (int i = 0; i < bucketArr.Length; i++)
{
if (bucketArr[i] == 0)
{
gameEnded = false;
break;
}
}
if (gameEnded)
{
DialogResult dialog = MessageBox.Show("All 4 cards were turned over...");
if (dialog == DialogResult.OK)
{
card1Pic.Image = Image.FromFile("..\\..\\17.png");
card2Pic.Image = Image.FromFile("..\\..\\17.png");
card3Pic.Image = Image.FromFile("..\\..\\17.png");
card4Pic.Image = Image.FromFile("..\\..\\17.png");
}
gameEnded = false;
for(int i = 0; i < bucketArr.Length; i++)
bucketArr[i] = 0;
}
}
Thanks alot for any help...
The problem you are having is the timer is continuing to run while the dialog box is shown. Simply stop the timer before the MessageBox is shown then restart the timer after the box returns.
private void cardsChangingTimer_Tick(object sender, EventArgs e)
{
int chosenImage = rnd.Next(1, 17);
int chosenCard = rnd.Next(0, 4);
/// ... Rest of the code goes here
break;
}
}
if (gameEnded)
{
//Get a reference to the timer and stop it.
var timer = (Timer)sender;
timer.Stop();
DialogResult dialog = MessageBox.Show("All 4 cards were turned over...");
if (dialog == DialogResult.OK)
{
card1Pic.Image = Image.FromFile("..\\..\\17.png");
card2Pic.Image = Image.FromFile("..\\..\\17.png");
card3Pic.Image = Image.FromFile("..\\..\\17.png");
card4Pic.Image = Image.FromFile("..\\..\\17.png");
}
gameEnded = false;
for(int i = 0; i < bucketArr.Length; i++)
bucketArr[i] = 0;
//start the timer here after everything has been re-initialized.
timer.Start();
}
}
I'm kinda new to both Keys event and timers in my code but for some reason there is this weird bug. (read the last edit)
public partial class Form1 : Form
{
bool start = false;
Snake ormen = new Snake(10);
short direction = 3;
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
button1.Hide();
timer1.Enabled = true;
start = true;
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
Graphics g = e.Graphics;
if (start)
{
ormen.rita(g);
}
}
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
switch (e.KeyCode)
{
case Keys.Up:
direction = 3;
break;
case Keys.Down:
direction = 1;
break;
case Keys.Left:
direction = 2;
break;
case Keys.Right:
direction = 0;
break;
default:
break;
}
}
private void timer1_Tick(object sender, EventArgs e)
{
ormen.flytta(direction);
Invalidate();
}
}
}
I also tried to use debug at the key event but it does not even activate until after the time period. Can anyone please tell me why? Also if there are any obvious mistakes i would appreciate it if you could mention them. I have also tried to make the timer interval higher to check if the program can't keep up but it can. (read the last edit)
[EDIT] I don't think it will help but here is the code for the class "Snake". I doubt it's a problem in there but anyways.
private short diameter = 0;
//0 = Right, 1 = Down, 2 = Left, 3 = Up
public Snake(short diameter)
{
this.diameter = diameter;
ormensPlatser.Enqueue(new Point(0, 0));
ormensPlatser.Enqueue(new Point(0 + diameter, 0));
ormensPlatser.Enqueue(new Point(0 + diameter + diameter, 0));
}
Queue<Point> ormensPlatser = new Queue<Point>();
public void rita(Graphics g)
{
Point temp;
for (int i = 0; i < ormensPlatser.Count; i++)
{
temp = ormensPlatser.Dequeue();
g.FillEllipse(new SolidBrush(Color.Red), temp.X, temp.Y, diameter, diameter);
ormensPlatser.Enqueue(temp);
}
}
private void ormNäraKant(short direction,ref Point ormBit)
{
switch (direction)
{
case 0:
ormBit.X = ormBit.X + diameter >= 380 ? 0 : ormBit.X + diameter;
break;
case 1:
ormBit.Y = ormBit.Y + diameter >= 360 ? 0 : ormBit.Y + diameter;
break;
case 2:
ormBit.X = ormBit.X - diameter < 0 ? 370 : ormBit.X - diameter;
break;
case 3:
ormBit.Y = ormBit.Y - diameter < 0 ? 350 : ormBit.Y - diameter;
break;
}
}
public void flytta(short direction)
{
Point temp;
int temp1 = ormensPlatser.Count - 1;
for (int i = 0; i < ormensPlatser.Count; i++)
{
if (i == temp1)
{
switch(direction)
{
case 0:
temp = ormensPlatser.Dequeue();
ormNäraKant(0, ref temp);
ormensPlatser.Enqueue(temp);
break;
case 1:
temp = ormensPlatser.Dequeue();
ormNäraKant(1, ref temp);
ormensPlatser.Enqueue(temp);
break;
case 2:
temp = ormensPlatser.Dequeue();
ormNäraKant(2, ref temp);
ormensPlatser.Enqueue(temp);
break;
case 3:
temp = ormensPlatser.Dequeue();
ormNäraKant(3, ref temp);
ormensPlatser.Enqueue(temp);
break;
}
}
else
{
ormensPlatser.Dequeue();
temp = ormensPlatser.Peek();
ormensPlatser.Enqueue(temp);
}
}
}
}
}
[EDIT2] Okey, apparently it wasn't about the time or anything like that, the code worked but i think it has something to do with what slawekwin said in the comments about the focus when the program starts. So the problem is still the same but if I ALT+tab to a another program then back to the snake program it works.
SO i finally figure it out, i thought that the problem was with the timer event and the key input event when they worked together but my assumption was wrong. So what i did is that i went through all the properties that the form has and i found a setting called "KeyPrevied" and it was false so i tried to set it to true and it worked :).
I wanna write an application to do below job:
We have 15 different location (that we present them with point (x1,y1) for first location, point (x1,y2) for second location and so on point (x1,y15) for last location).
100 image must to be shown at this locations (with specific order) with pictureBox.
Each image that shown, must start to move horizontally to reach new point (e.g. point (Xc, Yc) ) and then move vertically and so on…
When the image reach to specific point (e.g. point (Xm,Ym) ), we decide that it must continue moving or it must destroy (with probability 20%) (which means that we can create next image at that initial location).
For example, an image create at location (Xi,Yi) with pictureBox1. Then it’s not allowed to create any more image at location (Xi,Yi) until pictureBox1 destroy or return to its initial location.
What I have written so far is:
create 15 location.
move one image to reach point (Xc,Yc).
I’ve some problems:
I use one timer to move an image. But I want to move 100 images. (from each 15 location, we create images and move them until we destroy them and then create next image).
So what I must to do? Use 15 timer for each location?!but How?
at specific point (e.g. point (Xk,Yk) ), the image must stop moving for random seconds and then continue moving. How I should do this? With another timer?!But how?
when image reach point (Xc,Yc) and with we decide to destroy it or not, nothing happen in my code…I don’t know why!
I’ve add an picture of what I want HERE
Here is my code so far:
public partial class Form1 : Form
{
Random r = new Random();
// falg to prevent create just one image at each location
private Boolean[] createNext = {true,true,true,true,true,true,true,
true,true,true,true,true,true,true,true};
private void setImage()
{
int i = 1 + r.Next() % 15;
while (createNext[i] != true)
i = 1 + r.Next() % 15;
switch (i)
{
case 1: pictureBox1.ImageLocation = "grin.png";
break;
case 2: pictureBox2.ImageLocation = "grin.png";
break;
case 3: pictureBox3.ImageLocation = "grin.png";
break;
case 4: pictureBox4.ImageLocation = "grin.png";
break;
case 5: pictureBox5.ImageLocation = "grin.png";
break;
case 6: pictureBox6.ImageLocation = "grin.png";
break;
case 7: pictureBox7.ImageLocation = "grin.png";
break;
case 8: pictureBox8.ImageLocation = "grin.png";
break;
case 9: pictureBox9.ImageLocation = "grin.png";
break;
case 10: pictureBox10.ImageLocation = "grin.png";
break;
case 11: pictureBox11.ImageLocation = "grin.png";
break;
case 12: pictureBox12.ImageLocation = "grin.png";
break;
case 13: pictureBox13.ImageLocation = "grin.png";
break;
case 14: pictureBox14.ImageLocation = "grin.png";
break;
case 15: pictureBox15.ImageLocation = "grin.png";
break;
}
}
private int k = 0;
private Boolean destroy = true;
// timer that move pictureBox1
void timer_Tick(object sender, EventArgs e)
{
k++;
int x = pictureBox1.Location.X;
int y = pictureBox1.Location.Y;
if (k <= 150)//go right 300 in 150 ticks
pictureBox1.Location = new Point(x + 2, y);
else if (k <= 300)
{
if (y < 200)
pictureBox1.Location = new Point(x, y + 1);
if (y > 200)
pictureBox1.Location = new Point(x, y - 1);
}
else if (k <= 400)
pictureBox1.Location = new Point(x + 2, y);
else if (k <= 550)
{
if (destroy == false)
pictureBox1.Location = new Point(x + 2, y);
if (destroy == true)
pictureBox1.Location = new Point(x, y - 3);
}
else if (k <= 650)
pictureBox1.Location = new Point(x, y - 1);
else if (k <= 850)
pictureBox1.Location = new Point(x - 2, y);
else if (k <= 950)
pictureBox1.Location = new Point(x, y + 1);
else
timer1.Stop();
}
public Form1()
{
InitializeComponent();
for (int i = 0; i < 15; i++)
{
setImage();
timer1.Start();
timer1.Interval = 15;
timer1.Tick += new EventHandler(timer_Tick);
}
}
Please help me to complete this application.
Thanks in advance.
You should probably just use one timer, and make a number of instances of a class that represents your moving picturebox. (This class would contain the points it will go to, ordered to the first point is always your next destination. Also it will contain the picturebox.. etc).
enum Action
{
None,
Stop,
CheckDestroy
}
class InterestingPoint
{
Point m_Point;
Action m_Action;
}
class MovingImage
{
public bool DestroyMe {get; private set; }
PictureBox m_PictureBox;
List<InterestingPoint> m_PointsToVisit;
int m_StoppedUntil = 0;
MovingImage(...)
{
// Constructor
}
void Update(int k)
{
if(m_StoppedUntil > k) return;
//Move m_PictureBox towards m_PointsToVisit.First
//when m_PictureBox.Location == m_PointToVisit.First, check if the InterestingPoint
//has a action you need to handle,
//like if the action is stop, you set m_StoppedUntil to k+ the number of frames you
//want the picturebox to stay still. (m_StoppedUntil = k+10 => doesnt update for 10 frames)
//if the action is checkdestroy, see if it shall be destroyed and set DestroyMe to true
}
So, you initialize your MovingImage objects with a picturebox and list of point it should move to, these points contain a action for the object to execute when it arrives there.
Keep your MovingImages in a list of some kind and iterate over them to update them.
In your Timer_Tick you do something like
void timer_Tick(object sender, EventArgs e)
{
k++
foreach(MovingImage m in m_MyMovingImages)
{
m.Update(k);
if(m.DestroyMe)
{
//Destroy it.
}
}
}