Hockey puck interaction and movement feedback

hockeypuck.rbxl (57.2 KB)

I wrote this code last night for a hockey-themed sports game I’m working on. However… it’s a little stutter-y. I’m not completely sure if it’s my code or the Roblox physics engine causing the stutter. Even if it’s not my fault (which I’m inclined to believe it is), I still would love to optimize the scripts all around.

ServerScriptService/PuckHandler
local Puck = workspace.Puck
local DefaultOrientation = Puck.CFrame
Puck.BodyGyro.CFrame = DefaultOrientation

--//SERVICE VARIABLES
local Players = game:GetService("Players")
----
local connection
local lastHit
local Debounce = false

Puck:SetNetworkOwner(nil)

local function followPlayer()
	 connection = Puck.HitDetection.Touched:Connect(function(hit)
		local Character = hit:FindFirstAncestorOfClass("Model")
		local Player = Players:GetPlayerFromCharacter(Character)
		if Player then
			if Debounce == true and Player.Name == lastHit then
				print(Player.Name.." cannot come in control of the puck again yet.")
			else
				connection:Disconnect()
			
				Puck:SetAttribute("Controller",Character.Name) 
				Puck.CanCollide = false
				Puck:PivotTo((Character.HumanoidRootPart.CFrame * CFrame.new(0,-2.75,-2)) * CFrame.Angles(0, math.rad(90), math.rad(-90)))
			
				local WeldConstraint = Instance.new("WeldConstraint")
				WeldConstraint.Name = "PuckWeld"
				WeldConstraint.Part0 = Character.HumanoidRootPart
				WeldConstraint.Part1 = Puck
				WeldConstraint.Parent = Character.HumanoidRootPart
				
				Puck.BodyGyro:Destroy()
			
				game:GetService("ReplicatedStorage").Remotes.PuckUpdate:FireClient(Player)
			end
		end
	end)
end

local function breakWeld()
	local Player = Players:FindFirstChild(lastHit)
	local Character = Player.Character
	local HumanoidRootPart = Character:FindFirstChild("HumanoidRootPart")
	local WeldConstraint = HumanoidRootPart:FindFirstChild("PuckWeld")
	
	WeldConstraint:Destroy()
	Puck.CanCollide = true
	
	local bg = Instance.new("BodyGyro")
	bg.Name = "BodyGyro"
	bg.D = 500
	bg.MaxTorque = Vector3.new(400000,400000,400000) 
	bg.P = 3000
	bg.CFrame = DefaultOrientation
	bg.Parent = Puck
	
	----
	followPlayer() --resets the script
	----
end

game.ReplicatedStorage.Remotes.PuckUpdate.OnServerEvent:Connect(function(plr,angle) --Puck has been shot!
	lastHit = plr.Name
	Debounce = true
	----
	----
	local bv = Instance.new("BodyVelocity")
	bv.MaxForce = Vector3.new(math.huge, 1000, math.huge) 
	bv.P = math.huge
	bv.Parent = Puck
	bv.Velocity = angle --propels the puck
	
	breakWeld()
	
	wait()
	bv:Destroy()
	
	wait(0.5)
	Debounce = false
end)

followPlayer()
StarterPlayerScripts/LocalScript
local Puck = workspace.Puck

--//SERVICE VARIABLES
local ContextActionService = game:GetService("ContextActionService")
local ReplicatedStorage = game:GetService("ReplicatedStorage")

local Power = 0
local ChargingUp = false

local function Shoot(actionName, inputState, inputObject)
	if inputState == Enum.UserInputState.Begin then
		ChargingUp = true
		repeat
			wait()
			Power += 5
		until Power == 100 or ChargingUp == false
	else
		ChargingUp = false
		game:GetService("ReplicatedStorage").Remotes.PuckUpdate:FireServer(workspace.CurrentCamera.CFrame.LookVector*Power)
		print(workspace.CurrentCamera.CFrame.LookVector*Power)
		Power = 0
		ContextActionService:UnbindAction("Shoot")
	end
end

local function bindShoot()
	ContextActionService:BindAction("Shoot",Shoot,true, Enum.UserInputType.MouseButton1, Enum.KeyCode.ButtonR2)
	ContextActionService:SetTitle("Shoot","Shoot")
	ContextActionService:SetPosition("Shoot", UDim2.new(1, -160, 0, 40))
end

ReplicatedStorage.Remotes.PuckUpdate.OnClientEvent:Connect(function()
	bindShoot()
end)

Any feedback would be greatly appreciated!

2 Likes

why did you get ReplicatedStorage like this if ReplicatedStorage is already a variable

EDIT:
I looked at the local script

1 Like

I some suggestions for you after reading your code.

Server Script:

There is never going to be a time when you will need to use wait() without a number in it. If the delay between the breakWeld function and destroying the BodyVelocity is unnecessary, omit wait() completely. If the delay is needed, use game:GetService("RunService").Heartbeat:Wait(), which is more than two times faster than wait(), and it will make your code significantly more efficient.


Set game:GetService("ReplicatedStorage") or game.ReplicatedStorage as one of your service variables in your server script to reduce redundancy and to improve organization.


SetNetworkOwner is nil by default, so this line is not needed.


Client:

Again, an unnecessary use of wait(). game:GetService("RunService").Heartbeat:Wait() will make this code much more efficient, even though it may seem long (you can set ``game:GetService(“RunService”)` as one of your service variables at the top.

1 Like

you could also use task.wait() since both of these function very similarly

2 Likes

I’ll apply the feedback from your comments and @Friendly4Crafter’s comments. Thank you!

Despite the feedback I’ve received so far, the same stuttering seems to still occur at an equal rate to before…

Wait breakable welds were added now!?

I saw at RDC they announced it but I didn’t think the update would be live (Unless your using the beta version of Studio, which knowing Roblox its probably not in there either lol)