Search code examples
c#winformsmethodspicturebox

How to make method be used individually for every PictrueBox


I am making a game where you need to click on certain objects (using PictureBoxes) that are moving in a DVDscreensaver-like fashion (bouncing of the edges). The problem is when I have more than 1 PictureBox on screen. When one touches the edge, all of the other PictureBoxes change their X or Y velocity value to negative and start moving as if they touched the edge. How can I make it work individually for every PictureBox?

Movement engine:

private void MovementTimer_Tick(object sender, EventArgs e) //movement engine
    {
        foreach (Control z in this.Controls)
        {
            if (z is PictureBox)
            {
                if (z.Location.X < 0 || z.Location.X + z.Width > Size.Width) //bouncing effect in horizontal
                {
                    x = -x;
                }
                if (z.Location.Y < 0 || z.Location.Y + z.Height > Size.Height) //bouncing effect in vertical
                {
                    y = -y;
                }
                z.Location = new Point(z.Location.X + x, z.Location.Y + y);
            }
        }
    }

Spawning Pictureboxes:

private void InitializePictureBox()
    {
        PictureBox[] pb = new PictureBox[12];
        for (int i = 0; i < 12; i++)
        {
            x = rng.Next(10, 16) * (rng.Next(0, 2) * 2 - 1); //velocity in horz dim
            y = rng.Next(10, 16) * (rng.Next(0, 2) * 2 - 1);  //velocity in vert dim
            locx = rng.Next(100, 500); //random locations
            locy = rng.Next(100, 500);
            pb[i] = new PictureBox(); 
            pb[i].Image = Image.FromFile("../red/rbr.png");
            pb[i].Location = new Point(locx, locy);
            pb[i].SizeMode = PictureBoxSizeMode.StretchImage;
            Controls.Add(pb[i]);
        }
    }

Solution

  • Instead of global x and y variables, store a Point in the .Tag property of each PictureBox so they will each have their own values that can be changed independently of each other.

    So in your InitializePictureBox() method:

    private void InitializePictureBox()
    {
        PictureBox[] pb = new PictureBox[12];
        for (int i = 0; i < 12; i++)
        {
            x = rng.Next(10, 16) * (rng.Next(0, 2) * 2 - 1); //velocity in horz dim
            y = rng.Next(10, 16) * (rng.Next(0, 2) * 2 - 1);  //velocity in vert dim
            locx = rng.Next(100, 500); //random locations
            locy = rng.Next(100, 500);
            pb[i] = new PictureBox(); 
            pb[i].Image = Image.FromFile("../red/rbr.png");
            pb[i].Location = new Point(locx, locy);
            pb[i].SizeMode = PictureBoxSizeMode.StretchImage;
    
            pb[i].Tag = new Point(x, y); // <-- Store a Point() in the Tag()!
    
            Controls.Add(pb[i]);
        }
    }
    

    Then in your Timer:

    private void MovementTimer_Tick(object sender, EventArgs e) //movement engine
    {
        foreach (Control z in this.Controls)
        {
            if (z is PictureBox)
            {
    
                Point pt = (Point)z.Tag; // <-- cast Tag() back to a Point()
                // Note the use of "pt" in the code below:
                if (z.Location.X < 0 || z.Location.X + z.Width > Size.Width) //bouncing effect in horizontal
                {
                    pt = new Point(-pt.X, pt.Y);
                }
                if (z.Location.Y < 0 || z.Location.Y + z.Height > Size.Height) //bouncing effect in vertical
                {
                    pt = new Point(pt.X, -pt.Y);
                }
                z.Location = new Point(z.Location.X + pt.X, z.Location.Y + pt.Y);
                z.Tag = pt; // <-- put updated Point() back in the Tag
            }
        }
    }