So, I want to make a Throwable Tool Object (Ball or other item), So i tried to script myself and it went horribly wrong and at this point i even forgot what was i Typing,
So, I want a Tool That goes where the Playerâs mouse is pointed at and it should go smooth.
I want to achieve a smooth, at constant speed Object that reaches its target!
At this point i have only tried Assembly Linear Velocity, Velocity (which is DEPRECATED) , body Velocity (Which is also DEPRECATED ( it did work but it was not smooth ), Tween Service (to make the ball go in smooth direction but it did not work) and normal CFrame positions which all failed because they either did not work or i might have not have implemented correctly. The ball might not be smooth because it is a script and running by the server but still i want other player to see too.
I have written this script:
(Script)
local LevelIncreaseRemote = game.ReplicatedStorage.LevelIncrease
local Tool = script.Parent
local Ball = Tool.Handle
local MouseLoc = Tool:WaitForChild("MouseLoc",10)
local PlayerCommunicate = game.ReplicatedStorage.HitBall
local db = false
-- Velocity power
local VelocityPower = 150
function FiretheBall(direction)
db = true
local vCharacter = Tool.Parent
local vPlayer = game.Players:GetPlayerFromCharacter(vCharacter)
local ball = Tool:FindFirstChild("Handle"):Clone()
local spawnPos = vCharacter.PrimaryPart.Position
spawnPos = spawnPos + (direction * 5)
-- Animation
local Throwanimation = vPlayer.Character:FindFirstChild("Humanoid"):LoadAnimation(script.Throw)
Throwanimation:Play()
task.wait(0.8)
-- Throwing
ball.Position = spawnPos
ball.AssemblyLinearVelocity = direction * VelocityPower
ball.Locked = true
ball.Name = "ThrownSnowball"
ball.Transparency = 0
ball.CanCollide = true
ball.Parent = workspace
-- Trails
local Attachment0 = Instance.new("Attachment", ball); Attachment0.Position = Vector3.new(-0.5,0,0); Attachment0.Orientation = Vector3.new(0,180,0)
local Attachment1 = Instance.new("Attachment", ball); Attachment1.Position = Vector3.new(0.5,0,0); Attachment1.Orientation = Vector3.new(0,0,0)
local Trail = Instance.new("Trail", ball); Trail.Attachment0 = Attachment0; Trail.Attachment1 = Attachment1
--damage function--
ball.Touched:Connect(function(hit)
ball.CanCollide = false
local human = hit:FindFirstChild("Humanoid") or hit.Parent:FindFirstChild("Humanoid")
if human and hit.Parent.Name ~= Tool.Parent.Name then
human.Health = 0
task.wait(1)
human.Health = 100
-- Give Rewards to the Plyaer who threw
LevelIncreaseRemote:Fire(vPlayer)
local HitPlayer = game.Players:GetPlayerFromCharacter(hit.Parent)
-- Will Change the Player's Team
PlayerCommunicate:FireClient(HitPlayer, "Hunters")
ball:Destroy()
else
ball:Destroy()
end
if wait(5) and Tool.Parent ~= vPlayer.Backpack then
db = false
Ball.Transparency = 0
end
end)
end
Tool.Enabled = true
function onActivated()
Tool.Enabled = false
local character = Tool.Parent
local humanoid = character:FindFirstChildOfClass("Humanoid")
Ball.Transparency = 1
-- The Mouse event is giving the Directions
local targetPos = MouseLoc:InvokeClient(game:GetService("Players"):GetPlayerFromCharacter(character))
local lookAt = (targetPos - character.Head.Position).unit
FiretheBall(lookAt)
wait(2)
Tool.Enabled = true
end
Tool.Activated:Connect(onActivated)
Local script
--Connect to Remote Function
local Tool = script.Parent
local MouseLoc = Tool:WaitForChild("MouseLoc")
function MouseLoc.OnClientInvoke()
return game:GetService("Players").LocalPlayer:GetMouse().Hit.p
end
Here is a good resource about creating throwable objects with proper motion:
Also as a sidenote I recommend not using RemoteFunctions OnClientInvoke. This can be abused to never trigger causing some shaky behaviors. I much more recommend on the localscript make Tool.Activated that uses RemoteEvent to fire the mouse hit position and activates the throwing. Much safer
So i tried to comprehend what the document was saying and i even tried to implement it but i do not think it worked out because of the complexity. Also it is for Advance version of Projectile Engine, i do want a simple Projectile Engine just like the game âSno dayâ if you might have played it!
Understandable . I can give a simple code example once I get home. Would you be able to update the scripts showing what you have so far so I can start from there?
Yeah so this is the script i have made:
it also do contains the script that the document has told
local Time = 1
local HumanRootPart
local Ball = script.Parent:WaitForChild("Handle")
local Tool = script.Parent
local mouse
local Remote = script.Parent.RemoteEvent
Remote.OnServerEvent:Connect(function(player, GetMouse)
HumanRootPart = player.Character:WaitForChild("HumanoidRootPart")
mouse = GetMouse
end)
local function OnActivated()
local Gravity = Vector3.new(0, -game.Workspace.Gravity, 0)
local X0 = HumanRootPart.CFrame * Vector3.new(0, 2, -2)
-- calculate the Velocity needed to reach the Target
local Velocity0 = (mouse.Hit.p - X0 - 0.5*Gravity*Time*Time)/Time
print(Velocity0)
print((0.5*Gravity*Time*Time)/Time)
-- Throwing the Ball
local BallClone = Ball:Clone()
BallClone.Velocity = Velocity0
BallClone.CFrame = CFrame.new(X0)
BallClone.CanCollide = true
BallClone.Parent = game.Workspace
-- I will add the rest of the script later
end
Tool.Activated:Connect(OnActivated)
the local script will just give the player and player:Getmouse() from the remote event
Alrighty, I actually just finished creating the code example just before you sent this . Your code is very close, but the only change youâd need to do is to call OnActivated after mouse = GetMouse and remove the Tool.Activated from the server script. That and mouse.Hit.p needs to be changed to just mouse.
Here is the example setup I made but feel free to modify it to your needs:
-- SnowballServer
local Tool = script.Parent
local ThrowRemote = Tool.Throw
local Handle = Tool.Handle
local ThrowTime = 1
ThrowRemote.OnServerEvent:Connect(function(TargetPlayer: Player, Target: Vector3)
local Character: Model | Instance = Tool.Parent
local Player = game.Players:GetPlayerFromCharacter(Character)
-- Exploiter could make someone else throw balls so we make sure its the correct player
if Player and Player == TargetPlayer and Character:IsA("Model") and Character.PrimaryPart then
local RootPart = Character.PrimaryPart
local GravityVector = Vector3.new(0,-game.Workspace.Gravity,0)
local StartPos = Handle.Position
local Velocity = (Target - StartPos - 0.5 * GravityVector * ThrowTime * ThrowTime) / ThrowTime
local NewBall = Handle:Clone()
NewBall:ClearAllChildren()
NewBall.AssemblyLinearVelocity = Velocity
NewBall.CanTouch = true
NewBall.Touched:Connect(function(Part: BasePart)
if Part:IsDescendantOf(Character) then
return
end
-- Do something, Damage?
NewBall:Destroy()
end)
NewBall.Parent = workspace
NewBall:SetNetworkOwner(Player)
end
end)
-- Localscript
local Player = game.Players.LocalPlayer
local Mouse = Player:GetMouse()
local Tool = script.Parent
local ThrowRemote = Tool.Throw
Tool.Activated:Connect(function()
ThrowRemote:FireServer(Mouse.Hit.Position)
end)
Hope this simple example helps. If you got any more questions, feel free to ask!
I do have a problem, How could i set the range or the speed of the ball, and Sometimes the touches event delays as even if the ball does not touch the Surface it is still going to destroy the ball without ever reaching the surface to touch, Now i think this might happen because there is a delay between the server and the client and when the ball touches the surface it delays in the client, And also because of this problem as the ball is in workspace, This makes the movement unsmooth which makes it jitter, I do read a document where they have said that you need to change the Ball movementâs to only visible to client and if other players also want to see it then we need to use the FireallClient method? But i still do not know what this might cause to do and how to implement it?
Also either can i use Tween service to smooth out the motion?
To achieve a smooth, constant speed object that reaches its target, you can use the BodyPosition class. Although it is deprecated, it can still be used for this purpose.
-- Create a part to act as the throwable object
local throwable = Instance.new("Part")
throwable.Size = Vector3.new(1, 1, 1)
throwable.BrickColor = BrickColor.new("Bright blue")
throwable.Parent = workspace
-- Create a BodyPosition object and parent it to the throwable part
local bodyPosition = Instance.new("BodyPosition")
bodyPosition.MaxForce = Vector3.new(math.huge, math.huge, math.huge)
bodyPosition.Parent = throwable
-- Function to throw the object
local function throwObject(mouse)
-- Calculate the direction from the player's mouse position
local direction = (mouse.Hit.p - throwable.Position).unit
-- Set the target position for the BodyPosition object
bodyPosition.Position = throwable.Position + direction * 50 -- Adjust the distance as needed
-- Enable the BodyPosition object to start moving the throwable part
bodyPosition:Apply()
end
-- Connect the throwObject function to the MouseButton1Click event of the player's mouse
game.Players.LocalPlayer:GetMouse().MouseButton1Click:Connect(throwObject)
We create a part called âthrowableâ and a BodyPosition object called âbodyPositionâ. When the player clicks the left mouse button, the throwObject function is called. It calculates the direction from the playerâs mouse position to the throwable part, sets the target position for the BodyPosition object, and enables it to start moving the throwable part towards the target position.
Note that this implementation is server-sided, so other players will also see the throwable object move smoothly.
I believe this is caused by the networkOwner changing or being something other then the client who threw it. Have you tried to setting it just like in the example code I gave you?
NewBall:SetNetworkOwner(Player)
As for speed, you could calculate the distance from your character to the target and divide it by a âthrow speedâ to calculate how many seconds it should travel. You can then assign this value to Time in your code. Example:
local ThrowSpeed = 30
local Time = (mouse - X0).Magnitude / ThrowSpeed
-- Math below
Same for range, you can just deem that the distance is too far away and not throw the ball. Hope this helps!
It works perfectly but there is one problem, So when i click only on a part, it activates and if i click in the sky or any place where a part does not exists, It will spawn the ball and second is that if i click on any part or player rather than going straight or like a normal object it goes highly up then lands on the part or the object!.
For Clicking in the sky, my best suggestion is to have the range check filter that out since this way of math we calculate the trajectory based on where it should land.
For when the ball goes too high up, I recommend lowering the time. The lower the time, the more âstraightâ it goes!
Hope these help! If you have any more questions, feel free to ask me
local Distance = (mouse - X0).Magnitude
if Distance < 100 then -- 100 means max 100 studs away you can throw. Change it to what you need
-- Do stuff here
end
It is the just the same, I have added your range filter code but the problem is that if the distance is above 100 it does not work. I have also modified for the above situation but it also does not work. I think the main problem here is that the ball needs somewhere to land at, if the pointer is pointing at a place where there is nothing to land upon then it errors. Also why do we need to add extra formulas and other stuff when we can use velocity or Changing the CFrame?
I seem to have misunderstood your original request for the throwing system . If Iâm understanding correctly (now) you wish to have a throwing system where instead of clicking on where you want the ball to land, you wish to have a throwing system where it throws to the general direction of where you are aiming. As you mentioned, this kind of system doesnât require any fancy formulas like the one I gave you before.
Here is the updated code I used to make this:
-- ServerScript
local Tool = script.Parent
local Handle = Tool.Handle
Tool.Throw.OnServerEvent:Connect(function(TargetPlayer: Player, Direction: Vector3)
local Character: Model | Instance = Tool.Parent
local Player = game.Players:GetPlayerFromCharacter(Character)
if Player and Player == TargetPlayer and Character:IsA("Model") and Character.PrimaryPart then
local NewBall = Handle:Clone()
NewBall:ClearAllChildren()
NewBall.AssemblyLinearVelocity = Direction.Unit * 100 -- Change throw speed here
NewBall.CanTouch = true
NewBall.Touched:Connect(function(Part: BasePart)
if Part:IsDescendantOf(Character) then
return
end
-- Do something, Damage?
NewBall:Destroy()
end)
NewBall.Parent = workspace
NewBall:SetNetworkOwner(Player)
end
end)
-- Localscript
local Player = game.Players.LocalPlayer
local Mouse = Player:GetMouse()
local Tool = script.Parent
local ThrowRemote = Tool.Throw
Tool.Activated:Connect(function()
ThrowRemote:FireServer(Mouse.UnitRay.Direction)
end)
Hopefully this is more of what you are looking for
I know, I am annoying you at this point but there is just one small problem here, The Ball goes quite offside when pointed somewhere, Letâs say that i am pointing straight, the ball would go a little right rather than at exact Mouse Look Vector
No problem . Regarding the shifting, it might be due to us setting the start position off the snowball to be the where the hand holds it. You can try adjusting the start position to be for example the head or humanoid root part.
Hopefully that should resolve it Feel free to let me know if you have anything else!