Collision with a picturebox
CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 8 of 8

Thread: Collision with a picturebox

Hybrid View

  1. #1
    Join Date
    Oct 2012
    Location
    england
    Posts
    7

    Cool Collision with a picturebox

    Hello,

    Situation:
    I am creating a 2D game for college which is a simple dodging game in C#, the player can move left and right to dodge falling pictureboxes as well as collecting them.

    problem:
    i have added collision to the pictureboxes which works absolutely fine except one problem; when the players avatar
    picturebox collides with the falling picturebox, the falling picturebox needs to be deleted otherwise it would keep taking chunks of health every tick of the timer which the detection if statement is in. but when i delete the picturebox using the remove control, the player still collides with where the picturebox was.

    question: hw do i fully delete a picturebox that doesnt leave anything behind.

    code for removing picturebox:

    Code:
     if (pictureBox1.Bounds.IntersectsWith(pictureBox5.Bounds)) {
                    
                    this.Controls.Remove(pictureBox5);
                    pictureBox5.Dispose();
                    hp = hp - 10;
    
                }
    thanks in advance.
    this is my first post on this forum, if there is anything i could do better in my post, please let me know <3

    Arrokai

  2. #2
    Join Date
    Nov 2012
    Posts
    6

    Re: Collision with a picturebox

    Hi arrokai,

    I'm having the same problem with the collision detection between the two pictureboxes.
    I have +- the same code for removing the picturebox, but -as you said- the player still collides with the place where the picturebox was.

    I'm wondering if you have found the solution for this problem because I can't find it ??

    Greetz

  3. #3
    Join Date
    Oct 2012
    Location
    england
    Posts
    7

    Re: Collision with a picturebox

    hey,
    TheGreatCthulhu has posted a response right after you commented if you saw :3

    arrokai

  4. #4
    Join Date
    Jan 2010
    Posts
    1,102

    Re: Collision with a picturebox

    Create a List<Control> member variable, and add all the controls that are to be checked for collision to it (if it's only the one picture box, then just add that; this way, if you want to introduce more colliders later, you won't have to change the collision handling code). Then instead of doing:

    if (pictureBox1.Bounds.IntersectsWith(pictureBox5.Bounds)) // this always checks against the pictureBox5 - the object is still in memory even if you remove it from the form
    { /* (omitted) */}

    do this:

    Code:
    // Suppose you declared your list like this (at some other place in the code):
    // List<Control> colliders = new List<Control>();
    
    for(int i = colliders.Count - 1; i >= 0 ; --i)    // looping backwards
    {
        if (pictureBox1.Bounds.IntersectsWith(colliders[i].Bounds))
        {
            this.Controls.Remove(colliders[i]);   // (1) remove from the form
            colliders[i].Dispose();                 // (2) dispose
            hp -=10;                              // (3) do game-related logic
            colliders.RemoveAt(i);          // (4) remove from the colliders collection
            
             // Important! Don't try to access the element at the index i anymore - it was deleted 
             // so it's either not the same element as before (deletion from the middle), 
             // or it doesn't even exist (deletion from the end)! 
        }
    }
    Why is the collection iterated backwards? Because objects are being removed, and the size of the list changes; going from the end to the start ensures that the changes are only localized to the elements that have already been visited, and the index remains valid, as well as the overall logic. For this reason, you cannot use the foreach loop - it's illegal to delete elements inside it.
    Last edited by TheGreatCthulhu; November 18th, 2012 at 02:57 PM.

  5. #5
    Join Date
    Oct 2012
    Location
    england
    Posts
    7

    Re: Collision with a picturebox

    Thank you for your reply,
    I see how that works and it fixed the problem

  6. #6
    Join Date
    Nov 2012
    Posts
    6

    Re: Collision with a picturebox

    Thank you for your quick responses !!

    In my case the for loop wouldn't work.
    I was really desperate but now I've found a solution for my problem. I just have to add before each if statement (for collision) an if statement if the picturebox is visible or not.

    Code:
    Code:
    if (picBox1.Visible)
    {
        if (picBoxBal.Bounds.IntersectsWith(picBox1.Bounds))
        {
            BalSpeedY = -BalSpeedY;
            score++;
            LblScore.Text = "Score: " + score.ToString();
            this.Controls.Remove(picBox1);
            picBox1.Dispose();
        }
    }

  7. #7
    Join Date
    Jan 2010
    Posts
    1,102

    Re: Collision with a picturebox

    It would work - and while your current solution works fine for your specific purpose, what if you later on decide you want to test against a different picture box, or that you want to add more than one collider (for example, you could create a simple game where the player must avoid several obstacles)?
    The difference is that, in your case, since you're relying on the Visible property, you don't have to remove the picture box from the Control collection - you can just set Visible to false; this way it's easier to switch it on and off at will.

    That said, there is a slight problem in your code above - you're lucky it works, because, it just so happens that one of the calls you make on the picBox1 has a convenient side effect of setting the Visible property to false. Note that, just by reading your code you can't tell why would the if condition fail on the next test. The method call that makes it all work is the call to the Dispose() method. However, once a control is disposed, it cannot be used normally anymore - some method and property calls will fail, others will not, and once again, you were lucky that the Visible property is still works.
    As all this behavior is not documented (you can't find anything on MSDN that explicitly states that calling Dispose sets Visible to false, or that Visible is guaranteed not to throw an ObjectDisposedException), in theory it could change from one implementation of .NET Library to another, so you shouldn't rely on it.

    It's better that you add one more line of code where you explicitly set the Visible property to false.

    Code:
    if (picBox1.Visible)
    {
        if (picBoxBal.Bounds.IntersectsWith(picBox1.Bounds))
        {
            BalSpeedY = -BalSpeedY;
            score++;
            LblScore.Text = "Score: " + score.ToString();
            picBox1.Visible = false;        
    
            // Now you can safely ditch these, which leaves you with the option to turn it back on in a simple way:
            // this.Controls.Remove(picBox1);
            // picBox1.Dispose();
        }
    }

    This way, everything is much more clear, and it will work for sure.
    Some other things you can do; you can extract this code into a method, and pass the collider to test against as a parameter:

    Code:
    private bool TestForCollisionWith(Control target)
    {
        bool result = false;
    
        if (target.Visible)
        {
            if (picBoxBal.Bounds.IntersectsWith(target.Bounds))
            {
                BalSpeedY = -BalSpeedY;
                score++;
                LblScore.Text = "Score: " + score.ToString();
                target.Visible = false;
    
                result = true;
            }
        }
    
        return result;   // false if no collision, true if a collision was detected
    }
    
    
    // And then you can call this method from where the original code used to be:
    TestForCollisionWith(picBox1);    // BENEFIT: you can now pass something other than picBox1
    The method returns a bool indicating if a collision was detected or not, for convenience.

    Finally, you can use a List<Control> and a loop in the same way as arrokai, except now the only thing you'd need to do inside the loop is to call the TestForCollisionWith() method. You can also remove the picture box from the list (but you don't have to, as now the code tests the Visible property; not removing it introduces some redundancy though, but for a small number of stored objects this is not a big problem).

  8. #8
    Join Date
    Nov 2012
    Posts
    6

    Re: Collision with a picturebox

    Thank you !!

    It was really helpful!

    I have now changed my code to your last piece of code because I use 7 pictureboxes.

    Thanks!!

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  


Windows Mobile Development Center


Click Here to Expand Forum to Full Width

This is a CodeGuru survey question.


Featured


HTML5 Development Center