Scripting Helpers is winding down operations and is now read-only. More info→
Ad
Log in to vote
0

How do you make a tracking part that sticks to a surface?

Asked by 6 years ago
Edited 6 years ago

https://www.roblox.com/games/652948132/Kingdom-Chaos-Grand-Opening In this game there's a mechanic allowing for a ring to appear directly below where ever the player stands, floating on the surface of the part beneath said player. How has he done it?

The X and Z are easy considering it follows the character, but what about the Y? A use of raycasting can get what ever is below but how did he get the surface? For instance, a part may be rotated causing so that the "top surface" isn't what you would expect anymore, infact the "top surface" may be pointing downwards depending on how it's rotated.

(TL;DR How would you make get the Y axis of the part's surface, despite it's rotation?)<<

I actually need something like this for a health bar, doing the bar is easy but the placement confuses me as it is flat upon the ground, and my mind is boggled on how it still runs so quickly in the Kingdom Chaos game.

Help is extremely appreciated.

Gyazo #1: https://gyazo.com/1775b21f95329791a2d4a51e01ce9e48

Gyazo #2: https://gyazo.com/9261434b10f27b3faf20797ad90f59f3

Here's what I was thinking at first:

local Player = game.Players.LocalPlayer repeat wait() until Player.Character~=nil local Character = Player.Character local Ring = game.ReplicatedStorage.ItsTheTag:clone() Ring.Parent = Character Ring.Anchored = true

Ring.CanCollide = false

local IGHM = {} local Back = Platform.CFrame * CFrame.new(0, 0, (Platform.Size.Z/2)) * CFrame.Angles(3.14, 0, 0).p IGHM[1] = Back local Front = Platform.CFrame * CFrame.new(0, 0, -(Platform.Size.Z/2)) * CFrame.Angles(3.14, 0, 0).p IGHM[2] = Front local Side1 = Platform.CFrame * CFrame.new(-(Platform.Size.X/2), 0, 0) * CFrame.Angles(3.14, 0, 0).p IGaveHerSheGotMad[3] = Side1 local Side2 = Platform.CFrame * CFrame.new(-(Platform.Size.X/2), 0, 0) * CFrame.Angles(3.14, 0, 0).p IGHM[4] = Side2 local Top = Platform.CFrame * CFrame.new(0, (Platform.Size.Y/2), 0) * CFrame.Angles(3.14, 0, 0).p IGHM[5] = Top local Bottom = Platform.CFrame * CFrame.new(0, -(Platform.Size.Y/2), 0) * CFrame.Angles(3.14, 0, 0).p

IGHM[6] = Bottom

for i = 1, 6 do --[[Here I would try to see which surface is closest to the player and choose that to sort out what the Y axis would be with several if statements, for instance: "if Back.Y>IGaveHerSheGotMad[i].Y then" "elseif Front.Y>IGaveHerSheGotMad[i].Y then" etc, but then I realized something, if it's a very small part then that would mess it up if you're standing somewhat to the side, plus the game im drawing the inspiration from doesen't have that type of issue, so surely i'm going about this wrong ]] end

game:GetService('RunService').RenderStepped:connect(function() Update()

end)

The main goal was to basically fill in the Y, but then I thought to myself, there has to be a quicker, less laggier way to do this right? What is it they did that i'm not doing?<<

Ring.CFrame = CFrame.new(Character.HumanoidRootPart.Position.X, ???, Character.HumanoidRootPart.Position.Z)

1 answer

Log in to vote
1
Answered by
Newrown 307 Moderation Voter
6 years ago
Edited 6 years ago

You can use Raycasting and FindPartOnRayWithIgnoreList to be able to get the position easily.

There are many ways to do this, one way is to cast a ray from the HumanoidRootPart of the character in the negative Y direction.

We are going to use the first two parameters of the FindPartOnRayWithIgnoreList, which return the part that has intersected the ray, and the position it intersects it at, respectively.

So it would look something like this:

repeat wait() until game.Players.LocalPlayer.Character

local player = game.Players.LocalPlayer
local character = player.Character
local runService = game:GetService("RunService")

local ignoreList = {}

function fillIgnoreList(character)
    for i, v in pairs(character:GetChildren()) do 
        if v.Parent:FindFirstChild("Humanoid") then
            table.insert(ignoreList, v) -- ignore all parts that are under a model with a humanoid
        end
    end
end

local trackingPart = Instance.new("Part") -- the tracking part that will be under the character
trackingPart.CanCollide = false
trackingPart.Anchored = true
trackingPart.Parent = character

fillIgnoreList(character) -- fill the ignore list with all the parts that have to be ignored if they intersect the ray

runService.RenderStepped:connect(function()  -- update every 1/60 of a second
    local ray = Ray.new(character.HumanoidRootPart.Position, Vector3.new(0, -1, 0) * 100)
    local hit, position = workspace:FindPartOnRayWithIgnoreList(ray, ignoreList)
    trackingPart.CFrame = CFrame.new(position)
end)

Hope it helped!

Ad

Answer this question