Closest Point to player on Top Surface

I want to make a custom movement engine, and to make a good jumping system, I want to get the closest vector to the player that is also on the “top-est” face within a part. You can see what I mean on the screenshots below. Red is the vector that should ideally be returned




Is there some algorithm that does this?

2 Likes

Ignoring my last attempt… maybe try…
Local Distance = (Player.HumanoidRootPart.Position - Part.Position)
Distance = (math.clamp(Distance.X, Part.Position.X-(Part.Size.X/2), Part.Position.X+(Part.Size.X/2), THEN Y AND Z in same pattern yk)

Then red dot.position = Distance … I think that could work.

My math ig:
PlrRootPos = vector3.new(0,0,0)
Part.Position = vector3.new(-1, 0, 1)
Part.Size = vector3.new(2,2,2)
Distance = vector3.new(1, 0, -1)

Then multiply that distance by the part’s CFrame like this:
Idk = part.CFrame * CFrame.new(Distance)

(Keep in mind I’m just bored and not qualified :slight_smile:

3 Likes

Here’s a function (getClosestPointOnTopFace) for this and the code I used to test the function. It converts the HumanoidRootPart’s position to the part’s local space, clamps it and converts the result back to world space. I used vector:Dot(Vector3.FromAxis(axis)) instead of vector[axis.Name] because strict type checking doesn’t like dynamic property accesses.

--!strict
local RunService = game:GetService("RunService")
local Players = game:GetService("Players")

local function getNormalIdForTopFace(part: Part): Enum.NormalId
	local greatestY: number = 0
	local normalIdWithGreatestY: Enum.NormalId
	for _, normalId: Enum.NormalId in Enum.NormalId:GetEnumItems() do
		local y: number = part.CFrame:VectorToWorldSpace(Vector3.FromNormalId(normalId)).Y
		if y > greatestY then
			greatestY = y
			normalIdWithGreatestY = normalId
		end
	end
	return normalIdWithGreatestY
end

local function getClosestPointOnTopFace(pos: Vector3, part: Part): Vector3
	local topFaceNormalId: Enum.NormalId = getNormalIdForTopFace(part)
	
	local normalAxisValue = topFaceNormalId.Value % 3
	local axisEnumItems: {Enum.Axis} = Enum.Axis:GetEnumItems()
	local otherAxis1: Enum.Axis = axisEnumItems[(normalAxisValue + 1) % 3 + 1]
	local otherAxis2: Enum.Axis = axisEnumItems[(normalAxisValue + 2) % 3 + 1]
	
	local normalVector: Vector3 = Vector3.FromNormalId(topFaceNormalId)
	local otherAxis1Vector: Vector3 = Vector3.FromAxis(otherAxis1)
	local otherAxis2Vector: Vector3 = Vector3.FromAxis(otherAxis2)

	local relativePos: Vector3 = part.CFrame:PointToObjectSpace(pos)
	local closestPointInPartSpace: Vector3 =
		.5 * math.abs(part.Size:Dot(normalVector)) * normalVector
		+ math.clamp(relativePos:Dot(otherAxis1Vector), -.5 * part.Size:Dot(otherAxis1Vector), .5 * part.Size:Dot(otherAxis1Vector)) * otherAxis1Vector
		+ math.clamp(relativePos:Dot(otherAxis2Vector), -.5 * part.Size:Dot(otherAxis2Vector), .5 * part.Size:Dot(otherAxis2Vector)) * otherAxis2Vector
	return part.CFrame:PointToWorldSpace(closestPointInPartSpace)
end

local char: Model = Players.PlayerAdded:Wait().CharacterAdded:Wait()

local part: Part = Instance.new("Part")
part.Name = "TopFaceClosestPointTestPart"
part.BottomSurface = Enum.SurfaceType.Smooth
part.Anchored = true
part.Orientation = 360 * Vector3.new(math.random(), math.random(), math.random())
part.Size = Vector3.new(16, 4, 8)
part.Position = Vector3.new(-10, 8, -20)
part.Parent = workspace

local closestPointAttachment: Attachment = Instance.new("Attachment")
closestPointAttachment.Name = "ClosestPointAttachment"
closestPointAttachment.Visible = true
closestPointAttachment.Parent = part

RunService.PostSimulation:Connect(function()
	closestPointAttachment.Position = part.CFrame:PointToObjectSpace(getClosestPointOnTopFace((char:FindFirstChild("HumanoidRootPart") :: Part).Position, part))
end)
5 Likes

Thanks! This worked just how I wanted!

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