How to make a part always be on the ground

I’m trying to make some kind of 3D crosshair that is always in front of the player and touching the ground (Like in pikmin, for example), but the crosshair is always is always floating. I don’t know how to fix this, please help!

Script (LocalScript)

local cursor = game:GetService("ReplicatedStorage").Cursor:Clone()
cursor.Parent = workspace
cursor.CanCollide = false
cursor.Transparency = 0
local players = game:GetService("Players")
players.LocalPlayer.CharacterAppearanceLoaded:Wait()
local playerchar = players.LocalPlayer.Character
local root = playerchar.HumanoidRootPart

local runservice = game:GetService("RunService")

local high = 10

local function SetCFrame()
	cursor.CFrame = root.CFrame * CFrame.new(0, high, -10)
end

local function raycastdown()
	local rayOrigin = cursor.Position
	local rayDirection = cursor.CFrame.UpVector * -300

	-- Build a "RaycastParams" object and cast the ray
	local raycastParams = RaycastParams.new()
	raycastParams.FilterDescendantsInstances = {cursor,
		root.Parent
	}
	raycastParams.FilterType = Enum.RaycastFilterType.Blacklist
	local raycastResult = workspace:Raycast(rayOrigin, rayDirection, raycastParams)
	
	return raycastResult
end


game:GetService("RunService").RenderStepped:Connect(function()
	local result = raycastdown()
	if result then
		high = result.Position.Y
	end
	SetCFrame()
end)

By the way, If you know how to make the crosshair ignore models with a humanoid inside, that would also be very helpful!

2 Likes

It would be nice if you showed us a screenshot or recording of the problem. We’re not robots and we can’t magically fix your problem with a lack of data.


Okay, but I don’t think this adds too much data…

1 Like

What is this high variable? :thinking:

the initial Y position, just to make sure the crosshair doesn’t appear under the ground, and make the raycast never touch anything.

10 studs high for a flat little disc? You sure about that?

Changed it to 1, disc is still floating as high as before.

Oops, I didn’t see that high was actually the variable being changed by the Raycast. But the issue still stems from that SetCFrame function.

root is the HumanoidRootPart of the player, which is conveniently also always floating above the surface. You can see for yourself by selecting the HumanoidRootPart in the explorer and looking for the blue outline.

Instead of raycasting directly below the player, you should raycast precisely where the crosshair should be. That means offsetting the original rayOrigin to be in front of the player. And then you just need to position the crosshair at exactly where that ray hit and orient it to be perpendicular to the surface normal to align it to the surface.

Can’t quite understand it, can you simplify the explanation, please?

1 Like

bro just raycast at where the crosshair should be
I expected protogens to be smart

local offset: CFrame = CFrame.new(0, 50, -10) --we go up just in case the player is on a slope or smth
local rcp: RaycastParams = RaycastParams.new()
rcp.FilderDescendantsInstances = {cursor, root.Parent}
rcp.FilterType = Enum.RaycastFilterType.Blacklist
local down: Vector3 = Vector3.yAxis * -1e2
local angle: CFrame = CFrame.Angles(math.rad(90), 0, 0) --this is probably wrong

local function raycastDown()
  local ray: RaycastResult = workspace:Raycast(root * offset, down, rcp)
  if ray then
    cursor.CFrame = CFrame.lookAt(ray.Position, ray.Position + ray.Normal) * angle
  end
end

5 Likes

Bro no need to be mean, I’m not that bright I know, and i’m still learning, I’ve started programming like 2 weeks ago.

4 Likes

He is starting where the cursor should be. The Origin is the cursor. Also, if you can’t say something positive, just shut up

1 Like

Ok I guess sarcasm just literally doesn’t exist on DevForum

There are plenty of tutorials on raycasting and on vectors in general

This one talks about normals:

Thanks for the help, but nothing works, or at least my brain isn’t the one working.

@KevinElCubo847 he actually showed it right in the picture. You should raycast to the floor from the top, then get touch position and place the cross to there

1 Like

Nvm the script was broken so I modified it and now it works thanks I guess!

(Accidentally replied to myself and devforum is now telling me to change the message bc it is too simillar)

There’s a problem, though. The crosshair always faces the same direction.

I thought I mentioned something in my previous reply about aligning the crosshair with the ground? Or is the issue that it is trying to align, just not correctly?

I made a demo if u want
3dcrosshairthiny.rbxl (39.1 KB)

5 Likes

What I meant is that the crosshair has an arrow-like shape, and the arrow is supposed to point the direction the player is facing.
This is what I mean with always facing the same direction:


The extrusion on the cursor always points at the same direction.