VB.NET – Handling shape movements and collision

This post was written by Brandon on December 10, 2008
Posted Under: Visual Basics .NET

Edit: Now a video is up of the attached demo:

In the previous post(Found here) I talked about creating shape objects at random positions and drawing them on the form. This tutorial will go over making them all move, and handling collisions. I made a Visual Basics project as a way to test "gravity." You click around the form and it will create a square at that position, they instantly bein to fall. Once they hit the ground (the bottom of the form) they stop moving, if they hit others that are touching the ground (double clicking in the air will not work) they will stack up and stop moving.

The project binary and full source code will be available at the end of this post.
Note: This was made in Visual Studio 2008, if you try on previous versions you may have problems! You can download Visual Studio 2008 for FREE on Microsoft's website!

[ad#inpost]


Note: The project that will be available for download has basic "winds" to cause the objects to be blown against the wall. Adding that will not be discussed here but it is in the project file. Also, the project file has a "growth" feature, where the longer you hold the mouse down, the bigger the shape gets.
Here are the new variables that must be declared, assuming you already have myGraphics and everything else from the previous post

Dim rectangleLock(500) As Boolean
Dim intersectLock(500) As Boolean
Dim connectsToGround(500) As Boolean
Dim drawnRectangles As Integer
Dim squareLocked(500) As Boolean

Notice how most of these are arrays of 500, just like the Rectangle array. Each rectangle will have its own slot in each of these arrays.

Add this to your form_load, this reduces the flicker when the form refreshes:

Me.DoubleBuffered = True

And add this to your form_load:

drawnRectangles = 1
unlockAll()
intersectUnlock()
connectsUnlock()
unlockSquares()

This is basically to call methods that will set all the boolean variables to false, useful for instantiating them and each time we decide to clear the form.

Here is the full code for the methods:

Sub unlockAll()
For i As Integer = 1 To 500 Step 1
rectangleLock(i) = False
Next
End Sub

Sub intersectUnlock()
For i As Integer = 1 To 500 Step 1
intersectLock(i) = False
Next
End Sub

Sub connectsUnlock()
For i As Integer = 1 To 500 Step 1
Next
End Sub

Sub unlockSquares()
For i As Integer = 1 To 500 Step 1
squareLocked(i) = False
Next
End Sub

The next thing to add is the mousedown event:

Private Sub Form1_Mousedown(ByVal sender As System.Object, ByVal e As _
System.Windows.Forms.MouseEventArgs) Handles MyBase.MouseDown
If e.Button = MouseButtons.Left Then
drawRectangle(drawnRectangles, e.X, e.Y)
drawnRectangles = drawnRectangles + 1
If drawnRectangles = 500 Then
drawnRectangles = 1
unlockAll()
intersectUnlock()
connectsUnlock()
End If
End If
End Sub

What this basically does is get the x and y position of where the mouse was clicked, pass the integer value drawnRectangles, x, and y to drawRectangle. Within drawRectangle it adds it to the array (as mentioned in the previous post) It then increases drawnRectagngles by 1, and if drawnRectangles is 500 (the size of the array) it will reset it down to 1 and clear the form of all squares by calling all the unlock functions.

Add a timer, call it tmrRefresh, set its interval to 1 and enable it right away. All the code this timer needs is:

Me.Refresh()

This will refresh the form and clear all the other shapes for them to be redrawn. After we add the movement section, try disabling this timer and see what happens!

Next is the timer that will force all the shapes downwards, name it tmrMove, in the project file its called Timer1. Give it a interval of 2


For i As Integer = 1 To (drawnRectangles - 1) Step 1
If (myRectangle(i).Top < Me.Height - 50) And rectangleLock(i) = False Then
If intersectLock(i) = False Then '
If (myRectangle(i).Left > 0) Then
myRectangle(i).Location = New Point(myRectangle(i).X, myRectangle(i).Y + 1)
Else
myRectangle(i).Location = New Point(myRectangle(i).X, myRectangle(i).Y + 1)
End If ' end if for the width check
End If
myGraphics.DrawRectangle(pen:=myPen, rect:=myRectangle(i))
myGraphics.FillRectangle(brush:=myBrush, rect:=myRectangle(i))
Else
If intersectLock(i) = False Then
myRectangle(i).Location = New Point(myRectangle(i).X, Me.Height - 50)
End If
rectangleLock(i) = True
connectsToGround(i) = True 'This one has hit the ground
myGraphics.DrawRectangle(pen:=myPen, rect:=myRectangle(i))
myGraphics.FillRectangle(brush:=myBrush, rect:=myRectangle(i))
End If
Next

Steps in the code:
1.The code starts with a loop from 1 to the number of rectangles drawn on the form (remember the variable was increased when we clicked?)

2. Within that it checks if the Top value (basically the y value) is less than the forms height, and rectangleLock at the array spot i, meaning the loop index is false.

3. Right after it checks if the boolean intersectLock is also false
Then it checks to makesure the left (or x value) is greater than 0. This part is mainly used for the "wind" code thats in the project file, to make sure the square is not moved off the form.

4. If all these if statements passed, then it runs the code of setting the rectangles location to a new point, of the rectangles y value, plus 1. This will make it slide down each timer tick.

5. If the rectangle's x value is less than 0, it will only pull it downwards. This is for the "wind" part, which is why it may not sound right. In the project file you will see it makes more sense.

6. The rectangle is then redrawn and refilled

7. The else statement is called for the first if statement (the one that checks if its y value is greater than the forms height). Within this, it checks to see if intersectLock is false, the purpose of this variable is described later. If the Y position of the square did go outside of the form, it resets it to the forms height, subtracted from 50. It then sets intersectLock to true, to prevent it from moving anymore. It will then lock it in and since it touched the ground, it sets that one to true. This is used later for the collision stacking.

8. The rectangles are drawn again and the final end if appears

9. The loop restarts, for the next rectangle.

So movement is out of the way, now for collision and stacking.

Add a new timer, this one will be to handle collisions. Call it tmrCollisions (in the project file its Timer2) and give it a interval of 1, enable it right away.

The code for this timer is much shorter, but more complex:

For i As Integer = 1 To (drawnRectangles - 1) Step 1
For x As Integer = 1 To (drawnRectangles - 1) Step 1
If i <> x Then
If connectsToGround(x) = True Then
If myRectangle(i).IntersectsWith(myRectangle(x)) Then
intersectLock(i) = True
connectsToGround(i) = True 'its connected to one thats touching the ground
End If
End If 'end if for if rectangleLock
End If
Next 'x
Next 'i

The code starts by starting a for loop to the size of the drawn rectangles, then another to the size of the rectangles. A nested for loop within the main for loop. Right away it checks to makesure I is not the same as X, to prevent it from checking a collision with itself (which will always be true). Then it checks if x is connected to the ground, if it is then that means its touching the floor. It then calls the .intersectsWith to check if i intersects with X. If it does, then it intersect locks it, and sets i being connected to the ground, as its connected to one that links to the ground. And thats it for that!

The 2 loops cause something like this:
i and x, i and x+1, i and x+2

x will always be incrementing, once x has finished its loop, i gets incremented, then the x loop starts again, comparing each with each other to check for intersections.

And thats it! You can get the source download below. No screenshot this time as the form is really big to allow the objects space to fall and stack.

Like always, the source is licensed under the GPL license. If you use it with the intent to re distribute it, the source must be released too, as well as a link back to BncApps.

Download: [download#3#size]

Helpful? why not buy me a coffee for my next project?

Reader Comments

Great! I love this, its fun to build things up and i cant believe its done in such short code!

#1 
Written By Netter on December 16th, 2008 @ 6:32 pm

Trackbacks

  1. VB.NET - Mouse Events  on December 10th, 2008 @ 8:38 pm
  2. BncApps.com | VB6 - Downloading a file  on December 18th, 2008 @ 7:45 pm

Add a Comment

required, use real name
required, will not be published
optional, your blog address

Previose Post: