Unwelding item from VR hand causes it to fling

Hello

I’ve been trying to create a custom VR system for a combat game for the past week or so and I’ve ran into an issue with my pick up & drop system.

Basically, whenever a player equips an item (an item in this case is a model with an unanchored handle to which every other part in the model in welded to), the item’s network owner is set to the player and after that, on the client, the item is pivoted and welded to the corresponding hand. Whenever the player unequips the item, the client destroys the WeldConstraint keeping the item attached to the hand, but the network owner is kept as the player to hopefully eliminate any jitter.

Now, the problem. Whenever the player unequips the item, it seemingly just flings downwards. When I set the handle’s Assembly angular and linear velocity to Vector3.zero, then the item doesn’t exactly fling, but it just kind of snaps to the floor without bouncing back up.

Also, I’ve tried welding the item to the hand on both the client and the server, but both appear to have the same result.

Here is the equip and unequip code on the client (Removed some sanity checks)

local function Equip(item: Model, handName: string)
	if not serverItemEvent:InvokeServer("Equip", item:GetAttribute("ID"), handName) then
		return -- The server returns false whenever sanity checks fail there
	end
	
	if handName == "LeftHand" then
		equippedItemL = item
	else
		equippedItemR = item
	end
	
	local hand: PVInstance = (handName == "LeftHand") and leftHand or rightHand
	item:PivotTo(hand:GetPivot())
	
	local itemWeld = Instance.new("WeldConstraint")
	itemWeld.Name = "ItemWeld"
	itemWeld.Part0 = hand
	itemWeld.Part1 = item.PrimaryPart
	itemWeld.Parent = hand
	
	itemScripts[item.Name].Equipped(hand, item)
end

local function Unequip(handName: string)
	local item: Model = handName == "LeftHand" and equippedItemL or equippedItemR	
	local hand: BasePart = handName == "LeftHand" and leftHand or rightHand

	hand.ItemWeld:Destroy()
	
	item.PrimaryPart.AssemblyLinearVelocity = Vector3.zero
	item.PrimaryPart.AssemblyAngularVelocity = Vector3.zero

	itemScripts[item.Name].Unequipped(hand)
	serverItemEvent:InvokeServer("Unequip", item:GetAttribute("ID"), handName)
	
	if handName == "LeftHand" then
		equippedItemL = nil
	else
		equippedItemR = nil
	end
end

And this is the server side equip and unequip (Also removed the sanity checks)

local function Equip(player: Player, item: Model, handName: string)
	local hand = player.Character:FindFirstChild(handName)
	
	item:SetAttribute("Owner", player.Name)
	item.PrimaryPart:SetNetworkOwner(player)
	CollectionService:RemoveTag(item, "Item")
	
	return true
end

local function Unequip(player: Player, item: Model, handName: string)
	local hand = player.Character:FindFirstChild(handName)
	
	item:SetAttribute("Owner", nil)
	CollectionService:AddTag(item, "Item")
	
	return true
end

For those that are interested in how the hands work:

-- This script is inside StarterCharacterScripts
local VRService = game:GetService("VRService")
local RunService = game:GetService("RunService")
local Players = game:GetService("Players")

local player = Players.LocalPlayer
local character = player.Character
local camera = workspace:WaitForChild("Camera")

local leftHand: BasePart = character:WaitForChild("LeftHand")
local rightHand: BasePart = character:WaitForChild("RightHand")

RunService.RenderStepped:Connect(function(delta: number)
	leftHand.LocalTransparencyModifier = 0
	rightHand.LocalTransparencyModifier = 0
	
	camera.CFrame = CFrame.new(character.HumanoidRootPart.Position + Vector3.new(0, 5, 0))
	
	local leftHandTrack = VRService:GetUserCFrame(Enum.UserCFrame.LeftHand)
	local rightHandTrack = VRService:GetUserCFrame(Enum.UserCFrame.RightHand)
	
	leftHand:PivotTo(camera.CFrame * leftHandTrack)
	rightHand:PivotTo(camera.CFrame * rightHandTrack)
end)

Now, I do understand that I should add a video of the problem in action, however I’m not entirely sure on how to do that yet. Once I do figure out how to do so, I’ll try to add a video too.

I’ve been debugging this for quite some time now, but to no result.
I hope I mentioned everything important above, however it is completely possible that I forgot something. So please, if any part of the information feels incomplete or even missing to you, ask me.

1 Like

Actually, after more digging, I’ve found that the position, specifically the height, of the hands are constantly fluctuating, even though it isn’t visible to the player, as it is always updated in RenderStepped.

Alright, I think I figured it out. The hands were unanchored so that their network owner could be set as the player, but that also meant that after RenderStepped, the hands had physics applied to them and they fell downwards. Since I was never resetting the velocity before unequiping, the hands built up momentum and caused a flinging like speed, which launched the item welded to the hand.

1 Like