Basically i am trying to make a script that allows the player to hold an item as in games like Amnesia,
However i have one problem. The part does not stay infront of the player, it’s really wonky:
local plr = game.Players.LocalPlayer
local mouse = plr:GetMouse()
local grabbing = false
local grabitem = nil
local dist = 4
local function calculatePos(angle)
local distZ = dist * angle
local distY = math.sqrt(dist^2 - distZ^2)
--print(distZ)
--print(distY)
return plr.Character.PrimaryPart.CFrame:ToWorldSpace(CFrame.new(0, -distY, -distZ))
end
mouse.Button1Down:Connect(function()
local brick = mouse.target
if brick:FindFirstChild("ID") then
grabbing = true
grabitem = brick
grabitem.Anchored = true
grabitem.CanCollide = false
end
end)
mouse.Button1Up:Connect(function()
if grabbing == true then
grabbing = false
grabitem.Anchored = false
grabitem.CanCollide = true
end
end)
while wait() do
if grabbing == true then
for i = 0, 1, 0.05 do
wait()
local opp = (plr.Character.PrimaryPart.Position.Y - mouse.hit.p.Y)
--print(opp)
local adj = (mouse.hit.p - Vector3.new(plr.Character.PrimaryPart.Position.X, mouse.hit.p.Y, plr.Character.PrimaryPart.Position.Z)).magnitude
local hyp = math.sqrt(opp^2 + adj^2)
local angle = math.acos(adj / hyp)
local newCframe = grabitem.CFrame:Lerp(calculatePos(angle), i)
grabitem.CFrame = newCframe
grabitem.CFrame = CFrame.new(grabitem.Position, plr.Character.PrimaryPart.Position)
end
end
end
If I were to create a system like this, I would probably use body movers instead of CFrame so the objects don’t clip through the floor.
We can simply set a BodyPosition’s position to the camera’s lookVector CFrame multiplied by a “radius” CFrame, or distance away from the characters camera. We can do this on InputChanged, which fires when the mouse is moved, so no unnecessary loop.
Then, you can use a BodyGyro to face the object at the players camera. You will need to update the BodyGyro’s CFrame relative to the camera’s CFrame on InputChanged as well. You can then change the gyro’s CFrame rotation if the player wants to rotate it midair with key combos like SHIFT+W/A/S/D.
If you don’t want object collisions, you can just set the objects to CanCollide false. BodyPosition and Gyro also have built in “lerping”!
What you currently have going on is nice, but with all these calculations it’s hard to understand what’s wrong.
What I propose is another approach to this:
local player = game.Players.LocalPlayer
local mouse = player:GetMouse()
local camera = workspace.CurrentCamera
local function pos(dist)
return camera.CFrame.Position + (mouse.UnitRay.Direction * dist)
end
And since this is gonna be a first person thing, thus the camera’s cframe is inside the head all is good.
The only problem is the rotation part which is not being counted for, which I guess is simple and can easily be fixed by rotating the part to the camera’s position, and since the camera in first person is inside of the head, the object would be looking at the character
@starmaq@KeysOfFate i have done both your suggestions, the body position & gyro is a good idea i don’t know why i didnt think of it. However when i try use your code starmaq it kinda bugs out again: https://gyazo.com/16a68d2558ad70a60a99702fe189f674
new code:
local plr = game.Players.LocalPlayer
local char = plr.Character
local grabbing = false
local grabbeditem = nil
local dist = 4
local userinputservice = game:GetService('UserInputService')
local mouse = plr:GetMouse()
local camera = workspace.CurrentCamera
mouse.Button1Down:Connect(function()
if mouse.Target and mouse.Target.Locked then
print("Block")
grabbing = true
grabbeditem = mouse.Target
local bp = Instance.new("BodyPosition", grabbeditem)
bp.D = 150
end
end)
mouse.Button1Up:Connect(function()
grabbing = false
if grabbeditem and grabbeditem:FindFirstChild("BodyPosition") then
grabbeditem.BodyPosition:Destroy()
end
end)
userinputservice.InputBegan:Connect(function(input, gameProcessedEvent)
if input.UserInputType == Enum.UserInputType.MouseMovement then
if grabbing == true then
grabbeditem.BodyPosition.Position = camera.CFrame * (mouse.UnitRay.Direction * dist)
end
end
end)
I mean you can technically do what @KeysOfFate proposed in the first place, utilising the fact that this is in first person, and position the part in the direction of the Camera/Mouse (in this case they’re same thing) and make it go further out a bit.
userinputservice.InputChanged:Connect(function(input, gameProcessedEvent)
if not gameProcessedEvent then
if input.UserInputType == Enum.UserInputType.MouseMovement then
if grabbing == true then
grabbeditem.BodyPosition.Position = (CFrame.new(camera.CFrame.Position,camera.CFrame.LookVector)* CFrame.new(dist,0,0)).Position
end
end
end
end)
local plr = game.Players.LocalPlayer
local char = plr.Character
local grabbing = false
local grabbeditem = nil
local dist = 4
local userinputservice = game:GetService('UserInputService')
local mouse = plr:GetMouse()
local camera = workspace.CurrentCamera
mouse.Button1Down:Connect(function()
if mouse.Target and mouse.Target.Locked then
print("Block")
grabbing = true
grabbeditem = mouse.Target
local bp = Instance.new("BodyPosition", grabbeditem)
end
end)
mouse.Button1Up:Connect(function()
grabbing = false
if grabbeditem and grabbeditem:FindFirstChild("BodyPosition") then
grabbeditem.BodyPosition:Destroy()
end
end)
userinputservice.InputChanged:Connect(function(input, gameProcessedEvent)
if not gameProcessedEvent then
if input.UserInputType == Enum.UserInputType.MouseMovement then
if grabbing == true then
grabbeditem.BodyPosition.Position = (CFrame.new(camera.CFrame.Position,camera.CFrame.LookVector)* CFrame.new(dist,0,0)).Position
end
end
end
end)
userinputservice.InputChanged:Connect(function(input, gameProcessedEvent)
if not gameProcessedEvent then
if input.UserInputType == Enum.UserInputType.MouseMovement then
if grabbing == true then
grabbeditem.BodyPosition.Position = ((camera.CFrame * CFrame.new(0,0,-dist)) ).Position
end
end
end
end)