Are Construct's Functions Really Limited, or Do I Just Not Know How To Use Them?

  • I was hoping to take the damage calculation logic I have in both my Player Event Sheet and Enemies Event Sheet, and turn it into a function that I could call and save a few lines of code. Was hoping to have paramaters that could take the hitbox family and target family, and run them through the logic, so one series of actions could cover any combination of hits/targets.

    However, it seems there's no way to sub in parameters in for objects in actions.

    Between this and only being able to take one "-> On X" condition per function, I'm running into tons of roadblocks that make C3's functions much less useful than traditional functions.

    Am I just missing something here? I thought in traditional programming, functions were essentially micro programs that you could throw anything into, and call when you need it. C3's Functions seem far less flexible.

  • Piece of advice: Pass the object in concern's UID through the function as a parameter.

    This will allow you to always pick the correct object, no matter the family, conditions, etc.

    Example:

    Family "hittables"

    Members:

    Player Sprite

    Enemy Sprite

    Event:

    On bullet collides with "hittables" -->

    Call function "bullet hits something"

    Pass parameters: bullet.damage, hittables.uid

    On function "bullet hits something" -->

    Condition:

    Pick "hittables" by UID function parameter (1) (or function "bullet hits something" parameter hittables.uid") -->

    Substract parameter bullet.damage from hittables.health

    Destroy bullet

  • Try Construct 3

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

    Try Now Construct 3 users don't see these ads
  • Piece of advice: Pass the object in concern's UID through the function as a parameter.

    This will allow you to always pick the correct object, no matter the family, conditions, etc.

    Example:

    Family "hittables"

    Members:

    Player Sprite

    Enemy Sprite

    Event:

    On bullet collides with "hittables" -->

    Call function "bullet hits something"

    Pass parameters: bullet.damage, hittables.uid

    On function "bullet hits something" -->

    Condition:

    Pick "hittables" by UID function parameter (1) (or function "bullet hits something" parameter hittables.uid") -->

    Substract parameter bullet.damage from hittables.health

    Destroy bullet

    I know this is an old post, but I got wrapped up in other things in the game and am just getting back to tackling this issue.

    I'll be honest, I have absolutely no clue how to call and object by UID like you're suggesting here. I understand what you're saying in terms of actual logic, but in terms of getting it to work in C3 I don't know what events would be used. Been banging my head against it for an hour now looking through the documentation with no luck.

    Could you post a quick screenshot using the events you're referring to just to give me a jumping off point?

  • While functions only support 3 primitive values (boolean, number and string) you can use a number parameter to pass the unique ID for an object instance.

    The event sheets use a selection/filtering technique for referring to an object. By default referring to "PlayerSprite" will affects all instances of "PlayerSprite", but some conditions can filter the selection down to some or one "PlayerSprite" instance. Conditions like collision triggers will only select the instance that collided for example. There's also some conditions that allow you to explicitly filter which ones you want, such as "compare instance variable" which allows you to choose instances with a certain value in an instance variable. One of the most useful it "Pick by UID" which allows you to filter to a single instance of an object, that matches a unique ID value. You can use this in combination with a function by adding a parameter for the UID ( which is a number ) then adding the "pick by UID" condition to the function itself. Like so:

  • While functions only support 3 primitive values (boolean, number and string) you can use a number parameter to pass the unique ID for an object instance.

    The event sheets use a selection/filtering technique for referring to an object. By default referring to "PlayerSprite" will affects all instances of "PlayerSprite", but some conditions can filter the selection down to some or one "PlayerSprite" instance. Conditions like collision triggers will only select the instance that collided for example. There's also some conditions that allow you to explicitly filter which ones you want, such as "compare instance variable" which allows you to choose instances with a certain value in an instance variable. One of the most useful it "Pick by UID" which allows you to filter to a single instance of an object, that matches a unique ID value. You can use this in combination with a function by adding a parameter for the UID ( which is a number ) then adding the "pick by UID" condition to the function itself. Like so:

    Yeah, I dunno what I'm doing wrong, but for the last 24 hours I've tried non-stop to implement UIDs like you've shown here in multiple different functions and setups, an each time it has completely broken my game. From breaking projectiles, to having attacks randomly start hitting every enemy on screen after working normally for awhile, to freezing the game entirely. This seems incredibly delicate for some reason. No clue what I'm doing wrong.

  • Please share a sample c3p that we can work with together.

  • Please share a sample c3p that we can work with together.

    I've rebuilt it a few times, but this is the latest attempt before letting it go and moving on to other things, if you can figure out what's wrong I'd be very appreciative.

    dropbox.com/s/qwjyve6prhkgsr2/azumi_fullgame3.c3p

  • Thanks, I've been looking at the code and trying to understand what you want to achieve.

    Right now you have the functon "damage" that only seems to handle damage dealt by the player to enemies.

    You got several hitbox objects that contain the damage value depending on the attack I suppose, and try to retrieve the correct damage value inside the function (for each playerhits : substract damage, etc).

    You should abstract the damage function in order to make it more universal. That means no object picking inside the function other than UIDs. The reason is, how the function is built now, it won't work in the absence of playerhits (the loop would run 0 times).

    Also, I think by Construct's picking laws, every shuriken would get destroyed. If you later decide to have more than 1 shuriken on screen at a time (power ups etc.) this would be a source for bugs.

    The basic function setup is fine, however I would extend it to a certain degree.

    Think of what can cause damage in your game (enemies, shurikens, sword strikes, etc). Create a family, put all relevant objects inside and name it "damagedealers" or something. Attach a variable damage to it and set it accordingly across all objects.

    Think of what can receive damage in your game (player, enemies, destructible objects), put all relevant objects inside and name it "damagereceivers" or similar.

    Then in your damage function, add number paramater "source" or something.

    Now you are able to build more generalized damage events.

    Handle the rest inside the function.

    For example, create a basic collision damage trigger.

    ->On collision damagedealers with damagereceivers: Call function "damage" , passing damagedealers.uid as source and damagereceivers.uid as target, damagedealers.damage as damage

    Now you got everything you need to work with inside the function.

    For example, you can let the player lose health, let the enemy lose HP, destroy the shuriken, etc.

    On function damage ->

    "damagedealers": Pick instance with UID source:Do generalized stuff valid for the whole family. E.g. play hit sound.

    "damagereceivers" Pick instance with UID target: Do generalized stuff, e.g. substract HP or play hit

    "shuriken" Pick instance with UID source: Destroy shuriken

    "playerhits" Pick instance with UID source:

    ---> "playerhits" is sword-> spawn damage on layer main etc.

    "hitbox6" Pick instance with UID source: Destroy "hitbox6"

    Etc.

    The key point is to have every sub event using UID instance picking to get the desired object.

    I hope this helps.

    P.S.: Cool prototype!

  • Thanks for the in depth reply!

    The reason I only have the functions set up for Enemies is because the player reacts differently to hits. The player takes knockback and has a window of invulnerability, and on death, it triggers a custom series of animations to be more dramatic, for lack of a better word.

    I suppose all that functionality could be broken off into their own functions and called on top of the base damage stuff, but that seems more complicated than what's there now, but maybe I'm overthinking it. I'd be interested to hear your take on the matter!

    The issue I was having with the implementation right now is that, certain enemies would get stuck in either the death function or hit function, and never play the respective animation. They'd lock up and break the entire game, since the function never exits.

    Did you run into that at all? 🤔

  • I would check conditions inside the damage function, and then launch animations subfunctions whatever accordingly.

    My experience is that if you funnel everything through a damage function, you have a single point were to debug later on.

    Best example is the classic of the player being alive with negative HP. Not saying that it happens in your game but in general. To prevent this from happening, you have to put an event somewhere in your code that checks if the player health is 0 or below. Then do stuff. Not only do you need to put it in the right place in the event order, but it will get called every tick even if not needed.

    A better way would be to check it only when needed, and that is inside the damage function, because intrinsically the function only gets called when needed (mainly collisions, overlaps).

    The "downside" is that you should let the player only lose health through the damage function then.

    I played your example a couple of minutes and didn't seem to run into any problem but again, maybe I was missing a certain constellation that makes this happen. Overall I would vouch you go with damage function generalization. E.g. also do the player damage stuff with progress bar from there.

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