The attached picture shows a game I'm working on. The Player is the white dot in the centre, and the map, including the brown houses, move around the Player according to where you click.
I have a "HitTest" function that stops the Player when he collides with a wall; it first detects whether the Player is inside or outside the house, and makes calculatations accordingly, allowing for the Player to travel through the grey doors.
My problem is, as you can see in the screenshot, while the Player does stop when he hits a wall, it's a little later than I'd like, resulting in the Player appearing to be half-in and half-out of the house (the Player's co-ordinates are taken to be the centre of the white dot).
I tried to get around this by detecting collision with an invisible "border" around the house - the problem then is that the player can't get OUT of the house, as when he exits through the door, the game stops him because he's still inside the border (I have since removed the border).
Here's the code - if anyone can find a solution to my problem, I'd be very grateful. If you see a way to improve on the code's efficiency also (shouldn't be too hard), please let me know
Declarations
Code:
Public Type PlayerObj
ZoneX As Long
ZoneY As Long
X As Single
Y As Single
XPos As Single
YPos As Single
House As Integer
Width As Long
Height As Long
Picture As StdPicture
Speed As Long
MoveTime As Long
MoveSpeedX As Single
MoveSpeedY As Single
End Type
Public Player As PlayerObj
Public Type HouseObj
XPos As Single
YPos As Single
X As Long
Y As Long
Width As Long
Height As Long
Colour As String
'Door (distance from top corner)
DX As Single
DY As Single
DWidth As Long
DHeight As Long
DColour As String
End Type
Public Type ZoneObj
Houses As Long
House() As HouseObj
End Type
Public Zone() As ZoneObj
HitTest Function
Code:
Public Function HitTest() As Integer
Dim i As Integer
Dim PX As Single, PY As Single, X2 As Single, Y2 As Single, _
DX1 As Single, DX2 As Single, DY1 As Single, DY2 As Single
With Player
PX = .X + .MoveSpeedX
PY = .Y + .MoveSpeedY
End With
'Returns a value depending on which side of the Player has collided
' __1__
' | |
' 4| [i] |2
' |_____|
' 3
'Check if the Player hits a house
For i = 1 To Zone(Player.ZoneX, Player.ZoneY).Houses
With Zone(Player.ZoneX, Player.ZoneY).House(i)
X2 = .X + .Width
Y2 = .Y + .Height
DY1 = .Y + .DY
DY2 = .Y + .DY + .DHeight
DX1 = .X + .DX
DX2 = .X + .DX + .DWidth
'Is the player outside?
If Player.House = 0 Then
'Is he entering a house...
If PX >= .X And PX <= X2 Then
If PY >= .Y And PY <= Y2 Then
'... from the left?
If Player.MoveSpeedX > 0 Then
If PX >= .X Then
'Is he using the door?
If PY >= DY1 And PY <= DY2 And DX1 = .X Then
Player.House = i 'Set house
Exit Function
Else
HitTest = 2
End If
End If
End If
'... from the right?
If Player.MoveSpeedX < 0 Then
If PX <= X2 Then
'Is he using the door?
If PY >= DY1 And PY <= DY2 And DX1 = X2 Then
Player.House = i 'Set house
Exit Function
Else
HitTest = 4
End If
End If
End If
'... from the top?
If Player.MoveSpeedY > 0 Then
If PY >= .Y Then
'Is he using the door?
If (PX >= DX1) And (PX <= DX2) Then
If DY1 = .Y Then
Player.House = i 'Set house
Exit Function
End If
Else
HitTest = 1
End If
End If
End If
'... from the bottom?
If Player.MoveSpeedY < 0 Then
If PY <= Y2 Then
'Is he using the door?
If PX >= DX1 And PX <= DX2 And DY1 = Y2 Then
Player.House = i 'Set house
Exit Function
Else
HitTest = 3
End If
End If
End If
End If
End If
'Or is he in a house, exiting...
ElseIf Player.House = i Then
'... from the left?
If Player.MoveSpeedX > 0 Then
If PX >= X2 Then
'Is he using the door?
If PY >= DY1 And PY <= DY2 And DX1 = X2 Then
Player.House = 0 'Set outside
Exit Function
Else
HitTest = 2
Player.X = X2
Halt
End If
End If
'... from the right?
Else
If PX <= .X Then
'Is he using the door?
If PY >= DY1 And PY <= DY2 And DX1 = .X Then
Player.House = 0 'Set outside
Exit Function
Else
HitTest = 4
Player.X = .X
Halt
End If
End If
End If
'... from the top?
If Player.MoveSpeedY > 0 Then
If PY >= Y2 Then
'Is he using the door?
If PX >= DX1 And PX <= DX2 And DY1 = Y2 Then
Player.House = 0 'Set outside
Exit Function
Else
HitTest = 3
Player.Y = Y2
Halt
End If
End If
'... from the bottom?
Else
If PY <= .Y Then
'Is he using the door?
If PX >= DX1 And PX <= DX2 And DY1 = .Y Then
Player.House = 0 'Set outside
Exit Function
Else
HitTest = 1
Player.Y = .Y
Halt
End If
End If
End If
End If
End With
Next i
End Function
Code that moves the Player
Code:
Private Sub MapUpdate_Timer()
Dim Hit As Integer
'Updates the map every frame
Game.Cls
'Draw Houses
UpdateMap
'Draw Player
With Player
If (.MoveTime > 0) Then
'Move Player
Hit = HitTest
If Hit = 0 Then
.X = .X + .MoveSpeedX
.Y = .Y + .MoveSpeedY
.MoveTime = .MoveTime - 1
End If
'Move zones
If (.X >= 500) Then
.X = 500 - .X
.ZoneX = .ZoneX + 1
ElseIf (.X <= 0) Then
.X = 500 + .X
.ZoneX = .ZoneX - 1
End If
If (.Y >= 500) Then
.Y = 500 - .Y
.ZoneY = .ZoneY + 1
ElseIf (.Y <= 0) Then
.Y = 500 + .Y
.ZoneY = .ZoneY - 1
End If
Else 'Stop
.MoveSpeedX = 0
.MoveSpeedY = 0
End If
'Draw Player
Call DrawPlayer(Player, .XPos, .YPos, .Width, .Height)
End With
Game.Refresh
End Sub