1. Hello Guest! It's with a heavy heart that we must announce the removal of the Legacy GMC Archive. If you wish to save anything from it, now's the time! Please see this topic for more information.
    Dismiss Notice

Passing local variables to scripts without 16 argument limitation? Is there a workaround? (solved)

Discussion in 'Programming' started by BlackAura, Jul 9, 2018.

  1. BlackAura

    BlackAura Guest

    Ok, long question. I'm rebuilding a project of mine from the ground up. I'm designing a system where all game world objects can interact with one another. Therefore, there's a kind of hierarchy of variables needed for each quality of an object. I'm trying to do this using scripts with as little repetition as possible so when I change a couple universal scripts, nearly all objects are affected.

    for example:
    is an object collectible? if so does it go to inventory?
    is an object carryable? if so can it be thrown? is it heavy to lift?
    does an object emit light? if so, where? what color? radius? sprite? cast shadows? etc etc etc.

    You see, I can create variables to describe all of these aspects. however, you can see that more fundamental "parent" variables would need subcategories of variables, and if that more fundamental variable is false (like if the object does not cast light with the lighting engine) then I've created a ton of "sub-variables" that just take up memory.

    My original solution was this. Every object has a big block of initialization code. (I'll post this for an example.) Then, I would edit this block to define almost any object in the game. This would be so virtually all objects can share a universal logical system and I could mix and match the behavioral dna if you will of any object. A simple parent and child object system is not enough. I've tried. I run into situations where I want an object with the qualities of various parents and to be checked for when either parent is checked for by other objects. To avoid creating a bunch of instance variables each specialized object would have no use of, I thought to use local variables for all variables that would only be used with certain objects, then call a script that would turn the local variables into instance variables if their "parent" variable was set to true. (this script would additionally create more specialized variables.) However, I wasn't thinking and forgot that a script cannot read the local variables in the same event calling it.

    Well, this is frustrating. Could I pass local variables into the script with arguments? Absolutely, that's the point of arguments. But here's the problem. I have like... 30 local variables. far more than the 16 argument limitation.

    I could just move the (turn relevant local variables into instance variables) script's code into the create event, but then if there's a modification I want to make, i no longer can modify a script and have to manually edit all my objects. Not going to happen, and completely destroys the point of having this kind of hierarchical, universal variable system. However I need all my objects to share a ton of code as objects will be endlessly reading each other's code and interacting with each other so I need to use scripts to ensure darn-near perfect interactive behavior using strict naming conventions and matching variable names throughout.

    Here are my two ideas.

    1: use instance variables from the start. is there a downside to having like 50 variables in every object, when each object only uses a handful of them? I thought "oh hey, is there a way to free/delete instance variables if I know for sure I won't use them like I can free a surface or data structure?" It doesn't appear so.

    2: my only possible workaround. Create a ton of global variables to act like arguments, to get around the 16 argument limitation. for example. create something like a global.arg at the beginning of the game, then in my code basically do this:

    global.arg[0]=var
    global.arg[1]=var
    global.arg[2]=var
    global.arg[3]=var
    customscript()
    and the customscript will reference that global array instead of the built in argument[0-15] variables.

    My question is this. What's the more efficient solution? Am I missing something that would be a lot more elegant?

    EDIT: Third idea. Place the script's code into the parent's create code (I have a parent object called OBancestor_obj. it is essentially the parent of all parents.), then in all create events, have this initialization block run, then at the end call an event_inherited()? will the local variables from the child objects continue into the code coming in from the parent object unlike it would if that code were coming from a script?

    Here's an example of that initialization code.

    Code:
    //Init Universal Variables: Main
        xv=x                                //x origin. can be different from object's x position but usually isn't.
        yv=y                                //y origin. can be different from object's x position but usually isn't.
        xspeed=0                            //
        yspeed=0                            //
        mobile=1                            //if object can change position.
    var i_physical=1                        //if object interacts with solids.
    var i_mask=mask_index                    //mask of object. must be set here and not in object properties.
    var i_grav=1                            //gravitational factor. 1:normal
    var i_rollable=1                        //if object rolls when moved           
    var i_topple=1                            //if object is bottom-heavy and balances self.
    var i_breakable=0                        //if object is broken by being thrown.
    var i_weight=16                            //weight of object, controls how wind, water, etc affect it.
    
    //Init Universal Variables: Material Properties
        material=Material.mat_metal            //material of object.                0:null|1:particle|2:organic|3:stone|4:metal|5:wood|6:grass|7:sand|8:snow|9:ice|10:waterbody|11:waterbodyelement|12:ghost
        mat_solid=0                            //if object is a solid.
        mat_buoyant=1                        //if object floats in water.        0:null|1:alwaysfloats|2:canbesunken
        mat_burnable=0                        //if object can be lit on fire.
        mat_shockable=1                        //if object can conduct electricity.
        mat_freezable=0                        //if object can be frozen in ice.
        mat_blowable=1                        //if object can be blown by the wind.
        mat_wettable=1                        //if object can get wet.
    
    //Init Universal Variables: Interactivity
        carriable=1                            //if object can be picked up.
        collectable=0                        //if object can be collected.
        container=1                            //if object can contain another object.
    var i_inst_contain=-1                    //handle for contained object.
    
    //Init Universal Variables: HP and DP
        hazardous=0                            //if object can deal damage.
    var i_dp=0                                //damage points (amount of dealt damage).
        destructable=0                        //if object can be destroyed
    var i_respawn=0                            //if object creates respawner object upon destruction
    var i_hp=100                            //health points (resistance to recieved damage)
    var i_hp_max=i_hp                        //maximum hp.
    var i_vv_iframe=0                        //invincibility frames.
    var i_damage_beam=1                        //factor by which damage to object is multiplied. 0:invulnerable -- 1:normal vulnerability
    var i_damage_bomb=1                        //factor by which damage to object is multiplied. 0:invulnerable -- 1:normal vulnerability
    var i_damage_burn=1                        //factor by which damage to object is multiplied. 0:invulnerable -- 1:normal vulnerability
    var i_damage_shock=1                    //factor by which damage to object is multiplied. 0:invulnerable -- 1:normal vulnerability
    var i_damage_freeze=1                    //factor by which damage to object is multiplied. 0:invulnerable -- 1:normal vulnerability
    var i_damage_wet=1                        //factor by which damage to object is multiplied. 0:invulnerable -- 1:normal vulnerability
    var i_damage_blade=1                    //factor by which damage to object is multiplied. 0:invulnerable -- 1:normal vulnerability
    var i_damage_lantern=1                    //factor by which damage to object is multiplied. 0:invulnerable -- 1:normal vulnerability
    
    //Init Universal Variables: Lightcast
        lightcast=0
    var i_spr_lightcast=-1
    var i_ff_lightcast=0
    var i_xv_lightcast=x
    var i_yv_lightcast=y
    var i_xx_lightcast=1
    var i_yy_lightcast=1
    var i_rr_lightcast=0
    var i_cc_lightcast=-1
    var i_aa_lightcast=1
    

    This is the code I wanted to run after to "clean up" my variable usage. I had this in a script but for some reason totally forgot about local variable scopes when using scripts. as you can see it does a little more than just that.

    Code:
    //Create Instance Variables From Local Variables
    if mobile=1
        {
        physical=i_physical
        mask=i_mask
        if physical=1
            {
            grounded=0
            slope=0
            weight=i_weight   
            waterlevel=0
            submerged=0
            rollable=i_rollable
            breakable=i_breakable
            grav=i_grav
            if rollable=1 {topple=i_topple rr_roll=0 rs_roll=0 vv_rollsettle=0}
            //event notifiers.
            event_bounce=0
            //universal sound timers
            tt_snd_lap=0
            }
        }
        
    if mat_buoyant=1
        {sv_buo=0      ss_buo=0        vv_waterfill=0}
    if pausable=1 paused=0
        
    if mat_burnable=1
        {vv_burn=0     vd_burn=0}
    if mat_shockable=1
        {vv_shock=0    vd_shock=0}
    if mat_freezable=1
        {vv_freeze=0   vd_freeze=0}
    if mat_wettable=1
        {vv_wet=0      vd_wet=0}
    
    if container=1
        inst_contain=i_inst_contain
        
    if carriable=1
        carry=0
    
    if hazardous=1
        dp=i_dp
    
    if destructable=1
        {
        respawn=i_respawn
        hp=i_hp
        hm_max=i_hp_max
        vv_hp=0
        vv_iframe=i_vv_iframe
        damage_beam=i_damage_beam
        damage_bomb=i_damage_bomb
        damage_burn=i_damage_burn
        damage_shock=i_damage_shock
        damage_freeze=i_damage_freeze
        damage_wet=i_damage_wet
        damage_blade=i_damage_blade
        damage_lantern=i_damage_lantern
        }
        
    if lightcast=1
        {
        spr_lightcast=i_spr_lightcast
        ff_lightcast=i_ff_lightcast
        xv_lightcast=i_xv_lightcast
        yv_lightcast=i_yv_lightcast
        xx_lightcast=i_xx_lightcast
        yy_lightcast=i_yy_lightcast
        rr_lightcast=i_rr_lightcast
        cc_lightcast=i_cc_lightcast
        aa_lightcast=i_aa_lightcast
        }
    
     
    Last edited by a moderator: Jul 9, 2018
  2. YellowAfterlife

    YellowAfterlife ᴏɴʟɪɴᴇ ᴍᴜʟᴛɪᴘʟᴀʏᴇʀ Forum Staff Moderator

    Joined:
    Apr 21, 2016
    Posts:
    2,445
    Are you sure that 16-argument limitation is in effect? As far as I'm concerned, it have been fixed a while ago, so shouldn't be the case unless you are using a much older version of GM.

    Splitting the script into several (one setting some global variables for the other) or storing these values in an array/list would be the usual solution.
     
  3. Electros

    Electros Member

    Joined:
    Jul 19, 2016
    Posts:
    320
    Just a note that you can pass an array in as a single argument if you did want to circumvent the limit, then access the array elements individually. It may be if you are hitting the limit that it would be cleaner to break it down through data structures or other methods to try and simplify somehow, but it is an option.
     
  4. BlackAura

    BlackAura Guest

    I'm using GMS 2. The limit is still 16 unfortunately. I suppose I could create a couple scripts. Not the best solution for organization but a good idea!

    Of course! That's an excellent idea. That should work beautifully! I don't think I've ever used arrays as arguments in scripts, that's pretty clever, and more organized as well. I think that's the solution :)
     
  5. flyingsaucerinvasion

    flyingsaucerinvasion Member

    Joined:
    Jun 20, 2016
    Posts:
    2,224
    Are you sure the limit is still 16? In GMS1.4, you can get more than 16 arguments by using this syntax: argument[0], argument[1], etc...
     
  6. NeZvers

    NeZvers Member

    Joined:
    Mar 24, 2018
    Posts:
    320
    You can definitely pass in more than 16 arguments. There are only 16 built-in argument calls (argument0 - argument15) but that doesn't mean you can't have more.
    You need to use argument_count, so script counts all inputs and GM:S doesn't throw red line, because of wrong argument count, and read the argument as an array - argument.
    it works GM:S 1.4 AND GM:S 2.

    Code:
    //input
    array_leng(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20);
    
    //Script
    for(var i=0; i<argument_count; i++){
        show_debug_message(string(argument[i]));
    }
    
    //Output
    0
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    
     
    IndianaBones likes this.

Share This Page

  1. This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
    By continuing to use this site, you are consenting to our use of cookies.
    Dismiss Notice