How to position an object relative to another object

Hey everyone! So I have a plot placement system however when I run the code that you see below, it is not on the plot. It is on the side of the plot. Why does this happen? Thanks

local newCFrame = Clone.CFrame:ToWorldSpace(game.Workspace.HomeArea.Plots[player.PlotOwner.Value].CFrame)
2 Likes

The function you are looking for is :ToObjectSpace()

2 Likes

Ok and if I replace that with “ToWorldSpace” will it solve the problem?

yes

This post can explain it better than I can. I cannot say if it will definitely fix it, however it answers the title of the post. This function sets a CFrame relative to another CFrame - hopefully that’s of some help?

Just to note that the target plot is in the top left hand corner.

Now that I changed it to “ToObjectSpace” it spawns diagonally.

How should this be fixed?

What are you trying to do?

What are your inputs, and what is your desired outcome?

I have no idea what the image you posted is supposed to look like. There’s just two brown rectangles on the screen and you say “it’s diagonal”—what does that mean?

Ok so let me explain. I have a data store that when you leave, it saves all the parts on you previous part. It save it through cframes. The only issue is when you are on a new plot they are loaded on your previous plot. I tried to save it through ToObjectSpace but the image I displayed above was the outcome. I don’t know why though since I think I did everything correctly.

There’s two problems here, then:

  1. Saving the relative position
  2. Loading the world position

(1) Is easy enough:

-- figure out what cframe to store:
local relative = Plot.CFrame:ToObjectSpace(ObjectToSaveCFrame)

Then you’d want to store relative.

(2) is also easy:

-- figure out what cframe to place at (once we load the above)
local whereItShouldGo = NewPlot.CFrame:ToWorldSpace(ObjectWeLoadedCFrame)
-- or just NewPlot.CFrame * ObjectWeLoadedCFrame (it's the same thing)

And you put the loaded object at that CFrame

1 Like

Most of my projects are related to placement systems what i would do is save the Objects Primary Part CFrame into Datastores and use SetPrimaryPartCFrame() or the new PivotTo() to move the object relatively to the plot

use this

v:SetPrimaryPartCFrame(Base.CFrame:toWorldSpace(SAVEDCFRAME))

to save use this

Base.CFrame:toObjectSpace(v.PrimaryPart.CFrame)

u can take reference from one of my placements scripts, most of time i encode and decode the saved cframes to put them into ds but both methods work

3 Likes

Oh I understand. Let me check it out and then I will get back to you

1 Like

Ok so everything works however there is one problem. The one I loaded from the data save is inversed. Let me send you an image.

This is the one I want to save.

And This is the one after it is loaded.

Seem like it is reversed. Is there a way to fix this?

Share the code you’re using to save and load

Here is the loading script

local function findOpenPlot(player)

repeat wait()

until player.Character

for i, plot in pairs(plotsFolder:GetChildren()) do
	if plot.Owner.Value == "" then
		if not player:FindFirstChild("PlotOwner") then
			plot.Owner.Value = player.Name 
			local PlotOwner = Instance.new("StringValue")
			PlotOwner.Value = plot.Name
			PlotOwner.Name = "PlotOwner"
			PlotOwner.Parent = player
			
			player.OwnedPlot.Value = plot.Name

			plot.NamePart.NameTag.SurfaceGui.TextLabel.Text = player.Name

			player.Character.HumanoidRootPart.CFrame = plot.CFrame + Vector3.new(0,10,0)
		end

	end
end





local data = PlotsDataStore:GetAsync(player.UserId.."_PlotStuff")


if data then
	
	for i, v in pairs(data) do
		if game.ReplicatedStorage.Parts:FindFirstChild(v) then
			
			local Clone = game.ReplicatedStorage.Parts[v]:Clone()
			
			Clone.BasePart.Transparency = 1
			
			if Clone:FindFirstChild("PartFound") then
				Clone.PartFound.Value = false
			end
			
			
		
			local Split = string.split(data[i+1], ",")
			--Clone.CFrame = CFrame.new(Split[1],Split[2],Split[3],Split[4],Split[5],Split[6],Split[7],Split[8],Split[9],Split[10],Split[11],Split[12])
			

			
			
		
			
			
			
			--local newCFrame = Clone.CFrame:ToObjectSpace(game.Workspace.HomeArea.Plots[player.OwnedPlot.Value].CFrame)
			Clone.CFrame = game.Workspace.HomeArea.Plots[player.OwnedPlot.Value].CFrame:ToWorldSpace(CFrame.new(Split[1],1.2,Split[3],Split[4],Split[5],Split[6],Split[7],Split[8],Split[9],Split[10],Split[11],Split[12]))
		
			
			
			
			
			Clone.BasePart.CFrame = Clone.CFrame - Vector3.new(0,0.2,0)
			
			--Clone.Position = Vector3.new(tonumber(data[i+1]), 1.2, tonumber(data[i+3]))
			--Clone.BasePart.Position = Vector3.new(tonumber(data[i+1]), 1, tonumber(data[i+3]))
			
			Clone.Parent = game.Workspace.HomeArea.Plots[player.OwnedPlot.Value]
			--print(Clone.CFrame)
		end
	end
end
end

Saving Script

local DataStoreService = game:GetService("DataStoreService")
local PlotsDataStore = DataStoreService:GetDataStore("Plots")

local function savePlotData(player)

local OwnedPlot = game.Workspace.HomeArea.Plots[player.PlotOwner.Value]

local PlotStuff = {}



for i, part in pairs(OwnedPlot:GetChildren()) do
	if part.Name ~= "Owner" and part.Name ~= "Border" and part.Name ~= "NamePart" then
		table.insert(PlotStuff, part.Name)
		table.insert(PlotStuff, tostring(part.CFrame:ToObjectSpace(game.Workspace.HomeArea.Plots[player.OwnedPlot.Value].CFrame)))
		--table.insert(PlotStuff, tostring(part.CFrame.Y:ToObjectSpace(game.Workspace.HomeArea.Plots[player.OwnedPlot.Value])))
		--table.insert(PlotStuff, tostring(part.CFrame.Z:ToObjectSpace(game.Workspace.HomeArea.Plots[player.OwnedPlot.Value])))
		
	end
	
end
local encoding = HttpService:JSONEncode(PlotStuff)

wait(1)

local decoding = HttpService:JSONDecode(encoding)

local success, err = pcall(function()
	PlotsDataStore:SetAsync(player.UserId.."_PlotStuff",decoding)
end)

if err then
	warn(err)
end

end

Did you find any issues with the code?

Flip those around, the plot CFrame should be first and the object CFrame should be in the parameters.