How would i make this "throw" work?

Im trying to make a item that has a realistic throw when you click while holding it.
I know stuff like Body Velocities/the property for velocity would work best, but the hardest part (for me) is making it where you click.

for example:
If you changed the body velocity to

Vector3.new(20,0,0)

it would fling it just in one direction.

I dont want that, and i want it to go wherever you click.
how would i do that?
(keep in mind it would still kind of need to look like a throw and have a decent/ customizable speed)

1 Like

if I’m understanding correctly you want to like, throw the item you’re holding from the character’s position to your mouse position right? The first way I can think of doing that is using Mouse Hit’s CFrame position and the character’s humanoidrootpart position to get vector3 that gives you the direction, and using that for the velocity.

Yeah i want the item to be thrown from the characters position. The script is not a local script and im assuming this only works in local scripts right?

yeah mouse.Hit only works for localscripts, but thats not a roadblock, it just means you have to use a remote event to send the value from the client to the server

Im TERRIBLE with remote events so let me show you what i did:

Local Script:

RemoteEvents.Throw.OnClientEvent:Connect(function()
	local Throw = Instance.new("BodyVelocity")
	Throw.Velocity = Vector3.new(mouse.Hit.Position)
	Throw.Parent = Test.Handle
end)

Normal Script:

Test.Activated:Connect(function(Throw)
		Test.Parent = workspace
game.ReplicatedStorage.RemoteEvents.Throw:FireClient()
	end)

Output:
image

edit: i removed the Throw.Velocity = mouse.Hit.p part at the end

Oh okay, theres some concepts about remote events you need to understand first,

game.ReplicatedStorage.RemoteEvents.Throw:FireClient()

this is missing the player object whose client belongs to, so in between the parenthesis you need to put the player object. since you’re using the .Activated event I’m guessing you’re using a tool for this?. if this is the case, then you must get the player from the character that is holding that tool, so:

game.ReplicatedStorage.RemoteEvents.Throw:FireClient(game.Players:GetPlayerFromCharacter(Test.Parent))

this is why its outputting (argument 1 missing) error.

now this is all good and all, but you are doing everything backwards. youre trying to trigger the event to the client so the client can handle the throwing direction? it should be the opposite. The goal of using a remote event was so you could send the value of the mouse.Hit position from the localscript to the script on the tool. give me a few mins and ill give you a code example

create a LocalScript inside of StarterPlayerScripts and copy this code into it

local userInputService = game:GetService("UserInputService")
local raycastParams = RaycastParams.new()

userInputService.InputBegan:connect(function(input, processed)
	if processed == true then return end
	if input.UserInputState ~= Enum.UserInputState.Begin then return end
	if input.UserInputType ~= Enum.UserInputType.MouseButton1 then return end

	-- Cast a ray to find out where the player clicked
	local position = userInputService:GetMouseLocation()
	local ray = workspace.CurrentCamera:ViewportPointToRay(position.X, position.Y)
	local raycastResult = workspace:Raycast(ray.Origin, ray.Direction * 1000, raycastParams)
	if raycastResult == nil then return end

	-- ratio effects the throw curve higher values will make the part stay lower and move faster lower values will make the part go higher and move slower 
	local ratio = 2

	-- Character PrimaryPart
	local primaryPart = game.Players.LocalPlayer.Character.PrimaryPart

	-- this is the position the part will start
	local startPosition = primaryPart.Position + primaryPart.CFrame.LookVector * 5

	-- the direction from the start position to the click position
	local direction = raycastResult.Position - startPosition

	-- calculate the force we must apply to the part so it can reach its destination
	local force = direction * ratio + Vector3.new(0, game.Workspace.Gravity * 0.5 / ratio, 0)

	-- create a part
	local part = Instance.new("Part")
	part.Size = Vector3.new(1, 1, 1)
	part.Position = startPosition
	part.Parent = workspace

	-- set the parts force
	part.AssemblyLinearVelocity = force
end)
2 Likes

Here, this is what i got working, I figured using a RemoteFunction instead of a RemoteEvent was better since all you really need is to call the hit value.
image

LocalScript:

local player = game.Players.LocalPlayer
local mouse = player:GetMouse()
local rfunc = script.Parent:WaitForChild('RemoteFunction')

rfunc.OnClientInvoke = function() --when the function is invoked/called
	print('invoked')
	return mouse.Hit.Position --return the value of mouse.hit
end

Script:

local tool = script.Parent
local part = tool.Handle
local rfunc = tool:WaitForChild('RemoteFunction')

local ratio = 2 --5uphi's ratio thing is very smart

local debounce = false --debounce so it cant be spam clicked
tool.Activated:Connect(function()
	if debounce then return end
	debounce = true
	
	local player = game.Players:GetPlayerFromCharacter(tool.Parent)
	local mousepos = rfunc:InvokeClient(player)
	
	local direction = (mousepos - tool.Parent.PrimaryPart.Position)
	
	--borrowed this from 5uphi lol
	local force = direction * ratio + Vector3.new(0, game.Workspace.Gravity * 0.5 / ratio, 0)
	
	tool.Parent = workspace
	part.AssemblyLinearVelocity = force
	
	debounce = false
end)

5uphi’s method works just fine however it only runs locally, and im guessing you want something on a script, and like a tool that can be thrown

This seems like it would work, but im getting an error:
image

seems like its failing to identify the primary part in this line

local direction = (mousepos - tool.Parent.PrimaryPart.Position)

which is weird, It shouldn’t have that behaviour, perhaps you put the script inside of something? that makes it so the tool’s parent is no longer the player’s character? in any case, replacing it with this should work

local direction = (mousepos - player.Character.PrimaryPart.Position)

heres the file of my tool in case it still doesnt work, since it works fine here
tool.rbxm (4.5 KB)

2 Likes

Much thanks! this will help a lot.

1 Like

I know this is a bit late, but apparently invoking client isn’t safe. Is there any other way?

you could try firing a remote event back and forth instead, otherwise I don’t know how else you could send the Hit value to the server

Don’t worry. I made a total different post about it and there was a way using a remote event

1 Like