Here’s how I would go about this.
Given the following scenario:
Where:
- u is initial velocity
- v is reflected velocity
- n is the normal to the wall which we collided with
- e is the coefficient of restitution (you can think of this as damping, i.e. if e = 0.5, we will lose half our speed per collision, if e equals 1, we never lose speed on collisions)
Then the we can find the reflected velocity through the following:
v = (u - 2 * u.n * n) * e
The derivation can be found here: Sunshine's Homepage - Vector reflection at a surface
So going about implementing this in ROBLOX.
In the ball I’d have a script:
local RUNSERVICE = game:GetService("RunService")
function update(delta_time) -- this function is called every frame prior to render
-- move ball forwards
-- check for collisions
-- if collided, then reflect
end
RUNSERVICE.RenderStepped:Connect(update)
Making the ball move fowards:
We just multiply the balls the cframe by another cframe
local ball = script.Parent
local SPEED = 50
-- MOVE
ball.CFrame = ball.CFrame * CFrame.new(0, 0, -SPEED * delta_time)
Make sure to multiply by delta_time so that the frame rate doesn’t affect the balls speed.
Detecting collisions
I would use raycasting. The origin would be the balls position, the direction would be the balls look vector. Make sure to multiply the direction by some amount, this represents “how far ahead” the collision detector looks for collisions (this value would have something to do with the speed at which the ball moves and the radius of the ball)
The good thing about raycasting is that we can do this:
local raycast = workspace:Raycast(origin, direction * distance, params)
print(raycast.Normal)
This is how we’ll get the normal for the reflection.
Reflection
local normal = raycast.Normal
local lookVector = ball.CFrame.lookVector
local reflectionVector = lookVector - 2 * lookVector:Dot(normal) * normal
-- after we obtain the reflection vector, we need to use cframes to rotate the ball
ball.CFrame = CFrame.lookAt(ball.Position, ball.Position + reflectionVector)
-- keep in mind im not the best with cframes, may be a better way to do this ^^^
This doesn’t allow for the “e” part of the equation, you’d have to do something like this.
local BALL_SPEED = 50
local e = 0.66
function reflect(normal, etc)
-- all that reflection code from before
BALL_SPEED *= e
end
Although I expect for brick breaker type of game, you wouldn’t want the ball slowing down anyway.
Keep in mind this is all a bit pseudocodey, I implemented it quickly in studio and it worked though. If you have any questions ask away