Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- ----------------------------------------------------------------
- --- THIS IS THE CLIENT HANDLING------------------------------
- --------------------------------------------------------------
- local plr = game.Players.LocalPlayer
- local Mouse = plr:GetMouse()
- local hitCircle = nil --this will be used to find parts in a range for the perdiction system
- local MousePlane = nil -- this plane will be use to catch the mouse.hit so we can use it and find the nearest part
- local Guideblock = nil -- this will be the ghost block that the player sees when trying to place a block
- local equiped = false
- local character = nil -- For safty, the character is set when equiped and set to nil when unequiped
- local MaxRange = 20
- local GuideMaxRange = 50
- local BlocksInPerdictionRange = {} -- list of building blocks in range
- -- were going to use a table for mouse Target filter since Target Filter is not a stackable
- local studStep = 3 -- snap amount
- -- surface offets for surface placement
- local SurfaceFaceOffset = {
- Top = Vector3.new(0, 1, 0),
- Bottom = Vector3.new(0, -1, 0),
- Left = Vector3.new(-1, 0, 0),
- Right = Vector3.new(1, 0, 0),
- Front = Vector3.new(0, 0, -1),
- Back = Vector3.new(0, 0, 1),
- }
- --These Parts will track the mouse position and the parts in range
- local function MakeMouseHitCircle()
- hitCircle = Instance.new("Part")
- hitCircle.Parent = game.Workspace
- hitCircle.Shape = Enum.PartType.Cylinder
- hitCircle.Transparency = 0.5
- hitCircle.Massless = true
- hitCircle.Position = Vector3.new(character:WaitForChild("HumanoidRootPart").Position.X, character:WaitForChild("HumanoidRootPart").Position.Y-12, character:WaitForChild("HumanoidRootPart").Position.Z)
- hitCircle.CanCollide = false
- hitCircle.Orientation = Vector3.new(0,0,90)
- hitCircle.Size = Vector3.new(15,50,50)
- --weld to player (less laggy than using CFrame and runservice)
- local cyl_weld = Instance.new("WeldConstraint")
- cyl_weld.Parent = hitCircle
- cyl_weld.Part0 = hitCircle
- cyl_weld.Part1 = character:WaitForChild("HumanoidRootPart")
- Mouse.TargetFilter = hitCircle
- MousePlane = Instance.new("Part")
- MousePlane.Parent = game.Workspace
- MousePlane.Shape = Enum.PartType.Cylinder
- MousePlane.Transparency = 0.5
- MousePlane.Massless = true
- MousePlane.Position = Vector3.new(character:WaitForChild("HumanoidRootPart").Position.X, character:WaitForChild("HumanoidRootPart").Position.Y-5, character:WaitForChild("HumanoidRootPart").Position.Z)
- MousePlane.CanCollide = false
- MousePlane.Orientation = Vector3.new(0,0,90)
- MousePlane.Size = Vector3.new(0.5,50,50)
- --weld to player (less laggy than using CFrame and runservice)
- local cyl_weld2 = Instance.new("WeldConstraint")
- cyl_weld2.Parent = MousePlane
- cyl_weld2.Part0 = MousePlane
- cyl_weld2.Part1 = character:WaitForChild("HumanoidRootPart")
- end
- --store the building blocks that are in the range for predictive placment so they can be called later
- game:GetService("RunService").Heartbeat:Connect(function()
- if equiped then
- local PartsInRange = hitCircle:GetTouchingParts()
- for ind, block in ipairs(BlocksInPerdictionRange) do
- if not table.find(PartsInRange, block) then
- table.remove(BlocksInPerdictionRange, ind)
- end
- end
- for _, v in pairs(PartsInRange) do
- local isInDict = false
- if v.Name == "BuildingBlock" and not table.find(BlocksInPerdictionRange, v) then
- table.insert(BlocksInPerdictionRange, v)
- end
- end
- end
- end)
- -- We are going to find the closest part and get the surface that is being touched by the ray from the mouse
- local function FindClosestPartAndSurface()
- if Mouse.Target == MousePlane then
- local PartsAndLens = {}
- local ShortestRay = 0
- for i,v in pairs(BlocksInPerdictionRange)do
- local castRayParams = RaycastParams.new()
- castRayParams.FilterType = Enum.RaycastFilterType.Include
- castRayParams.FilterDescendantsInstances = BlocksInPerdictionRange
- local castRay = game.Workspace:Raycast(Mouse.Hit.Position, (v.Position - Mouse.Hit.Position).Unit * (v.Position - Mouse.Hit.Position).magnitude,castRayParams)
- --require(script.RaycastVisualizer).VisualizeCast(castRay, Mouse.Hit.Position, (v.Position - Mouse.Hit.Position).Unit * (v.Position - Mouse.Hit.Position).magnitude,0.5)
- if castRay then
- PartsAndLens[castRay.Distance] = {castRay.Position, castRay.Normal}
- end
- end
- local index = 0
- for key, position in pairs(PartsAndLens)do
- index += 1
- if index == 1 then
- ShortestRay = key
- else
- if key < ShortestRay then
- ShortestRay = key
- end
- end
- end
- if ShortestRay == 0 then
- return nil
- else
- return PartsAndLens[ShortestRay][1], PartsAndLens[ShortestRay][2]
- end
- end
- end
- -- get the information of the playes mouse and adjusts the "GhostBlock/GuideBlock" (NOTE: I learned this clever grid methood from dev fourm, I did not make this methood)
- local function PartPlacement()
- if equiped then
- if (character:WaitForChild("HumanoidRootPart").Position - Mouse.Hit.Position).magnitude < GuideMaxRange then
- ---------------------------------------
- Guideblock.Transparency = 0.4
- Guideblock.SelectionBox.Visible = true
- ---------------------------------------
- for i = 1,2 do
- local PerdictivePos, PerdictiveVector = FindClosestPartAndSurface()
- local MousePos = PerdictivePos or Mouse.Hit.Position
- local surface = Mouse.TargetSurface.Name
- local surfaceVector = PerdictiveVector or SurfaceFaceOffset[surface]
- local PlacePos = Vector3.new(0,Guideblock.Size.Y/2,0)
- PlacePos += MousePos
- ----------------------------------------------
- local adjustedX = MousePos.X + surfaceVector.X -- surface vector of part mouse is touching
- local adjustedY = MousePos.Y + surfaceVector.Y
- local adjustedZ = MousePos.Z + surfaceVector.Z
- ----------------------------------------------
- local X = math.round(adjustedX / studStep) * studStep -- round to the nearest cordinate in the grid
- local Y = math.round(adjustedY / studStep) * studStep
- local Z = math.round(adjustedZ / studStep) * studStep
- -----------------------------------------------------
- PlacePos = Vector3.new(X,Y,Z)
- Guideblock.Position = PlacePos
- ----------------------------------------------------------------------------------------------------------
- pcall(function()
- if (character:WaitForChild("HumanoidRootPart").Position - Guideblock.Position).magnitude < MaxRange then
- Guideblock:FindFirstChild("SelectionBox").Color3 = Color3.fromRGB(25, 92, 116)
- else
- Guideblock:FindFirstChild("SelectionBox").Color3 = Color3.new(0.886275, 0, 0)
- end
- end)
- -----------------------------------------------------------------------------------------------------------
- task.wait(0.1)
- end
- elseif Guideblock then
- if Guideblock then
- Guideblock.Transparency = 1
- Guideblock.SelectionBox.Visible = false
- end
- end
- end
- end
- -- Create the guide block when equiped
- script.Parent.Equipped:Connect(function()
- if Guideblock then
- Guideblock:Destroy()
- end
- character = plr.Character or plr.CharacterAdded:Wait()
- MakeMouseHitCircle()
- equiped = true
- Guideblock = Instance.new("Part")
- Guideblock.Size = Vector3.new(3,3,3)
- Guideblock.Transparency = 0.4
- Guideblock.Parent = script
- Guideblock.CanCollide = false
- Guideblock.Anchored = true
- Guideblock.CanTouch = false
- Guideblock.CanQuery = false
- local outline = Instance.new("SelectionBox")
- outline.Parent = Guideblock
- outline.Adornee = Guideblock
- PartPlacement()
- end)
- script.Parent.Unequipped:Connect(function()
- BlocksInPerdictionRange = {}
- equiped = false
- hitCircle:Destroy()
- MousePlane:Destroy()
- hitCircle = nil
- character = nil
- end)
- --sends the GuideBlock position to the server when the plaler invokes the funtion(Player activates build tool)
- script.Parent:WaitForChild("build").RemoteFunction.OnClientInvoke = function()
- local char = plr.Character
- if (char:WaitForChild("HumanoidRootPart").Position - Guideblock.Position).magnitude < MaxRange then -- check if the player is in range
- local animation = script.Parent:WaitForChild("activate")
- local anim = char:WaitForChild("Humanoid"):LoadAnimation(animation)
- anim:Play()
- end
- return Guideblock.Position
- end
- Mouse.Move:Connect(PartPlacement)
- script.Parent.Activated:Connect(PartPlacement)
- -----------------------------------------------------------------------------------------
- --------------------SERVER SIDE HANDLING-------------------------------------------------
- ----------------------------------------------------------------------------------------
- local tool = script.Parent
- local MaxRange = 20
- cooldown = false -- Will be used for a cooldown lateron to prevent auto clicking
- script.Parent.Activated:Connect(function()
- local plr = game.Players:GetPlayerFromCharacter(script.Parent.Parent)
- local pos = script.RemoteFunction:InvokeClient(game.Players:GetPlayerFromCharacter(script.Parent.Parent)) -- Get the position of the block thats going to be placed
- if (script.Parent.Parent:WaitForChild("HumanoidRootPart").Position - pos).magnitude < MaxRange and cooldown == false then -- make sure its in range
- cooldown = true
- local placeSound = script.Parent.Handle.Place:Clone()
- local DestroyByRocket = script:WaitForChild("DestroyByRocket"):Clone()-- This may be scraped later on since tags exist now
- local part = Instance.new("Part")
- -- these values will allow me to make a destroy mechanic later on
- local Health = Instance.new("IntValue",part)
- local HeathStatus = Instance.new("IntValue",part)
- Health.Name = "Health"
- HeathStatus.Name = "HealthStatus"
- -- add decals for the crack for the destroy/mine mechanic
- for i = 1,6 do
- local decal = script.Parent:WaitForChild("Cracks"):Clone()
- decal.Parent = part
- if i == 1 then
- decal.Face = Enum.NormalId.Front
- elseif i == 2 then
- decal.Face = Enum.NormalId.Back
- elseif i == 3 then
- decal.Face = Enum.NormalId.Left
- elseif i == 4 then
- decal.Face = Enum.NormalId.Right
- elseif i == 5 then
- decal.Face = Enum.NormalId.Top
- else
- decal.Face = Enum.NormalId.Bottom
- end
- end
- HeathStatus.Value = 3
- Health.Value = 3
- -- again, this may be scraped soon
- DestroyByRocket.Parent = part
- DestroyByRocket.Enabled = true
- placeSound.Parent = part
- placeSound:Play()
- part.Size = Vector3.new(3,3,3)
- part.Name = "BuildingBlock"
- part.Anchored = true
- part.Parent = game.Workspace:WaitForChild("Builds")
- print(pos)
- part.Position = pos
- task.wait(0.085)
- cooldown = false
- end
- end)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement