Grid Snap stops after hovering over a part

Hey! I’ve gotten this code after learning some help about however, I got a main issue with placing them where they connect on the side instead of go off a stud-distance.

So far the issue is like this:


Screenshot 2022-06-01 104812

The Code:

local GridPlacementSettings = {Studs = 4, BuildZone = nil, Allowed = false};
local PlacementViewPart = nil

local Player = game:GetService("Players").LocalPlayer
local UserInputService = game:GetService("UserInputService")

local Camera = game:GetService("Workspace").CurrentCamera
local Mouse = Player:GetMouse()

local PlacementPosition = Vector3.new(0, 0, 0)

local RunService = game:GetService("RunService");
local TweenService = game:GetService("TweenService");
RunService.Heartbeat:Connect(function()
	if PlacementViewPart ~= nil then
		if GridPlacementSettings.Allowed then
			local Params = RaycastParams.new()
			local Array = {PlacementViewPart}
			for _, Players in pairs(game:GetService("Players"):GetPlayers()) do
				if Players.Character then
					table.insert(Array, Players.Character)
				end
			end			
			Params.FilterDescendantsInstances = Array
			Params.FilterType = Enum.RaycastFilterType.Blacklist
			
			local MousePosition = UserInputService:GetMouseLocation()
			
			local UnitRay = Camera:ScreenPointToRay(MousePosition.X, MousePosition.Y)
			local Result = game:GetService("Workspace"):Raycast(UnitRay.Origin, UnitRay.Direction * 500, Params)
			if Result and Result.Instance then
				local RoundedPosition = Vector3.new (math.round (Result.Position.X / GridPlacementSettings.Studs) * GridPlacementSettings.Studs, 
					Result.Position.Y,
					math.round(Result.Position.Z / GridPlacementSettings.Studs) * GridPlacementSettings.Studs
				)
				
				PlacementPosition = RoundedPosition + Result.Normal * (PlacementViewPart.Size / 2)
				
				PlacementViewPart.Position = RoundedPosition + Result.Normal * (PlacementViewPart.Size / 2)
				PlacementViewPart.Parent = workspace
			end
		end
	end
end)

UserInputService.InputBegan:Connect(function(Input)
	if Input.KeyCode == Enum.KeyCode.E then
		if not GridPlacementSettings.Allowed then
			if game:GetService("ReplicatedStorage"):FindFirstChild("GrassBlock") then
				PlacementViewPart = game:GetService("ReplicatedStorage").GrassBlock:Clone()
				PlacementViewPart.CanCollide = false
				
				local NewHighlight = Instance.new("Highlight")
				NewHighlight.FillColor = Color3.fromRGB(0, 255, 0)
				NewHighlight.FillTransparency = .7
				NewHighlight.Parent = PlacementViewPart
				
				GridPlacementSettings.Allowed = true
			end
		end
	elseif Input.KeyCode == Enum.KeyCode.C then
		if GridPlacementSettings.Allowed and PlacementViewPart ~= nil then
			GridPlacementSettings.Allowed = false
			
			TweenService:Create(PlacementViewPart, TweenInfo.new(.25), {Size = Vector3.new(0, 0, 0)}):Play()
			game:GetService("Debris"):AddItem(PlacementViewPart, .25)
		end
	elseif Input.UserInputType == Enum.UserInputType.MouseButton1 then
		if PlacementViewPart ~= nil then
			GridPlacementSettings.Allowed = false

			local Placement = PlacementPosition;
			local Block = game:GetService("ReplicatedStorage").GrassBlock:Clone()
			
			Block.Parent = workspace
			Block.Position = Placement
		end
	end
end)
2 Likes

Thats because you arent snapping the Y.

oh im not? lol sorry i’m such a rookie on this, let me try looking into it for a moment.

Nope unfortunately it’s not, I tried snapping the Y axis and it didn’t connect.

Image:
Screenshot 2022-06-01 105952

I didn’t consider this type of use case for the code that I had provided in the previous thread. I did some debugging on it and figured out the issue, as well as a fix for the code in order to make it work as you want it to.

I’ll post the full script that I created so you can test it on your end.

local UserInputService = game:GetService ("UserInputService")

local Player = game:GetService ("Players").LocalPlayer
local Camera = workspace.CurrentCamera
local SnapDistance = 2
local Part

local Params = RaycastParams.new ()
Params.FilterType = Enum.RaycastFilterType.Blacklist

local UpVector = Vector3.new (0, 1, 0)

function AdjustPosition ()
	local mouseLocation = UserInputService:GetMouseLocation ()

	local unitRay = Camera:ScreenPointToRay (mouseLocation.X, mouseLocation.Y)
	local result = workspace:Raycast (unitRay.Origin, unitRay.Direction * 500, Params)
	
	if result and result.Instance then
		-- Placing on the sides requires a different position calculation
		if result.Normal ~= UpVector and result.Normal ~= -UpVector then
			Part.Position = result.Instance.Position + (result.Normal * Part.Size)
			return
				
		end
		
		-- Placing above or below uses the same position calculation as before
		local roundedPosition = Vector3.new (math.round (result.Position.X / SnapDistance) * SnapDistance,
			math.round (result.Position.Y / SnapDistance) * SnapDistance,
			math.round (result.Position.Z / SnapDistance) * SnapDistance)
		
		
		Part.Position = roundedPosition + (result.Normal * Part.Size / 2)
	end
end

UserInputService.InputChanged:Connect (function (input, gameProcessed)
	if gameProcessed or input.UserInputType ~= Enum.UserInputType.MouseMovement or not Part then
		return
			
	end
	
	AdjustPosition ()	
end)

UserInputService.InputBegan:Connect (function (input, gameProcessed)
	if gameProcessed then
		return
			
	end
	
	if input.UserInputType == Enum.UserInputType.MouseButton1 and Part then
		Part = nil
		
	elseif input.UserInputType == Enum.UserInputType.MouseButton2 and not Part then
		Part = Instance.new ("Part")
		Part.Size = Vector3.one * 2
		Part.BrickColor = BrickColor.Random ()
		Part.Anchored = true
		Part.Parent = workspace

		Params.FilterDescendantsInstances = {Player.Character, Part}

		AdjustPosition()
	end
end)

The only real change that I implemented was the position calculation, which you can see here.

if result and result.Instance then
		-- Placing on the sides requires a different position calculation
		if result.Normal ~= UpVector and result.Normal ~= -UpVector then
			Part.Position = result.Instance.Position + (result.Normal * Part.Size)
			return
				
		end
		
		-- Placing above or below uses the same position calculation as before
		local roundedPosition = Vector3.new (math.round (result.Position.X / SnapDistance) * SnapDistance,
			math.round (result.Position.Y / SnapDistance) * SnapDistance,
			math.round (result.Position.Z / SnapDistance) * SnapDistance)
		
		
		Part.Position = roundedPosition + (result.Normal * Part.Size / 2)
	end

The results from these changes allows the creation of intricate structures, which I highlight here.

2 Likes

Oh thank you lol! This is exactly what I needed, I’m not very good with raycasting so this is starter experience for me, however I’ve gotten it to work with the new code you’ve changed :slight_smile: Thank you!

1 Like