Set boundaries for where picturebox can move?

TheLaw

Member
Joined
Oct 30, 2010
Messages
13
Programming Experience
Beginner
Hello,

I'm making a game. Essentially there is a boat on the sea and it goes places. Yadeeyadeeya. You get it.

I'm using KeyDown to get the picturebox to move around, but I don't know how to keep the boat within the boundaries of the form. So if it hits the side of the form, I want it to just stop.

What control/procedure should I use to do this?

Thanks.
 
Just write an if statment,compare the location of the picbox and the size of the form

KeyDown to get the picturebox to move around.. don't know how to keep the boat within the boundaries of the form..

What control/procedure should I use to do this?
You can simply just get the location of the picturebox and the size of the container and write an if statement. Add the size of the picturebox with the location to get the right or bottom location of the picture box for when you are trying to move right or down. The left and top, just check that it is greater than or equal to 0.

So here's a Boolean method to check if it is within bounds. example:

    'the futurePosition is the location where the obj would be if it was to move
    'the objMoving would be the size of your picturebox in this case
    'you may want to use ClientSize for the container
    Private Function moveIsInBounds(ByVal futurePosition As Point, ByVal objMoving As Size, ByVal container As Size) As Boolean
        Dim xInBounds As Boolean = (futurePosition.x >= 0) AndAlso (futurePosition.x + objMoving.Width <= container.Width)
        Dim yInBounds As Boolean = (futurePosition.y >= 0) AndAlso (futurePosition.y + objMoving.Height <= container.Height)

        If xInBounds AndAlso yInBounds Then
            Return True
        Else
            Return False
        End If
    End Function


Call that method somewhere like in your if statement to decide whether or not you want to move the obj. Instead of using Me.Size to get the size of the form you can use ClientSize. Since if your form has a border you are going to need an offset, but ClientSize will get just the size of the space you have to work with.
 
Okay great.

Thank you.

I have another question. I want to have another picturebox move up and down (enemy ship on patrol) and change direction when it hits the form boundaries (top and bottom of forum).

I'm currently trying to get it to work using a timer and a case/If statement. But I was also trying to do something with a Do Loop While, but I can't seem to figure it out.

Ideas?

Thanks.
 
np, glad to help.

Can you elaborate what your having trouble with exactly?

It sounds like you got the idea... so just write a method that moves the picturebox on every tick event.. if it is in bounds move it, if it is at one of the sides reverse direction..
 
VB.NET:
Private Sub tmrBad1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles tmrBad1.Tick

        If (Me.picBad1.Top - 10) < 0 Then
            picBad1.Top += 10

        ElseIf (Me.picBad1.Top - 10) > 0 Then
            picBad1.Top -= 10
        End If
    End Sub

Well I was doing some more research, and I found out *possibly* a better way to keep it in bounds, so I'm trying it on these "sprites".

So I want this enemy ship to bounce back and forth from the top of the form to the bottom. I put it on a timer so that the PictureBox moves upwards at an interval. When it hits the top, it goes down , but then the first part of the If statement draws it back upward once it gets too far away from the top of the form.

It's kind of "caught" up against the top of the form, going down one, and then up one, and then down one, and then up one....because of the If statement.


So I thought I would do a Loop While somehow....

VB.NET:
    Private Sub tmrBad1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles tmrBad1.Tick

        If (Me.picBad1.Top - 10) Then
            Do
                Me.picBad1.Top -= 10
            Loop While (Me.picBad1.Top - 10) > 0
        Else
            Do
                Me.picBad1.Top += 10
            Loop While (Me.picBad1.Top + Me.picBad1.Height + 10) < Me.ClientRectangle.Bottom

        End If
    End Sub

But this doesn't work either. I was never too good with Do Loops.

Do you (or anyone else) have a recommendation on how to do this? It's kind of like playing pong I guess...but endlessly.

Thanks.
 
add a boolean to determine direction, no need for looping inside the tick method

VB.NET:
Private Sub tmrBad1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles tmrBad1.Tick

        If (Me.picBad1.Top - 10) < 0 Then
            picBad1.Top += 10

        ElseIf (Me.picBad1.Top - 10) > 0 Then
            picBad1.Top -= 10
        End If
    End Sub
.. bounce back and forth from the top of the form to the bottom. I put it on a timer so that the PictureBox moves upwards at an interval. When it hits the top, it goes down...

It's kind of "caught" up against the top of the form, going down one, and then up one, and then down one, and then up one....because of the If statement.

To make your tick method work, i think the easiest thing to do is to make a boolean that is of class-level scope. Store the direction it is moving in that boolean. So heres a simple example to make your method work.

    Private moveUp As Boolean = True
    Private moveSpeed As Integer = 5
    Private Sub tmrBad1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles tmrBad1.Tick
        If moveUp Then
            If (Me.picBad1.Top - moveSpeed) > 0 Then
                Me.picBad1.Top -= moveSpeed
            Else
                moveUp = False
            End If
        Else
            If (Me.picBad1.Top + Me.PictureBox1.Height + moveSpeed) < Me.ClientRectangle.Bottom Then
                Me.picBad1.Top += moveSpeed
            Else
                moveUp = True
            End If
        End If
    End Sub



the loop method you tried:
So I thought I would do a Loop While somehow....

VB.NET:
    Private Sub tmrBad1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles tmrBad1.Tick

        If (Me.picBad1.Top - 10) Then
            Do
                Me.picBad1.Top -= 10
            Loop While (Me.picBad1.Top - 10) > 0
        Else
            Do
                Me.picBad1.Top += 10
            Loop While (Me.picBad1.Top + Me.picBad1.Height + 10) < Me.ClientRectangle.Bottom

        End If
    End Sub

This has the same kinda logic error, also the first if statement does not return a (true or false - you forgot to compare the result with 0 or whatever), if you use a boolean like the above e.g. it should work. However, note that if you are using a loop you will lose your control over the speed of it moving up/down. Although you can add a timer or some kind of thread sleep/wait, that should be down outside of the tick event if you wanted to use a loop. The timer is already looping in a way since that tick event will be called ever 0.001 second or whatever interval you set, until you stop the timer. This way to change the speed of the movement you can just change the timer interval and/or the amount it moves each time.

i recommend that you use some kind of timer to control the speed, there is no need for a loop like that inside of the tick event.



Do you (or anyone else) have a recommendation on how to do this? It's kind of like playing pong I guess...but endlessly.

I think the way you are doing it with the timer is fine, i think it should be sufficient. If you can explain a bit more on the functionality or gameplay of this maybe someone or i can make a better recommendation? I'm not sure what topics you are familiar with in programming either, so a bit of
 
Alright thanks I don't really have time to work on it right now, but tomorrow I'll definitley give it a look. Thank you.
 
So think of a guard on patrol. Its going from the top to bottom and keeps on doing that. Here's a new idea that uses two timers....

I think this would be the best option, but once the picturebox hits the top of the form, it stops there and doesn't switch over to the other timer and go down. So it just goes up and stops. I've asked some of my friends who code, and we thought this would work well, but it doesn't.

Any ideas? Tmr1 is enabled on default. Tmr2 is disabled. However, it still doesn't work if I turn one on or the other etc.


VB.NET:
 Private Sub tmrBad1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles tmrBad1.Tick
        Dim blnTop As Boolean

        If blnTop = True Then
            tmrBad2.Start()
            tmrBad1.Stop()
        End If

        If Me.picBad1.Location.Y < 0 Then
            blnTop = True
        Else
            Me.picBad1.Top -= 10
        End If
    End Sub

Private Sub tmrBad2_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles tmrBad2.Tick
        Dim blnBottom As Boolean

        If blnBottom = True Then
            tmrBad1.Stop()
            tmrBad2.Start()
        End If

        If Me.picBad1.Location.Y < 480 Then
            blnBottom = True
        Else
            Me.picBad1.Top += 10
        End If
    End Sub
 
Looking at your code from a glance, it seems like the issue is probably your boolean. It appears that the boolean you declared is only visible in that method, the scope of the variable is just inside the method it is declared. Once that method finish executing and the tick event fires again blnTop is recreated and you are not really storing the value anywhere.

Try declaring your boolean's in the class level, and also you may want to check that the location is <= 0, since it could be equal to 0 if the picture started at 0,0
 
Working Sample using two timers, Moves image up and down continously

Here's a quick example using two timers but without a boolean. It doesn't necessary need a boolean, just an if statement is enough.

Here's a quick explanation about the logic behind it. You have two timers. Lets call them TimerDown and TimerUp, makes more sense. Timer up will check to see that if the image is moved, will it exceed the height of the form? if it does then don't move it and turn the timer off. Then start the TimerDown.

TimerDown does the exact opposite. If you wanted to, like i suggested, using one timer and one boolean is probably a better idea, this way you do not have redundant/similar code with slight differences, but it depends on your situation and how you want to write it.


Here's a sample (tested working code):
Public Class Form1
    Inherits System.Windows.Forms.Form
    Private imgBall As New Bitmap(50, 50)
    Private rateOfMovement As Integer = 10

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Dim g As Graphics = Graphics.FromImage(imgBall)
        g.FillEllipse(Brushes.Aqua, New Rectangle(0, 0, 25, 25))
        g.Dispose()
        g = Nothing
        picBall.Image = imgBall

        timerUp.Start()
    End Sub

    'this moves pic up
    Private Sub timerUp_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles timerUp.Tick
        If (Me.picBall.Location.Y - rateOfMovement) < 0 Then
            timerDown.Start()
            timerUp.Stop()
        Else
            Me.picBall.Top -= rateOfMovement
        End If
    End Sub

    'moves pic down
    Private Sub timerDown_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles timerDown.Tick
        If (Me.picBall.Location.Y + rateOfMovement + Me.picBall.Height) > ClientSize.Height Then
            timerUp.Start()
            timerDown.Stop()
        Else
            Me.picBall.Top += rateOfMovement
        End If
    End Sub
#Region "GUI Related"
    Private components As System.ComponentModel.IContainer
    Friend WithEvents picBall As System.Windows.Forms.PictureBox
    Friend WithEvents timerUp As System.Windows.Forms.Timer
    Friend WithEvents timerDown As System.Windows.Forms.Timer
    Sub New()
        InitializeComponent()
    End Sub
    Private Sub InitializeComponent()
        Me.components = New System.ComponentModel.Container()
        Me.picBall = New System.Windows.Forms.PictureBox()
        Me.timerUp = New System.Windows.Forms.Timer(Me.components)
        Me.timerDown = New System.Windows.Forms.Timer(Me.components)
        CType(Me.picBall, System.ComponentModel.ISupportInitialize).BeginInit()
        Me.SuspendLayout()
        Me.picBall.Image = Nothing
        Me.picBall.Location = New System.Drawing.Point(0, 0)
        Me.picBall.Size = New System.Drawing.Size(33, 33)
        Me.picBall.TabIndex = 0
        Me.picBall.TabStop = False
        Me.AutoScaleDimensions = New System.Drawing.SizeF(6.0!, 13.0!)
        Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font
        Me.ClientSize = New System.Drawing.Size(278, 194)
        Me.Controls.Add(Me.picBall)
        CType(Me.picBall, System.ComponentModel.ISupportInitialize).EndInit()
        Me.ResumeLayout(False)
    End Sub
    Protected Overrides Sub Dispose(ByVal disposing As Boolean)
        Try
            If disposing AndAlso components IsNot Nothing Then
                components.Dispose()
            End If
        Finally
            MyBase.Dispose(disposing)
        End Try
    End Sub
#End Region
End Class
 
Last edited:
I've done exactly what you said, and STILL, it stalls at the top. I really don't know what's wrong. I'm thinking its something beyond this...

Thanks.
 
You probably have other code then? If you need help with that, please post what is relevant. The example i posted above is a working example. I just updated it with the GUI, this way you can copy and paste into a vb file and run the form.
 
Well it's alright now.

Thanks.


May I ask one more question..?

I'm doing a simple animation using an array of pictures. It works fine, but I'm going to need to be able to play this on computers that are not mine, and do not have my files (pictures) on them.

So I'm doing like...

strImage(0) = "C:\Me\VB\bin\boat1.png"
strImage(1) = "C:\Me\VB\bin\boat2.png"


I've been trying a lot of things, but it seems that there's no easy way around it. I've tried resources, putting the pictures in different folders etc....but if I send it to my friend and he tries opening the .exe, when this animation tries to initiate, the program breaks because the files cannot be found.

What do I do?

Thank you.
 
Add a existing resource to your project, and get it by using My.Resources.NAMEHERE

Thanks.

May I ask one more question..?
:) No Problem, of course you can.
I'm doing a simple animation using an array of pictures. It works fine, but I'm going to need to be able to play this on computers that are not mine, and do not have my files (pictures) on them.

strImage(0) = "C:\Me\VB\bin\boat1.png"
strImage(1) = "C:\Me\VB\bin\boat2.png"

I've tried resources, putting the pictures in different folders etc....

What do I do?

Please see the documentation MSDN has about using resources. If you are using them correctly they should be in the exe. See the links at the bottom of the page too.

How to: Add or Remove Resources

MSDN has detailed instructions on how to add/remove and use them, i do not know what version you have but on the top of the page you can change the version so you get instructions that match yours.


I use 2010, for the most part i think its the same in 2008. Go to properties by right clicking on your solution in the 'Solution Explorer' or double clicking on 'My Project'. Then go to the resources tab. Import the resource images by clicking on 'Add Resource' > 'Add Exisiting File...' > select the files you want to add.

Then in your code when using the resources, use the My.Resources.RESOURCENAMEHERE to access it.

ex. (using images i added to my project)
Dim imgs() As Image = {My.Resources.clickherebutton, My.Resources.clickherebutton_MD}


When you compile the files, and go to your release/debug bin, those exe's should have the resources in them.
 
Thanks a lot. Microsoft actually has a lot of information. I should consider going on MSDN more often...

It works well.
 
Back
Top