In this "3D Arkanoid clone" I'm making, the ball moves along a 2D plane like in the original Arkanoid, the default velocity for the ball is 0.02 units per cycle on the X axis and 0.04 units on the Y axis, and the bricks are boxes 0.6 units wide, 0.4 units tall and 0.4 units deep.
Right now, to detect collisions between the ball and a brick, I proceed as follows:
1) for every iteration of the main program loop, I check the distance from the ball and every brick in the level by repeatedly calling this function:
Function BrickCollision(BRICK)
`A generic control to check whether the ball is colliding with a brick or not
BALLBRICKXDIST#=Abs(BALLPOSX#(0)-Object Position X(BRICK))
BALLBRICKYDIST#=Abs(BALLPOSY#(0)-Object Position Y(BRICK))
If BALLBRICKXDIST#<0.3 And BALLBRICKYDIST#<0.2
RESULT=1
Else
RESULT=0
Endif
Endfunction RESULT
where BALLPOSX#(0) and BALLPOSY#(0) are global variables storing the current X and Y position of the ball (the Z position is fixed).
If the function returns 1, it means the ball is actually colliding with a brick. To decide what kind of bounce the ball must make, I need to know what side of the brick it has touched, because if it touched the higher or lower side of the brick, the Y component of the ball's velocity must be inverted, while if it touched the left or right side of the brick, the X component of the ball's velocity must be inverted. Currently, I use this function to decide what side of the brick the ball touched:
Function WhatBrickCollision(BRICK)
`Purpose of the function: tell which side of the brick (up, down, left,
`right) was touched by the ball. It returns:
`1 - the ball is colliding with the lower edge of the brick
`2 - the ball is colliding with the upper edge of the brick
`3 - the ball is colliding with the right edge of the brick
`4 - the ball is colliding with the left edge of the brick
`To see WHERE it is colliding, we must check 4 surrounding points
POINTUPX#=BALLPOSX#(0): POINTUPY#=BALLPOSY#(0)+0.05
POINTDOWNX#=BALLPOSX#(0): POINTDOWNY#=BALLPOSY#(0)-0.05
POINTLEFTX#=BALLPOSX#(0)-0.05: POINTLEFTY#=BALLPOSY#(0)
POINTRIGHTX#=BALLPOSX#(0)+0.05: POINTRIGHTY#=BALLPOSY#(0)
XDISTUP#=Abs(POINTUPX#-Object Position X(BRICK))
YDISTUP#=Abs(POINTUPY#-Object Position Y(BRICK))
XDISTDOWN#=Abs(POINTDOWNX#-Object Position X(BRICK))
YDISTDOWN#=Abs(POINTDOWNY#-Object Position Y(BRICK))
XDISTLEFT#=Abs(POINTLEFTX#-Object Position X(BRICK))
YDISTLEFT#=Abs(POINTLEFTY#-Object Position Y(BRICK))
XDISTRIGHT#=Abs(POINTRIGHTX#-Object Position X(BRICK))
YDISTRIGHT#=Abs(POINTRIGHTY#-Object Position Y(BRICK))
If (XDISTDOWN#>=0.3 Or YDISTDOWN#>=0.2)
`Down
RESULT=1
Else
If (XDISTUP#>=0.3 Or YDISTUP#>=0.2)
`Up
RESULT=2
Else
If (XDISTRIGHT#>=0.3 Or YDISTRIGHT#>=0.2)
`Right
RESULT=3
Else
If (XDISTLEFT#>=0.3 Or YDISTLEFT#>=0.2)
`Left
RESULT=4
Endif
Endif
Endif
Endif
Endfunction RESULT
After calling this function in the main program loop, I use this code to decide which component of the ball velocity to invert:
If BCOLL(0)<>0
Select BCOLL(0)
Case 1
BALLYVEL#(0)=0.0-BALLYVEL#(0)
BALLPOSY#(0)=(BALLPOSY#(0)+BALLYVEL#(0))
`DIRECTION$="DOWN"
Endcase
Case 2
BALLYVEL#(0)=0.0-BALLYVEL#(0)
BALLPOSY#(0)=(BALLPOSY#(0)+BALLYVEL#(0))
`DIRECTION$="UP"
Endcase
Case 3
BALLXVEL#(0)=0.0-BALLXVEL#(0)
BALLPOSX#(0)=(BALLPOSX#(0)+BALLXVEL#(0))
`DIRECTION$="RIGHT"
Endcase
Case 4
BALLXVEL#(0)=0.0-BALLXVEL#(0)
BALLPOSX#(0)=(BALLPOSX#(0)+BALLXVEL#(0))
`DIRECTION$="LEFT"
Endcase
Endselect
Position Object 1,BALLPOSX#(0),BALLPOSY#(0),30.0
Position Object 2,BALLPOSX#(0),BALLPOSY#(0),30.0
Endif
The problem with this approach is that as the ball velocity increases, the function becomes less precise and the ball may unpredictably bounce horizontally when it should bounce vertically, or viceversa. This is why I ask: is there a more accurate way to know which side of a brick the ball touched?