Hello! I am wondering how can I make it so pets will always touch the ground, like in Pet Simulator X, no matter where you go, the pets will always be touching the ground. How can I achieve this? This is the Pet Position script I am currently using, and I am wondering how to make the pet always touch the ground because currently its depending on your avatar size, which could make the pets collide with the floor if their avatar it too tall, or too small.
local runService = game:GetService("RunService")
local playerPets = workspace:WaitForChild("Player_Pets")
local circle = math.pi * 2
local function getPosition(angle, radius)
local x = math.cos(angle) * radius
local z = math.sin(angle) * radius
return x, z
end
local function positionPets(character, folder)
for i, pet in pairs(folder:GetChildren()) do
-- local radius = 2+#folder:GetChildren()
local radius = 5
local angle = i + (circle / #folder:GetChildren())
local x, z = getPosition(angle, radius)
local _, characterSize = character:GetBoundingBox()
local _, petSize = pet:GetBoundingBox()
local offsetY = - characterSize.Y/2 + petSize.Y/4
local sin = (math.sin(15 * time() + 1.6)/.5)+1
local cos = math.cos(7 * time() + 1)/4
if character.Humanoid.MoveDirection.Magnitude > 0 then
if pet:FindFirstChild("Walks") then
pet:SetPrimaryPartCFrame(pet.PrimaryPart.CFrame:Lerp(character.PrimaryPart.CFrame * CFrame.new(x, offsetY+sin, z) * CFrame.fromEulerAnglesXYZ(0,0,cos),0.1))
else
pet:SetPrimaryPartCFrame(pet.PrimaryPart.CFrame:Lerp(character.PrimaryPart.CFrame * CFrame.new(x, offsetY/2+math.sin(time()*3)+1, z),0.1))
end
else
if pet:FindFirstChild("Walks") then
pet:SetPrimaryPartCFrame(pet.PrimaryPart.CFrame:Lerp(character.PrimaryPart.CFrame * CFrame.new(x, offsetY, z) ,0.1))
else
pet:SetPrimaryPartCFrame(pet.PrimaryPart.CFrame:Lerp(character.PrimaryPart.CFrame * CFrame.new(x, offsetY/2+math.sin(time()*3)+1, z) ,0.1))
end
end
end
end
runService.RenderStepped:Connect(function()
for _, PlrFolder in pairs(playerPets:GetChildren()) do
local Player = game.Players:FindFirstChild(PlrFolder.Name) or nil
if Player ~= nil then
local character = Player.Character or nil
if character ~= nil then
positionPets(character, PlrFolder)
end
end
end
end)
I would appreciate it if you could, but would I put a Script inside all the pets? Like how exactly would I do this? Where would I put the script to find the floor beneath the pet model and for it go above the floor beneath it.
You will need to adjust it a bit, because the position is based on the center of the object, and half of it will be going through the ground.
local runService = game:GetService("RunService")
local playerPets = workspace:WaitForChild("Player_Pets")
local circle = math.pi * 2
local function getPosition(angle, radius)
local x = math.cos(angle) * radius
local z = math.sin(angle) * radius
return x, z
end
local function positionPets(character, folder)
for i, pet in pairs(folder:GetChildren()) do
-- local radius = 2+#folder:GetChildren()
local radius = 5
local angle = i + (circle / #folder:GetChildren())
local x, z = getPosition(angle, radius)
local _, characterSize = character:GetBoundingBox()
local _, petSize = pet:GetBoundingBox()
local offsetY = - characterSize.Y/2 + petSize.Y/4
local sin = (math.sin(15 * time() + 1.6)/.5)+1
local cos = math.cos(7 * time() + 1)/4
if character.Humanoid.MoveDirection.Magnitude > 0 then
if pet:FindFirstChild("Walks") then
pet:SetPrimaryPartCFrame(pet.PrimaryPart.CFrame:Lerp(character.PrimaryPart.CFrame * CFrame.new(x, offsetY+sin, z) * CFrame.fromEulerAnglesXYZ(0,0,cos),0.1))
else
pet:SetPrimaryPartCFrame(pet.PrimaryPart.CFrame:Lerp(character.PrimaryPart.CFrame * CFrame.new(x, offsetY/2+math.sin(time()*3)+1, z),0.1))
end
else
if pet:FindFirstChild("Walks") then
pet:SetPrimaryPartCFrame(pet.PrimaryPart.CFrame:Lerp(character.PrimaryPart.CFrame * CFrame.new(x, offsetY, z) ,0.1))
else
pet:SetPrimaryPartCFrame(pet.PrimaryPart.CFrame:Lerp(character.PrimaryPart.CFrame * CFrame.new(x, offsetY/2+math.sin(time()*3)+1, z) ,0.1))
end
end
pet.PrimaryPart.Position = workspace:Raycast(pet.PrimaryPart.Position, Vector3.new(0,-100,0)).Position
end
end
runService.RenderStepped:Connect(function()
for _, PlrFolder in pairs(playerPets:GetChildren()) do
local Player = game.Players:FindFirstChild(PlrFolder.Name) or nil
if Player ~= nil then
local character = Player.Character or nil
if character ~= nil then
positionPets(character, PlrFolder)
end
end
end
end)
To adjust this, you will need to subtract from the Vector3 returned by .Position. Let me know if you need help with that as well.
This is because he never did the Instance part of the Raycast.
local runService = game:GetService("RunService")
local playerPets = workspace:WaitForChild("Player_Pets")
local circle = math.pi * 2
local function getPosition(angle, radius)
local x = math.cos(angle) * radius
local z = math.sin(angle) * radius
return x, z
end
local function positionPets(character, folder)
for i, pet in pairs(folder:GetChildren()) do
-- local radius = 2+#folder:GetChildren()
local radius = 5
local angle = i + (circle / #folder:GetChildren())
local x, z = getPosition(angle, radius)
local _, characterSize = character:GetBoundingBox()
local _, petSize = pet:GetBoundingBox()
local offsetY = - characterSize.Y/2 + petSize.Y/4
local sin = (math.sin(15 * time() + 1.6)/.5)+1
local cos = math.cos(7 * time() + 1)/4
if character.Humanoid.MoveDirection.Magnitude > 0 then
if pet:FindFirstChild("Walks") then
pet:SetPrimaryPartCFrame(pet.PrimaryPart.CFrame:Lerp(character.PrimaryPart.CFrame * CFrame.new(x, offsetY+sin, z) * CFrame.fromEulerAnglesXYZ(0,0,cos),0.1))
else
pet:SetPrimaryPartCFrame(pet.PrimaryPart.CFrame:Lerp(character.PrimaryPart.CFrame * CFrame.new(x, offsetY/2+math.sin(time()*3)+1, z),0.1))
end
else
if pet:FindFirstChild("Walks") then
pet:SetPrimaryPartCFrame(pet.PrimaryPart.CFrame:Lerp(character.PrimaryPart.CFrame * CFrame.new(x, offsetY, z) ,0.1))
else
pet:SetPrimaryPartCFrame(pet.PrimaryPart.CFrame:Lerp(character.PrimaryPart.CFrame * CFrame.new(x, offsetY/2+math.sin(time()*3)+1, z) ,0.1))
end
end
local ground = workspace:Raycast(pet.PrimaryPart.Position, Vector3.new(0,-100,0)
if ground and ground.Instance then
local newC = pet.PrimaryPart.CFrame
newC.Position.Y = ground.Instance.Position.Y + (ground.Instance.Size.Y/2) + (pet.PrimaryPart.Size.Y/2)
pet:SetPrimaryPartCFrame(newC)
end
end
end
runService.RenderStepped:Connect(function()
for _, PlrFolder in pairs(playerPets:GetChildren()) do
local Player = game.Players:FindFirstChild(PlrFolder.Name) or nil
if Player ~= nil then
local character = Player.Character or nil
if character ~= nil then
positionPets(character, PlrFolder)
end
end
end
end)
(I believe that is the problem, it might not be, so if it’s wrong sorry)
I got the position of the RaycastResult. Your code is close, but it gets the position of the instance it touches, which would be the position of the ground, not the exact point where it intersects.
It is mostly likely due to the constant change between in the air and on the ground. I don’t think CFrame looping is ethical, and rather the use of BodyGyros.
ground.Instance returns the part that the Raycast intersects with. For example, this could be the entire baseplate. Then, using .Position, you are getting the position of that part, NOT the actual point of intersection by the Raycast. Therefore, the position would be inaccurate.
The best and only way to get the exact position of where the Raycast ends is using RaycastResult.Position.
I see, thank you for explaining. Although this will minimize the overlap, the issue now is that the position is going “crazy” because it is looping from the air to the ground simultaneously.
It seems that I cannot change the y position like that so, here:
local runService = game:GetService("RunService")
local playerPets = workspace:WaitForChild("Player_Pets")
local circle = math.pi * 2
local function getPosition(angle, radius)
local x = math.cos(angle) * radius
local z = math.sin(angle) * radius
return x, z
end
local function positionPets(character, folder)
for i, pet in pairs(folder:GetChildren()) do
-- local radius = 2+#folder:GetChildren()
local radius = 5
local angle = i + (circle / #folder:GetChildren())
local x, z = getPosition(angle, radius)
local _, characterSize = character:GetBoundingBox()
local _, petSize = pet:GetBoundingBox()
local offsetY = - characterSize.Y/2 + petSize.Y/4
local sin = (math.sin(15 * time() + 1.6)/.5)+1
local cos = math.cos(7 * time() + 1)/4
if character.Humanoid.MoveDirection.Magnitude > 0 then
if pet:FindFirstChild("Walks") then
pet:SetPrimaryPartCFrame(pet.PrimaryPart.CFrame:Lerp(character.PrimaryPart.CFrame * CFrame.new(x, offsetY+sin, z) * CFrame.fromEulerAnglesXYZ(0,0,cos),0.1))
else
pet:SetPrimaryPartCFrame(pet.PrimaryPart.CFrame:Lerp(character.PrimaryPart.CFrame * CFrame.new(x, offsetY/2+math.sin(time()*3)+1, z),0.1))
end
else
if pet:FindFirstChild("Walks") then
pet:SetPrimaryPartCFrame(pet.PrimaryPart.CFrame:Lerp(character.PrimaryPart.CFrame * CFrame.new(x, offsetY, z) ,0.1))
else
pet:SetPrimaryPartCFrame(pet.PrimaryPart.CFrame:Lerp(character.PrimaryPart.CFrame * CFrame.new(x, offsetY/2+math.sin(time()*3)+1, z) ,0.1))
end
end
local ground = workspace:Raycast(pet.PrimaryPart.Position, Vector3.new(0,-100,0)
if ground and ground.Instance then
local petC= pet.PrimaryPart.CFrame
pet:SetPrimaryPartCFrame(CFrame.new(Vector3.new(petC.Position.X, ground.Instance.Position.Y + (ground.Instance.Size.Y/2) + (pet.PrimaryPart.Size.Y/2), petC.Position.Z)))
end
end
end
runService.RenderStepped:Connect(function()
for _, PlrFolder in pairs(playerPets:GetChildren()) do
local Player = game.Players:FindFirstChild(PlrFolder.Name) or nil
if Player ~= nil then
local character = Player.Character or nil
if character ~= nil then
positionPets(character, PlrFolder)
end
end
end
end)