Very funny ball tool

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
  • :moyai:

0 voters

11 Likes

literally the most funny community resource ever :100:

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 :rage: