fisholith's Forum Posts

  • My project was suddenly unable to be previewed after updating to the "Stable r432" version of Construct. I wanted to share the details of my problem and temporary solution in case it's useful to anyone else.

    Summary

    It looks like r432 may have a problem with the one symlink folder in my project.

    Every prior version of Construct I've used from r424.2 backwards has had no problem with this symlink folder.

    Project overview

    I have a fully script based project, with no event sheets.

    I edit the JS files in VSCode, and use Git to track changes.

    C3 provides a "Scripts" folder, which is the default place for your JavaScript files.

    I have several sub-folders inside that "Scripts" folder.

    One of these folders "eggECS_4", is a symbolic link instead of a conventional folder.

    Symbolic link folders have never caused me any issues in prior versions of Construct, but it might be involved with my sudden inability to preview in Construct version r432.

    Last working state

    My project ran with no problems on the "Stable r424.2" version of Construct.

    Problem

    Immediately after updating to the newest "Stable r432" version, my project could no longer be previewed at all.

    On r432, when attempting to preview I would get the following:

    A popup saying:

    "Failed to start preview. Try reloading Construct before trying again."

    And this console error:

    "Error starting preview: Error: Could not find source file: 'file:///scripts/project/eggECS_4/!Notes/!Unsorted_Notes.js'"

    Things I initially tried that didn't work include, reloading Construct, clearing cache and cookies, and trying multiple browsers (Chrome, Brave, Firefox).

    Cause?

    I can't be 100% sure, but what stands out to me about that console error, is that the file it's saying it can't find is the alphabetically first file inside the "eggECS_4" folder, which is the only symbolic link folder in the project. I removed that file from the project, attempted to preview again, and the alphabetically next file inside "eggECS_4" showed up in that console error.

    Again, I've been previewing and working on this project for quite a while with no issues, in "Stable r424.2" and earlier, with the symbolic link folder behaving as expected within both Construct and VSCode.

    Temporary Solution

    I was able to roll back to the r424.2 version of Construct, using the following link:

    editor.construct.net/r424-2

    And the project opens and previews perfectly again.

  • Hey max fang, and BigBuckBunny, I just encountered something similar. I'm still investigating, but I wanted to leave my symptoms and solution, so far, in case it happens to be useful to you, or anyone else that happens by.

    Project overview

    I have a fully script based project, with no event sheets.

    C3 provides a "Scripts" folder, which is the default place for your JavaScript files.

    I have several sub-folders inside that "Scripts" folder.

    One of these folders "eggECS_4", is a symbolic link instead of a conventional folder.

    Symbolic link folders have never caused me any issues in prior versions of Construct, but it might be involved with my sudden inability to preview in Construct 3 version r432.

    Last working state

    My project ran with no problems on the "Stable r424.2" version of Construct 3.

    Problem

    Immediately after updating to the newest "Stable r432" version, my project could no longer be previewed at all.

    On r432, when attempting to preview I would get the following:

    • A popup saying: "Failed to start preview. Try reloading Construct before trying again."
    • And this console error: "Error starting preview: Error: Could not find source file: 'file:///scripts/project/eggECS_4/!Notes/!Unsorted_Notes.js'"

    Cause?

    I can't be 100% sure, but what stands out to me about that console error, is that the file it's saying it can't find is the alphabetically first file inside the "eggECS_4" folder, which is the only symbolic link folder in the project.

    Again, I've been previewing and working on this project for quite a while with no issues, in "Stable r424.2" and earlier, with the symbolic link folder behaving as expected within both Construct 3 and VSCode.

    Solution

    I was able to roll back to the r424.2 version of Construct 3, using the following link:

    editor.construct.net/r424-2

    And the project opens and previews perfectly again.

  • No worries at all, dop2000 :)

    Also, Looking again, I see what you mean, that Famous's original question is in terms of events.

    I've talked with Famous a few times in the past about this project, and in each case it involved in-event-sheet JavaScript, so I think I just assumed it was still kind of taking the JavaScript route, but you're right. That also makes way more sense to me now, because I kept wondering what that little arrow "→" was. I was thinking some kind of psudocode.

    So, ImPrettyFamous, I think most of my solution will work as in-event-sheet JS, with the only major difference being in the last block of code. Where the code outside the tick() function is basically just some global variables. And the code inside the tick() function, (just the code inside, and not the tick() function as a whole), you'd place in the event sheet as JS triggered by an "Every Tick" event.

    You could also just convert it all to C3 events, as it's really just a matter of keeping the index of the next song segment, and the check for when to switch. Though I think the nested song data is a little easier to interact with directly in JS.

    Also, just as an extra note, if you rebuild the JS code example but as event sheet code, all the variables I created as a "const" in the JS example, would be regular variables in the event sheet, not constants. (In JS a constant can be assigned a value from an expression, but in Construct they are static values you type in, so they can't be decided while the program is running.)

  • Hey dop2000,

    No part of my response or my code is AI generated.

    I'm not sure if you're joking or if your serious, but I'll assume that you're serious just in case. No hard feelings either way though.

    I have been making help and tutorial posts with this same kind of structure and style for Construct 1, 2, and 3, going all the way back to 2009.

    (15-ish years. That feels weird to realize.)

    e.g.

    Here's an example from 8 years ago, where, for part of my reply explaining alpha blend modes, I built an application in Construct 2 where you could interact with all possible alpha blend mode combinations in a sandbox environment.

    construct.net/en/forum/construct-2/how-do-i-18/help-object-blend-modes-121928

    e.g.

    Here's an example from 6 years ago, where I was asking a question, using the same structure and style, and you helped me troubleshoot my problem. Also, thanks again, by the way. Your suggestion of looking at the JavaScript console error log helped save my project.

    construct.net/en/forum/construct-2/how-do-i-18/solved-preview-crash-139313

    e.g.

    My solution write-up for that problem you helped me with, is likewise basically the same style I used above in my reply to Famous:

    construct.net/en/forum/construct-2/how-do-i-18/solved-on-preview-i-get-a-cras-139313

    The majority of my long form posts are in this style, and have been for over a decade.

    That's basically the style I use whenever I'm trying to explain something with a bunch of parts, mainly because I want to keep things clear and easy to follow. I don't know that I always succeed at that, but that's what I'm generally trying for.

    As an aside, I actually kind of miss the older Construct 2 forum software, that supported custom text colors, because I frequently color coded variable names in my examples and replies, to make them easier to visually keep track of for anyone reading. After the migration to the newer forum software, the color coding in my older posts was lost. There were several post I made on color math, where I actually color coded the R G and B values. I probably would have backed those up in their original form if I'd realized the formatting was going to be stripped. Granted, probably not that important in the long run.

    Anyway, again no worries. I am a real person though, and that is my actual work.

  • Hey, Famous

    So, if I understand, in the game, you have various songs that play, and each song has segments of time that are either vocals or just instrumental.

    You have a character in the game, and you want the character animations to match up with those segments in the song.

    Specifically, the character's animation should be set to the "sing" animation during the vocals segments in the song, and the "perform" animation during instrumental segments in the song.

    Finally, you have the time stamps for the start and end of each segment, which you currently have stored in a JSON file, or string.

    I think you're on the right track for how to get it working.

    I have a few thoughts on how you might be able to simplify things a bit.

    JSON to JS

    One thing that might help simplify the process of getting data from JSON, is to convert it to nested native JS objects and stuff.

    You can use "JSON.parse()" to convert a JSON string, to the equivalent nested JS objects and arrays.

    e.g.

    // We have a string containing the JSON.
    const songsJson = '{ "Song1": { "Stamps": [ {"start": 14.0, "end": 30.0}, {"start": 32.0, "end": 40} ] } }';
    // We feed it to JSON.parse(), and get back a hierarchy of 
    // JS stuff that exactly matches the JSON.
    const songsData = JSON.parse( songsJson );
    console.log( songsData.Song1.Stamps[0].start );
    // Logs: 14
    

    The official-ish term for what JSON.parse() returns is a "JS object hierarchy", which is a little more general than it sounds, in that arrays and stuff can be part of that hierarchy, exactly like they can in JSON.

    Basically it's exactly the same as JSON, but made out of native Javascript stuff. And so it has the nice benefit that you can access all the data just using regular JS dot and bracket syntax.

    Also, just to be clear, a "JS object hierarchy" is not some special thing. It is literally just a JS object, with properties that can store other JS objects, or arrays or whatever. It's exactly the same thing you would get if you just made it by hand. Which brings me to my next suggestion...

    JS instead of JSON

    An alternative is to skip JSON all together, and just store the timestamps directly in nested JS objects and arrays, to begin with.

    e.g.

    const songsData = { 
    	Song1 : { 
    		Stamps : [ 
    			{ start : 14.0 , end : 30.0 } , 
    			{ start : 32.0 , end : 40 } ,
    		] ,
    	} ,
    };
    console.log( songsData.Song1.Stamps[1].start );
    // Logs: 32
    

    This is basically the same as the prior example, but it cuts out a step, and it's usually easier to write and read, because you don't need quotes around all the object property names.

    This is probably what I'd recommend going with, as if you use JSON, the best way to access it is to convert it into JS data anyway.

    Timestamps

    If the song can be broken into segments, like "vocals" and "instrumental", then instead of storing timestamps for the start and end of each segment, you can just store the timestamps for the start of each segment, and what kind of segment it is, "sing" or "perform". The start of a new segment can be treated as the end of the prior segment.

    You can also add more segment types, like idle, If you want to have the character idle before the song starts, or after it ends.

    So the JSON for this format might look like this:

    const songsData = { 
    	song1 : { 
    		stamps : [ 
    			{ time : 0 , anim : 'idle' } , 
    			{ time : 14 , anim : 'sing' } , 
    			{ time : 30 , anim : 'perform' } , 
    			{ time : 32 , anim : 'sing' } ,
    			{ time : 40 , anim : 'idle' } , 
    		] 
    	} 
    }
    
    console.log( songsData.song1.stamps[2].time );
    // Logs: 30
    console.log( songsData.song1.stamps[2].anim );
    // Logs: perform
    

    Making it work

    So if you use the format above, you have the song broken into segments, with each segment's info (start time and animation) stored in an array of segments. The first segment is at index zero, next segment is at index 1, etc.

    To get it working, you need the game to know what segment you're on. Well, almost...

    You actually only need to know what segment comes next, because you need to know when you reach it. Whatever the current segment is, it's already started, so it can't change anything anymore. Only the next segment can change the animation when it arrives. So the next segment is the one we care about.

    Anyway, we'll need a variable to store the nextSongSegmentIndex, since that's the one we need to be checking for.

    It will start at index zero, (before the songs starts, segment zero really is the next segment to play), and each tick, you can check to see if it should switch to that next segment.

    When that check determines that you do need to switch to the next segment, you grab the animation name out of that segment's "anim" property, and make the character sprite play that animation by name. So if that segment's "anim" property stored the name "sing", then your character will play the sing animation. You also add 1 to the nextSongSegmentIndex.

    The code might look something like this:

    // The data for all the songs. 
    // (I only have one song filled in here for this example.)
    const songsData = { 
    	song1 : { 
    		stamps : [ 
    			{ time : 0 , anim : 'idle' } , 
    			{ time : 14 , anim : 'sing' } , 
    			{ time : 30 , anim : 'perform' } , 
    			{ time : 32 , anim : 'sing' } ,
    			{ time : 40 , anim : 'idle' } , 
    		] ,
    	} ,
    	song2 : {} , // More data for song 2.
    	song3 : {} , // More data for song 3.
    };
    
    // Name of the current song. For looking up its data. 
    currentSong = null;
    
    // We need to know when the song started playing, so we can 
    // calculate how long it's been playing.
    songStartTime = null;
    
    // The array index of the next segment to play. 
    // Should be set to 0 before a song starts.
    nextSongSegmentIndex = 0;
    
    // The game tick, in which we'll do the check for advancing 
    // to the next song segment, and set the character animation.
    function tick ( runtime ) {
    	// We'll assume that the "currentSong" variable has 
    	// been set to the currently playing song, "song1"
    	// in this case.
    
    	// "songCurrentTime" is the time in seconds since the 
    	// song started. This line below assumes we saved the 
    	// "runtime.gameTime" value in the "songStartTime" 
    	// variable earlier, when the song started. 
    	// We subtract the current time from the song's start 
    	// time to find out how long it's been playing.
    	const songCurrentTime = runtime.gameTime - songStartTime;
    
    	// We need to get the next song segment's data.
    	const currentSongData = songsData[ currentSong ];
    	const currentSongStamps = currentSongData.stamps;
    	const nextSegmentData = currentSongStamps[ songSegmentIndex ];
    	// Segment start timestamp.
    	const nextSegmentTime = nextSegmentData.time; 
    	// The animation to play.
    	const nextSegmentAnim = nextSegmentData.anim; 
    
    	// Check if we need to switch to the next song segment.
    	// If the song time equals or passes the start time of 
    	// the next segment, then we switch to it and play it's
    	// animation. 
    	if ( songCurrentTime >= nextSegmentTime ) {
    		// Make the character sprite play the animation 
    		// named by that segment.
    		characterSprite.setAnimation( nextSegmentAnim );
    		// Advance to the next segment.
    		nextSongSegmentIndex += 1;
    	}
    }
    

    It's a bit simplified, but that's the basic framework, and I think it does more or less what you're looking for.

    Hope it helps out. :)

  • Okay cool, that makes sense. I figured it had to be that I was just overlooking something.

    I'm pretty sure my version was behind because, through a combination of random chance and me just being kind of dumb across several days, I somehow never thought to reload the C3 Chrome tab I'd been using as a sandbox for testing script related stuff.

    I also just saw that there was even another Stable release, that came out a week or so back, that had the Platform Info update. And in hind sight, I'm pretty sure I actually had that version open in my main project Chrome tab, right beside the outdated sandbox tab. Ironically, I didn't test in the main project tab, because I hadn't gotten it working in the sandbox tab yet. With work split up across several days, I think I may have just been generally aware that I'd updated C3, but it didn't occur to me, later on, that it was just my main project tab, and not all tabs were running the same version.

    Anyway, thanks again Ashley and R0J0hound.

  • Try Construct 3

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

    Try Now Construct 3 users don't see these ads
  • Thanks Ashley,

    When I loaded your example, I got a prompt that the version I was using (r388.2 stable) was too old to open the file (made in r398.2 beta), so I enabled beta releases in the construct settings, and got r398.2 beta.

    In r398.2 beta, your cp3 previews correctly on my computer, and in Chrome dev tools, runtime.platformInfo now shows up in the debug view as expected.

    It looks like my C3 version was just behind enough to be missing the runtime.platformInfo script interface.

    As a test, I created a completely blank project in the newer r398.2 beta, and runtime.platformInfo is present as a property of runtime, even without adding the Platform Info object to the project bar. It shows up between mouse and ticksPerSecond.

    I then returned to an instance of the older r388.2 stable, and even when I add the Platform Info object to the project bar, runtime.platformInfo doesn't appear to be present as a property of runtime.

    So I think it may have just been a case of my version not being up to date enough.

  • Hey R0J0hound, thanks for the reply.

    That's what I thought initially, but I've also tried evaluating those same lines in the middle of the tick() function, at which time I'd expect everything to be loaded.

    I basically just modified the tick function as follows,

    let tickCount = 0; 
    function Tick(runtime)
    {
    	console.log( 'Tick()' );
    	if ( tickCount === 0 ){
    		
    		console.log( runtime.platformInfo );
    		console.log( runtime.objects.PlatformInfo.getFirstInstance() );
    		console.log( runtime.objects.PlatformInfo.getFirstInstance().os );
    		console.log( runtime.objects.PlatformInfo );
    		console.log( runtime.objects.PlatformInfo.os );
    
    	} 
    	// Code to run every tick
    	tickCount ++;
    }

    I get the same output as in my original post above,

    // undefined
    // [object Object]
    // undefined
    // [object Object]
    // undefined
    

    (just copied this from the console after running the modified code above)

    and I still don't find any sign of the "runtime.platformInfo" property.

    Likewise, I've used Chrome dev tools to pause mid tick(), and on inspection of the objects returned by these two expressions,

    runtime.objects.PlatformInfo
    runtime.objects.PlatformInfo.getFirstInstance()
    

    I still don't find the property "os" owned by either object, or any of their prototypes.

  • Solved:

    Solution

    I updated C3 to the most recent version, and the Platform Info script interface now works as expected.

    Problem

    Without realizing it, I had been using an outdated version of C3, that predated the addition of the Platform Info script interface.

    Cause

    It was me all along! My C3 version was out of date as a result of my having left the same C3 Chrome tab open across several days. Without refreshing the tab, the version fell behind. I'd updated the C3 version in an adjacent tab at some point, and didn't realize later on that I then had multiple C3 tabs open that were running different versions.

    Original post:

    I'm trying to use the "Platform Info" script interface to determine if my project is running in a browser, or in NW.js.

    I can't seem to access or interact with the platform info script interface at all.

    I assume I'm doing something wrong, but I'm not sure what.

    What I tried

    I initially just wanted to test out printing the platform info's os value to verify that I could.

    1. I created a new empty project.

    2. In the layout editor I right clicked to insert a new object, and chose the "Platform Info" object.

    So, in the project bar, in the "Object types" folder, there is now an object named "PlatformInfo".

    3. In the "Scripts" folder, I double-clicked "main.js" to open it in a tab.

    4. In the main.js tab, in the function body for

    async function OnBeforeProjectStart(runtime){}

    (edit: Following R0J0Hound's reply below, I should also mention I've also done all of these tests from within the Tick() function as well, just to be sure that pretty much everything would get a chance to load.)

    I added the following five console.log statements to the top of the function body. Each line is just trying a different way to access the platform info data.

    console.log( runtime.platformInfo );
    console.log( runtime.objects.PlatformInfo.getFirstInstance() );
    console.log( runtime.objects.PlatformInfo.getFirstInstance().os );
    console.log( runtime.objects.PlatformInfo );
    console.log( runtime.objects.PlatformInfo.os );

    5. I ran the project in preview mode, in Chrome, and when checking the Chrome dev tools, I got the following output in the console:

    // undefined
    // [object Object]
    // undefined
    // [object Object]
    // undefined
    

    For clarity, here are the expressions and their output shown together:

    runtime.platformInfo 
    // undefined
    
    runtime.objects.PlatformInfo.getFirstInstance() 
    // [object Object]
    
    runtime.objects.PlatformInfo.getFirstInstance().os 
    // undefined
    
    runtime.objects.PlatformInfo 
    // [object Object]
    
    runtime.objects.PlatformInfo.os 
    // undefined

    Chrome dev tools

    To better understand what I was looking at, I used a break point in Chrome dev tools to pause execution of the preview. I set the break point at the end of the function body for

    async function OnBeforeProjectStart(runtime){}

    and with the execution paused, I inspected the "runtime" variable to see if I could find

    "runtime.platformInfo", but I wasn't able to.

    I was looking for this property on runtime because I thought the Platform Info script interface documentation was explaining in the second paragraph that it is the preferred way to interact with the platform info features.

    So, I'm pretty sure I'm just missing something pretty obvious, but I'm not sure where I've diverged from what I'm supposed to be doing.

  • Thanks for the info and the suggestion Ashley.

    I like your idea of grouping all the imports in a hub file, so the individual files get to stay individual, but in a web context they can still all be imported through that one hub file.

    In my particular case, I think it's not a problem that, when running in a web context, the game won't know about additional files after export, as I'd likely only need that functionality in a Node version of the project anyway.

    I expect I'll ultimately export the final incarnation using Node, and incorporate some fs reliant features, but in the meantime, just being able to do the majority of the previewing directly in Chrome with a single click is really nice and streamlined. And the hub file idea should make that work pretty nicely.

    I plan to make my game logic interact with stored data through a custom data storage interface, that detects the web or Node context the project is running in, changing file access techniques and enabling or disabling related features. So the hub file was kind of the last puzzle piece to let me keep nearly everything the same for the core game data.

    Thanks again Ashley, I really appreciate that you take the time to answer so much stuff in the forums.

  • Is it possible to dynamically import all .js files found in a specified subfolder of the C3 project Scripts folder? I think this may work in Node, but in a browser it looks trickier, and might involve C3 scripting API use. Though I'm not sure getting a C3 project folder's file/contents list is supported in the C3 API.

    e.g.

    Suppose, within the C3 project "Scripts" folder, I create an "entity_definitions" folder. In that subfolder, I create several individual js files, each exporting an entity definition. Can I, at runtime, get a list of the files names in that folder, and dynamically import them?

    Motivation

    There are a variety of preset js-objects I want to define, and I'd like to organize these definitions as one definition per .js file.

    I want to collect these .js files in to packs of definitions that all reside in their own folder.

    Roughly speaking, I'll end up with some folders (e.g. "pack1", "pack2", "pack3"), each containing a bunch of little .js files.

    For flexibility and extensibility reasons, I would prefer not to have to hardcode the names of all these files directly into import statements in the game code. (Also kind of nice for modding.)

    My understanding of the Node context so far

    I think this should be possible in a Node context using the core "fs" module.

    That is, if I export for node, or use remote preview for Node, I think this is doable.

    My understanding of the Browser context so far

    However, in a browser context, the file-system is not directly accessible, so I think I'd need to use some C3 API feature to get access to files that were part of the C3 project file hierarchy. I'm pretty sure C3 provides a way to get single files by name, but I'm not sure about getting a list of file names from a C3 project folder.

    Some notes

    It's not a must that the final project work directly in a web browser, but it's a nice-to-have, and it would be convenient to use the default chrome-based preview, instead of remote preview. (Though I do very much appreciate that the remote preview in Node feature exists, as it may turn out to be a critical part of my work on this project.)

    Anyway, any thoughts or suggestions are welcome.

  • Thanks for the replies, R0J0hound and Oosyrag, :)

    What you both mentioned about a 2D world's data growing in memory at a much slower rate than a 3D volumetric one, and possibly fitting entirely in RAM for much longer is a really good point.

    And your caution about getting stuck in the pre-optimization weeds before it's actually solving a concrete problem is good advice, Oosyrag.

    Mainly, I just wanted to check with people more familiar with C3, that streaming to/from file wasn't ruled out by something I wasn't aware of. I figure at some point, an infinite world is going to have to go to disk, and even if it's a problem to solve much later on, I'm just at the engine scouting phase. So it's handy to have an idea of how much a given engine will be working for or against certain aspects of the project, before committing to one.

    It sounds like NW.js would be the way to go for file read/write stuff, which has been my experience with C2. I made a C2 color theme editor quite a while back, and it relied on the NW.js file facilities, though I don't recall if I could invoke a save/load without a prompt using the built-in NW.js C2 object. I could always code a plugin though, if the functionality is available somewhere in NW.js features.

    Anyway, thanks again for the info, R0J0hound and Oosyrag. :)

  • Given a tile-based procedurally generated world, in the vein of Minecraft or Terraria, is there a good way to save and load map data chunks to disk as needed?

    That is if a player travels East, new chunks are procedurally created ahead of them, and old chunks far behind them are saved to disk and unloaded from memory. Then when the player turns back and travels West, the chunks ahead of them to the West are reloaded from disk as needed.

    I know that the browser-based nature of C3 is likely to make this a bit tricky, because browsers don't have free reign to write files for security reasons.

    Ideally I'd be looking for desktop style behavior, where the game stores map data essentially the same way Minecraft does.

    e.g. Loosely speaking, Minecraft streams map chunck data to and from a local folder, which differs slightly by platform.

    • Win: %appdata%\.minecraft
    • Mac: ~/Library/Application Support/minecraft
    • Linux: /home/USERNAME/.minecraft/

    Another benefit of this desktop-style behavior, is that world data stored in the folder isn't vulnerable to erasure by clearing local browser data.

    I'm not sure what the best approach would be, but my initial impression is that this would require exporting for NW.js in order to take advantage of the more desktop-like context NW.js operates in.

    Would an NW.js exported application allow saving and loading of map data, without prompting the user for a save location for each chunk file? I figure that prompting multiple chunk file saves every few blocks would slightly encroach on the spirit of exploration. :)

    I'm not familiar with the nuances of C3, but my experience with the prior incarnations of Construct so far, is that just about anything is possible, with enough insight.

    If there's a better approach, or if it's genuinely not doable, or simply not something that C3 is a good fit for, any thoughts or suggestions are welcome. :)

  • Thanks Wisdoms. :)

  • Hey Ashley, :)

    Hope you're doing well. I don't know if you remember me, but quite a while back I used to spend a lot of time writing up tutorials and answers to user questions for Construct 1 and 2 in the forums. I've talked with you a few times here and there.

    I just got my C2-based game funded on Kickstarter, and it's still climbing past the original funding goal, and I wanted to thank you and the rest of the Scirra team.

    It's not an exaggeration to say that my dream is becoming real because of you. So thank you, Ashley. :)

    I posted about my game in the "Your Construct 2 Creations" forum, though I know most traffic has likely moved to C3 at this point.

    I would like to share the game with the wider Construct community, but I'm not sure if there's a good place to do that. If you have any advice or suggestions, I'm all ears. No worries if not though.

    This is the post I just made in the "Your Construct 2 Creations" forum.

    Down Ward - an Owl Flight Platformer

    Thanks again, and best wishes for the continued success and growth of Construct 3. I'm looking forward to getting familiar with it in the future. :)