Recall script next frame?

maxdax5

Member
Sup! Cant find if its possible to 'recall' the current script next frame in that script.
(within a script, a code that will re-execute the script next frame)
 

FrostyCat

Member
Never try to do anything over the span of multiple frame steps inside a single script. If you want a script to trigger follow-up action later, one alternative is to create an object that executes the follow-up action with a delay (easy to do with an alarm), and generate an instance of that in the script.
 

maxdax5

Member
That is exactly what i dont want to do. I like to keep my games optimized at maximum and this is a part of it.
EX: create enemy, in enemy create event execute scr_spawn, (in scr_spawn: if alpha < 1 {alpha += 0.05}), and here is where i want to recall the script next frame until alpha = 1.
 

FrostyCat

Member
That is exactly what i dont want to do. I like to keep my games optimized at maximum and this is a part of it.
EX: create enemy, in enemy create event execute scr_spawn, (in scr_spawn: if alpha < 1 {alpha += 0.05}), and here is where i want to recall the script next frame until alpha = 1.
Then just run that in the Step event, plain and simple. Stop putting so much emphasis on optimization to the point that you do nonsense. Adding one little event isn't going to amount to much in the long run, but inventing syntax and hoping for non-existent functionality will stop you dead.
 

TsukaYuriko

☄️
Forum Staff
Moderator
That is exactly what i dont want to do. I like to keep my games optimized at maximum and this is a part of it.
EX: create enemy, in enemy create event execute scr_spawn, (in scr_spawn: if alpha < 1 {alpha += 0.05}), and here is where i want to recall the script next frame until alpha = 1.
That is what Step events are for.

If you're doing this for the sake of optimization, you're not doing yourself a favor by adding the overhead that would come with this way of handling repeated actions. Not that it would hamper performance by much unless you liberally use this everywhere, but it certainly doesn't speed up anything. (Unless you're talking about development speed, not game speed... but even then, I can barely see any gain from doing this.)


What you could do to achieve a similar effect is to have a list of scripts in each object that should offer this feature, which is then iterated through every step and has all scripts in it executed. You can add scripts to this list to schedule them for repetition and remove them to cancel it, as long as you pay attention not to remove from this list while it is being iterated over (as doing so would mess up the order and cause some to be skipped that step, leading to all sorts of unwanted effects). That's a bunch of extra hassle and a human error pitfall in exchange for a feature that, at least to me, doesn't sound very useful, though - this is not meant to be a solution suggestion, but a deterrent due to its impracticality.
 

maxdax5

Member
A simple 'if' code in an object, every step is not that much. A single 'if' code in 378 objects, every step + all the other optimisation you tought was useless = failing.
So my question is still: Is it possible, from a script, to execute a script the next step?
 

Homunculus

Member
That’s not where you should be optimizing, even with 10 times that number of instances. You can’t set a script to run on another step though, you’ll have to use an alarm or an event of the caller object by setting the condition yourself.
 
Last edited:

Ido-f

Member
I have a system for that.
Basically, I have my logic singleton go through a list of commands and preform them in 'with' statements. Then a delay_script script can add an item to that list with relevant data.

scr_delay_script:
Code:
///@func scr_delay_script(id, steps, script, arguments_array)
///@arg id instance to run the code
///@arg steps number of steps to delay the code
///@arg script
///@arg arguments_array
///scripts will run at the start of the begin_step, at the end of obj_logic's event. So no draw functions.

ds_list_add(LOGIC.delayed_scripts, [argument0, argument1, argument2, argument3]);

enum delayed
{
    id,
    steps,
    script,
    args
}
singleton begin-step event:
Code:
#region delayed scripts
var _delayed = delayed_scripts,
    _size = ds_list_size(_delayed),
    _item,
    i = 0;
repeat(_size)
{
    _item = _delayed[| i];
    if (--_item[@ delayed.steps] <= 0)
    {
        with _item[delayed.id]
        {
            scr_script_execute(_item[delayed.script], _item[delayed.args])
        }
        ds_list_delete(_delayed, i)
        i--;
    }
    i++;
}
#endregion
scr_script_execute:
Code:
var _script = argument0,
    _args = argument1;

switch (array_length_1d(_args))
{
    case 0 : script_execute(_script); break;
    case 1 : script_execute(_script, _args[0]); break;
    case 2 : script_execute(_script, _args[0], _args[1]); break;
    case 3 : script_execute(_script, _args[0], _args[1], _args[2]); break;
    case 4 : script_execute(_script, _args[0], _args[1], _args[2], _args[3]); break;
    case 5 : script_execute(_script, _args[0], _args[1], _args[2], _args[3], _args[4]); break;
    case 6 : script_execute(_script, _args[0], _args[1], _args[2], _args[3], _args[4], _args[5]); break;
    case 7 : script_execute(_script, _args[0], _args[1], _args[2], _args[3], _args[4], _args[5], _args[6]); break;
    case 8 : script_execute(_script, _args[0], _args[1], _args[2], _args[3], _args[4], _args[5], _args[6], _args[7]); break;
    case 9 : script_execute(_script, _args[0], _args[1], _args[2], _args[3], _args[4], _args[5], _args[6], _args[7], _args[8]); break;
    case 10: script_execute(_script, _args[0], _args[1], _args[2], _args[3], _args[4], _args[5], _args[6], _args[7], _args[8], _args[9]); break;
    case 11: script_execute(_script, _args[0], _args[1], _args[2], _args[3], _args[4], _args[5], _args[6], _args[7], _args[8], _args[9], _args[10]); break;
    case 12: script_execute(_script, _args[0], _args[1], _args[2], _args[3], _args[4], _args[5], _args[6], _args[7], _args[8], _args[9], _args[10], _args[11]); break;
    case 13: script_execute(_script, _args[0], _args[1], _args[2], _args[3], _args[4], _args[5], _args[6], _args[7], _args[8], _args[9], _args[10], _args[11], _args[12]); break;
    case 14: script_execute(_script, _args[0], _args[1], _args[2], _args[3], _args[4], _args[5], _args[6], _args[7], _args[8], _args[9], _args[10], _args[11], _args[12], _args[13]); break;
    case 15: script_execute(_script, _args[0], _args[1], _args[2], _args[3], _args[4], _args[5], _args[6], _args[7], _args[8], _args[9], _args[10], _args[11], _args[12], _args[13], _args[14]); break;
    case 16: script_execute(_script, _args[0], _args[1], _args[2], _args[3], _args[4], _args[5], _args[6], _args[7], _args[8], _args[9], _args[10], _args[11], _args[12], _args[13], _args[14], _args[15]); break;
    default: show_error("scr_script_execute got too many arguments", true); break;
}
LOGIC is a macro defined as global.logic, which is assigned the singlton instance's id at the start of the program.
only other set-up needed is creating a delayed_scripts list for the singleton.
 
Last edited:

Binsk

Member
A simple 'if' code in an object, every step is not that much. A single 'if' code in 378 objects, every step + all the other optimisation you tought was useless = failing.
So my question is still: Is it possible, from a script, to execute a script the next step?
No. Listen to your seniors who know more than you and take their advice mentioned above. Use the step event. You either do it the right way or you have to create messy workarounds like the example given by @Ido-f where, even though useful and functional for certain purposes, has significantly more overhead.
 

maxdax5

Member
Got to give you a point on this one. Just made a test to see how much juice it take and it is pretty low. The test bellow is on a 10 second period every time.

No instances
1:max 5714, avg 3768
2:5882, 4221
3:5988, 4205

200 instances with 1 if statement
1:3472, 2863
2:3401, 2515
3:3412, 2803

200 instances with 2 if statement
1:3424, 2512
2:3236, 2544
3:4901, 2221

400 instances with 2 if statement
1:2331, 1897
2:2409, 1709
3:2309, 1770

Even if they were basic lines of code, it was less juice eating than i tought. I still want my games flawless and feel like creating an instance for couple of steps or have that line of code that is used only for a couple steps then become a stick in you wheel after that could be avoided. Thx for your help anyway!
 

TheouAegis

Member
That's where state machines come into play. But then you're still reading the state every step,so no real gain there. Creating an instance has the overhead of creating the instance (updating the instance list, initializing all the variables), then every event checking if that object has any code. Now, that does seem like a viable option, but it's very unorthodox.
 

Ido-f

Member
No. Listen to your seniors who know more than you and take their advice mentioned above. Use the step event. You either do it the right way or you have to create messy workarounds like the example given by @Ido-f where, even though useful and functional for certain purposes, has significantly more overhead.
Thanks for the recognition, but I think it should have the same overhead as the instances method, maybe even less.
Iterating through a list, comparing and reducing a counter: The same as iterating through the instances list, checking and reducing an alarm.
And it's easier to work with as you have a universal script and all of the information you need is in the line of code you called it with, compared to hiding that information in the resource tree's instances or in unnamed alarm events.
 
Top