Checking if two parts /remain/ touching after a period of time before awarding a badge

I have a basic script that detects if two parts touch, which when they do, awards everyone in the server a badge. However, I’m making a variant meant to give players a badge when a car is firmly stuck in another part.

I figured the simple way to do this was to set a true/false to whether or not the parts were touching after a certain period of time, but I’m not sure how to format this.

Here’s my script currently (note “[BADGE]” is properly filled in, it’s just a placeholder for the forum):

local part = script.Parent
local otherPart = game.Workspace.Jeep2
local BadgeService = game:GetService("BadgeService")
local badgeid = [BADGE]
local IsCarStuck = false

local function onPartTouched(otherPart)
	print(part.Name .. " has touched " .. otherPart.Name)
	wait(2)
	-- check if part is still touching otherPart
	-- if the parts are still touching then
		local IsCarStuck = true
	-- end?
	if IsCarStuck == true then
		local players = game:GetService("Players"):GetPlayers()
		for i,v in pairs(players) do
		BadgeService:AwardBadge(v.UserId, badgeid)
		end
	end
	wait(1) -- debounce
	local IsCarStuck = false
end
	
part.Touched:Connect(onPartTouched)

Help’s appreciated!

https://developer.roblox.com/en-us/api-reference/function/WorldRoot/ArePartsTouchingOthers

2 Likes

Could use overlap params, they’re like rays but for checking if two parts are in one another. You also could just wait if the velocity of said object is 0, therefore stuck.

But wouldn’t overlap params still reward the badge if the parts were touching, since they have a tendency to even slightly overlap?

Velocity wouldn’t cut it either, since very often we end up with cars on top of the part rather then stuck inside it, and if a car were to stop on top of the part the badge would still get awarded.

Oh boy I don’t know what any of this means!
How does this function any different than onTouched anyway, other than having an area of ignorance? How would I even find a good number for that area anyway?

I’m a little confused of what your end goal is. You want two parts to touch and if they remain in contact for a certain amount of time it awards a badge?

Yes! Precisely this.
This safety net of the items needed to touch for a certain amount of time will make sure normal bumps against the part do not award the badge.

Another way you can make this is by getting if the part touches the part you want it to stick to, log its position start a loop checking its distancing from where it originally touched it. Then make a variable with either tick() or time() and then have the loops condition if the time exceeds how long you wanted it to stay or if it moved too far. Once the loop is broken check time() or time() subtracted from ur variable. Blamo you got a check for if a part sticks.

I’m trying to figure out how to script this and I can’t seem to figure it out using basic loops. I’m still a bit new to loops in Lua.

I know I’ll have to measure the magnitude of the parts using (part.Position - otherPart.Position).Magnitude and then write if conditions in the loop that check the magnitude of part to otherPart for a valid magnitude that will set IsCarStuck to true, but the rest I’m unsure how to write.

It’d be something like this:

part.Touched:connect(function(hit)
     local originalPos = hit.Position
     local startTime = time()

     repeat
           task.wait()
     until time()-startTime >= 2 --[[this is just 2 seconds]] or (hit.Position-originalPos).Magnitude >= 5

     if time()-startTime >= 2 then
         --reward badge
     end
end)

On touch, you log the parts position immediately and set a variable to compare passage of time to. Then loop constantly checking the time and the distance moved from the start.

this doesnt appear to be doing the trick.

incoporating it into my own script (BadgeService items negated for the sake of easy debugging),

local part = script.Parent
local ootherPart = game.Workspace.Jeep1

local function onPartTouched(ootherPart)
	print(part.Name .. " has touched " .. ootherPart.Name)
	local partPos = part.Position
	local otherpartPos = ootherPart.Position
	local startTime = time()
	repeat
		task.wait()
	until time()-startTime >= 8
	
	if time()-startTime >= 8 and (partPos-otherpartPos).Magnitude >= 2 then
		print('car not stuck')
	end
	
	if time()-startTime >= 8 and (partPos-otherpartPos).Magnitude <= 2 then
		print('car is stuck')
		print('badge awarded')
	end
end

part.Touched:Connect(onPartTouched)

when the game initially loads, the console returns “car is not stuck”, which seems correct, right?
however, when the car is actually firmly stuck in part, the console returns “car is not stuck”. not once is “car is stuck” printed.

ive reversed the >= and <= on both if statements to no success- swapping the two results in “car is stuck” and “badge awarded” being printed the second the game loads. using elseif also gives me the same issue.

also, for some reason, the game detects other parts as touching it even though i only want it to react to parts from ootherPart. i thought renaming it would fix it, again to no avail. the game detects a part thats properly attached to part as well as all the parts of a players Humanoid.
im guessing this is a correct function of onPartTouched? but i defined ootherPart as what i want it to detect, so i dont know whats up here or how to fix it.
this isnt really my problem though, as the prints do only react to ootherPart as i want them too, so ignore this if you want.

are my and statements not the right statements to use? should i swap one or both for or? my worry is that, again, this will negate one of the two variables this requires for the badge to be properly given.

im really stumped.

i tried working out a new version of the initial script to see if what im trying to do makes any more sense. i just wanna see if part a is stuck in part b and reward a badge if so.

local part = script.Parent
local otherPart = game.Workspace.Jeep1
local partPos = part.Position
local otherpartPos = otherPart.Position
local magni = (partPos-otherpartPos).Magnitude

local function onPartTouched(otherPart)
	local startTime = time()
	local timerUp = false
	repeat
		task.wait()
	until time()-startTime >= 8
end

if time()-startTime >= 8 then
	local timerUp = true
end

if timerUp == true then
	if magni <= 2 then
		print('car is stuck')
		print('badge awarded')
	else
		print('car not stuck')
	end
end

i really dont know what to do, ill try asking elsewhere, but let me know if you come up with anything.

In regards to your bottom script:
You define otherPart, but then immediately redefine it in the function
Also, the end statement after the repeat until should be at the end. The other things are never gonna fire

I’d recommend writing it like this:

local part = script.Parent
local otherPart = game.Workspace.Jeep1
local partPos = part.Position
local otherpartPos = otherPart.Position
local magni = (partPos-otherpartPos).Magnitude

local function onPartTouched(otherPart)
	local startTime = time()
	repeat
		task.wait()
        magni = (partPos-otherpartPos).Magnitude
	until time()-startTime >= 8 or magni >= 2
    if time()-startTime < 8 then
        print('car not stuck')
    else
        print('car is stuck')
        print('badge awarded')
    end
end

I think it may not work because you’re not putting the checks in the function. So it’s running on start and not rechecking. Then again I have no clue how that script is set up, I’m just going off what you have posted.