Basic Movement Tutorial

noi_max
07-12-2004, 02:24 PM
I've seen this pop up a few times over in the game programming section so I thought I would take a crack at my first tutorial.

Plus, I just love to move stuff around, so here we go...

Moving a picturebox on a form:

I'll start by creating a new project and adding a picturebox and a timer control to the form. I've kept the default names for sake of simplicity.

The key thing with using these objects is the dimensions and how they work.
The picture box, for example has a Top, Left, Height and Width property that we can utilize. The form has these properties as well. The very Top/Left of the form would be considered 0, 0. To move the picturebox down and
to the right on the form you would need to add to the .Top and .Left dimensions of the picturebox respectively.
To demonstrate, I will set some things up in the Form_Load event to set where the picturebox will appear on the form. Feel free to follow along...

Private Sub Form_Load()

Picture1.Top = 500
Picture1.Left = 500

End Sub

This will offset the picturebox from the top/left corner of the form. This offest is ulimately how we will move the picturebox.

The Timer Control:

Think of the timer control as a loop, that will start and stop when we want it to.
Each time the timer control 'fires' we will move the picturebox using the .Top
property.

When you double click on the Timer control on your form, you'll see that it has
it's own procedure. It's in there that the movement will happen.

We'll set how often the timer fires in the Form_Load. Here is the code in the
project so far...

Private Sub Form_Load()

Picture1.Top = 500
Picture1.Left = 500

'Set the interval. This is measured in milliseconds
Timer1.Interval = 10

'Start the timer
Timer1.Enabled = True

End Sub

Private Sub Timer1_Timer()

'The timer fires once every 10 milliseconds. So in that time, let's move the
'picture box downward by adding to the Picture1.Top property

Picture1.Top = Picture1.Top + 30

End Sub

I put 30 in there for movement. Feel free to change that number to see what
happens.

Basic Wrap:

If you've been following along, you'll notice that the picturebox moves beyond the bottom of the form and then disappears. The timer is still going, in fact the picturebox is still moving, we just can no longer see it!

Since we have the dimensions of the form and picturebox available we can make a simple wrap function to have the picturebox re-appear at the top of the screen after it's reached the bottom. Here's an example:

Private Sub CheckWrap()

'If we kept moving the picturebox, it would disappear. It's still moving, but it's
'coordinates are out of visible range. A simple wrap around function will keep it
'on the screen.

'To do this we need to check if the picture top has gone beyond the
'scaleheight of the form. If it has, set the picturebox's top property to re-'start at the top.

'Here, I used 0 - Picture1.ScaleHeight to make it appear as though the picture is
'coming from beyond the top of the form. Try changing that and see what happens!

If Picture1.Top > Form1.ScaleHeight Then
Picture1.Top = 0 - Picture1.ScaleHeight
End If

End Sub

I then simply added the CheckWrap procedure to the timer procedure:

Private Sub Timer1_Timer()

Picture1.Top = Picture1.Top + 30
CheckWrap

End Sub

Basic Keyboard Handling:

This one gets asked a lot and I feel it's somewhat relative to what I'm doing
so I'll put it here.

There exists for the form a Keydown and KeyUp event that will handle these
keyboard actions for us using a KeyCode constant. Once you learn a few of these constants the rest would be easy enough to guess, but here's the actual list:

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vbenlr98/html/vamsckeycodeconstants.asp

The events in the sample code will look like this:

Private Sub Form_KeyDown(KeyCode As Integer, Shift As Integer)

'If the spacebar is pressed, start the timer.

If KeyCode = vbKeySpace Then
Timer1.Enabled = True
End If

End Sub

Private Sub Form_KeyUp(KeyCode As Integer, Shift As Integer)

'If the spacebar is released stop the timer.

If KeyCode = vbKeySpace Then
Timer1.Enabled = False
End If

End Sub

I then modified the Form_Load like this:

Private Sub Form_Load()

Picture1.Top = 500
Picture1.Left = 500

'Set the interval. This is measured in milliseconds
Timer1.Interval = 10

'Let the keyboard start/stop the timer
Timer1.Enabled = False

'This line is needed for the KeyDown/KeyUp events
KeyPreview = True

End Sub

Put together, this will make the picture box move only when the spacebar is
pressed.

More Keyboard and Wrap:

I suppose the next thing would be to change keyboard handling for the arrow keys and make the wrap procedure handle all 4 directions.

To do this I needed to set up a few booleans in the General Declarations section of the form.

Option Explicit

'Boolean data to handle the keypresses
Private k_Up As Boolean
Private k_Down As Boolean
Private k_Left As Boolean
Private k_Right As Boolean

And now to change the KeyDown/KeyUp events to handle the booleans

Private Sub Form_KeyDown(KeyCode As Integer, Shift As Integer)

'Using a select case statement, check for the key pressed and
'set a boolean value to be used later in the movement of the picture box

Select Case KeyCode
Case vbKeyUp
k_Up = True
k_Down = False
Case vbKeyDown
k_Down = True
k_Up = False
Case vbKeyLeft
k_Left = True
k_Right = False
Case vbKeyRight
k_Right = True
k_Left = False
End Select

End Sub

Private Sub Form_KeyUp(KeyCode As Integer, Shift As Integer)

Select Case KeyCode
Case vbKeyUp
k_Up = False
Case vbKeyDown
k_Down = False
Case vbKeyLeft
k_Left = False
Case vbKeyRight
k_Right = False
End Select

End Sub

Now, change the timer procedure to handle all of the directions. This will
introduce the .Left property of the picture box.
Remember, since we add to the .Top and .Left properties to offset down and right respectively, we will need to subtract to go Left and Up.

Private Sub Timer1_Timer()

If k_Up = True Then
Picture1.Top = Picture1.Top - 30
End If

If k_Down = True Then
Picture1.Top = Picture1.Top + 30
End If

If k_Left = True Then
Picture1.Left = Picture1.Left - 30
End If

If k_Right = True Then
Picture1.Left = Picture1.Left + 30
End If

CheckWrap

End Sub

Finally, it's time to modify the CheckWrap procedure to handle all of the
directions, using a similar formula as before.

Private Sub CheckWrap()

'If the picture goes beyond the bottom of the form, have it
'reappear atthe top.
If Picture1.Top > Form1.ScaleHeight Then
Picture1.Top = (0 - Picture1.Height)
End If

'If the picture goes beyond the top of the form, have it
'reappear at the bottom
If Picture1.Top < (0 - Picture1.Height) Then
Picture1.Top = Form1.ScaleHeight
End If

'If the picture goes beyond the right side of the form, have it
'reappear at the left.
If Picture1.Left > Form1.ScaleWidth Then
Picture1.Left = (0 - Picture1.Width)
End If

'If the picture goes beyond the left side of the form, have it
'reappear at the right.
If Picture1.Left < (0 - Picture1.Width) Then
Picture1.Left = Form1.ScaleWidth
End If

End Sub

And there you have it. Basic movement in a nutshell.

The timer control is a good place to begin, however the accuracy is, well, not
extremely accurate.

I could, in a follow up tutorial, cover the basics of the QueryPerformanceCounter API function that can be used in place of the timer control for more precision movement.

Here is the completed sample project. Of course you can put a picture into the picturebox if you like. That would probably make it more interesting :)

Iceplug
07-12-2004, 03:15 PM
Well, it looks fine. As you said, the Timer control is not accurate, but seeing a timer interval being set to 1 looks so horrible, as the timer cannot handle that. I would at least put it to 10. Also, QueryPerformance seems like a lot of overkill for moving controls around the form.

But, looks very good.
Also, you may want to touch on absolute and relative movement (if you want to) and acceleration and jumping and turning and... ok nevermind.

Good job.

noi_max
07-13-2004, 09:17 AM
Well, it looks fine. As you said, the Timer control is not accurate, but seeing a timer interval being set to 1 looks so horrible, as the timer cannot handle that. I would at least put it to 10. Also, QueryPerformance seems like a lot of overkill for moving controls around the form.

But, looks very good.
Also, you may want to touch on absolute and relative movement (if you want to) and acceleration and jumping and turning and... ok nevermind.

Good job.

Thanks Iceplug! :D

I do have a jump example I can post, but ulimately you would have to receive credit for it. I was following a thread about jumping (http://www.xtremevbtalk.com/showthread.php?t=173674&highlight=jump) that you posted on and used that info in the current project.

The basic idea was to use an integer variable to move an object, starting with a negative number and then adding to it until it became a positive number.

In my example, I used a variable named "StartPoint", to establish where the picturebox started before the jump. Then I used another variable named "Jump" to move the picturebox.

Something like this:

In declarations:

Private Jump As Integer 'the 'velocity'
Private m_Space As Boolean 'the space key
Private m_KeyDown As Boolean 'boolean to prevent multiple jumps
Private StartPoint As Long 'initial box starting position

Then in Form_Load :

'capture the starting point to evaluate where the box will land
StartPoint = Picture1.Top

Added this to the timer control:

'Check keys and use the MoveBox procedure to make it jump!
If m_Space = True Then
m_KeyDown = True
MoveBox
End If

Almost done... just a couple more changes. Aded this to the Form_KeyDown:

'use a boolean to prevent multiple jumps
If m_KeyDown = True Then Exit Sub 'has the box landed yet?

If KeyCode = vbKeySpace Then
Jump = -350 'start with a negative number
m_Space = True
End If

Ok, finally on to the actual jumping procedure. This takes the negative "Jump" integer and adds to it, while changing the Picture1.Top property. The Jump variable will continue, going from negative to positive as we add to it, until the Picture1.Top property reaches the "StartPoint".
This was more or less a way to make the picture box land after it jumped, otherwise it would continue beyond the bottom of the form.
A more appropriate way to manage this is with collision detection (http://www.xtremevbtalk.com/showthread.php?t=54042), but that's IcePlug's territory and I'm already posting some of his jumping algorithm anyway :p

ok, on with the procedure:

Private Sub MoveBox()

'the jumping box procedure. This is called from the timer control and will continue
'to be called until m_Space = false (the box 'lands')

Picture1.Top = Picture1.Top + Jump 'box begins to move up

'Add to the initial negative number (move up) until it becomes positive (move down)
'and then finally reaches the Startpoint number and stops.

Jump = Jump + 20 '

'if block to stop jump movement after the box has 'landed'
If Picture1.Top >= StartPoint Then
Picture1.Top = StartPoint
m_Space = False
m_KeyDown = False
End If

End Sub


I will post the actual finished project below.
So far this has all been very simple stuff using only basic math. I was never any good at math :(

EZ Archive Ads Plugin for vBulletin Copyright 2006 Computer Help Forum