In your case, the best option is to use layers, but be aware of possible issues with objects overlapping or being hidden behind objects in adjacent layers.
The advantage of layers is that you can perform certain actions (e.g., toggle visibility) on all objects in a layer without having to think about the object type of the instances you're dealing with. Layer interactivity is also a key feature.
One thing I would suggest is using Construct 3's hierarchy system. A while ago, I made a fairly large building game with a complex UI. I assembled each panel (like the ones at the center of the window in your image) in a dedicated layout, using templates to make my life easier. Then, when needed, I would create the panels with the "Create hierarchy" option enabled, so that with just one action, the entire panel content was created.
By setting the base of the panel as the parent and its content as its children, I was able to make the process of building the UI much less tedious.
Looking back, though, I would rework this system by having a "container" as the parent. For example, I would create the panel with the player stats like this:
- An invisible container named PlayerStatsPanel, which acts as the parent, with instance variables related to the panel itself.
- The base panel (the rectangle that acts as the background), which is a child of the container.
- The other objects, which are children of the base panel.
You could also use sub-containers to make your life easier. For example, the objects that make up the stats pentagon could be children of a sub-container (which is a child of the base panel). The idea is to break down the UI into smaller parts, and then break these smaller parts into simple components.
Here’s a trick that may help you. Let’s say you want to perform an action on a lot of objects: for example, you want to make each object of the player stats pentagon gray. You can’t do that just using the basic properties of the hierarchy, but a little script can help. We have our sub-container, and each object of the stats pentagon is a child of that sub-container. Then, we can do this:
/*place inside a function with 3 parameters:
number containerUID - the uid of your container
string property - the property on the container children you want to change
string newValue - the new value for the property
*/
function isJson(str) {
try {
JSON.parse(str);
} catch (e) {
return false;
}
return true;
}
let newValue = localVars.newValue;
if(isJson(newValue)) newValue = JSON.parse(newValue);
if(newValue) {
const container = runtime.getInstanceByUid(localVars.containerUID);
for(let child of container.allChildren()) {
if(child[localVars.property] == undefined) continue;
child[localVars.property] = newValue;
}
}
This script changes any non nested property on every child of the container (also works for children of children). Place it in a function (let's call it ChangeProperty(...))
Then you can use it in Construct events like this:
ChangeProperty(Container.UID , "colorRgb" , "[0.5 , 0.5 , 0.5]")
Also, make use of families and tags, they're very useful when dealing with UI :)