Hello people of the internet! I recently started to make a sandbox tycoon game, i want to know how to make a preview. (Also, if you could keep it usable with my currentbuilding setup.)
I've done a bit of research, and couldn't find a way to do it. Thanks in advance!
How my building system look right now
Replicated Storage(For those ones who want to mimic my current setup)
SERVER SCRIPT
local place = game:GetService("ReplicatedStorage").Placement.Remotes.Place game.ReplicatedStorage.Placement.Remotes.Place.OnServerEvent:Connect(function(plr, building, position) -- Are you kidding me, you guy not indenting properly is trigger my OCD local position2 = position local building2 = building:Clone() building2.Parent = workspace building2:MoveTo(position2) end)
LOCAL SCRIPT
local player = game:GetService("Players").LocalPlayer -- Define the player local mouse = player:GetMouse() -- Define the mouse local UIS = game:GetService("UserInputService") -- UIS for activate of placement local active = true -- Is placement active? local activekeycode = Enum.KeyCode.E -- When the player presses E, they start placement. local event = game:GetService("ReplicatedStorage").Placement.Remotes.Place local changeevent = game:GetService("ReplicatedStorage").Placement.Remotes.ChangeBuilding local currentbuilding = game:GetService("ReplicatedStorage").Placement.Buildings.Model UIS.InputBegan:Connect(function(input, gp) --Change if it is active or not if input == activekeycode and gp and active == true then active = true else active = false end end) mouse.Button1Down:Connect(function()--Start the placement if active == true then -- Ensure it is active print("Activated") local building = currentbuilding local position = mouse.Hit.p -- Don't know if i should use "mouse.Hit.p" or "mouse.Hit" event:FireServer(building, position) end end) changeevent.OnClientEvent:Connect(function(building)-- Change building if not active == false and building ~= currentbuilding then -- Ensure it is not active currentbuilding = building end end) mouse.Move:Connect(function() -- Basically my preview if active == true then local position = mouse.Hit.p local building = currentbuilding:Clone() building.Parent = workspace building:MoveTo(position) local parts = building:GetChildren() parts.Transparency = 0.4 end end)
Before you copy and paste the code: create two RemoteEvents on Placement.Remotes, one named "MovePreview" and the other "CreatePreview". At least try to understand what I wrote. Its quite a big Code:
Server Script Code:
local place = game:GetService("ReplicatedStorage").Placement.Remotes.Place local movepreview = game:GetService("ReplicatedStorage").Placement.Remotes.MovePreview local createpreview = game:GetService("ReplicatedStorage").Placement.Remotes.CreatePreview function newPlayer(player)--Create a Value inside the player that shows what is the currentpreview local currentpreview = Instance.new("ObjectValue") currentpreview.Parent = player currentpreview.Name = "CurrentPreview" end game.Players.PlayerAdded:Connect(newPlayer) function onPreviewDeleted(obj,target)--Sometimes ObjectValues hold values of instances that got destroyed if obj == target.Value then target.Value = nil end end function findPartOnRayCheck(camerap,mousep,currentpreview) local ori = camerap local dir = mousep local ray = Ray.new(ori,(dir-ori).unit*999) local ignoreList = {currentpreview}--Ignores the CurrentPreview so I cant move over itself local part, rayposition = workspace:FindPartOnRayWithIgnoreList(ray,ignoreList) return part,rayposition end function movepreview(player,camerap,mousep)--Moves the Preview if camerap and mousep and player:findFirstChild("CurrentPreview") then local currentpreview = player.CurrentPreview.Value if currentpreview then local part,rayposition = findPartOnRayCheck(camerap,mousep,currentpreview) if part then if currentpreview.PrimaryPart then currentpreview:SetPrimaryPartCFrame(CFrame.new(rayposition)) else currentpreview:MoveTo(rayposition) end end end end end game.ReplicatedStorage.Placement.Remotes.MovePreview.OnServerEvent:Connect(movepreview) function createPreview(player,building,mousep)--Creates the preview if building and mousep and player:findFirstChild("CurrentPreview") and player.CurrentPreview.Value == nil then local currentpreview = player.CurrentPreview currentpreview.Value = building:Clone() workspace.DescendantRemoving:Connect(function(obj) onPreviewDeleted(obj,currentpreview) end) local parts = currentpreview.Value:GetDescendants() for i=1,#parts do if parts[i]:IsA("BasePart") then parts[i].CanCollide = false parts[i].BrickColor = BrickColor.new("Bright red") parts[i].Transparency = .5 end end currentpreview.Value.Parent = workspace if currentpreview.Value.PrimaryPart then currentpreview.Value:SetPrimaryPartCFrame(CFrame.new(mousep)) else currentpreview.Value:MoveTo(mousep) end end end game.ReplicatedStorage.Placement.Remotes.CreatePreview.OnServerEvent:Connect(createPreview) game.ReplicatedStorage.Placement.Remotes.Place.OnServerEvent:Connect(function(plr,building,camerap,mousep) local previewpos = nil if plr:findFirstChild("CurrentPreview") and plr.CurrentPreview.Value ~= nil then--Destroy Preview, as it wont be used anymore local part,rayposition = findPartOnRayCheck(camerap,mousep,plr.CurrentPreview.Value) if part then previewpos = rayposition end plr.CurrentPreview.Value:Destroy() end if not previewpos then previewpos = mousep end if previewpos then --Why would you create a local position2 = position? local building2 = building:Clone() building2.Parent = workspace if building2.PrimaryPart and previewpos then building2:SetPrimaryPartCFrame(CFrame.new(previewpos)) else building2:MoveTo(previewpos) end --return building2 end end)
Local Script Code:
local player = game:GetService("Players").LocalPlayer -- Define the player local mouse = player:GetMouse() -- Define the mouse local UIS = game:GetService("UserInputService") -- UIS for activate of placement local active = true -- Is placement active? local activekeycode = Enum.KeyCode.E -- When the player presses E, they start placement. local event = game:GetService("ReplicatedStorage").Placement.Remotes.Place local changeevent = game:GetService("ReplicatedStorage").Placement.Remotes.ChangeBuilding local currentbuilding = game:GetService("ReplicatedStorage").Placement.Buildings.Model local camera = workspace.CurrentCamera UIS.InputBegan:Connect(function(input, gp) -- I don't think this works right now, maybe i'll fix it soon. if input == activekeycode and gp and active == false then active = true elseif input == activekeycode and gp and active == true then active = false end end) mouse.Move:connect(function()game.ReplicatedStorage.Placement.Remotes.MovePreview:FireServer(camera.CFrame.Position,mouse.Hit.p) end) mouse.Button1Down:connect(function()game.ReplicatedStorage.Placement.Remotes.CreatePreview:FireServer(currentbuilding,mouse.Hit.p) end) mouse.Button1Up:Connect(function()--Start the placement if active == true then -- Ensure it is active print("Activated") local building = currentbuilding --local position = mouse.Hit.p -- Don't know if i should use "mouse.Hit.p" or "mouse.Hit" game.ReplicatedStorage.Placement.Remotes.Place:FireServer(building,camera.CFrame.Position,mouse.Hit.p) --local building = game.ReplicatedStorage.Placement.Remotes.Place:InvokeServer(building,mouse.Hit.p) end end) changeevent.OnClientEvent:Connect(function(building)-- Change Building if not active == false and building ~= currentbuilding then -- Ensure it is not active currentbuilding = building end end)