More about Construct's new functions

17
Official Construct Post
Ashley's avatar
Ashley
  • 15 Apr, 2019
  • 1,150 words
  • ~5-8 mins
  • 4,939 visits
  • 11 favourites

We recently introduced a new redesigned functions feature for Construct 3. Check out that blog post in case you missed it. We have a few more things we wanted to highlight about the new functions feature!

'Wait' in functions

With the old Function plugin, the system Wait action would cause parameters to be lost. This was a common issue people ran in to and often resulted in questions on the forum. The problem was as soon as you wait, the function ends and its parameters are discarded. Then when it resumes actions after a delay, expressions like Functions.Param(0) don't have the parameters any more, so just return 0. In other words Wait had the effect of clearing all parameters.

With the new built-in functions, Construct now knows to save all the function parameters when it reaches Wait. Then when it resumes actions after a delay, it restores them. This means waiting in a function works like you expect! All parameters are still available no matter how long or how many times you wait in a function.

The example above will correctly set the parameter number in the text after the wait.

Function maps

The new functions feature didn't originally support calling a function by an expression of its name, which the old Function plugin supported. However this is one of the design shortcuts that in turn caused some problems. Firstly if you call a function by an expression like "Func" & number, Construct can't tell in advance from the editor alone which function will be run - it depends on runtime values. This means when you use Find all references, it doesn't know if that function call references the function you're searching for or not - so it errs on the side of caution and always includes it, marked as an ambiguous result. In large projects this means Find all references results eventually clog up with lots of ambiguous results you have to sift through. Further an advantage of the new functions is when you rename them, all their references throughout the project update automatically. However if the same ability to call by an expression was supported, it would also be unable to update calls by expression. Then sometimes renaming a function will require you to manually update events - reversing one of their benefits.

To solve this, Function maps are a new feature inspired by the approach you'd use in a real programming language, that associates a string with a function. This is the best of both worlds: you can call a function by its string, but since it never uses an expression for a function name, Find all references is always perfectly accurate, and you can always rename functions with the confidence it won't break anything.

This is a fairly advanced feature, but should be straightforward once you get used to it. Here's how it looks in events:

The process to use them is as follows:

  1. On startup, create a function map, which "maps" (associates) a string with a function.
  2. Normally you'd want to pass parameters, so when you call the function, first do it via another function (in the example above, this is CallColor).
  3. Then use the Call mapped function action to call a function by its string. This can also forward some of the parameters from the current function call, so the called function receives the same parameters. Normally when you do this you'd omit the parameter that specified the string, since the called function generally doesn't need it any more.

One extra capability is you can also set a default mapped function, which is called when the string doesn't match any function. It's often useful to have a "catch-all" to fall back on. This wasn't easily possible with calling functions by an expression so is a useful new part of the feature! Also when calling the default, all parameters are always forwarded. This lets the default function look at the string that was used, so it can be compared and used in expressions and so on.

Even when calling through an intermediate function, our benchmarks show function maps are about 30% faster than the equivalent using the Function plugin calling a function by an expression! So this approach is still faster. If you want to try this out, take a look at the new Function maps advanced example in the latest release.

Automatically converting old functions

Updating existing projects using lots of functions with the old Function plugin could be a bit of a chore. Luckily the latest release also includes a new option to automatically convert old functions to the new built-in functions! Simply right-click a On function condition from the old Function plugin and select Replace with built-in function.

Once converted a new function appears, the old one is disabled, and all references to the function across your project are updated to reference the built-in function instead.

Unfortunately the conversion may not always be successful. The new functions feature works differently in some cases, and these differences sometimes prevent automatic conversion. Some of the reasons conversion might not work include:

  • Using parameters as both numbers and strings. This is the most common problem. New functions use a specific parameter types - either string or number - and can't be both, like they could in the old Function plugin.
  • Using dynamic parameter indices - i.e. an expression for the parameter index in Function.Param(n)
  • Using multiple On function events - new functions only allow one.
  • Calling functions as both actions and expressions - new functions can only be used as one or the other.
  • Calling functions by expressions also can't be converted, since as before, the editor can't work out which function it would call.

However our experiments show it works about 3/4 of the time, so it's still a useful time-saver. You can try converting your project's functions one at a time and manually convert any that aren't automatically converted.

Do note however that this feature makes far-reaching changes to your project, and cannot be undone. So please be sure to back up your project before you use it!

Conclusion

Construct 3's new built-in functions feature is much better designed. Along with the benefits noted in the previous blog, it also fixes a long-standing issue with Wait, function maps cover calling functions by a string without the editor having to make guesses about dynamic function names, and there's even an option to help you switch over automatically. The old Function plugin is now deprecated so you should think about switching over if you can - or even upgrading your project to the C3 runtime if you haven't already, since new functions are only available there. We think the new functions feature will be much easier to use, and especially easier to manage in large projects, and they're far faster too! We hope you enjoy using them!

Subscribe

Get emailed when there are new posts!

  • 19 Comments

  • Order by
Want to leave a comment? Login or Register an account!
  • I know you made a lot of effort in trying to achieve a built-in approach, I appreciate that. But seriously, I've encountered much redundancies in this approach, causing more development time and complexity than necessary. But okay, as long as it works, we can just leave it as be and get used to it.

    But, when we achieved a limitation, it became nearly impossible to deal with without having to go JS scripting. But if we start to approach things like this, event-based programming would be losing its purpose of being a main scripting feature.

    "To solve this, Function maps are a new feature inspired by the approach you'd use in a real programming language"

    You mentioned this. In real programming, you can:

    1. Swap Function Parameters for the next function call.

    2. Pick what parameters to pass.

    3. Easily define and call functions dynamically.

    The new Functions feature lacks the 3, which is, with respect, contradictory.

    • In the efforts of implementing an integrated approach for the Functions feature, including the parameter names. You guys didn't notice that you've sacrificed the "ease of use" and some important features.

      It's not a real Function when instead of this:

      ----------------------

      *Function (var1, var2, var3)

      ----------------------

      You get this:

      ----------------------

      *Function (var1, leftover1, leftover2, leftover3, var2, leftover4, var3)

      ----------------------

      It's not unorganized. Even JS has a feature for that, it's because there is a purpose behind that. A new Function can have its own specific parameters it needs from the other Function. And passing it included into the new passed Function is redundant and messy.

      I hope you understand my point on how this is essential.

      • When passing Function parameters, "YOU MUST BE ALLOWED TO CHOOSE WHICH TO ACTUALLY PASS". Otherwise, it's , with respect to the developers, a design-flaw.

        Also, currently, in-related to the previous concern, you "MUST" be able to swap parameters, "I'm sure you guys are well aware", it's for the benefit of readability and organization of events.

        I hope you guys can reconsider.

        ---------------------------------------------------

        I do have a proposal fix to this issue:

        2 actions to solve them.

        1. Call Custom Function

        2. Add Parameter.

        Where the custom parameters are pushed on a Call Custom Function.

        What do you think?

        ----------------------------------------------------

        Thank you for the time.

        Load more comments (1 replies)
  • Nice work on the new functions, including the new function map, allowing for more flexibility and the bug fix for JS callFunction parameters. C3 is really on a nice roll now.

  • The function map feature is really great, thanks for including it.

  • Function maps is a feature I really dislike on the new runtime, I mean there's no really dynamic call. I can't do things like concatenating the name of the function I wanted to call, I always from now and on, need to know the exact function I'm executing thus dynamic functions are really not in there anymore. Although I've managed to map and semi-dynamically execute callback functions for buttons, for instance, I need to run an initial mapping function in order for this to work, therefore reusing this code is always bound to knowing exactly what you are going to call. Having a "find references" for dynamic functions as one of the selling arguments for mapping adds no value to the engine (just my opinion), you guys are doing a great job with Construct, I really liked it and now I'm creating my own plugins, but definitely function mapping is something that, for a programmer like me, makes me feel crippled from a code perspective.

      • [-] [+]
      • -1
      • Ashley's avatar
      • Ashley
      • Construct Team Founder
      • -1 points
      • (1 child)

      The way function parameters now work is far better. The problem with completely dynamic calls is there is no way to know which parameters should be added. Function mapping solves the problem of calling by a string while still being able to pass along known parameters. Normally completely dynamic function calls are not necessary - if you restructure your functions to work with the new system, they may well be much cleaner and easier to understand afterwards.

      • I'm not saying the way it works now is worst, I just don't feel as free as I used to before changing to function maps. Just take that in consideration now that you are working with the javascript feature, it will definitely constrast.

        Keep up the good work.

  • awesomeness!

  • Sweet.

  • Interesting. Glad we got some deeper info on how this all works now.

  • You didn't use the word "simply" which is simply fabulous.

  • doesn't matter how much improvement you make, we can never make a good performance game because of the html5 (its not stable , it doesn't have a good performance on android and ios, just look at "cats gunner game" performance, its a simple game but...)

    and i know you are going to delete this comment like always you just want the good stuff but its the true.

      • [-] [+]
      • 1
      • Ashley's avatar
      • Ashley
      • Construct Team Founder
      • 1 points
      • (3 children)

      HTML5 games can perform great, especially on modern devices. These days we hear very few complaints about performance. Do you have any specific benchmarks or examples?

      • its not stable even on modern devices and we have to ask users to update the chrome or webview and that is really inconvenient and all other export to apk support is no longer exists i mean intel xdk or crosswalk or cocoon or ... there is nothing anymore and we just have to use webview and its not stable , in a lot of devices its crashes or slows down , for example i said look at "cats gunner game" comment section for all of problems users have with it , and the developer is not happy with the performance too like many of us, its obvious and no need for proof , you just don't want to accept html5 didn't get where you thought it was, and i don't know why you insist on html5 when all other company's abandoned it when you can have c# and export to all other platforms with great performance.

        you can test it yourself just make a simple scene with construct and unity and see for yourself how much other engines are better and more stable across all devices.

        Load more comments (2 replies)