In regards to your suggestion, isn’t RenderStepped client side only? The script inside the puck is server side. Also isn’t SetNetworkOwner server side only? If this is true I would have to set a remote event that fires every second.
I never said anything about RenderStepped in my post.
That’s what I originally thought. I figured it was Stepped you were talking about, but I couldn’t get my code to work so I took my friends word for it. My apologies.
Here is the code I can’t seem to get to work properly. It works for the first few seconds and then it doesn’t work again for another 20 seconds or so, and it repeats this. I’ll show you with this video…
function FindNearestPlayer()
local nearestPlayer = nil
local dist = math.huge
for i,v in pairs(game.Players:GetPlayers()) do
if v.Character then
local hockeystick = v.Character:FindFirstChild("GeneralGoalieStick")
if hockeystick ~= nil then
hockeystick.BladeTape.Color = Color3.fromRGB(198,157,99)
local magnitude = (hockeystick.BladeTape.Position - script.Parent.Position).Magnitude
if magnitude < 50 and script.Parent.Anchored == false then
if magnitude < dist then
dist = magnitude
nearestPlayer = v.Name
script.Parent:SetNetworkOwner(v)
hockeystick.BladeTape.Color = Color3.fromRGB(0,255,0)
end
end
end
local hockeystick2 = v.Character:FindFirstChild("Hockey Stick")
if hockeystick2 ~= nil then
hockeystick2.blade.Color = Color3.fromRGB(198,157,99)
hockeystick2.blade1.Color = Color3.fromRGB(198,157,99)
local magnitude = (hockeystick2.blade.Position - script.Parent.Position).Magnitude
if magnitude < 50 and script.Parent.Anchored == false then
if magnitude < dist then
dist = magnitude
nearestPlayer = v.Name
script.Parent:SetNetworkOwner(v)
hockeystick2.blade.Color = Color3.fromRGB(0,255,0)
hockeystick2.blade1.Color = Color3.fromRGB(0,255,0)
print 'Given ownership'
end
end
end
end
end
end
game:GetService('RunService').Stepped:Connect(function()
FindNearestPlayer()
end)
This is my first time ever using Stepped in a script, so sorry if I didn’t do this right.
No, that should be correct, but it seems like the problem got even worse. I don’t know whether it’s because FindNearestPlayer is expensive, or because Stepped is frame dependent whereas while waits for the code to finish before the next iteration begins or if this is just something impossible to cure. I haven’t quite worked with physics-dependent games.
There is one point I don’t see addressed, which is honestly my last bastion for hoping to contribute anything and that’s to apply a negligible amount of Velocity to the puck so it’s always, in some regard, actively moving but not enough to be “seen” per se.
That’s my final suggestion. If this doesn’t work, I haven’t a clue. Sorry.
Thank you for your advice. I definitely will experiment with velocity. It has always been a battle to make “physics-dependent” games on Roblox since 2010. I have seen significant improvement throughout the years. I hope there is more physics updates to come next year so I can strive to take this game to the next level. I appreciate the recommendations you gave me though. If I discover something significant that helps with collision issues, I will let everybody know.
I found out this might not be from the puck falling asleep. Why? Well because I tested with “Allow Sleep” disabled. After testing, I can now confirm the issue still occurs. I started experimenting with my gameplay I used in 2019 and everything was working so much better than my new gameplay for 2020. After hours of testing I think I finally figured out what could actually be causing all of this in the first place. It’s the new rig I created. For some reason when you make this rig as a “StarterCharacter” the collisions significantly decrease in performance.
Also I revisited @colbert2677’s idea of RunService.Stepped and found out I set the collisions groups incorrectly in the server I was testing on.
Unfortunately, it made no difference despite running correctly. Here is the current script in the puck now days…
function FindNearestPlayer()
local nearestPlayer = nil
local dist = math.huge
for i,v in pairs(game.Players:GetPlayers()) do
if v.Character then
local hockeystick = v.Character:FindFirstChild("Hockey Stick 2")
if hockeystick ~= nil then
--hockeystick.blade.Color = Color3.fromRGB(198,157,99)
--hockeystick.blade1.Color = Color3.fromRGB(198,157,99)
local magnitude = (hockeystick.Hitbox.Position - script.Parent.Position).Magnitude
if magnitude < 6 and script.Parent.Anchored == false then
if magnitude < dist then
dist = magnitude
nearestPlayer = v.Name
script.Parent:SetNetworkOwner(v)
--hockeystick.blade.Color = Color3.fromRGB(0,255,0)
--hockeystick.blade1.Color = Color3.fromRGB(0,255,0)
end
end
end
local hockeystick = v.Character:FindFirstChild("2020 Hockey Stick")
if hockeystick ~= nil then
local magnitude = (hockeystick.Blade.Position - script.Parent.Position).Magnitude
if magnitude < 6 and script.Parent.Anchored == false then
if magnitude < dist then
dist = magnitude
nearestPlayer = v.Name
script.Parent:SetNetworkOwner(v)
end
end
end
local hockeystick = v.Character:FindFirstChild("Hockey Stick")
if hockeystick ~= nil then
local magnitude = (hockeystick.Blade.Position - script.Parent.Position).Magnitude
if magnitude < 6 and script.Parent.Anchored == false then
if magnitude < dist then
dist = magnitude
nearestPlayer = v.Name
script.Parent:SetNetworkOwner(v)
end
end
end
end
end
end
game:GetService('RunService').Stepped:Connect(function()
FindNearestPlayer()
end)
The script has ownership for each stick that I have tested with over the last couple of days. All sticks had the same result depending on what rig I was using. All testing was done with the “Allow Sleep” disabled. It doesn’t matter what option you choose, allowing sleep still had the exact same result.
I set the Default R15 rig with the Robloxian 2.0 Package and set it as a StarterCharacter (copy and pasted the model of my user.) This seemed to be the most successful result. Proven by the video below…
It also important to note the behavior from the physics displayed in the video above is the same when I didn’t set the Default R15 rig as a StarterCharacter. I was just testing to make sure StarterCharacter wasn’t the problem (which it wasn’t.)
This is what it looks like with my new rig I made set as a StarterCharacter.
As you can see, there is a major difference. The puck even went through the glass at the end there. It just seems like the performance is different when it uses this rig for whatever reason.
An idea I got for testing is trying out some random free model R15 rigs and see if the issue occurs with those rigs as well. I am curious to see the results from that.
Another idea I have is possibly changing body parts of the original character to the ones from the rig I made. The issue with this though is the Motor6D’s didn’t end up at the proper spots and they look improper on the character. You can see the script I used for that here…
local remoteevent = script.Parent:WaitForChild("RemoteEvent")
local ss = game.ServerStorage
local rig = ss:WaitForChild("Bob")
remoteevent.OnServerEvent:connect(function(player)
local char = player.Character
local humanoid = char:FindFirstChild("Humanoid")
humanoid:SetStateEnabled(Enum.HumanoidStateType.Dead, false)
if char then
if not humanoid then return end
for _, v in ipairs(rig:GetChildren()) do
if v:IsA("BasePart") and v.Name ~= "Part" and v.Name ~= "HumanoidRootPart" and v.Name ~= "Visor" then --hrp
humanoid:ReplaceBodyPartR15(Enum.BodyPartR15[v.Name], v:Clone()) --:Clone()
end
end
end
char.Humanoid:BuildRigFromAttachments()
char.Humanoid.HipHeight = 2.5
humanoid:SetStateEnabled(Enum.HumanoidStateType.Dead, true)
end)
I have no idea where to go next other than keep experimenting with other rigs. I could just use the Robloxian 2.0 and call it a day, but I’m determined to use the character that looks more like a hockey player. It would be a disappointment if a physics issue with the rig I created was the reason I couldn’t use it for my game. If anyone has any idea how to fix the collisions with this rig, fix the Motor6D locations of my body morphing, and/or have other ideas on how to fix anything mentioned above let me know.
Cheers!
I have been following your topic here, since you first posted, as I find it an interesting issue / problem, and have two comments:
1)
Looking at your latest video, the one that is 25 seconds long, I am starting to think that your issue could be due to “too small collision-boxes”, or perhaps of “too large displacement of collision-boxes between the physics-calculated frames.”
Maybe the video does not have enough ‘high frame rate’ to show it correctly, but to me, when looking from timestamp 10s through to 14s, it could look like the hockey stick’s blade’s collision-box just isn’t touching/hitting the puck’s collision-box, when doing a fast rotation. - It basically “phase through” the puck.
Have you compared your older vs. newer hockey stick’s blade’s collision-boxes sizes?
Relying on game-engine physics calculations using fast moving collision-boxes that are slim/tiny, will always be a problem, due to the time between frames.
From ‘Collision detection’ article on Wikipedia:
[…] On the other hand, a posteriori algorithms cause problems in the “fixing” step, where intersections (which aren’t physically correct) need to be corrected. Moreover, if the discrete step is too large, the collision could go undetected, resulting in an object which passes through another if it is sufficiently fast or small. […]
Perhaps you need to look into “helping” the physics calculations, in the situations where puck is close to the hockey stick and when player-character performs fast movements and/or rotations, then explicitly script a “push the puck”-event?
2)
Seeing your first post’s function of FindNearestPlayer
, and then now the newer implementation, they, to me, do not look optimal, as they will, in worst case, change network-ownership multiple times to the next-then-next-then…-nearest player within just the one for
-loop.
So I took some time to experiment with refactoring the code, and produced the following.
This ensures, that there won’t be any excess calls to SetNetworkOwner
, also when the nearest player has not changed since last Stepped
execution. - I also reduced the “duplicated code”, and added a SetHockeyStickColor
function (see further below).
(Disclaimer: I have not actually run this code, due to not having any props/objects in Workspace
)
local HockeySticks = {
["Hockey Stick 2"] = { defaultColor = Color3.fromRGB(198,157,99), nearestColor = Color3.fromRGB(0,255,0) },
["2020 Hockey Stick"] = { defaultColor = Color3.fromRGB(198,157,99), nearestColor = Color3.fromRGB(0,255,0) },
["Hockey Stick"] = { defaultColor = Color3.fromRGB(198,157,99), nearestColor = Color3.fromRGB(0,255,0) },
}
local function FindNearestHockeyStick(puckPosition)
-- Structure containing several properties, that will be returned from this function
local nearest = {
distance = 6, -- Distance must be less than this, to be even considered
player = nil,
hockeyStickObj = nil,
}
local hockeyStickObj, magnitude
for _,player in ipairs(game.Players:GetPlayers()) do
if player.Character then
for hockeyStickName,_ in pairs(HockeySticks) do
hockeyStickObj = player.Character:FindFirstChild(hockeyStickName)
if hockeyStickObj then
break
end
end
if hockeyStickObj then
if nil ~= hockeyStickObj.Hitbox then
magnitude = (hockeyStickObj.Hitbox.Position - puckPosition).Magnitude
else
magnitude = (hockeyStickObj.Blade.Position - puckPosition).Magnitude
end
if magnitude < nearest.distance then
nearest.distance = magnitude
nearest.player = player
nearest.hockeyStickObj = hockeyStickObj
end
end
end
end
return nearest
end
-- Structure containing the current player (if any) and hockeystick, that is closest to the puck
local currentNearest = {
player = nil,
hockeyStickObj = nil,
}
local function SetPuckOwnershipToNearest(puck)
local nearest = FindNearestHockeyStick(puck.Position)
-- Has nearest player changed, since last check?
if nearest.player ~= currentNearest.player then
-- Reset blade color of the previous nearest hockeystick
SetHockeyStickColor(currentNearest.hockeyStickObj, "defaultColor")
-- Update structure to the new nearest player
currentNearest = nearest
-- Update network owner. Will automatically set to server (i.e. `nil`), if there is no nearest player
puck:SetNetworkOwner(currentNearest.player)
-- Set blade color of this new nearest hockeystick
SetHockeyStickColor(currentNearest.hockeyStickObj, "nearestColor")
end
end
--
local puck = script.Parent
game:GetService("RunService").Stepped:Connect(function()
if puck.Anchored == false then
SetPuckOwnershipToNearest(puck)
end
end)
This is the function used, to update a hockey stick object’s color:
local function SetHockeyStickColor(hockeyStickObj, colorFieldName)
if not hockeyStickObj then
return
end
local hockeyStickColors = HockeySticks[hockeyStickObj.Name]
if not hockeyStickColors then
error(("Hockeystick with name '%s' was not defined in `HockeySticks` table"):format(hockeyStickObj.Name))
end
local newColor = hockeyStickColors[colorFieldName]
if not newColor then
error(("Field `%s` was not defined for element '%s' in `HockeySticks` table"):format(colorFieldName, hockeyStickObj.Name))
end
if nil ~= hockeyStickObj.blade then
hockeyStickObj.blade.Color = newColor
end
if nil ~= hockeyStickObj.blade1 then
hockeyStickObj.blade1.Color = newColor
end
end
1.) How can you explain the first video though? It was working really well. I think you are on the right track though. It does seem like sometimes the physics engine can’t calculate fast enough to respond to the speed the player hits the puck. How come this happens more frequent with certain rigs than others though? I have tested with all sorts of shapes and sizes. I tried big blades, small blades, big pucks, small pucks. I also tried wedges, regular parts, cylinders. I tried different rigs as well. it doesn’t seem to make a difference.
I created a place for everyone to try out my old hockey stuff. It’s for anybody to get a feel of how the physics respond to the player whacking at the puck with a tool. Feel free to take anything in that place for yourself and create your own tests and experiments. I got all sorts of unique pucks and hockey sticks in it. It also includes all the ownership scripts we have tested with up to this point. Also it has the rig that I have been explaining that works even worse than the Default R15 Robloxian 2.0 rig.
A ““ push the puck ”-event” script is something I will consider. I am worried it might make it too difficult to get the appropriate power on the shots needed because of the specific force that will always be applied to the puck. The puck won’t be able to accelerate appropriately.
2.) I tried out the script you made and the puck was stuttering when in motion. I had a similar thing like that happen when I set the magnitude of the puck to a higher number. The higher the magnitude, the more the puck started to stutter when in motion.
1)
I took a quick look at what you have shared, though could not play it via Roblox Studio due to animations failed to load. So equipped hockey sticks never reached the ice floor.
Playing the place online, I found best results with the largest ‘2011 Puck’, though there were still issues when doing fast rotations/movements of hockey stick attempting to push the puck.
I see that the physical sizes of the younger puck objects, have become smaller, to the point of 0.6 x 0.28 x 0.6, which is a very tiny object, considering physics calculations.
Perhaps make it 1 x 0.5 x 1 (or larger), and then instead scale the mesh part down, so it visually looks smaller than what it is. - Yes this will make it look like the hockey stick blade does not directly touches the puck, but it should help the physics calculations a bit more, to detect when puck and blade (their larger) collision-boxes intersect.
2)
Regarding the stuttering of the puck, that is probably caused by switching network-ownership very often. - When ownership changes, some synchronization of “who knows what properties-and-values” needs to occur, which, depending on network-latency and such, will take some fractions of a second to complete.
I do not know what other ‘magnitude’ you are referring to, if it is not the .Magnitude
distance calculation in the OwnershipScript
script.
3)
I also noticed that CollisionGroupId
for the pucks and hockey sticks were set to not be zero, though the pucks has value ‘3’, where as the hockey sticks have ‘5’.
I don’t see you mentioning having experimented with collision-groups, so I am a bit confused as of why the CollisionGroupId
properties are set as they are.
Though it gave me an idea; what if there were two pucks in the game. One visible normal sized puck, and another invisible much larger puck.
The visible puck should be set to only collide with the ice/walls/goals, never with players or hockey sticks, and must “follow closely” the invisible larger puck. Some fancy scripting or perhaps a short rope-constraint will be needed to make that happen.
For the invisible and larger puck, this is the actual one that can collide with anything. - Having a larger collision-box (even when it is invisible) helps the physics-engine to better determine when objects collide.
A relatively simple solution would be to trick the game into not letting the puck sleep. You could do this by setting velocity to be non zero on Heartbeat I believe:
local RunService = game:GetService("RunService")
RunService.Heartbeat:Connect(function()
puck.Velocity = Vector3.new(math.max(math.abs(puck.Velocity.X), 0.01) * math.sign(puck.Velocity.X), math.max(math.abs(puck.Velocity.Y), 0.01) * math.sign(puck.Velocity.Y), math.max(math.abs(puck.Velocity.Z), 0.01) * math.sign(puck.Velocity.Z))
end)
This should stop physics from sleeping for the puck since it should always be simulating physics. Since it’s an important object to not have sleeping this kind of makes sense to do and it shouldn’t impact performance at all although it might be considered a little hacky.
Seemed like a good idea. I tried it out, and there was three noticeable issues.
- The pucks velocity was delayed. I am worried it might be too noticeable for the players.
-
Also if you watch the video you can see the puck doesn’t always respond to the collisions.
-
Finally, when I checked with the “Awake Parts” visualization it was showing that the puck was still falling asleep.
1.) My bad! I didn’t even think of that. At least you were still able to try it out online. I agree that the “2011 Puck” probably had the best reaction to the collisions. It still wasn’t 100% perfect though.
As the years went by I tried to reduce the size of the puck to make it seem more realistic. Now it might be too small though. I might make the puck slightly bigger.
I am also considering to do the mesh illusion method you mentioned where you “scale the mesh part down”. I’ll get some players to try it out and see if they would be comfortable with the puck not being directly on the blade.
2.) I figured it was along the lines of network ownership. Would there be a way to edit the script so that it could decrease the amount of stuttering?
For the magnitude I was talking about the calculation between the distance of the stick blade and the puck…
`local magnitude = (hockeystick.blade.Position - script.Parent.Position).Magnitude`
if magnitude < 5 and script.Parent.Anchored == false then
When you change the magnitude distance from “<5” to say something like “<20” the puck stuttered often because more players were within range of the puck, so the script would be changing who gets ownership of the puck more often. When the distance was less than 5 only the players really close to the puck could win over the ownership. It would stutter when the players fight for the puck, but it was less noticeable because the players and their sticks were blocking the view of the puck. It looked more natural.
The downside to this is that the passing took a hit because the ownership can’t transfer quick enough to the receiving player who needs the physics to get the puck to collide properly with his stick. Five magnitude distance usually isn’t enough time for the ownership to transfer; that is unless you make a slow enough pass to the other player. It also depends on internet connection and computer ability of course.
3.) The collisions groups are something that was critically needed for the 2019 gameplay.
0- Default: Everything else.
1- TheIce: To identify the ice, the lines on the ice, the circles, logos, etc.
2- DontTouchTheIce: For everything I don’t want to collide with the ice.
3- ThePuck: To identify all the pucks in the game.
4- DontTouchThePuck: For everything I don’t want to collide with the puck.
5- TheSticks: To identify all tools used by the characters.
All the collision groups mix and match for the most comfortable experience for the user. It helps prevent players from getting stuck, from players accidentally kicking the puck and making it fling into oblivion, and tools getting stuck.
Every player that joins the game has their HumanoidRootPart’s set to CollisionGroupId
3. It uses the following code…
local puckGroup = "ThePuck"
local hrp = player.Character:WaitForChild("HumanoidRootPart")
for _,v in pairs(game:GetService("PhysicsService"):GetCollisionGroups()) do
if v.name == "DontTouchThePuck" then
PhysicsService:SetPartCollisionGroup(hrp, v.name)
end
end
The purpose for this is to prevent players from flinging the puck into space when they touched it with their character. Worked like a charm.
Finally, to your last recommendation. I love this idea. I am definitely going to give this a try. I think first approach would be to try a weld. I’ll let you know how it goes.
Not sure if sleep is really your issue, but here’s what I did to address it.
I’m rotating a cannon connected to a motorised hinge constraint with left and right “buttons” (just parts) on the gun. I’m using the UserInputService in a localscript to work out when the user is holding the left mouse button (and when they release) and sending this via a bindableEvent to a server side buttonControl script which moves/stops the hinge by setting the AngularVelocity (i.e. to 1, 0 or -1).
This works fine for the most part unless I release and click again around 0.5 second later. In that case I can see that the angular speed of the hinge is getting set but the hinge doesn’t move. Walking up to the cannon while still holding the mouse button wakes the gun up and it starts moving. So it’s a sleep issue. I can verify this by highlighting awake parts in settings.
My fairly dodgy workaround for this was to make a new part called Waker and weld it to the gun. Make it transparent and turn off collisions. Add a bindable event and a script. In the script add a loop that toggles the Waker’s Massless attribute every 0.4 seconds on a loop (20 loops seems long enough for my purposes). Then just trigger the Waker’s bindable event when I click the left/right buttons on the cannon. Other attributes like Anchored have same effect, i.e. they wake the physics for that object and any attached to it. Massless seemed the most innocuous for a small object.
Since the buttons are used by the player for fine left and right aiming they are generally clicked reasonably rapidly, hence I encounter the sleep issue if the next click is within about 0.5 seconds of the last. Using this method I keep the cannon awake for a longer period than is normal and it successfully responds to all my rapid clicks i.e. setting the AngularVelocity actually has an effect every time. I really hate this workaround but either the sleep settings are just too aggressive or I’m doing something in a dumb way. Until there’s a fix, this is what I’ll do.
In your case, you could try using this method to keep the puck awake all the time instead of just for a short period like I am. Might not be your issue but worth a try. You might want to set the Waker’s Density way down so it doesn’t affect the puck too much when it’s not Massless.
Wow! I didn’t think it was possible to keep a part awake using “Massless”. It definitely worked when it came to keeping the part awake forever. If anyone is having a sleeping issue with their game I definitely recommend trying this method out! Unfortunately, after testing it on the puck I can confirm that it did not solve the situation. This again confirms that it isn’t a sleeping issue with the puck. Thanks for showing me this method though.
I too am currently experiencing this issue, mine is slightly different however.
When the player swings the hockey stick the puck doesn’t move and the players stick cant go through the puck as well. (I saw that the stick was going through the puck for you). I’m not really sure why this is happening as it only happens to a select few of people for only about a minute, then throughout the rest of the game play it seems to not happen again.
Update on the situation…
As mentioned before this is no longer an awake parts issue. Don’t get me wrong, the new Roblox update will help tremendously…
Especially for users with slower computers and devices. This is a different bug that is causing the puck to go through the hockey stick right now though.
I did not find the source causing the bug. I did find a solution though…
Believe it or not, the solution to the problem is adding a “Legacy Body Mover” or “Body Mover” into the player. For some reason (don’t ask me how) it makes the puck rarely ever go through the hockey stick. If you use the “Body Movers” make sure you have your “Constraint” attached to the “Attachment” appropriately. See…
The “Body Movers” can be any part of the body and/or any piece of equipment welded to the player. It also can be inside a “Model”, “Part”, or pretty much anything attached to the character. It also can be any type of “Legacy Body Mover” or “Body Mover” type.
In my example, I put the “BodyForce” into the “HockeyPants” “Model” of the player. With this new Roblox update it almost never goes through at all anymore. The moment I remove the “BodyForce” the problems come back again.
Here is the evidence…
It would be nice to find the cause of the bug, so we can come up with better solutions for it in the future. For now, this will get the job done!
Glad you found a solution (if a strange one). Thanks for posting the link to the new physics changes. I hadn’t seen it. Will try my canon again without my waker script and see what happens. I feel like it should work now.
Hey, I’m experiencing a similar problem. Your problem seems to be that you go through the puck, my problem is that the puck doesn’t move at all and the player cant go through it, they just get stuck running into it. After running into the puck for some time the player can move the puck, not sure why that is. I tried putting a BodyForce in the player but it didn’t stop it from happening. Have you ran into this at all?
Yes, we have had that issue happen so many times prior to me adding an ownership script into the puck. We almost had to shutdown the game because of it. Our community calls this “entry.”
It’s a problem that normally occurs when a player joins the game recently and attempts to make contact with the puck. It started happening roughly 4-5 years ago. We think what is happening is that the server is slow to react to giving the players ownership when the player is new to the server. It also seems to impact players with lower end internet connectivity and/or lower end devices.
To test for this, you can activate “Are Owners Shown” in the Studio Settings. Fool around with it until you are able to have the bug happen. You will notice every once in a while the pucks outline color will not match your characters outline color. Not sure if this still happens because I tested with this two years ago. Give it a try though, and see if you can get it to happen.
The only way to get rid of it without using ownership is to let the player handle the puck for about 10-15 seconds. Be warned, it can come back at anytime though.
If you are fine with using ownership you can add a server script into the puck and use “RunService.Stepped” to detect the magnitude of the players, and give the player who is closest to the puck ownership.
Performance wise this fixes it, but visually you are going to have slight puck teleportation and pauses because the ownership is constantly changing between the players. If the players know how to spread out and properly play their position this isn’t much of an issue. If you got some random players who bunch up and wack at the puck than this could be an issue.
Worst case scenario I could be all wrong about this, and your issue could be something completely different. I talked to many other people who own Roblox sports games, and lots of them have told me they had this issue (especially the hockey ones.)
That sounds about right. I had it earlier in the game but removed it due to a little teleportation/ less control but I’ll re-add it because the pros outweight the cons.
What I did though instead of finding nearest player is when they touch the puck they got ownership.
Edit: Trying out giving ownership to closest player.