Yeah, though that might be a little hacky and at that point it’d be more worth attempting to move the actual rig instead of resorting to any cloning. I don’t have any experience with this so I can try working away at a repro.
Hexcede’s post is worth referring to for attempting something of this nature.
I don’t really understand about this, can you further explain a bit more with examples if possible?
What’s the difference between RenderStepped and Stepped?
RenderStepped is run when the game is rendered, while Stepped is run before physics (thanks @ScriptingSupport for just teaching me that just now haha). Stepped is used by animations and it’s the only time the Transform property of Motor6Ds can be used.
This is what I meant (there’s purposely room for improvement but I think I explained what I am doing well enough in the comments):
RunService.RenderStepped:Connect(function()
for _, part in ipairs(character:GetDescendants()) do -- Definitely don't use GetDescendants in here if you have a lot of instances (e.g. 40 or more) in the player's character since it'll cause a lot of lag
if part:IsA("BasePart") then -- Not all of these will be parts so we need to check
part.LocalTransparencyModifier = 0 -- Read the documentation for more information on this property. It basically is used to hide the character's parts when they zoom in without actually using .Transparency. Setting it to 0 makes the part's "actual" transparency equal to its Transparency property which is 0, so the part is fully visible.
end
end
end)
RunService.Stepped:Connect(function()
local camera = workspace.CurrentCamera
local cameraCFrame = camera.CFrame
for _, motor in ipairs(baseArmMotors) do
local cameraOffset = motor.Part0 * camera.CFrame:Inverse() -- An offset to move/rotate the viewmodel by. We calculate it by converting the camera's position to the actual position of the root part. That means the parts will display in their "real" location but we can easily adjust their location by applying a CFrame to this value.
local offset = motor.C0 * motor.C1:Inverse() -- This is the formula used by joints to get an offset from Part0 to display Part1. We will make the camera act as if it were the Part0 of the weld by applying the offset to the camera's CFrame instead of the Part0's CFrame.
local newLocation = camera.CFrame * cameraOffset * offset -- We apply the offset to the desired cframe which is the camera CFrame offset by another cframe. This cameraOffset CFrame can be used to move the model forward/backward, left/right.
local oldLocation = motor.Part0.CFrame * offset -- This is the offset produced by the Motor, not including movements from animations
motor.Transform = motor.Transform*oldLocation:Inverse()*newLocation -- We subtract the old location from the transform to "0" the viewed position of the arms. Now they're centered on the origin with the offsets from their animations still applied. That means we can add the new location which reapplies the weld offsets with the camera CFrame and now the arms are centered around the camera, offset to their proper positions away from the camera, and they include the playing animation's offsets.
end
end)
The ViewModel wouldn’t be a seperate model, it would be using the character’s arms. You’d be using the shoulder joints located in Torso (or arms/legs for R15) of the character. Essentially you’re moving their arms on the client to be centered around the camera using the Transform property used by animations. This is more desirable since the Transform property doesn’t need to be handled in your scripts, you can just apply offsets to it on Stepped. That means less cleanup and your C0 and C1 properties on the joints are free for use by any of your scripts.
For R6 characters the should joints have a space in the name (e.g. “Right Shoulder”). For R15 the joints are properly named imo so they don’t have a space in the name (e.g. “RightShoulder”). The main reason this hasn’t been changed yet is because of backwards compatibility. Old games (and new games) use the joints and are expecting a space in the name for R6 characters.
Yep! Those are the joints which attach the character’s arms to their Torso/UpperTorso so those are the joints you want to offset. You should read the comments in my code so you can try and understand it.
The role of cameraOffset is important in the location of your ViewModel. Whatever it’s set to is the offset from the camera that their arms appear (you may want to move them back/forward). In my script you’ll see I set it to motor.Part0.CFrame and subtract the camera’s CFrame. If you think about CFrames like a single number instead of a position you’ll be able to understand it much better. (That’s actually often how I figure out my CFrame logic)
If this overall viewmodel offset from it’s real root part is the offset from the root location to get a cameraOffset which achieves the original position you want to subtract your root CFrame so that the part is “0 plus the animation offsets” and then you’d add the motor.Part0 location to get the original CFrame.
If you want the arms to be centered directly around the camera instead, you’d want to change the cameraOffset value to a different offset from the camera instead of the one I come up with there.
For example: If you used CFrame.new(0, 0, 2) would move the arms 2 studs backwards on their camera.
I highly considered and attempt this idea (Which is the one from @Hexcede), it’s a fact that it doesn’t require any hacky way, including creating new rigs.
I low-key achieved what I want it to be, I sightly modified the rig that you gave me and I found it differs and offset from the real character rig, that’s probably the reason why it offsets a little bit.
After that I modified the CFrame and now it seems to be working fine! What I need to do now is replicate the weapon to the ViewModel. It might be a little bit frustrating because I do not use the legacy Right Grip by the default Roblox Tool. The tool is connected to the Torso by Motor6D. I’m considering on connect to a real part that’s similar to the ViewModel’s Torso, maybe HumanoidRootPart or I’ll create a new part.
If you want the gun to attach to a seperate viewmodel on the client you can simply change the Part1 (might be Part0) of the RightGrip weld to attach to the viewmodel in a LocalScript. That should not unequip the gun from the player so you should have the gun attached to the fake arms.
As long as the tool remains parented to the character you should be fine.
I modified the legacy Roblox tools, I do not use the RightGrip weld, instead, I used a Motor6D that connect the Torso and a part named “BodyAttach” inside the weapon. It acts like a handle in terms of Roblox legacy tool.
FYI check out this:
My current problem is how do I clone the tool to the ViewModel with all the CFrame positioining correct and animations being played.
Right now during the RenderStep, I’ll check is there a tool inside the player, if yes, I’ll clone it to the ViewModel. @ScriptingSupport You might want to check out this problem since you are more familiar to this ViewModel.
I also added a new Motor named “ToolGrip”, which is exactly the one that the real character uses to connect the tool and the torso. I directly copied it from the real character so they should be the same, this is the ViewModel right now.
This is the Rig, which is same as the character’s one.
if Character:FindFirstChildOfClass("Tool")~= nil and ViewModel.ReplicatedWeapon.Value == false then
ViewModel.ReplicatedWeapon.Value = true
local a = Character:FindFirstChildOfClass("Tool"):Clone() -- Clone the entire tool
for i,v in pairs (a:GetChildren()) do -- Put the tool inside a model
v.Parent = ViewModel.VMWeapon
end
ViewModelRoot.ToolGrip.Part1 = ViewModel.VMWeapon:WaitForChild("BodyAttach")
end
It did clone it and put it inside the ViewModel, however, it’s position is completely wrong.
I tried to use the transform property on ViewModel’s ToolGrip Motor to the real character.Torso.ToolGrip motor, however nothing changes. The gun animations such as pulling out the magazine is not even showing, how do I resolve this?
This is probably the final step of this entire ViewModel, thanks for helping
I mean attach the weapon to the viewmodel arms instead of anywhere on the character. If you do that client side the player should see the tool properly.
I can’t get the view model to stop pushing the character. To have this compatible with R15 would I have to write a script that glues the arms to the humanoidrootpart?