I am working in one pet system. Everything works fine but the position for each pet is giving some problems. Lest say max pets I can have is 3.
And it works
the script is something like this:
local LERP_ALPHA = 0.05;
local pet = script.Parent
local character = script.Parent.Parent
local function Update()
local petCframe = pet.PrimaryPart.CFrame
local characterCframe = character.PrimaryPart.CFrame
local targetCframe = characterCframe:ToWorldSpace(CFrame.new(5,-2.95,0)) --this is difrent for each pet..
local newCframe = petCframe:Lerp(targetCframe, LERP_ALPHA)
pet:SetPrimaryPartCFrame(newCframe)
end
game:GetService("RunService").Heartbeat:Connect(Update)
Now if lest say I have 2 rabbit and I equip 2 rabbit and other random pet.
this is what happen.(the same pet stays in the same position)
I am trying to make something like this…
I already tried to look into other posts to see how I could fix this but I dont find any solution
You could have a table/module with different positions and get a random one from it. However make sure u implement a system where u can’t use the same pos another pet is using.
Aligning each pet can be simplified using CFrame math. Since each pet will in theory be evenly spaced from each other angle-wise, we can use that to our advantage and find the angle between each pet first.
It looks like we can achieve that intended behavior by pretending there is one extra pet on the end of the 180-degree semi-circle. For example, with three pets:
This will let us calculate the angle per pet as 180 degrees divided by the number of pets + 1, with the +1 being the extra pet.
local allPets = -- an array of pets
local anglePerPet = 180 / (#allPets + 1)
We can create a new CFrame for a pet by finding where in the ordering the pet is in and using the index to multiply by anglePerPet. Note that the index must be stable, although this can be done through :GetChildren().
local petIndex = -- which index the pet has if it was in an array with all the pets
local function Update()
-- get pet and character Cframes...
local targetCframe = characterCframe
-- turn the CFrame to the beginning of the semi-circle
* CFrame.Angles(0, math.rad(-90), 0)
-- turn the CFrame by anglePerPet
* CFrame.Angles(0, math.rad(petIndex * anglePerPet), 0)
-- move it back X studs
* CFrame.new(0, 0, DISTANCE_FROM_CHARACTER)
-- lerp the target Cframe and :SetPrimaryCFrame
This would probably be how I would’ve implemented it.
-- set up pet and character
local allEquippedPets = -- an array of all the player's equipped pets
local anglePerPet = 180 / (#allEquippedPets + 1) -- in degrees
local petIndex = table.find(allEquippedPets, pet)
assert(petIndex, "The player doesn't have this pet equipped!")
local DISTANCE_FROM_CHARACTER = 5
local petCframeOffset = CFrame.Angles(0, math.rad(-90), 0) -- turn the CFrame to the beginning of the semi-circle
* CFrame.Angles(0, math.rad(petIndex * anglePerPet), 0) -- turn the CFrame by anglePerPet
* CFrame(0, 0, DISTANCE_FROM_CHARACTER) -- move it back X studs
-- maybe connect an event here that updates the variables above?
-- e.g., .ChildAdded/.ChildRemoved event
local LERP_ALPHA = 0.05
local function Update()
local petCframe = pet.PrimaryPart.CFrame
local characterCframe = character.PrimaryPart.CFrame
local targetCframe = characterCframe * petCframeOffset
local newCFrame = petCframe:Lerp(targetCframe, LERP_ALPHA)
pet:SetPrimaryPartCFrame(newCframe)
end
game:GetService("RunService").Heartbeat:Connect(Update)
Edit: It could also be simpler to have one script doing all the Cframing so you can use a for loop iterating through allEquippedPets instead of using a petIndex.
local allEquippedPets = script.Parent.Parent:GetChildren()
local pet = script.Parent
local anglePerPet = 180 / (#allEquippedPets + 1) -- in degrees
local petIndex = table.find(allEquippedPets, pet)
warn(petIndex, "The player doesn't have this pet equipped!")
local DISTANCE_FROM_CHARACTER = 5
local petCframeOffset = CFrame.Angles(0, math.rad(-90), 0) -- turn the CFrame to the beginning of the semi-circle
* CFrame.Angles(0, math.rad(petIndex * anglePerPet), 0) -- turn the CFrame by anglePerPet
* CFrame(0, 0, DISTANCE_FROM_CHARACTER) -- move it back X studs
local LERP_ALPHA = 0.05
local character = script.Parent.Parent
local function Update()
local petCframe = pet.PrimaryPart.CFrame
local characterCframe = character.PrimaryPart.CFrame
local targetCframe = characterCframe * petCframeOffset
local newCFrame = petCframe:Lerp(targetCframe, LERP_ALPHA)
pet:SetPrimaryPartCFrame(newCFrame)
end
game:GetService("RunService").Heartbeat:Connect(Update)
I dont really know how I can apply this in 1 script. I have tried everything but this is being soo hard. I got the folder I can clone the pets into the folder but Idk how I could make they move (in circle) and change position if they get any new pet in that folder.
On line 13, it’a supposed to be CFrame.new(...), not CFrame(...).
local allEquippedPets = script.Parent.Parent:GetChildren()
local pet = script.Parent
local anglePerPet = 180 / (#allEquippedPets + 1) -- in degrees
local petIndex = table.find(allEquippedPets, pet)
warn(petIndex, "The player doesn't have this pet equipped!")
local DISTANCE_FROM_CHARACTER = 5
local petCframeOffset = CFrame.Angles(0, math.rad(-90), 0) -- turn the CFrame to the beginning of the semi-circle
* CFrame.Angles(0, math.rad(petIndex * anglePerPet), 0) -- turn the CFrame by anglePerPet
* CFrame.new(0, 0, DISTANCE_FROM_CHARACTER) -- move it back X studs
local LERP_ALPHA = 0.05
local character = script.Parent.Parent
local function Update()
local petCframe = pet.PrimaryPart.CFrame
local characterCframe = character.PrimaryPart.CFrame
local targetCframe = characterCframe * petCframeOffset
local newCFrame = petCframe:Lerp(targetCframe, LERP_ALPHA)
pet:SetPrimaryPartCFrame(newCFrame)
end
game:GetService("RunService").Heartbeat:Connect(Update)
I’m really sorry about answering late, I’ve been very busy!
You wouldn’t have to do it all in one script, it still works in separate scripts.
To update the positions, you can try connecting a .ChildAdded and .ChildRemoved event to the folder and redefine all the variables above LERP_ALPHA except for DISTANCE_FROM_CHARACTER.
e.g.,
-- after petCframeOffset is defined,
local function updatePetCframeOffset()
allEquippedPets = script.Parent.Parent:GetChildren()
anglePerPet = 180 / (#allEquippedPets + 1)
petIndex = table.find(allEquippedPets, pet)
warn(petIndex, "The player doesn't have this pet equipped!")
petCframeOffset = CFrame.Angles(0, math.rad(-90), 0)
* CFrame.Angles(0, math.rad(petIndex * anglePerPet), 0)
* CFrame.new(0, 0, DISTANCE_FROM_CHARACTER)
end
script.Parent.Parent.ChildAdded:Connect(updatePetCframeOffset)
script.Parent.Parent.ChildRemoved:Connect(updatePetCframeOffset)
-- LERP_ALPHA, character, function Update() ...
Yep, just raycast down 5 or so studs from newCframe.Position and go back up by half the pet’s size in the Y direction.
-- at the start of the script
local RAY_VECTOR = Vector3.new(0, -5, 0)
local DEFAULT_RAY_OFFSET = Vector3.new(0, -3, 0)
-- ...
-- after defining newCframe,
local result = workspace:Raycast(newCframe.Position, RAY_VECTOR)
if result then
newCframe += result.Position - newCframe.Position
else
newCframe += DEFAULT_RAY_OFFSET
end
local _, petSize = pet:GetBoundingBox()
newCframe += Vector3.new(0, petSize.Y / 2, 0)
pet:SetPrimaryPartCFrame(newCframe)
end
What do you mean by “rejoining”? Do you just mean respawning the character?
Assuming rejoining is the character respawning, what do you do with the pets when the character dies? Do you parent them to nil on dying and reparent them when their character is added back, or do all the pets get destroyed and you create new ones when the character respawns?