I'm making a Battleship game, and I'm using buttons as the grid(playerboard). I'm using a picture box as the ship, and I'm trying to make it so that the picturebox snaps to the buttons that it is colliding with.
I have already done the drag and drop, and collision part, but I'm struggling with the snapping to buttons part. The picture box is the size of two buttons. I tried to align the picturebox with the buttons, by using picturebox.left = button.left, but it chooses the wrong button of the two.
Dim Off As Point
Private Sub picDestroyer_MouseDown(sender As Object, e As MouseEventArgs) Handles picDestroyer.MouseDown
Off.X = MousePosition.X - sender.Left 'Click and Drag ship
Off.Y = MousePosition.Y - sender.Top
End Sub
Private Sub picDestroyer_MouseMove(sender As Object, e As MouseEventArgs) Handles picDestroyer.MouseMove
If e.Button = MouseButtons.Left Then
sender.Left = MousePosition.X - Off.X 'Click and Drag ship
sender.Top = MousePosition.Y - Off.Y
End If
End Sub
Private Sub picDestroyer_DoubleClick(sender As Object, e As EventArgs) Handles picDestroyer.DoubleClick
If picDestroyer.Size = New Size(52, 21) Then 'Rotate Pic if double clicked
picDestroyer.Size = New Size(21, 52)
ElseIf picDestroyer.Size = New Size(21, 52) Then
picDestroyer.Size = New Size(52, 21)
End If
End Sub
Private Sub picDestroyer_MouseLeave(sender As Object, e As EventArgs) Handles picDestroyer.MouseLeave
For Each button In Me.Controls
If picDestroyer.Bounds.IntersectsWith(button.bounds) Then
button.backcolor = Color.Red
picDestroyer.BackColor = SystemColors.Control
End If
If picDestroyer.Bounds.IntersectsWith(button.bounds) And picDestroyer.Size = New Size(52, 21) Then
picDestroyer.Top = button.top
End If
If picDestroyer.Bounds.IntersectsWith(button.bounds) And picDestroyer.Size = New Size(21, 52) Then
picDestroyer.Left = button.left
End If
Next
To get the button which you want to snap to you can temporarily disable the
PictureBox
and callGetChildAtPoint()
on the form to get the child control at the location of thePictureBox
, specifyingGetChildAtPointSkip.Disabled
as the second parameter so that the search won't include your disabledPictureBox
but all the other controls above/below it.After that you can just set the
PictureBox
's coordinates to that of the button.There are also a few improvements that can be made to your code:
You can use the
MouseUp
event instead ofMouseLeave
to update the picture box's position immediately after you drop it.Set both the X- and Y-coordinates for the picture box when snapping (not just one of them,
Left = X, Top = Y
) so that it is snapped correctly in the top-left corner of the button.In the loop iterate through
Me.Controls.OfType(Of Button)()
instead of justMe.Controls
, sinceOfType(Of TResult)
will get only the controls of a certain type (in this caseButton
s). Iterating through onlyMe.Controls
will for example include thePictureBox
itself which could cause issues in the future (perhaps that was the reason you set itsBackColor
toControl
every time?).All that said, this code should work:
Another thing to keep in mind is to use
AndAlso
instead ofAnd
, andOrElse
instead ofOr
inIf
-statements sinceAndAlso
andOrElse
are short-circuited.