Advertisement
CrownedFigure

Building system roblox

Jun 11th, 2024
390
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 10.61 KB | Source Code | 0 0
  1. ----------------------------------------------------------------
  2. ---   THIS IS THE CLIENT HANDLING------------------------------
  3. --------------------------------------------------------------
  4. local plr = game.Players.LocalPlayer
  5. local Mouse = plr:GetMouse()
  6.  
  7. local hitCircle = nil --this will be used to find parts in a range for the perdiction system
  8. local MousePlane = nil -- this plane will be use to catch the mouse.hit so we can use it and find the nearest part
  9.  
  10. local Guideblock = nil -- this will be the ghost block that the player sees when trying to place a block
  11. local equiped = false
  12. local character = nil -- For safty, the character is set when equiped and set to nil when unequiped
  13. local MaxRange = 20
  14. local GuideMaxRange = 50
  15.  
  16.  
  17.  
  18. local BlocksInPerdictionRange = {} -- list of building blocks in range
  19. -- were going to use a table for mouse Target filter since Target Filter is not a stackable
  20.  
  21.  
  22.  
  23.  
  24.  
  25.  
  26.  
  27.  
  28.  
  29.  
  30.  
  31. local studStep = 3 -- snap amount
  32.  
  33. -- surface offets for surface placement
  34. local SurfaceFaceOffset = {
  35.     Top = Vector3.new(0, 1, 0),
  36.     Bottom = Vector3.new(0, -1, 0),
  37.     Left = Vector3.new(-1, 0, 0),
  38.     Right = Vector3.new(1, 0, 0),
  39.     Front = Vector3.new(0, 0, -1),
  40.     Back = Vector3.new(0, 0, 1),
  41. }
  42.  
  43. --These Parts will track the mouse position and the parts in range
  44. local function MakeMouseHitCircle()
  45.  
  46.     hitCircle = Instance.new("Part")
  47.     hitCircle.Parent = game.Workspace
  48.     hitCircle.Shape = Enum.PartType.Cylinder
  49.     hitCircle.Transparency = 0.5
  50.     hitCircle.Massless = true
  51.     hitCircle.Position = Vector3.new(character:WaitForChild("HumanoidRootPart").Position.X, character:WaitForChild("HumanoidRootPart").Position.Y-12, character:WaitForChild("HumanoidRootPart").Position.Z)
  52.     hitCircle.CanCollide = false
  53.     hitCircle.Orientation = Vector3.new(0,0,90)
  54.     hitCircle.Size = Vector3.new(15,50,50)
  55.     --weld to player (less laggy than using CFrame and runservice)
  56.     local cyl_weld = Instance.new("WeldConstraint")
  57.     cyl_weld.Parent = hitCircle
  58.     cyl_weld.Part0 = hitCircle
  59.     cyl_weld.Part1 = character:WaitForChild("HumanoidRootPart")
  60.    
  61.     Mouse.TargetFilter = hitCircle
  62.    
  63.    
  64.     MousePlane = Instance.new("Part")
  65.     MousePlane.Parent = game.Workspace
  66.     MousePlane.Shape = Enum.PartType.Cylinder
  67.     MousePlane.Transparency = 0.5
  68.     MousePlane.Massless = true
  69.     MousePlane.Position = Vector3.new(character:WaitForChild("HumanoidRootPart").Position.X, character:WaitForChild("HumanoidRootPart").Position.Y-5, character:WaitForChild("HumanoidRootPart").Position.Z)
  70.     MousePlane.CanCollide = false
  71.     MousePlane.Orientation = Vector3.new(0,0,90)
  72.     MousePlane.Size = Vector3.new(0.5,50,50)
  73.     --weld to player (less laggy than using CFrame and runservice)
  74.     local cyl_weld2 = Instance.new("WeldConstraint")
  75.     cyl_weld2.Parent = MousePlane
  76.     cyl_weld2.Part0 = MousePlane
  77.     cyl_weld2.Part1 = character:WaitForChild("HumanoidRootPart")
  78.    
  79.  
  80.    
  81. end
  82.  
  83.  
  84.  
  85.  
  86.  
  87. --store the building blocks that are in the range for predictive placment so they can be called later
  88. game:GetService("RunService").Heartbeat:Connect(function()
  89.     if equiped then
  90.         local PartsInRange = hitCircle:GetTouchingParts()
  91.  
  92.         for ind, block in ipairs(BlocksInPerdictionRange) do
  93.             if not table.find(PartsInRange, block) then
  94.                 table.remove(BlocksInPerdictionRange, ind)
  95.             end
  96.         end
  97.  
  98.         for _, v in pairs(PartsInRange) do
  99.             local isInDict = false
  100.            
  101.             if v.Name == "BuildingBlock" and not table.find(BlocksInPerdictionRange, v) then
  102.                 table.insert(BlocksInPerdictionRange, v)
  103.             end
  104.         end
  105.     end
  106. end)
  107.  
  108. -- We are going to find the closest part and get the surface that is being touched by the ray from the mouse
  109. local function FindClosestPartAndSurface()
  110.     if Mouse.Target == MousePlane then
  111.  
  112.         local PartsAndLens = {}
  113.         local ShortestRay = 0
  114.  
  115.         for i,v in pairs(BlocksInPerdictionRange)do
  116.             local castRayParams = RaycastParams.new()
  117.             castRayParams.FilterType = Enum.RaycastFilterType.Include
  118.             castRayParams.FilterDescendantsInstances = BlocksInPerdictionRange
  119.             local castRay = game.Workspace:Raycast(Mouse.Hit.Position, (v.Position - Mouse.Hit.Position).Unit * (v.Position - Mouse.Hit.Position).magnitude,castRayParams)
  120.             --require(script.RaycastVisualizer).VisualizeCast(castRay, Mouse.Hit.Position, (v.Position - Mouse.Hit.Position).Unit * (v.Position - Mouse.Hit.Position).magnitude,0.5)
  121.             if castRay then
  122.                 PartsAndLens[castRay.Distance] = {castRay.Position, castRay.Normal}
  123.             end
  124.         end
  125.  
  126.         local index = 0
  127.         for key, position in pairs(PartsAndLens)do
  128.             index += 1
  129.             if index == 1 then
  130.                 ShortestRay = key
  131.             else
  132.                 if key < ShortestRay then
  133.                     ShortestRay = key
  134.                 end
  135.             end
  136.         end
  137.  
  138.         if ShortestRay == 0 then
  139.  
  140.             return nil
  141.         else
  142.  
  143.             return PartsAndLens[ShortestRay][1], PartsAndLens[ShortestRay][2]
  144.            
  145.         end
  146.  
  147.  
  148.     end
  149. end
  150.  
  151.  
  152. -- 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)
  153.  
  154. local function PartPlacement()
  155.     if equiped then
  156.         if (character:WaitForChild("HumanoidRootPart").Position - Mouse.Hit.Position).magnitude < GuideMaxRange then
  157.            
  158.            
  159.             ---------------------------------------
  160.  
  161.             Guideblock.Transparency = 0.4
  162.             Guideblock.SelectionBox.Visible = true
  163.             ---------------------------------------
  164.             for i = 1,2 do
  165.                 local PerdictivePos, PerdictiveVector = FindClosestPartAndSurface()
  166.                
  167.                 local MousePos = PerdictivePos or Mouse.Hit.Position
  168.                 local surface = Mouse.TargetSurface.Name
  169.                 local surfaceVector = PerdictiveVector or SurfaceFaceOffset[surface]
  170.                 local PlacePos = Vector3.new(0,Guideblock.Size.Y/2,0)
  171.                 PlacePos += MousePos
  172.                 ----------------------------------------------
  173.                 local adjustedX = MousePos.X + surfaceVector.X -- surface vector of part mouse is touching
  174.                 local adjustedY = MousePos.Y + surfaceVector.Y
  175.                 local adjustedZ = MousePos.Z + surfaceVector.Z
  176.                 ----------------------------------------------
  177.                 local X = math.round(adjustedX / studStep) * studStep -- round to the nearest cordinate in the grid
  178.                 local Y = math.round(adjustedY / studStep) * studStep
  179.                 local Z = math.round(adjustedZ / studStep) * studStep
  180.                 -----------------------------------------------------
  181.                 PlacePos = Vector3.new(X,Y,Z)
  182.                 Guideblock.Position = PlacePos
  183.                 ----------------------------------------------------------------------------------------------------------
  184.                 pcall(function()
  185.                 if (character:WaitForChild("HumanoidRootPart").Position - Guideblock.Position).magnitude < MaxRange then
  186.                     Guideblock:FindFirstChild("SelectionBox").Color3 = Color3.fromRGB(25, 92, 116)
  187.                 else
  188.                     Guideblock:FindFirstChild("SelectionBox").Color3 = Color3.new(0.886275, 0, 0)
  189.                 end
  190.                 end)
  191.                 -----------------------------------------------------------------------------------------------------------
  192.                 task.wait(0.1)
  193.             end
  194.         elseif Guideblock then
  195.             if Guideblock then
  196.                 Guideblock.Transparency = 1
  197.                 Guideblock.SelectionBox.Visible = false
  198.             end
  199.         end
  200.     end
  201. end
  202.  
  203. -- Create the guide block when equiped
  204. script.Parent.Equipped:Connect(function()
  205.     if Guideblock then
  206.         Guideblock:Destroy()
  207.     end
  208.     character =  plr.Character or plr.CharacterAdded:Wait()
  209.     MakeMouseHitCircle()
  210.     equiped = true
  211.     Guideblock = Instance.new("Part")
  212.     Guideblock.Size = Vector3.new(3,3,3)
  213.     Guideblock.Transparency = 0.4
  214.     Guideblock.Parent = script
  215.     Guideblock.CanCollide = false
  216.     Guideblock.Anchored = true
  217.     Guideblock.CanTouch = false
  218.     Guideblock.CanQuery = false
  219.  
  220.     local outline = Instance.new("SelectionBox")
  221.     outline.Parent = Guideblock
  222.     outline.Adornee = Guideblock
  223.  
  224.  
  225.  
  226.     PartPlacement()
  227.  
  228.  
  229. end)
  230.  
  231. script.Parent.Unequipped:Connect(function()
  232.     BlocksInPerdictionRange = {}
  233.     equiped = false
  234.     hitCircle:Destroy()
  235.     MousePlane:Destroy()
  236.     hitCircle = nil
  237.     character = nil
  238. end)
  239.  
  240.  
  241.  
  242.  
  243.  
  244. --sends the GuideBlock position to the server when the plaler invokes the funtion(Player activates build tool)
  245. script.Parent:WaitForChild("build").RemoteFunction.OnClientInvoke = function()
  246.     local char = plr.Character
  247.     if (char:WaitForChild("HumanoidRootPart").Position - Guideblock.Position).magnitude < MaxRange then -- check if the player is in range
  248.         local animation = script.Parent:WaitForChild("activate")
  249.         local anim = char:WaitForChild("Humanoid"):LoadAnimation(animation)
  250.         anim:Play()
  251.     end
  252.  
  253.     return Guideblock.Position
  254.  
  255. end
  256.  
  257. Mouse.Move:Connect(PartPlacement)
  258. script.Parent.Activated:Connect(PartPlacement)
  259.  
  260. -----------------------------------------------------------------------------------------
  261. --------------------SERVER SIDE HANDLING-------------------------------------------------
  262. ----------------------------------------------------------------------------------------
  263. local tool = script.Parent
  264. local MaxRange = 20
  265.  
  266. cooldown = false -- Will be used for a cooldown lateron to prevent auto clicking
  267.  
  268.  
  269. script.Parent.Activated:Connect(function()
  270.     local plr = game.Players:GetPlayerFromCharacter(script.Parent.Parent)
  271.     local pos = script.RemoteFunction:InvokeClient(game.Players:GetPlayerFromCharacter(script.Parent.Parent)) -- Get the position of the block thats going to be placed
  272.    
  273.     if (script.Parent.Parent:WaitForChild("HumanoidRootPart").Position - pos).magnitude < MaxRange and cooldown == false  then -- make sure its in range
  274.         cooldown = true
  275.         local placeSound = script.Parent.Handle.Place:Clone()
  276.         local DestroyByRocket = script:WaitForChild("DestroyByRocket"):Clone()-- This may be scraped later on since tags exist now
  277.         local part = Instance.new("Part")
  278.        
  279.         -- these values will allow me to make a destroy mechanic later on
  280.         local Health = Instance.new("IntValue",part)
  281.         local HeathStatus = Instance.new("IntValue",part)
  282.         Health.Name = "Health"
  283.         HeathStatus.Name = "HealthStatus"
  284.        
  285.         -- add decals for the crack for the destroy/mine mechanic
  286.         for i = 1,6 do
  287.             local decal = script.Parent:WaitForChild("Cracks"):Clone()
  288.             decal.Parent = part
  289.             if i == 1 then
  290.                 decal.Face = Enum.NormalId.Front
  291.             elseif i == 2  then
  292.                 decal.Face = Enum.NormalId.Back
  293.             elseif i == 3 then
  294.                 decal.Face = Enum.NormalId.Left
  295.             elseif i == 4 then
  296.                 decal.Face = Enum.NormalId.Right
  297.             elseif i == 5 then
  298.                 decal.Face = Enum.NormalId.Top
  299.             else
  300.                 decal.Face = Enum.NormalId.Bottom
  301.             end
  302.         end
  303.        
  304.         HeathStatus.Value = 3
  305.         Health.Value = 3
  306.        
  307.         -- again, this may be scraped soon
  308.         DestroyByRocket.Parent = part
  309.         DestroyByRocket.Enabled = true
  310.    
  311.         placeSound.Parent = part
  312.         placeSound:Play()
  313.        
  314.         part.Size = Vector3.new(3,3,3)
  315.         part.Name = "BuildingBlock"
  316.         part.Anchored = true
  317.         part.Parent = game.Workspace:WaitForChild("Builds")
  318.         print(pos)
  319.         part.Position = pos
  320.         task.wait(0.085)
  321.         cooldown = false
  322.     end
  323. end)
  324.  
  325.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement