Throwing a Tool Seems to Throw the Player Instead

Attention!

I have marked a solution that answers the original question “how do I throw a tool” below, so if you’re in a rush, go ahead and click on @Hest_z’s solution and be on your merry way. If you stick around, however, you’ll get to see a different solution to this problem that has nothing to do with Tools. Go ahead and pick your cake!


Hello all.

I just started working on a basketball game, and my first step is to code the shooting physics.

The first thing I did was implement a projectile motion function. With the help of this guide, I believe I was able to solve the following problem:

Knowing the initial and terminal position, as well as gravity and time = 1, how can we calculate the initial velocity required to reach the terminal position?

local t = 1;
local Player = game.Players.LocalPlayer
local character_loaded = Player.Character or Player.CharacterAdded:Wait()
local HRP = character_loaded:WaitForChild("HumanoidRootPart")
local bball_tool = script.Parent
local bball_handle = script.Parent:WaitForChild("Handle")
local net = game.Workspace.hoop

bball_tool.Activated:Connect(function()
	local g = Vector3.new(0, -game.Workspace.Gravity, 0);
	local x0 = HRP.CFrame * Vector3.new(0, 2, -2)

	-- calculate the v0 needed to reach mouse.Hit.p
	local v0 = (net.Position - x0 - 0.5*g*t*t)/t;

	-- have the ball travel that path
	bball_tool.Parent = game.Workspace
	bball_handle.AssemblyLinearVelocity = v0;
	bball_handle.CFrame = CFrame.new(x0);
end)

There are a couple differences from my code and @EgoMoose’s…

  1. The ball’s final position is permanently set to the net. Wherever the player is, they will always score green.

  2. As such, I have omitted the mouse class and the tool is activated using the basic Activated() function.

  3. The tool is not cloned. My intent with this program is to literally throw the ball.


So, this is what I want the program to do. Note that the following clip uses cloning like the guide. To visualize what I really want, imagine the same visual but with the ball leaving the players hand:

And this is what I get when I try to throw the tool itself:

Why am I being thrown instead?


I tried some debugging to figure out what might be going on:

  1. Change x0 value to HRP.CFrame * Vector3.new(0, 20, -20)
    My thought process is: “Maybe the ball is colliding with the player as soon as it’s launched?” In which case, I want to change the initial position to something far away from the player to see if this is true.


    Nope. Still getting launched up.

  2. Adding script.Parent:WaitForChild("TouchInterest"):Destroy() Right after bball_tool.Parent = game.Workspace
    The idea is to temporarily prevent the player from interacting with the ball in order to prevent grabbing the ball.


    Well, now there’s no velocity being applied to the ball.

  3. Using task.wait()
    Here, I tried to use task.wait() after setting the tool’s parent to game.Workspace to try to discern what’s going on at each stage of the shot.


    The ball just kind of… spazzes for a moment.

I should also mention that, in all of the clips, the ball has been set to massless.


I am 10000% sure this is the result of some quirk of the physics engine. Unfortunately, it is something that I have very little experience with; I have no idea where to look or what’s going on at all, really.

Any and all help is greatly appreciated, and I know I’ll learn a lot regardless of the outcome!

3 Likes

From my personal guess, it might be something with the way roblox deals with tool instances.
Tool handles are (at least, as far as I know) welded to the player’s hand.
If I were to fix this, try making a weld point on the player’s hand, and make your own custom “grabbing” system for the ball (basically, when you touch the ball it gets welded to the grab point, then later on you press a key or something and it gets unwelded and the rest.)
This is what I’m personally thinking, and actually ties in perfectly with me wanting to make a “Store Wars!” game. I’ll have to make my own throwing system, so if I find anything I’ll tell you.

2 Likes

You are ball. Embrace ball. Human basketball. It’s a feature, not a bug.

7 Likes

First guess it’s probably cause of the tools weld in the right arm called “RightGrip” try deleting that weld before doing the projectile motion code and it probably will fix it.

1 Like

ez fix cancollide is set to true

1 Like

It needs to be for the bounce mechanics…

I’ll try @satqx1 and @Rowlier’s suggestions for now. I think I’ll see if I can just delete the “RightGrip” (wherever it may be) first. If it doesn’t work then I’ll go ahead and try to make my own welding system.

HRP.CFrame * Vector3.new(…). Multiplying by a CFrame returns a point relative to the HumanoidRootPart, so the ball may be spawning inside the player and the velocity applies to the player’s physics.

Also added handle.CanCollide = true, so it doesn’t pass through the player..

local t = 1
local Player = game.Players.LocalPlayer
local char = Player.Character or Player.CharacterAdded:Wait()
local HRP = char:WaitForChild("HumanoidRootPart")
local tool = script.Parent
local handle = tool:WaitForChild("Handle")
local net = workspace.hoop

tool.Activated:Connect(function()
	local g = Vector3.new(0, -workspace.Gravity, 0)
	local x0 = HRP.Position + Vector3.new(0, 2, -2)
	local v0 = (net.Position - x0 - 0.5*g*t*t)/t
	tool.Parent = workspace
	handle.CanCollide = true
	handle.CFrame = CFrame.new(x0)
	handle.AssemblyLinearVelocity = v0
end)

This should make the ball spawn slightly in front of the player without affecting their own physics,
I hope.. Pretty sure that’s is the only way possible that is happening.

Another thing I may want to mention after reading @2112Jay’s suggestion; If neither of these work, use collision groups. Set the player to have its own, regular collision group, and the ball to have its own as well. Then make it so that player and ball collision groups cannot collide. (There is an entire tab/window for collision group editing, that’s what I mean by all of this.)
They should hopefully still collide correctly with everything else, but not with each other.

2 Likes

Hey all.

Last night I was busy with homework and watching Blue Lock with my girlfriend so I couldn’t work on this until a couple minutes ago during class. I haven’t solved this yet, but I have tried some of your suggestions. Thank you all so much for replying and helping me out so far!


  1. Deleting “RightGrip” weld (suggested by @Rowlier)

From what I understand, tools automatically weld to the “RightGrip” weld created by Studio. The idea is to delete “RightGrip” before throwing the tool because maybe the weld is messing with interaction and what not.
First, I tried writing bball_handle:Destroy("RightGrip")


This just… deletes the handle? Definitely not what I want, and probably not what Row meant. So, I found someone else who wanted to destroy the “RightGrip” weld. The script I added from the blog was:

script.Parent.DescendantAdded:Connect(function(Unwelcomeone)
		if Unwelcomeone:IsA("Weld") and Unwelcomeone.Name == "RightGrip" then
			task.wait()
			Unwelcomeone:Destroy()
		end
	end)

This script goes through all of bball_tool’s descendants, checks if there is a weld AND if that weld is named “RightGrip”, waits for it to be loaded in, and then destroys it. Definitely slower but it’s a good way to see if destroying the weld will help.

Unfortunately, it didn’t. Adding it before or after bball_tool is parented to workspace results in the same thing.

On to the next.

  1. Change x0 calculation (suggested by @2112Jay)

I agree that the root cause may be the ball spawning inside the player, which causes the balls velocity to apply to the player’s physics. I tried adding the Vector3.new to the HRP.Position, but I get the following error:

image

I’m guessing that adding a Vector3 to a CFrame just results in a CFrame. Dunno why the same doesn’t happen when it multiplies but…

  1. Collision Groups (suggested by @satqx1)

Using Studio’s built in Collision Group manager, I attempted to specify whether or not the ball can collide with the player. I created two collision groups; “Player” and “BBall.”


“Player” should not be able to collide with “BBall.” To test this, I assigned the pole to “BBall.”

Meanwhile, in the “AntiBBallCollision” Script that I placed in ServerScriptStorage, I applied my character to the “Player” Collision Group.

local PhysicsService = game:GetService("PhysicsService")
local Players = game:GetService("Players")

PhysicsService:RegisterCollisionGroup("Characters")
PhysicsService:CollisionGroupSetCollidable("Characters", "BBall", false)

local function onDescendantAdded(descendant)
	-- Set collision group for any part descendant
	if descendant:IsA("BasePart") then
		descendant.CollisionGroup = "Characters"
	end
end

local function onCharacterAdded(character)
	-- Process existing and new descendants for physics setup
	for _, descendant in character:GetDescendants() do
		onDescendantAdded(descendant)
	end
	character.DescendantAdded:Connect(onDescendantAdded)
end

Players.PlayerAdded:Connect(function(player)
	-- Detect when the player's character is added
	player.CharacterAdded:Connect(onCharacterAdded)
end)

This script is based on the same one given in the Collisions documentation.

Perfect! The player can’t collide with anything in the “BBall” group. Now we just need to add the ball to the group and see if it works.


:(


I think my current plan of action is to follow @satqx1’s suggestion and create my own welding system. I think what I’ll do is:

  1. Have a “ball” part that can’t collide with the player
  2. When the player touches the ball, it will weld to their hand
  3. Write a script that will launch the ball ONLY if the ball is welded to the player

This lowkey feels like writing the tool system from scratch, or like “a Tool with extra steps,” but it’s the only option I got. I don’t think it’ll be hard necessarily, but I’m still surprised that this problem even exists in the first place. It seems so easy at first glance; just throw the tool! But, that’s how programming is.

Like I said, I don’t think that this will be an extremely difficult task. In fact, I’m pretty sure that this is how Azure (the game that inspired me to start this project) handles the football during a match.

In AZL, the ball is a physical thing in the world. Meanwhile, the player, can use most of their moveset without the ball in their hands (feet?).


Kicking…

Dashing…

Even some “ball only” moves…

They’re all available off the ball. Only when you get possession do these actions actually affect the ball.



As I write this I believe that the ball isn’t actually a tool but just a physics object welded to a player that reacts to player input.


So, with all of this in mind, I’ll get rid of the tool system and implement @satqx1’s suggestion. I realize that this post may have derailed the original topic (from trying to throw a tool to systematically different), but I suppose that’s how most problems are solved. You try to do one thing, it doesn’t work, you try to tweak it and try again. Sometimes the tweaking works, and sometimes, you need something else.

I’ll try this and get back when I’ve succeeded. Until then, thank you everyone who’s replied and I can’t wait to solve this!

1 Like

EDIT:

I realize that in Suggestion 2, I don’t even end up using the “Player” Collision Group because my script creates it’s own group called “Character” and assigns the player to it. However, this still works out because the player doesn’t collide with the pole, regardless. I’m too lazy to go back and edit the original post sorry lol

Thats not what I meant theres a weld in the players character’s right arm you were destroying something else completely. also if it was something collision related just try debugging and disable the cancollide property if you don’t boost up in the air then set up collision groups.

put the weld part before your calculations in the tool activated function

    local Players = game:GetService("Players")
    local Player = Players.LocalPlayer
    local Character = Player.Character or Player.CharacterAdded:Wait()
    
    local Weld = Character:WaitForChild("Right Arm"):WaitForChild("RightGrip")
    Weld:Destroy()
1 Like

I do have some news:
After working on my remake for a little while (nearly 7 hours straight), in that time I did get a grabbing system to function. It uses motor6d’s to weld the object to the player’s Right Arm, and then sets the position of the object infront of the player, and sets its velocity once a key is pressed.
Again as I said before, it’s usually better in most cases to have a minature “tool” like system, especially with things that are going to be thrown around a lot.

If tools were serversided dont use clientside work because physics actually serverside calculates not clientside

Try this but not anymore localscript

local t = 1;

local Character=nil -- Should be nil

local bball_tool = script.Parent
local bball_handle = script.Parent:WaitForChild("Handle")
local net = game.Workspace.hoop

bball_tool.Equipped:Connect(function()
	Character=bball_tool.Parent -- once equip get the character
end)

bball_tool.Activated:Connect(function()
	local g = Vector3.new(0, -game.Workspace.Gravity, 0);
	local x0 = Character.HumanoidRootPart.CFrame * Vector3.new(0, 2, -2)

	-- calculate the v0 needed to reach mouse.Hit.p
	local v0 = (net.Position - x0 - 0.5*g*t*t)/t;

	-- have the ball travel that path
	bball_tool.Parent = game.Workspace
	bball_handle.AssemblyLinearVelocity = v0;
	bball_handle.CFrame = CFrame.new(x0);
end)
1 Like

Did you weld any parts of the tool to the character?

Hey all.

First off I’d like to apologize for how long this took. I had some other stuff to do, but honestly there was a lot of free time where I could have worked on this, but didn’t. But that was then, and this is now, and now, I present to you a solution!


Tool Solution

Before we begin, I’d like to implement one last suggestion by @Hest_z. Let’s try out their solution before we take a look at mine.

All we need to do is change the tool’s local script into a normal script and set the Character value when the ball is touched.

local t = 1;

local Character=nil -- Should be nil

local bball_tool = script.Parent
local bball_handle = script.Parent:WaitForChild("Handle")
local hoop = workspace.Net.Hoop

bball_tool.Equipped:Connect(function()
	Character=bball_tool.Parent -- once equip get the character
end)

bball_tool.Activated:Connect(function()
	local g = Vector3.new(0, -game.Workspace.Gravity, 0);
	local x0 = Character.HumanoidRootPart.CFrame * Vector3.new(0, 2, -2)

	-- calculate the v0 needed to reach mouse.Hit.p
	local v0 = (hoop.Position - x0 - 0.5*g*t*t)/t;

	-- have the ball travel that path
	bball_tool.Parent = game.Workspace
	bball_handle.AssemblyLinearVelocity = v0;
	bball_handle.CFrame = CFrame.new(x0);
end)

Note that I moved the target part hoop to a model Net.

Look at that! We can successfully throw the tool itself and retrieve it after. Everyone say, “thank you @Hest_z!”


Custom Welding Solution

For those of you in a rush, please go ahead and implement @Hest_z’s solution and keep up the good work. But if you have the time, I would like to present my custom welding solution to those who are curious.

As I discussed earlier, my goal is to weld a part to the player and write a scrip that will destroy the grip before launching the part.

Because I won’t be using a Tool (which is stored in StarterPack, thus making it client-sided), and because the ball is a server-wide entity, I’ll need to separate the input of the player from the output of the ball being launched. We can do this using a localscript for the input, a script for the ball’s behavior, and a remoteEvent that will tie the two together.

Let’s set up our workspace.


Here we have our ball and a script named BBallHandler that will do all the physics stuff.

image
This will be the script that handles input.

image
And this will be our RemoteEvent.

Handling Input

When we get the player input (let’s use the E key), we want the script to send a signal to the ball to launch itself. This is how we do that:

local UIS = game:GetService("UserInputService")
local remoteEvent = game.ReplicatedStorage.RemoteEvent

-- player input
UIS.InputBegan:Connect(function(input, gameProcessed)
	
	-- only trigger input if player isn't typing in chat
	if gameProcessed then return end
	
	-- tell BBallHandler to throw ball when player presses the 'E' key
	if input.KeyCode == Enum.KeyCode.E then
		remoteEvent:FireServer()
	end
end)

For those who are unaware, the line if gameProcessed then return end basically prevents us from calling this function if the player types the letter ‘e’ in the chat. So if someone wants to type “electricity” or something with the ball, they won’t unintentionally shoot it.

When you use remoteEvent:FireServer(), you tell the RemoteEventobject to fire a signal to be received by any server script that is listening, which, in our case, will be BallHandler.

Welding the ball to the player

Meanwhile, in our BBallHandler script, we can set up all our necessary variables for now.

local bball = script.Parent
local Players = game:GetService("Players")
local t = 1
local hoop = workspace.Net.Hoop
local remoteEvent = game.ReplicatedStorage.RemoteEvent
local motor6d = nil

As suggested by @satqx1, we will be using a Motor6D to weld the ball to the player’s right arm. motor6d will eventually hold that Motor6D, but for now we will set it as nil because we don’t have that information right away.

We also have a variable remoteEvent that references the RemoteEvent object that we put in ReplicatedStorage. We will use this later to receive the signal sent from InputHandler to launch the ball.

So… how do we weld an object using Motor6D?

Documentation defines Motor6D as an object that “joins two BaseParts (Part0 and Part1) together in an animatable way.” This is nearly identical to a Weld, which “hold[s] two objects together in a relative position, regardless of whether they’re touching.” In most cases, either is fine, but Motor6D works for this project specifically because it can be used for animations.

As stated, Motor6D needs two parts to work:

  1. Part0, which is the first part that the joint connects. This will be the ball.
  2. Part1, the second part that the joint connects. This will be the the player’s right hand.

But how do we tell our motor6D variable which part we want to apply to Part0 and Part1? Well, Roblox already has a built in function called Touched that will fire a signal when an object is, well, touched. So, in BBallHandler, we can put

bball.Touched:Connect(function(hit)
end)

Here, I put a parameter into the function so that we can get whatever the ball is touching. You can write something like print(tostring(hit)) you’ll be able to see everything in the output box. This is great and all, but we’ve only solved one part of the touching problem. The value hit is indiscriminate, so now we need to actually differentiate a player from every other object. Fortunately for us, Roblox already has a tool for this: GetPlayerFromCharacter. This function allows us access the player’s Character and all the data we need from it.

For our case, we’ll use Players:GetPlayerFromCharacter(hit.Parent) to see if hit is a player. And because this function will return nil if no player exists, then we can add this as:

bball.Touched:Connect(function(hit)
	if Players:GetPlayerFromCharacter(hit.Parent) then
		
	end
end)

This way we can have the ball check if a player is touching it when a touch event occurs. Awesome! Now we have a way to set Part0 and Part1 to the right objects 100% of the time.

motor6d = Instance.new("Motor6D")
motor6d.Part0 = bball
motor6d.Part1 = hit.Parent:WaitForChild("Right Arm")
motor6d.C0 = motor6d.C1 * CFrame.new(0, 2, 0)
motor6d.Parent = bball

Here we set motor6d as a new instance of Motor6D, parent Part0 to the ball, and then parent Part1 to the "Right Arm" child of the player (hit.Parent). We can also alter the CFrame of the ball by using the C0 property. In our case, we set it to the location of the player’s hand by getting the CFrame of Part1 through the C1 property, then offsetting the y-axis by 2 studs. Lastly we parent motor6d to the ball.

One last thing before we’re done with this part; we need to add a debounce so that the player doesn’t accidentally fire off multiple touched events. We want to check if a value is false, set it to true, wait a moment, and then set it to false again. In this case our value will be the “Touched” attribute. We can use bball:GetAttribute("Touched") to check if “Touched” is false, and then we can set it to true/false using bball:SetAttribute("Touched", boolean)

All in all, we’re left with this as our final solution to the welding.

bball.Touched:Connect(function(hit)
	if Players:GetPlayerFromCharacter(hit.Parent) then
		if not bball:GetAttribute("Touched") then
			bball:SetAttribute("Touched", true)
			motor6d = Instance.new("Motor6D")
			motor6d.Part0 = bball
			motor6d.Part1 = hit.Parent:WaitForChild("Right Arm")
			motor6d.C0 = motor6d.C1 * CFrame.new(0, 2, 0)
			motor6d.Parent = bball
			task.wait(1)
			bball:SetAttribute("Touched", false)
		end
	end
end)


Sweet! Now we’ll move on to actually firing the ball.

Throwing the Ball

Earlier we decided that we needed a local script to handle input, and we worked out a small program that will fire a RemoteEvent when we press ‘E.’ However, while the signal is sent, nothing in our game actually cares about that signal. This is where local remoteEvent = ReplicatedStorage.RemoteEvent definied in BBallHandler comes into play. We’ll use the OnServerEvent function to execute a function when we call FireServer() from our local script.

remoteEvent.OnServerEvent:Connect(function(player)
end)

FireServer has an implicit parameter player. An implicit parameter a type of value that’s passed automatically by the system/runtime rather than explicitly by the programmer. This is especially useful for us because we can get the player who activated the FireServer function through this parameter, which we need to calculate the initial position for the velocity of the ball.

local character = player.Character or player.CharacterAdded:Wait()
local HRP : Part = character:WaitForChild("HumanoidRootPart")

-- calculate initial position and velocity
local g = Vector3.new(0, -workspace.Gravity, 0)
local x0 = HRP.CFrame * Vector3.new(0, 2, -2)
local v0 = (hoop.Position - x0 - 0.5*g*t*t)/t;

Now all that’s left is to throw the ball. Before we throw the ball, we want to destroy the Motor6D so we, the player, don’t get flung. We’ll also disable CanTouch until the ball is thrown, after which we’ll enable CanTouch again.

-- throw ball
bball.CanTouch = false
motor6d:Destroy()
bball.CFrame = CFrame.new(x0)
bball.AssemblyLinearVelocity = v0
task.wait(1)
bball.CanTouch = true
motor6d = nil

We set motor6d back to nil so we can’t access motor6d again until we touch the ball. Speaking of which, we want to make sure that the ball can only be thrown if the ball is being held by a player. We’ll check if Part1, which should be the player, exists. If it doesn’t, then the ball shouldn’t be activated if we press the ‘E’ key.

if motor6d.Part1 == player.Character:WaitForChild("Right Arm") then

So with this check in mind, the part of the script that throws the ball should look like:

-- throw ball
remoteEvent.OnServerEvent:Connect(function(player)
	if motor6d.Part1 == player.Character:WaitForChild("Right Arm") then
		local character = player.Character or player.CharacterAdded:Wait()
		local HRP : Part = character:WaitForChild("HumanoidRootPart")

		-- calculate initial position and velocity
		local g = Vector3.new(0, -workspace.Gravity, 0)
		local x0 = HRP.CFrame * Vector3.new(0, 2, -2)
		local v0 = (hoop.Position - x0 - 0.5*g*t*t)/t;

		-- throw ball
		bball.CanTouch = false
		motor6d:Destroy()
		bball.CFrame = CFrame.new(x0)
		bball.AssemblyLinearVelocity = v0
		task.wait(1)
		bball.CanTouch = true
		motor6d = nil
	end
end)

Great! We have now solved the problem of welding the ball to the player, as well as throwing the ball when the player presses a button.

InputHandler

local UIS = game:GetService("UserInputService")
local remoteEvent = game.ReplicatedStorage.RemoteEvent

-- player input
UIS.InputBegan:Connect(function(input, gameProcessed)
	
	-- only trigger input if player isn't typing in chat
	if gameProcessed then return end
	
	-- tell BBallHandler to throw ball when player presses the 'E' key
	if input.KeyCode == Enum.KeyCode.E then
		remoteEvent:FireServer()
	end
end)

BBallHandler

-- variables
local bball = script.Parent
local Players = game:GetService("Players")
local t = 1
local hoop = workspace.Net.Hoop
local remoteEvent = game.ReplicatedStorage.RemoteEvent
local motor6d = nil

-- functions

-- weld ball to player's hand
bball.Touched:Connect(function(hit)
	if Players:GetPlayerFromCharacter(hit.Parent) then
		if not bball:GetAttribute("Touched") then
			bball:SetAttribute("Touched", true)
			motor6d = Instance.new("Motor6D")
			motor6d.Part0 = bball
			motor6d.Part1 = hit.Parent:WaitForChild("Right Arm")
			motor6d.C0 = motor6d.C1 * CFrame.new(0, 2, 0)
			motor6d.Parent = bball
			print("Now equipping: " .. tostring(motor6d))
			task.wait(1)
			bball:SetAttribute("Touched", false)
		end
	end
end)

-- throw ball
remoteEvent.OnServerEvent:Connect(function(player)
	if motor6d.Part1 == player.Character:WaitForChild("Right Arm") then
		local character = player.Character or player.CharacterAdded:Wait()
		local HRP : Part = character:WaitForChild("HumanoidRootPart")

		-- calculate initial position and velocity
		local g = Vector3.new(0, -workspace.Gravity, 0)
		local x0 = HRP.CFrame * Vector3.new(0, 2, -2)
		local v0 = (hoop.Position - x0 - 0.5*g*t*t)/t;

		-- throw ball
		bball.CanTouch = false
		motor6d:Destroy()
		bball.CFrame = CFrame.new(x0)
		bball.AssemblyLinearVelocity = v0
		task.wait(1)
		bball.CanTouch = true
		motor6d = nil
	end
end)

Alright, let’s test this out. I’ll showcase it with two players just to make sure that no data carries over from Player1 to Player2 or anything like that.

:smiley: Hooray! We did it! We’ve successfully recreated shooting a virtual basketball!


I’d like to thank everyone who responded to this post and to you, the reader, for making it this far. I hope I haven’t been too verbose; I really enjoy tutorials that break down the thought process behind everything instead of just throwing a code on the screen. I hope that you’ve gotten something out of this forum and my rambling.

Have a great day, and good luck on your project!

Awesome! Glad you got it to work.
If you want some more tweaks, I’d recommend setting the ball to massless, and setting the ball to its own collision group for a few seconds separate from the player to keep them from colliding.
Gives me the idea for a football game. Might have to think about that.

1 Like

Wow. You made the solution into a Resources > Community Tutorials lmao