I have a ball shooting system where the ball goes through several raycasts to reflect its velocity. There is a problem where when a ball hits one of the walls, it sometimes doesn’t reflect the velocity and instead goes through the wall.
https://gyazo.com/0faef75cf36ac167b98b0738cfd4bd2f
Code here:
local Players = game:GetService('Players')
local Player = Players.LocalPlayer
local Character = Player.Character or Player.CharacterAdded:Wait()
local CollectionService = game:GetService('CollectionService')
local PlayerBalls = workspace:WaitForChild('PlayerBalls')
local RunService = game:GetService('RunService')
local Cursor = workspace:WaitForChild('Cursor')
local Line = Cursor:WaitForChild('Line')
local Line2 = Line:WaitForChild('Line2')
local LineLine = Line:WaitForChild('Line')
local Arrow = Cursor:WaitForChild('Arrow')
local Circle = Cursor:WaitForChild('Circle')
local Button = script.Parent
local TextLabel = Button:WaitForChild('ShootTextLabel')
local Gradient = Button:WaitForChild('UIGradient')
local OGColor = Gradient.Color
function update(ball, SPEED) -- this function is called every frame prior to render
RunService.Heartbeat:Connect(function(delta_time)
if not ball or not ball.PrimaryPart then return end
-- MOVE
ball.PrimaryPart.CFrame = ball.PrimaryPart.CFrame * CFrame.new(0, 0, -SPEED * delta_time)
ball.PrimaryPart.Orientation = Vector3.new(0, ball.PrimaryPart.Orientation.Y, ball.PrimaryPart.Orientation.Z)
-- check for collisions
local params = RaycastParams.new()
params.FilterType = Enum.RaycastFilterType.Exclude
params.FilterDescendantsInstances = {Arrow, Circle, Line2, LineLine, CollectionService:GetTagged('ShootingZone'), CollectionService:GetTagged('Barrier'), Character}
local raycast = workspace:Spherecast(ball.PrimaryPart.Position, 1, ball.PrimaryPart.CFrame.LookVector, params)
-- if collided, then reflect
if raycast and raycast.Normal and raycast.Instance.Name ~= 'Color' and not CollectionService:HasTag(raycast.Instance.Parent, 'Ball') and raycast.Instance.Name ~= 'AreaZone' then
local normal = raycast.Normal
local instance = raycast.Instance
if instance.Parent:HasTag('Block') then
instance.Parent:SetAttribute('HP', instance.Parent:GetAttribute('HP') - 1)
end
local lookVector = ball.PrimaryPart.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.PrimaryPart.CFrame = CFrame.lookAt(ball.PrimaryPart.Position, ball.PrimaryPart.Position + reflectionVector)
-- keep in mind im not the best with cframes, may be a better way to do this ^^^
end
if ball.PrimaryPart.CFrame.Z > -396 or ball.PrimaryPart.CFrame.Z < -500 then
ball:Destroy()
return
end
end)
end
script.Parent.MouseButton1Click:Connect(function()
if TextLabel.Text == 'SHOOT!' then
TextLabel.Text = 'STOP'
Gradient.Color = ColorSequence.new({ColorSequenceKeypoint.new(0, Color3.fromRGB(255, 0, 0)), ColorSequenceKeypoint.new(1, Color3.fromRGB(139, 0, 0))})
for i = 1, 3 do
if TextLabel.Text == 'STOP' then
local ball = workspace:WaitForChild('Balls'):WaitForChild('Big Ball'):Clone()
ball.Parent = PlayerBalls
ball.PrimaryPart.CFrame = CFrame.lookAt(Line2.Position, Circle.Position)
ball.PrimaryPart.Orientation = Vector3.new(0, ball.PrimaryPart.Orientation.Y, ball.PrimaryPart.Orientation.Z)
update(ball, 100)
task.wait(.4)
end
end
repeat task.wait() until #PlayerBalls:GetChildren() == 0
TextLabel.Text = 'SHOOT!'
Gradient.Color = OGColor
else
for i, v in PlayerBalls:GetChildren() do
v:Destroy()
end
TextLabel.Text = 'SHOOT!'
Gradient.Color = OGColor
end
end)