Any tips for working on large projects?

Not favoritedFavorited Favorited 1 favourites
From the Asset Store
_______ Huge collection of metal fixtures ________
  • so, im making a drifting game and i wanna make it so when your moving, it plays a sound once, but when your speed=0, it stops, how do i do this?

  • so, im making a drifting game and i wanna make it so when your moving, it plays a sound once, but when your speed=0, it stops, how do i do this?

    You question has nothing to do with the topic. Make a new post in How do I subforum or ask on Discord.

  • Just sharing some of my weird ideas recently:

    When I made event triggers, I made some modular objects and check whether it has a specific child object to gave them specific functions and.

    For example, when I needed this event to show a dialogue, I added the dialogue icon to the trigger.

    The green blocks as triggers, they are all the same, And they don't have any instance variables. when player colliding or overlapping trigger, check the trigger's hierarchy to see if a specific child object exists.

    In each child icon, there are instance variables that determine what events they will trigger.

    Some of the instructions are:

    • trigger when entering the area
    • Press the interaction key to trigger when overlapping the area
    • Hide after triggering(Destroy but reset at next time when enter the Layout)
    • Permanently remove from current game(Destroy + Persistent & Local Storage)
    • Send signal when trigger

    ~~~

    These icons are from: game-icons.net

  • XHXIAIEIN Neat idea! You can instantly see what each trigger does, without clicking and checking its variables.

  • Doing complex things with events can be very tedious and frustrating. Construct's "no errors" agenda can really hurt the debugging process, you need to place safety nets everywhere and it all becomes hard to read. Also events are generally slower than code, in some places MUCH slower. So I really recommend you to learn basic scripting stuff and use it where it makes sense, though PLEASE write code in TypeScript. Thank god Construct 3 now has built-in setup for it. Vanilla JavaScript is pretty dangerous to your mental health

    Also, test your game on low-end devices, the earlier you start the better. Just doing testing on your mobile is really good (even if the game is not meant to mobile).

    I agree that caring about performance too much is bad, and the main goal to actually make stuff first. But still, "don't care about performance lol" mindset can do bad things to you. You can ruin performance really fast if you don't know what are you doing. Especially since most popular usecase of C3 is making web+mobile games, and performance matters a lot there.

    C3 is pretty bad at debugging performance, and this topic deserves its own article, but you can get some basic ideas with googling and practicing yourself and it would already help a lot.

  • Try Construct 3

    Develop games in your browser. Powerful, performant & highly capable.

    Try Now Construct 3 users don't see these ads
  • Monday, March 3, 2025

    8:20 PM

    I've only been using Construct and developing for six months but I've come up with a few tricks to keep my own sanity that I haven't seen in this thread yet.

    1. Use "Lookup Variables" for strings that need to be passed as parameters in expressions/conditions.

    a. e.g. Prevents having to remember the tag string you used in a timer/timeline/flowchart somewhere else and from mistakes from typo's.

    2. Use families to create organized "variable groups" within objects you are using as global variable banks.

    a. You can reduce the number of global objects you use as global instance variable banks.

    b. Looks cleaner and more organized when looking at the instance variables in the Properties bar

    c. Keeps the global variable name space tidy. Just enter the family name of the subset of variables you want to enter into an expression and get a smaller autocomplete set.

    d. My examples below show me using this for a set of lookups (I think of these as the construct version of lookup tables) but you could use them for any set of variables in a global variables object.

    3. Make logging work for you and your visual style.

    a. The more complicated your project with logic broken out in more event sheets, the harder it is to debug.

    b. Create your own logging functions to give you information in the console that makes sense to you and helps you debug your particular logic structure

    Here is a vertical slice example of how I use "lookup variables" in family-organized "variable groups" to support my logging functions which give me visual clarity into what my application is actually doing.

    Set up multiple families for each group of variables on the same object:

    NOTE: Here I am using ForConstruct's "Globals" object plugin, but you could do the same with any sprite on a layout that you mark "Global"

    Now create FAMILY-LEVEL instance variables on your global object:

    Now your variables (in this case they are being used as global constants) are divided into easy to read groups (Construct 3's version of lookup tables in this case).

    NOTE: I am creating an underwater game, so I was actually able to find corresponding emojis to many of my enemy types. I use them in the console logging because I'm a nut.

    Now you can search the autocomplete namespace by using the family name when using in expressions:

    Now for my logging. My undersea enemies have complex movement that can't be replicated by a single movement behavior in Construct 3. In order to get the different movement patterns I want I have a hierarchy of actions named Phases, Modes, and Behaviors.

    • Phases call a specific Custom Action which starts a specific movement/animation combination. (e.g., signal you are about to move, move to location, pause for a duration)

    • Modes are combinations of one or more Phases

    ○ e.g. Mode "Pulse" = Signal Move, Glide to position, Pause

    ○ Mode "Drift" = Drift slowly to ocean floor.

    • Behaviors are combinations of or repetitions of Modes,

    ○ e.g. Behavior "Rise_And_Fall" = Set Mode "Pulse" repeated till you hit the surface, then switch to "Drift" until you reach the ocean floor, repeat.

    But I have this logic spread out among different event sheets, Phases and Modes in their own sheet and Behaviors in a master Enemy Logic sheet, plus another sheet for Advanced Signal Listeners (Thanks Overboy!) and triggers, which control the shifts between the different states

    . It can be tough tracking bugs across all this.In this console screen shot I use indents and icons to visually show the filtered behavior of a single enemy and I can see its entire behavior cycle across my various event sheets.:

    I can now see the enemies AI lifecyle in a visual manner that makes sense to me and allows me to easily spot when things are happening out of order or are missing. For instance:

    All game events call signals to logging functions so I know exactly what is happening, for instance when a player is struck by an enemy:

    The attack is resolved in its entirety before the system moves on to anything else.

    But when I hit an enemy with a projectile I see this:

    The game is allowing the enemy to call parts of its action AI before the attack is entirely resolved. Even though this isn't causing any bugs right now, I know this is asking for trouble. There are almost certainly going to be bugs where an attack results in an enemy death, but the proper animations don't fire because its calling the AI which is also messing with animations and variables. I now know I need to fix this to avoid problems in the future.

    Anyways, curious to see people's thoughts on the above. Has anybody been using families with global variables like this already? Does anybody else have console logs that look children's picture books? Am I just weird with this stuff?

  • The "Lookup Variables" idea is interesting, but setting it up must be a chore.

    Here are my tips:

    1. In all my big projects, I create a PlayAudio function and call it whenever I need to play a sound, instead of using the Audio Play action directly. This makes it easy to modify the entire sound system later. For example, you can quickly implement a global volume setting or adjust how audio tags are named.

    2. Similarly, I use a single _LOG function for console logging. This allows me to disable all logs before publishing the game, turning logging off completely.

    3. Another logging tip: right-clicking anywhere prints all objects under mouse cursor to the console. This is incredibly useful in large games with thousands of objects, many of which are hidden. I used to waste a lot of time manually searching for the right instance in the debugger.

    Here is the code:

    const excludeFamilies = true;
    
    const results = []; // Collect results in an array
    
    for (const objectTypeName in runtime.objects) {
    
    	const allInstances = runtime.objects[objectTypeName].getAllInstances();
     const filteredInstances = allInstances.filter((e) => e.layer && e.layer.name);
    
    	var idx=0;
    	for(var i=0; i<filteredInstances.length; i++) {
    		const instance = filteredInstances[i];
    		const layerIndex = instance.layer.index;
     const x = runtime.objects.Mouse.getMouseX(layerIndex);
     const y = runtime.objects.Mouse.getMouseY(layerIndex);
    
    		const left = instance.getBoundingBox().left;
     const top = instance.getBoundingBox().top;
     const right = instance.getBoundingBox().right;
     const bottom = instance.getBoundingBox().bottom;
    
     // Check if the mouse cursor is within the instance's bounding box
    		// If excludeFamilies=true, duplicate UIDs will be skipped
    		if (excludeFamilies===false || !results.some(record => record.UID === instance.uid)) {
    			if (x >= left && x <= right && y >= top && y <= bottom) {
    				// console.log(`${objectTypeName}\t\tLayer: ${instance.layer.name},\t\tUID: ${instance.uid}`);
    					results.push({
    						Object: objectTypeName,
    						Layer: instance.layer.name,
    						UID: instance.uid,
    						IID: idx,
    						Visible: instance.isVisible,
    						Collisions: instance.isCollisionEnabled || "",
    						Animation: (instance.animation ? (instance.animation.name+":"+instance.animationFrame) : "")
    					});
    
    			}
    		}
    		idx++;
    
     }
    }
    
    console.table(results);

    4. My final logging tip: I created an addon (which, unfortunately, won't work with SDK2) that adds event sheet names and event numbers to all log messages. It also allows logging to be completely disabled. I wish the Browser object had built-in settings for this.

Jump to:
Active Users
There are 2 visitors browsing this topic (0 users and 2 guests)