How to make a raycast placement in a isometric camera?

As the title says, how I implement a grid positioning system having an isometric camera, as the viewport raycast is not possible as the camera is fixed on one of the axes.

My Code:

local Players = game:GetService("Players")
local RunService = game:GetService("RunService")
local SoundService = game:GetService("SoundService")
local UserInputService = game:GetService("UserInputService")
local ReplicatedStorage = game:GetService("ReplicatedStorage")

local Player = Players.LocalPlayer
local Character = Player.Character or Player.CharacterAdded:Wait()
local Mouse = Player:GetMouse()
local Camera = game.Workspace.CurrentCamera
local Assets = ReplicatedStorage:WaitForChild("Assets")
local PreviewPart = Assets.PreviewPart

local Zoom = 150
local FoV = 7
local preview = nil
local PlayerController = {}

local function CreatePreviewPart()
	preview = PreviewPart:Clone()
	preview.Parent = workspace
end

local function RenderPreview()
	
end

function PlayerController:Init()
	local controls = require(Player:WaitForChild("PlayerScripts"):WaitForChild("PlayerModule")):GetControls()
	controls:Disable()
	
	self:EnableCustomMovement()
	CreatePreviewPart()
	
	Camera.CameraType = Enum.CameraType.Custom
	RunService.RenderStepped:Connect(function()
		Camera.FieldOfView = FoV
		if Character then
			if Character:FindFirstChild("Head") then
				SoundService:SetListener(Enum.ListenerType.ObjectCFrame, Character.Head)
				Camera.CFrame =
					CFrame.new(Vector3.new(Character.Head.Position.X + Zoom, Character.Head.Position.Y + Zoom, Character.Head.Position.Z + 100), Character.Head.Position)
			end
		end
	end)
	RunService:BindToRenderStep("Preview", Enum.RenderPriority.Camera.Value, RenderPreview)
end

function PlayerController:EnableCustomMovement()
	Mouse.Button1Down:Connect(function()
		print("Move to Position")
	end)
end

return PlayerController
2 Likes

What do you mean by this? Raycast works perfectly fine. Get the raycast position/direction from Camera:ViewportPointToRay().

1 Like

You literally showed us the entirely wrong script, you need help with the grid placement but you sent us your character controller

Sorry for not explaining it correctly. The part created with CreatePreviewPart should be correctly aligned to the ground in RenderPreview().

Full Code (As I had previously deleted the old RenderPreview code, it is not aligned in a grid but if I can solve this, aligning it in a grid is easy):

local Players = game:GetService("Players")
local RunService = game:GetService("RunService")
local SoundService = game:GetService("SoundService")
local UserInputService = game:GetService("UserInputService")
local ReplicatedStorage = game:GetService("ReplicatedStorage")

local Player = Players.LocalPlayer
local Character = Player.Character or Player.CharacterAdded:Wait()
local Mouse = Player:GetMouse()
local Camera = game.Workspace.CurrentCamera
local Assets = ReplicatedStorage:WaitForChild("Assets")
local PreviewPart = Assets.PreviewPart

local Zoom = 150
local FoV = 7
local preview = nil
local PlayerController = {}

local function CreatePreviewPart()
	preview = PreviewPart:Clone()
	preview.Parent = workspace
end

local function RenderPreview()
	local mousePos = UserInputService:GetMouseLocation()
	local unitRay = Camera:ViewportPointToRay(mousePos.X, mousePos.Y)
	local rayCast = workspace:Raycast(unitRay.Origin, unitRay.Direction * 1000)
	if rayCast and preview then
		preview.Position = rayCast.Position
	end
end

function PlayerController:Init()
	local controls = require(Player:WaitForChild("PlayerScripts"):WaitForChild("PlayerModule")):GetControls()
	controls:Disable()
	
	self:EnableCustomMovement()
	CreatePreviewPart()
	
	Camera.CameraType = Enum.CameraType.Custom
	RunService.RenderStepped:Connect(function()
		Camera.FieldOfView = FoV
		if Character then
			if Character:FindFirstChild("Head") then
				SoundService:SetListener(Enum.ListenerType.ObjectCFrame, Character.Head)
				Camera.CFrame =
					CFrame.new(Vector3.new(Character.Head.Position.X + Zoom, Character.Head.Position.Y + Zoom, Character.Head.Position.Z + 100), Character.Head.Position)
			end
		end
	end)
	RunService:BindToRenderStep("Preview", Enum.RenderPriority.Camera.Value, RenderPreview)
end

function PlayerController:EnableCustomMovement()
	Mouse.Button1Down:Connect(function()
		print("Move to Position")
	end)
end

return PlayerController

2 Likes

Alright could you tell us the expected behavior?

1 Like


Like this (the white border means the block)

So you want it to snap to that size grid?

Exactly that, but I tried using raycast but it looks as shown in the video so I don’t know how I would do it

How is that grid showed in the screenshot created exactly?

Each block in the grid is a separated part

Yeah but wheres the code you used to actually create the grid and give them different colors

There is no code, they are in the workspace in the grid folder. In this case, my system is to move on the grid, when clicking on the block your character would move there. And it would be a limited space, at the moment each block of the grid is a separate part as I thought it would facilitate the creation of this system.

Oh and about the colors, I left them like this just to make it easier to differentiate between each block

1 Like

Why don’t you just loop through the grid folder and fire a ray using ScreenPointToRay, and then whatever grid part it hits snap to that one?

1 Like

Like this?

local function RenderPreview()
	local mousePos = UserInputService:GetMouseLocation()
	local unitRay = Camera:ScreenPointToRay(mousePos.X, mousePos.Y)
	local hitGridPart = nil

	for _, gridPart in ipairs(workspace.Grid:GetChildren()) do
		local rayCast = workspace:Raycast(unitRay.Origin, (gridPart.Position - unitRay.Origin).unit * 1000)
		if rayCast and rayCast.Instance == gridPart then
			hitGridPart = gridPart
			break
		end
	end

	if hitGridPart and preview then
		preview.Position = hitGridPart.Position
	end
end

If yes, this doesn’t works.
I make a test with this code:

local function RenderPreview()
	local mousePos = UserInputService:GetMouseLocation()
	local unitRay = Camera:ScreenPointToRay(mousePos.X, mousePos.Y)
	local rayCast = workspace:Raycast(unitRay.Origin, unitRay.Direction * 1000)
	if rayCast and preview then
		local hitPart = rayCast.Instance
		print(hitPart)
		if hitPart:IsDescendantOf(workspace.Grid) then
			preview.Position = hitPart.Position
		end
	end
end

Console Log (It’s not printing the part my mouse is on, but parts of the character):

- PlayerController:30
  21:12:16.460  Head  -  Cliente - PlayerController:30
  21:12:16.503  Head  -  Cliente - PlayerController:30
  21:12:16.516  Head  -  Cliente - PlayerController:30
  21:12:16.542  Head  -  Cliente - PlayerController:30
  21:12:16.583  Head  -  Cliente - PlayerController:30
  21:12:16.599  Head  -  Cliente - PlayerController:30
  21:12:16.627  Head  -  Cliente - PlayerController:30
  21:12:16.668  Head  -  Cliente - PlayerController:30
  21:12:16.678  Head  -  Cliente - PlayerController:30
  21:12:16.710  Head  -  Cliente - PlayerController:30
  21:12:16.757  Head  -  Cliente - PlayerController:30
  21:12:16.768  Head  -  Cliente - PlayerController:30
  21:12:16.796  Head  -  Cliente - PlayerController:30
  21:12:16.832  Head  -  Cliente - PlayerController:30
  21:12:16.846  Head  -  Cliente - PlayerController:30
1 Like

I managed to fix it, for those who are still curious about how to do it.

local ReplicatedStorage = game:GetService("ReplicatedStorage")

local player = Players.LocalPlayer
local mouse = player:GetMouse()
local blockTemplate = ReplicatedStorage:FindFirstChild("BlockTemplate") 

local gridSize = 8
local previewBlock = blockTemplate:Clone()
previewBlock.Transparency = 0.5
previewBlock.CanCollide = false
previewBlock.Parent = workspace

local function roundToGrid(value, gridSize)
	return math.floor(value / gridSize + 0.5) * gridSize
end

local function onUpdate()
	local mouseRay = mouse.UnitRay
	local raycastParams = RaycastParams.new()
	raycastParams.FilterDescendantsInstances = {workspace.Grid}
	raycastParams.FilterType = Enum.RaycastFilterType.Include
	raycastParams.IgnoreWater = true

	local raycastResult = workspace:Raycast(mouseRay.Origin, mouseRay.Direction * 1000, raycastParams)
	if raycastResult then
		local hitPos = raycastResult.Position
		local gridPos = Vector3.new(
			roundToGrid(hitPos.X, gridSize),
			roundToGrid(hitPos.Y, gridSize),
			roundToGrid(hitPos.Z, gridSize)
		)
		previewBlock.Position = gridPos
	end
end

RunService.RenderStepped:Connect(onUpdate)

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.