I’ve been struggling with this problem for about a year and it’s where viewmodels are positioned improperly based off of avatar type
Due to the nature of the gun system that it is used for, i will not tolerate solutions that boil down to making a viewmodel a seperate object, or a generic viewmodel.
I’m trying to make a viewmodel that is just positioned properly on all avatar types.
This is what it is supposed to look like
This is what it looks like on other avatars
And when i aim down sights before the aim attachment of the weapon is in a certain position, the weapon isn’t positioned properly and this occurs when i ads while the draw animation is still playing, or if i ads too quickly after ending it
local HideArms = false
local ArmNames = {"Arm", "Hand"}
-- camera spring, use that to adjust the recoil
--local SpringDamp = 1
local PlayersService = game:GetService("Players")
local RunService = game:GetService("RunService")
local function Lerp(a,b,t)
return a*(1-t)+b*t
end
local h=Instance.new("Hint")
local function printh(...:string|number)
h.Text=table.concat({...}," ")
h.Parent=workspace
end
local module = {}
module.__index = module
function module.new()
local Viewmodel = setmetatable({}, module)
Viewmodel.Active = false
return Viewmodel
end
--local DefaultFOV = 70
function module:Create(Gun:Tool, GunRootPart:BasePart, AimAtt:Attachment, ScopeAtt:Attachment, FirstAimOffset:CFrame, ScopeOffset:Vector3, ...)
-- To use the ... in the Create function
--[[local Args = {
{
nil, -- Motor Object
Name", -- String that should match the name of the Motor Object
CFrame -- CFrame to set the Motors C0 to every frame
}
}]]
-- ... = {Motor, Name, CF}, Make ... into a table
self.Active = true
local Args = {...}
local Modules = Gun:WaitForChild("Modules")
local Remotes = Gun:WaitForChild("Remotes")
local Events = Gun:WaitForChild("Events")
local GunRoot:Motor6D
local Spring = require(Modules:WaitForChild("Spring"))
local OnFire = Remotes:WaitForChild("OnRecoilRequest")
local RecoilEvent = Events.Recoil
local OnDraw = Events:WaitForChild("Draw")
local OnAim = Events:WaitForChild("Aim")
local Camera = workspace.CurrentCamera
local Player = PlayersService.LocalPlayer
local Character = Player.Character or Player.CharacterAdded:Wait()
local Humanoid:Humanoid = Character:WaitForChild("Humanoid")
--local CrouchingValue = Character:WaitForChild("Crouching")
local LowerTorso, UpperTorso, Head
local Root, Waist, Neck
local HRP
local Mag
local SecondMag
local Connections:{RBXScriptConnection} = {}
local CameraSpring = Spring.spring.new(Vector3.zero)
CameraSpring.s = 30
CameraSpring.d = 1
local StabilizeSpring = Spring.spring.new(Vector3.zero)
StabilizeSpring.s = 30
StabilizeSpring.d = 1
local Alternation = 0
local AimOffset = CFrame.new(0, 0, 0)
local CameraOffset = Vector3.zero
local AimValue = 0
local LerpedAimOffset = AimOffset
local LerpedAimValue = AimValue
local Aimed = false
if Humanoid.RigType == Enum.HumanoidRigType.R15 then
LowerTorso = Character:WaitForChild("LowerTorso")
UpperTorso = Character:WaitForChild("UpperTorso")
Head = Character:WaitForChild("Head")
HRP = Character:WaitForChild("HumanoidRootPart")
Root = LowerTorso:WaitForChild("Root")
Waist = UpperTorso:WaitForChild("Waist")
Neck = Head:WaitForChild("Neck")
elseif Humanoid.RigType == Enum.HumanoidRigType.R6 then
LowerTorso = Character:WaitForChild("HumanoidRootPart")
HRP = LowerTorso
Root = LowerTorso:WaitForChild("RootJoint")
end
local function FindStringByTable(tbl:{string}, str:string)
for index, pattern in pairs(tbl) do
if string.find(str, pattern) then
return true
end
end
return false
end
local function GetArms()
local Arms = {}
for index, part in pairs(Character:GetChildren()) do
if part:IsA("BasePart") and FindStringByTable(ArmNames, part.Name) then
table.insert(Arms, part)
end
end
return Arms
end
local Arms = GetArms()
local function SetArmsVisible()
for index, arm in pairs(Arms) do
arm.LocalTransparencyModifier = 0
end
end
local function Recoil(strength:number, horizontalstrength:number, Stability:number, StabilizeRate:number)
if Alternation == 0 then
Alternation = 1
else
Alternation = 0
end
StabilizeSpring.s = StabilizeRate or 30
Stability = Stability or 1
horizontalstrength = horizontalstrength or 0
horizontalstrength = Alternation == 1 and horizontalstrength or -horizontalstrength
CameraSpring:Accelerate(Vector3.new(strength*0.02, horizontalstrength*0.02, 0))
--if Stabilizes then
task.delay(0.05, function()
CameraSpring:Accelerate(Vector3.new(-(strength * math.clamp(Stability, 0, 1))*0.02, -(horizontalstrength *math.clamp(Stability, 0, 1))*0.02, 0))
end)
--end
end
local DefaultRootC0 = Root.C0
local DefaultRootC1 = Root.C1
local DefaultWaistC0 = Waist.C0
local DefaultWaistC1 = Waist.C1
local DefaultNeckC0 = Neck.C0
local DefaultNeckC1 = Neck.C1
local HasDoneResetting = true
function self:Reset()
if Humanoid.RigType == Enum.HumanoidRigType.R15 then
Root.C0 = DefaultRootC0
Root.C1 = DefaultRootC1
elseif Humanoid.RigType == Enum.HumanoidRigType.R6 then
Root.C0 = CFrame.Angles(math.rad(90), math.rad(180), 0)
end
end
local function Update(dt)
local CamCF = Camera.CFrame
local CamFocus = Camera.Focus
local CamCFPosition = CamCF.Position
local CamFocusPosition = CamFocus.Position
local FocusDirection = CamFocusPosition - CamCFPosition
local FocusUnit = FocusDirection.Unit
local FocusMagnitude = FocusDirection.Magnitude
local CamRotation = CamCF.Rotation
local CamRX, CamRY, CamRZ = CamRotation:ToOrientation()
local IsInFirstPerson = math.floor(FocusMagnitude) <= 0
Camera.CFrame = CamCF:ToWorldSpace(CFrame.Angles(CameraSpring.p.X, CameraSpring.p.Y, CameraSpring.p.Z))
if IsInFirstPerson then
if not HideArms then
SetArmsVisible()
end
if AimAtt then
local CameraCF = Camera.CFrame
end
-- according to camera modules, r15 head y offset = 1.5
--local HeadOffset = CFrame.new((DefaultRootC1:Inverse()*DefaultWaistC0*DefaultWaistC1:Inverse()*DefaultNeckC0*DefaultNeckC1:Inverse()).Position)
--printh(HeadOffset.X,HeadOffset.Y, HeadOffset.Z)
HasDoneResetting = false
--LerpedAimOffset = LerpedAimOffset:Lerp(AimOffset, AimValue > 1/2 and 0.2 or 0.4)
Root.C1 = DefaultRootC1
LerpedAimOffset = LerpedAimOffset:Lerp(Aimed and Camera.CFrame:ToObjectSpace(AimAtt.WorldCFrame) or CFrame.identity, AimValue > 1/2 and 0.2 or 0.4)
LerpedAimValue = Lerp(LerpedAimValue,AimValue,0.1)
if Humanoid.RigType == Enum.HumanoidRigType.R15 then
-- should have done this to fix it. huzzah
Root.C0 = CFrame.new(0,-1,0)
:ToWorldSpace(CFrame.new(0,2.5,0))
:ToWorldSpace(CFrame.Angles(CamRX, 0, 0))
:ToWorldSpace(CFrame.new(0,2.5,0):Inverse())
Root.C1 = DefaultRootC1
:ToWorldSpace(CFrame.new(LerpedAimOffset.p))
for _, Object in pairs(Args) do
if Object[1] ~= nil then
Object[1].C0 = Object[3](CamRX, LerpedAimOffset)
end
end
Humanoid.CameraOffset = LerpedAimValue >= 0.9 and CameraOffset or Vector3.zero
elseif Humanoid.RigType == Enum.HumanoidRigType.R6 then
Root.C0 = CFrame.Angles(math.rad(90), math.rad(180), 0)
:ToWorldSpace(CFrame.new(0, 0, 1.5))
:ToWorldSpace(CFrame.Angles(CamRX, 0, 0):Inverse())
:ToWorldSpace(CFrame.new(0, 0, 1.5):Inverse())
end
else
if not HasDoneResetting then
self:Reset()
end
HasDoneResetting = true
end
if not self.Active then
RunService:UnbindFromRenderStep("UpdateViewmodel_"..Gun.Name)
self:Reset()
for Index, Connection in pairs(Connections) do
Connection:Disconnect()
end
end
end
local function GetGunAttachment(child:Instance)
if child:IsA("Motor6D") then
for i, v in pairs(Args) do
task.spawn(function()
if child.Name == Args[i][2] then
Args[i][1] = child
repeat
child.AncestryChanged:Wait()
until child.Parent ~= HRP
end
if Args[i][1] == child then
Args[i][1] = nil
end
end)
end
end
end
if AimAtt ~= nil then
local function ADSPositionCamNew(Aiming)
local RootToCameraOffset = Vector3.new(0, 2.5, 0)
local AimPositionCF = AimAtt.WorldCFrame
Aimed = Aiming
--AimOffset = Aimed and --[[(FirstAimOffset ~= nil and FirstAimOffset or]] Camera.CFrame:ToObjectSpace(AimPositionCF) or CFrame.new(0,0,0)
--AimOffset = Aiming and --[[(FirstAimOffset ~= nil and FirstAimOffset or]] CameraCF:ToObjectSpace(AimPositionCF) or CFrame.new(0,0,0)
if not FirstAimOffset and Aiming then
warn("It is recommended to copy this and paste to variable FirstAimOffset: CFrame.new("..tostring(AimOffset)..")")
end
if ScopeAtt ~= nil then
AimValue = Aiming and 1 or 0
CameraOffset = Aiming and (ScopeOffset ~= nil and ScopeOffset) or Vector3.zero
if not ScopeOffset and Aiming then
task.delay(1, function()
--warn("It is recommended to copy this and paste to variable ScopeOffset: Vector3.new("..tostring(CameraCF:ToObjectSpace(ScopeAtt.WorldCFrame).Position)..")")
end)
end
end
end
table.insert(Connections, OnAim.Event:Connect(ADSPositionCamNew))
end
--local function ADSPositionCam(Aiming)
-- local CameraCF = Camera.CFrame
-- local AimPositionCF = AimAtt.WorldCFrame
-- AimOffset = Aiming and --[[(FirstAimOffset ~= nil and FirstAimOffset or]] CameraCF:ToObjectSpace(AimPositionCF) or CFrame.new(0,0,0)
-- if not FirstAimOffset and Aiming then
-- warn("It is recommended to copy this and paste to variable FirstAimOffset: CFrame.new("..tostring(AimOffset)..")")
-- end
-- if ScopeAtt ~= nil then
-- AimValue = Aiming and 1 or 0
-- CameraOffset = Aiming and (ScopeOffset ~= nil and ScopeOffset) or Vector3.zero
-- if not ScopeOffset and Aiming then
-- task.delay(1, function()
-- warn("It is recommended to copy this and paste to variable ScopeOffset: Vector3.new("..tostring(CameraCF:ToObjectSpace(ScopeAtt.WorldCFrame).Position)..")")
-- end)
-- end
-- end
--end
--table.insert(Connections, OnAim.Event:Connect(ADSPositionCam))
RunService:BindToRenderStep("UpdateViewmodel_"..Gun.Name, Enum.RenderPriority.Character.Value, Update)
table.insert(Connections, OnFire.OnClientEvent:Connect(Recoil))
table.insert(Connections, RecoilEvent.Event:Connect(Recoil))
table.insert(Connections, HRP.ChildAdded:Connect(GetGunAttachment))
end
function module:Destroy()
self.Active = false
self:Reset()
end
return module
This code moves rotates the lowertorso of the player, making what resembles a viewmodel.
the function was based on this. the camera should set itself on point A when you ads but the problem is that the distance between A and C is not equal to that of other characters