update: added spherecast
video: https://www.youtube.com/watch?v=ZMkY8BwQ7xU
model: https://create.roblox.com/store/asset/95635639470917/
rbxm model file: Superball.rbxm (12.5 KB)
uncopylocked place: https://www.roblox.com/games/118904893923407/ball
would you use?
- yeah
- looks good but I don’t need it.
- no.
- yea but it could improve
11 Likes
literally the most funny community resource ever
2 Likes
script.Parent:WaitForChild("Fire").OnServerEvent:Connect(function(Player, target: Vector3)
local RootPart: BasePart = Player.Character:FindFirstChild("HumanoidRootPart")
if not RootPart then return end
if not script.Parent.Enabled then return end
script.Parent.Enabled = false
local ball = script.Parent:WaitForChild("Handle"):Clone()
ball.Anchored = true
ball.Name = "SuperballProjectile"
ball.CFrame = CFrame.new(RootPart.Position + (CFrame.new(RootPart.Position, target).LookVector * 5))
ball.Velocity = CFrame.new(ball.Position, target).LookVector * 120
ball.Velocity += Vector3.new(0, 10, 0)
ball.Trail.Enabled = true
ball.CanCollide = false
local soundattachment = Instance.new("Attachment", ball)
soundattachment.Name = "SoundAttachment"
ball.Parent = workspace
script.Parent.Handle.Boing:Play()
local characters = {}
for i, v in ipairs(workspace:GetChildren()) do
if v:FindFirstChildWhichIsA("Humanoid") then
table.insert(characters, v)
end
end
task.spawn(function()
local step = tick()
local start = tick()
while task.wait() do
if ball == nil or ball.Parent == nil or workspace:IsAncestorOf(ball) ~= true then
if ball and ball.Parent ~= nil then
ball:Destroy()
end
return
end
local dt = tick() - step
step = tick()
local params = RaycastParams.new()
params.IgnoreWater = true
params.RespectCanCollide = true
local params2 = RaycastParams.new()
params2.FilterType = Enum.RaycastFilterType.Include
params2.FilterDescendantsInstances = characters
local raycast = workspace:Raycast(ball.Position, (ball.Velocity * dt) + ball.Velocity.Unit, params)
if not raycast then
raycast = workspace:Raycast(ball.Position, (ball.Velocity * dt) + ball.Velocity.Unit, params2)
end
if raycast then
local humanoid = raycast.Instance.Parent:FindFirstChildWhichIsA("Humanoid")
if humanoid and humanoid.Health > 0 and humanoid.RootPart then
if humanoid.RootPart:CanSetNetworkOwnership() then
humanoid.RootPart:SetNetworkOwner(nil)
humanoid:ChangeState(Enum.HumanoidStateType.FallingDown)
end
humanoid:TakeDamage(25)
local linearvelocity = Instance.new("LinearVelocity")
linearvelocity.Parent = humanoid.RootPart
linearvelocity.MaxForce = math.huge
linearvelocity.RelativeTo = Enum.ActuatorRelativeTo.World
linearvelocity.VectorVelocity = ball.Velocity * 0.2
linearvelocity.Attachment0 = humanoid.RootPart:FindFirstChild("RootAttachment")
if not linearvelocity.Attachment0 then
Instance.new("Attachment", humanoid.RootPart).Name = "RootAttachment"
end
game:GetService("Debris"):AddItem(linearvelocity, 0.1)
local sound = script.Parent:WaitForChild("Hit"):Clone()
sound.Parent = humanoid.RootPart
sound:Play()
sound.TimePosition = 0.12
game:GetService("Debris"):AddItem(sound, sound.TimeLength / sound.PlaybackSpeed)
local attachment = Instance.new("Attachment", raycast.Instance)
attachment.WorldPosition = raycast.Position
local particles = script.Parent:WaitForChild("Particles"):Clone()
particles.Parent = attachment
particles:Emit(math.random(28, 36))
game:GetService("Debris"):AddItem(attachment, 36)
humanoid.StateChanged:Once(function(new)
if new == Enum.HumanoidStateType.GettingUp then
local hitplayer = game:GetService("Players"):GetPlayerFromCharacter(raycast.Instance.Parent)
if hitplayer and humanoid.RootPart:CanSetNetworkOwnership() then
humanoid.RootPart:SetNetworkOwner(hitplayer)
end
end
end)
elseif raycast.Instance.CanCollide then
raycast.Instance:ApplyImpulseAtPosition(ball.Velocity, raycast.Position)
end
if raycast.Instance.CanCollide or humanoid then
local sound = ball.Boing:Clone()
sound.PlaybackSpeed = math.random(90, 110) / 100
sound.Parent = soundattachment
sound:Play()
game:GetService("Debris"):AddItem(sound, sound.TimeLength / sound.PlaybackSpeed)
ball.CFrame = ball.CFrame.Rotation + (raycast.Position + raycast.Normal)
local reflectedNormal = ball.Velocity.Unit - (2 * ball.Velocity.Unit:Dot(raycast.Normal) * raycast.Normal)
ball.Velocity = reflectedNormal * ball.Velocity.Magnitude
else
ball.CFrame += ball.Velocity * dt
ball.Velocity -= Vector3.new(0, workspace.Gravity * dt, 0)
end
else
ball.CFrame += ball.Velocity * dt
ball.Velocity -= Vector3.new(0, workspace.Gravity * dt, 0)
end
if tick() - start > 5 or ball.Velocity.Magnitude <= 0 then
ball:Destroy()
return
end
end
end)
task.wait(2)
script.Parent.Enabled = true
end)
heres the indented cleaned up code btw hope this helps for readablility
2 Likes
jokes aside this is actually really awesome i love the ricochet
good stuff
3 Likes
Ironically it also fixed a bug in the original script
update: I fixed the ball ignoring players if the raycast hits an accessory for the model and the uncopylocked place
Superball.rbxm (12.1 KB)
Is force and max distance tunesble ?
I mean you can tune it yourself in the script if that works.
ball.Velocity = CFrame.new(ball.Position, target).LookVector * 120
update: I fixed some stuff and added a hitbox using spherecast https://create.roblox.com/store/asset/95635639470917/
Where is the second law of thermodynamics