Hello developers!
I’m developing a system that allow users to shoot a (golf)ball.I currently create a module script with a function in it to shoot a ball. The problem is that the ball will be shot in a nice curve (like in the real world) but then it won’t come to a real stop. I need to change the velocity, but that is not smooth enough. Also the time the ball will stop needs to be randomly picked between 0.5 - 1.5 seconds (after the ball stops bouncing).
The question: how can I improve the following script to match the criteria I mentioned above?
The script:
function swingModule.Shoot(ball, plr, character, strength, strengthMultiplier)
-- Calculate the used strength
local usedStrength = (swingModule.DefaultStrength + strength) * strengthMultiplier
-- Get the start and to positions for the ball
local startPosition = ball.Position
local toPosition, ok = GetPositionFromCharacterToPoint(character, usedStrength)
if not ok then
return false
end
-- Calculate the force to shoot the ball with
local direction = toPosition - startPosition
local duration = math.log(1.001 + direction.Magnitude * 0.01)
local force = direction / duration + Vector3.new(0, game.Workspace.Gravity * duration * 0.5, 0)
-- Get the player's plot part where to count the distance from
local plot = PlotManager.returnPlot(workspace.Plots, plr)
local shootToPart = plot.ScriptParts.ShootToPart
-- Shoot the ball
SendBallStartPositionEvent:FireClient(plr, shootToPart.Position)
PlaySoundEvent:FireClient(plr, "Hit")
ball:ApplyImpulse(force * ball.AssemblyMass)
ball:SetNetworkOwner(nil)
-- Stop the ball
task.wait(duration)
ball.Velocity = Vector3.new(0, ball.Velocity.Y, 0)
-- Calculate the distance the ball went
local distance = (ball.Position - shootToPart.Position).Magnitude
local roundedDistance = math.round(distance)
-- Check if it is the player's personal best score
local personalBestStore = Datastore2("PersonalBest", plr)
local newPersonalBest = false
if personalBestStore:Get(0) < roundedDistance then
newPersonalBest = true
personalBestStore:Set(roundedDistance)
end
-- Calculate the rewards
local cashReward = math.round(roundedDistance * swingModule.CashPerStud)
local gemReward = math.round(roundedDistance * swingModule.GemPerStud)
AddRewardEvent:Fire(plr, cashReward, gemReward, roundedDistance, newPersonalBest)
-- Unanchor the HumanoidRootPart of the player, so it can move again
local humRP = character:FindFirstChild("HumanoidRootPart")
if humRP then
humRP.Anchored = false
end
-- Destroy the ball
ball:Destroy()
end
The GetPositionFromCharacterToPoint()
function:
local function GetPositionFromCharacterToPoint(character, spawnDistance)
local humanoidRootPart = character:FindFirstChild("HumanoidRootPart")
if not humanoidRootPart then
return Vector3.new(0, 0, 0), false
end
local forwardVector = humanoidRootPart.CFrame.LookVector
local spawnPosition = humanoidRootPart.Position + (forwardVector * spawnDistance)
local raycastResult = workspace:Raycast(spawnPosition, Vector3.new(0, -spawnDistance, 0))
if raycastResult then
spawnPosition = raycastResult.Position
end
return spawnPosition, true
end
Thanks in advance!