Ad
Still have questions? Join our Discord server and get real time help.
Log in to vote
0

How can i make a preview of what i am placing?

Asked by
BashGuy10 379 Moderation Voter
1 year ago
Edited 1 year ago

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)

What my "Preview" looks like

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)

1 answer

Log in to vote
1
Answered by
Dfzoz 345 Moderation Voter
1 year ago

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)
0
It works, thanks! Few problems here and there, but overall really good. BashGuy10 379 — 1y
Ad

Answer this question