Why is this touch event acting weirdly?

you need to apply the if statement to both functions this was an example

And to be sure i added another check

if hit.parent findblablabla and not hit:IsDescendantOf(ToolModel) and hit ~= ToolModel then

The nature of your desired effect and the fact that this is client-sided, the code you made is missing quite a few steps.

  1. You would want to query if there are still humanoid models inside the part whenever Touched and TouchEnded gets fired. Otherwise, the latest event overrides the water color, regardless if there are still humanoid models in it.
  2. Since this is client-sided, by default (unless switched off), your game is subject to streaming. To save on memory, parts will stream in and out (disappear and appear) around you that is based on the player’s hardware and settings. To account for that, we use CollectionService to listen for those streaming parts. We connect when it streams in, we disconnect when it streams out.
    The reason why this is important because the change water part may not exist, and the script will throw an error.

Below is the revised code you should place in StarterPlayerScripts, along with explanations that you should read. Make sure you tag the part that changes water with the CHANGE_WATER_TAG listed in the script.

--!strict

-- define services
local CollectionService = game:GetService("CollectionService")
local TweenService = game:GetService("TweenService")
local Terrain = workspace.Terrain

-- define settings
local CHANGE_WATER_TAG: string = "ChangeWater"
local TWEEN_INFO: TweenInfo = TweenInfo.new(1, Enum.EasingStyle.Linear)
local RED_PROPERTIES: {[string]: any} = {WaterColor = Color3.fromRGB(255, 0, 4)}
local BLUE_PROPERTIES: {[string]: any} = {WaterColor = Color3.fromRGB(12, 84, 92)}
local RED_TWEEN: Tween = TweenService:Create(Terrain, TWEEN_INFO, RED_PROPERTIES)
local BLUE_TWEEN: Tween = TweenService:Create(Terrain, TWEEN_INFO, BLUE_PROPERTIES)

-- main script
local touching: boolean = false
local connections: {[Instance]: {RBXScriptConnection}} = {}

-- function to detect if a part has a humanoid model in it.
-- we use this whenever Touched and TouchEnded gets fired.
local function hasHumanoidInPart(part: BasePart): boolean
	for _: number, touchingPart: Part in workspace:GetPartsInPart(part) do
		if (touchingPart.Parent :: Instance):FindFirstChildOfClass("Humanoid") ~= nil then
			return true
		end
	end
	
	return false
end

-- instance added listener for CHANGE_WATER_TAG.
-- connects if the part has been added/streamed in.
local function onInstanceAdded(instance: Instance): ()
	if instance:IsA("BasePart") == true and connections[instance] == nil then
		-- create connections for instance to disconnect later
		-- to prevent memory leaks.
		connections[instance] = {}
		
		-- if the touching variable is not true and we detect a humanoid model
		-- inside the part, we flip that touching variable to true and play
		-- the red tween. we decided to include the debounce variable of touching
		-- for 2 reasons:
		
		-- 1. the red tween smoothly tweens without it firing multiple times
		-- from multiple touches.
		
		-- 2. we minimize the amount of spatial query by only checking if it's
		-- not active.
		table.insert(connections[instance], (instance :: BasePart).Touched:Connect(function(hit: BasePart): ()
			if touching == false and hasHumanoidInPart(instance :: BasePart) == true then
				touching = true
				
				RED_TWEEN:Play()
			end
		end))
		
		-- same thing as above, but in reverse.
		table.insert(connections[instance], (instance :: BasePart).TouchEnded:Connect(function(hit: BasePart): ()
			if touching == true and hasHumanoidInPart(instance :: BasePart) == false then
				touching = false
				
				BLUE_TWEEN:Play()
			end
		end))
	end
end

-- instance removed listener for CHANGE_WATER_TAG.
-- disconnects if the part has been destroyed/streamed out
-- to prevent memory leaks.
local function onInstanceRemoved(instance: Instance): ()
	if connections[instance] ~= nil then
		for _: number, connection: RBXScriptConnection in connections[instance] do
			connection:Disconnect()
		end
		
		table.clear(connections[instance])
		connections[instance] = nil
	end
end

-- bind signals to listener functions, listening for any
-- future instances getting added.
CollectionService:GetInstanceAddedSignal(CHANGE_WATER_TAG):Connect(onInstanceAdded)
CollectionService:GetInstanceRemovedSignal(CHANGE_WATER_TAG):Connect(onInstanceRemoved)

-- we want to add any parts that might already exist, so we
-- loop though every existing tagged part and manually fire.
for _: number, instance: Instance in CollectionService:GetTagged(CHANGE_WATER_TAG) do
	task.spawn(onInstanceAdded, instance)
end
2 Likes

Thank you very much, your explanation was very concise and helpful.

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