Efficient way to go about coloring section of wall?

So basically, I have this wall segment:
RobloxScreenShot20190116_093106173 RobloxScreenShot20190116_093100917

Which looks like this as a model

Now the point of Primary1 and Primary2 (along with Secondary1 and Secondary2) is to get the different sides of the wall painted a different color.

RobloxScreenShot20190116_093113768
RobloxScreenShot20190116_093125453

However, every other object in the game only use 2 colors (Primary and Secondary)

So my question is, how could I go about making this as efficient as possible?

Here’s the code I use to change the colors of the wall. It technically works, so if you click on the side that is 1, it colors that side only and vice versa. I’m sure there’s a nicer way to write this though? or atleast something more efficient?

function start(player, playersPlot, target, primary, secondary)
	if not target then return end
	
	if target.Parent.Parent ~= playersPlot.Purchases then return end
	
	local model = target.Parent
	if not model then return end
			
	for _, v in pairs(model:GetChildren()) do
		if v.Name == 'Primary'then
			v.BrickColor = primary
		end
		if v.Name == 'Secondary' then
			v.BrickColor = secondary
		end
		if target.Name == 'Primary1' then
			target.BrickColor = primary
			if v.Name == 'Secondary1' then
				v.BrickColor = secondary
			end
		end
		if target.Name == 'Primary2' then
			target.BrickColor = primary
			if v.Name == 'Secondary2' then
				v.BrickColor = secondary
			end
		end
	end
end

Another problem then arises with the saving.

local primaryColor = item:FindFirstChild('Primary').BrickColor.Name
itemData.PrimaryColor = primaryColor

if item:FindFirstChild('Secondary') then
	local secondaryColor = item.Secondary.BrickColor.Name
	itemData.SecondaryColor = secondaryColor
end

This is what I’d normally do, because before every model had a part/multiple parts called Primary, and a few would have Secondary parts. But now with Primary1 and Primary2, I’d have to save each one individually? Would it be best to just go through all the models, and change Primary and Secondary to Primary1 and Secondary1? And then have it save Primary2 and Secondary2 if the model has a second set of colors??

This would be pretty quick and shouldn’t make much of a difference. That being said, to humor you, for the sake of theoretical discussion, and for future reference, there is an easy way to make this decision process faster: don’t do it.

Let me explain…

When you load in a model for the first time, you don’t know a lot about it. If you wanted to color all the parts in there, then you would have to iterate through the structure and find the right parts to color. However, if the player started with nothing and placed parts, then all you have to do is remember the colorable parts so you don’t have to find them later. Even if you are loading in a player’s plot, you could try remembering the colorable parts while the server isn’t busy so that when a large operation needs to be done (like changing thousands of parts colors at once) you don’t need to spend additional time finding those parts.

To implement this I would make a structure to cache information about player plots, if you don’t already have one. In this structure, I’d make two arrays: primaryColorParts and secondaryColorParts. When you want to change colors you can efficiently iterate through them.

You can make a cache for single models if you really wanted too. In the plot cache structure you could make an map using the model as the key to true if the model contains multiple Primary/Secondary parts or false otherwise. Another method of caching with model granularity would be to use the CollectionService to tag models that 1. contain only one Primary and Secondary part and 2. models that contain multiple Primary ans Secondary parts.

1 Like

I have no clue what that meant… but I figured out saving (going with Primary1 Secondary1)

The coloring part is the tricky part now though.

So when you click to paint, it gets all the children of the model right. If there is NOT a Primary2, that means there’s only Primary1 and Secondary1 in the model, so easy, color those in. Problem arises when there is multiple Primary Colors.

for _, v in pairs(model:GetChildren()) do
		if v.Name == 'Primary2' then
			if target.Name == 'Primary1' then
				target.BrickColor = primary
			end
			if target.Name == 'Secondary1' then
				target.BrickColor = secondary
			end
			if target.Name == 'Primary2' then
				target.BrickColor = primary
			end
			if target.Name == 'Secondary2' then
				target.BrickColor = secondary
			end
		else
			if v.Name == 'Primary1' then
				v.BrickColor = primary
			end
			if v.Name == 'Secondary1' then
				v.BrickColor = secondary
			end
		end
	end

Problem with what I have is if a player clicks a hitbox right. So model:GetChildren() would return Hitbox, Primary1, Primary2, Secondary1, Secondary2 right? After the line that says if v.Name == 'Primary2' then but I can’t use v.BrickColor, as that just sets all their colors to be the same, and when I use the target it don’t work, because majority of the time the player will be clicking on the Hitbox (and I cannot remove the Hitboxes as they serve as the PrimaryPart to determine their positions, make sure objects can’t collide, etc.)

So how can I do this? is there a way to disable players from clicking the hitbox? Because I need to know what side of the wall they are clicking on, whether it’s the side 1 or side 2 so I know what side to color it

Is there a way to disable players from clicking the hitbox?

You could use Mouse.TargetFilter, setting it to the Hitbox and re-acquiring the target if the initial target is a Hitbox. (Make sure you only do this once, and discard the result if the new target is also a Hitbox)

Alternatively, if you have the Hitboxes in a separate Model you can set that Model to the TargetFilter to ignore all of them continuously.

Because I need to know what side of the wall they are clicking on, whether it’s the side 1 or side 2 so I know what side to color it

If you’re careful about how you orient your Hitboxes with respect to the models, you could use Mouse.TargetSurface to determine whether to use Primary/Secondary1 or Primary/Secondary2.


What I would do in this situation is actually make each wall two models, so there’s no ambiguity about which side is being targeted. You can have some logic to determine which pairs of walls are connected, or do something fancy with the hierarchy:

  • Wall (Model)
    • Anchor
    • Side1 (Model)
      • Hitbox
      • Primary
      • Secondary
    • Side2 (Model)
      • Hitbox
      • Primary
      • Secondary

You’d have to add the “Anchor” for movement, since I assume you’re doing that based on the Hitboxes right now.

1 Like

Trying to use the Mouse.TargetFilter, if I did set it to hitbox, wouldn’t it just always pick up the hitbox?

Is I was to do what you suggested with the 2 wall models in the 1 model, if there’s the ‘anchor’ (hitbox) for the main model still there players could still click on it? I obviously still need a hitbox inside the main model, as that’s the PrimaryPart and is what is used for placing

You’ve got it backwards: the TargetFilter is for things you want the mouse to ignore.

As for the Anchor… just make it tiny. You can use the Hitboxes inside the sub-Models for the actual collision detection. The Anchor would be exclusively for positioning the combined Wall Model.

Ohhh that makes more sense. Where would I put the TargetFilter tho?

mouse.Button1Down:connect(function()
	if var.Painting then
		paint:FireServer(
			playersPlot, 
			mouse.Target, 
			var.Primary_Color, 
			var.Secondary_Color
		)
	end
end)

There’s no way to set the TargetFilter to every single models hitbox?

mouse.Button1Down:connect(function()
    if mouse.Target.Name == "Hitbox" then
        mouse.TargetFilter = mouse.Target
    end
	if var.Painting and mouse.Target.Name ~= "Hitbox" then
		paint:FireServer(
			playersPlot, 
			mouse.Target, 
			var.Primary_Color, 
			var.Secondary_Color
		)
	end
end)

I can’t recall of mouse.Target updates instantly when you set the TargetFilter property, so you might have to wait for a frame there (aka RenderStepped:wait()).

I don’t suggest using this method, the “edge” cases are incredibly common and difficult to work around. I suggest using either the sub-model method or checking the TargetSurface of the Hitbox.

The sub-model method has the least amount of logic, which is why I said I’d use it.