Building System Help

  1. What do you want to achieve?
    A building system that enables you to build horizontally (or any direction other than vertical) by having your mouse hover over another part.

  2. What is the issue?
    Normally, people would use ray normals to achieve this, but i would like it to also work on rotated parts (which results in a long string of decimals for its normal).

  3. What solutions have you tried so far?
    I have spitballed some random math and such and tried completely different systems, but they do not work properly.

Thank you!

1 Like

But what’s the issue? Are you asking for a whole system? Provide code if you need help with that.

local ReplicatedStorage = game:GetService('ReplicatedStorage')
local RunService = game:GetService('RunService')

local Server = {} Server.__index = Server
local Client = {} Client.__index = Client

local function CanculatePos<V: Vector3>(BoxSize: V, origin: V, mouseHit: V): Vector3?
   local MouseDir = (origin - mouseHit).Unit
   
   local RayResult = workspace:RayCast(origin, MouseDir*50)
   if not RayCast and then return end
   
   return RayResult.Position + BoxSize*RayResult.Normal/2
end

function Server:Build(mouseHit: Vector3)
   if (self.char.Head.Position - mouseHit).Magnitude > 50 then return end

   local Position = CanculatePos(
     Vector3.One, 
     self.char.Head,
     mouseHit)
   
   if not Position then return end
   
   local Part = Instance.new('Part')
   Part.Size = Vector3.One 
   Part.Anchored = true
   Part.Position = Position
   Part.Parent = workspace
end

function Client:Start()
   if self.Started then return end
   self.Started = true
     
   self.VisualPart.Parent = workspace
   self.RenderTheard = RunService.RenderStepped:Connect(function()
      self.VisualPart.Position = CanculatePos(
         Vector3.One, 
         self.char.Head,
         self.mouse.Hit.Position) or Vector3.zero
   end)
end

function Client:Stop()
   self.VisualPart.Parent = ReplicatedStorage
   self.RenderTheard:Disconnect()
   self.Started = false
end

function Client:Build()
   self.RemoteEvent:FireServer(self.mouse.Hit.Position)
end

local InitClient = function(Player: Player, OnBuild: RemoteEvent)
   local self = setmetatable({}, Constructor)
   
   self.RenderTheard = nil :: RBXScriptSignal
   
   self.plr = Player 
   self.mouse = plr:GetMouse()
   self.char = plr.Character or plr.CharacterAdded:Wait()

   self.RemoteEvent = OnBuild
   
   self.Started = false
   self.VisualPart = (function()
      local Part = Instance.new('Part')
      Part.Size = Vector3.One 
      Part.Anchored = true
      Part.Transparency = .5
      
      Part.Parent = ReplicatedStorage
      
      return Part
   end)()
   
   return self
end

local InitServer = function(Player: Player, OnBuild: RemoteEvent)
   local self = setmetatable({
     char = Player.Character or Player.CharacterAdded:Wait()
   }, Server)
   
   OnBuild.OnServerEvent:Connect(function(plr: Player, mouseHit: Vector3)
      self:Build(mouseHit)
   end)
   return self 
end

return {InitClient = InitClient, InitServer = InitServer}

Thank you for taking the time to write that! Would you mind providing an additional explanation of the code? It is far more advanced than what I am used to, so I would greatly appreciate further elaboration. Thank you! :))