• Hey Guest! Ever feel like entering a Game Jam, but the time limit is always too much pressure? We get it... You lead a hectic life and dedicating 3 whole days to make a game just doesn't work for you! So, why not enter the GMC SLOW JAM? Take your time! Kick back and make your game over 4 months! Interested? Then just click here!

reset a function when not being used ?

jonjons

Member
hello
Is there a way to know when a function is stoped or is not being used ?

for example if i have a state with 2 functions
GML:
switch (state)
{
    case 1:
        AA_counter(10);
        break;
    case 2:
        BB_counter(20);
        break;   
}
If i switch from state 1 to state 2 the delay will not reset to zero
if the AA_counter(10) is 200, it will stop in state 2. And will continue 200++ again in state 1 ?
 

NightFrost

Member
You mention a "delay" but your code does not appear to refer to anything like that. A delay what? You also mention a number 200 but there's no context to that in the code. I don't really understand what kind of code structure you're wanting to create.
 
hello
Is there a way to know when a function is stoped or is not being used ?

for example if i have a state with 2 functions
GML:
switch (state)
{
    case 1:
        AA_counter(10);
        break;
    case 2:
        BB_counter(20);
        break; 
}
If i switch from state 1 to state 2 the delay will not reset to zero
if the AA_counter(10) is 200, it will stop in state 2. And will continue 200++ again in state 1 ?
Hi, could you explain more of the context of what you are doing with your code?
I'm not sure of what is going on in each function.

So you have a counter variable that each function is setting, or is this 200 value a counter instance variable it is reading?
 

jonjons

Member
The function is not important ive made it up...
this function...

GML:
delaySet =50;

delay = delaySet;


function AA_delay()
{
    if ( delay > 0 )
    {
        delay -= room_speed /30;  
   
        if ( delay <= 0 )
        {
            delay = delaySet;
        }
    }
}
if started in state 1

GML:
switch (state)
{
    case 1:
        AA_delay();
        break;
    case 2:
        //////////////////////////
        break;
}
Is there a way to reset it once i exit state 1 ?
if iam in state 1 and AA_delay is 14 it will stop at 14 if i go to state 2
and it will continue in 14 if i go back to state 1
[edit] and if i use AA_delay() in state 2 it will start at 14 instead of zero
 
The function is not important ive made it up...
this function...

GML:
delaySet =50;

delay = delaySet;


function AA_delay()
{
    if ( delay > 0 )
    {
        delay -= room_speed /30; 
  
        if ( delay <= 0 )
        {
            delay = delaySet;
        }
    }
}
if started in state 1

GML:
switch (state)
{
    case 1:
        AA_delay();
        break;
    case 2:
        //////////////////////////
        break;
}
Is there a way to reset it once i exit state 1 ?
if iam in state 1 and AA_delay is 14 it will stop at 14 if i go to state 2
and it will continue in 14 if i go back to state 1
[edit] and if i use AA_delay() in state 2 it will start at 14 instead of zero
I agree alarms sound like a good idea so you don't need to write your own from scratch.

But if you want to write your own, I can think of two ideas:
1. reset the counter when you change states
2. keep track of last frame's state in an instance variable and compare it to this frame's state. When they differ, reset the time.
 

jonjons

Member
I agree alarms sound like a good idea so you don't need to write your own from scratch.

But if you want to write your own, I can think of two ideas:
1. reset the counter when you change states
2. keep track of last frame's state in an instance variable and compare it to this frame's state. When they differ, reset the time.
yes that way will work, maybe by adding a variable stateNumber to the function. The problem is the funtion will only work in switch states
GML:
function AA_delay( stateNumber )
{

var abc123= variable_instance_get(id, stateNumber );

if ( state != abc123  )
{
    if ( delay > 0 )
    {
        delay -= room_speed /30;
 
        if ( delay <= 0 )
        {
            delay = delaySet;
        }
    }

}


}

btw is there a way to delete a static var ? static_destroy(varName) ???
 
yes that way will work, maybe by adding a variable stateNumber to the function
GML:
function AA_delay( stateNumber )
{

var abc123= variable_instance_get(id, stateNumber );

if ( state != abc123  )
{
    if ( delay > 0 )
    {
        delay -= room_speed /30;
 
        if ( delay <= 0 )
        {
            delay = delaySet;
        }
    }

}


}

btw is there a way to delete a static var ? static_destroy(varName) ???
There's no need to delete this. It is called a local or temporary variable by the way. These are deleted/removed from the stack automatically when the function/event ends.
Also, if you use variable_instance_get() you'll need to pass a string name of the variable. Instead I think it is easier to simply read the variable by name directly, like:
Code:
if (state != stateNumber)
...
Hope this helps :)
 

kburkhart84

Firehammer Games
You should read up on state machines. A machine not only knows what state it is in, but handles transitions between states as well.

Since you tagged this post 2.3+, I'd recommend you get familiar with structs. I used them on my Jam entry for the state machine, and it worked really well. Each state can be represented by a struct. When you start, you create the struct(and assign it to a state variable on your object instance). The constructor code for the struct not only initializes the needed variables, but it also serves as the "enter state" function. You would then create the "run" or "step" function for the state, and an "exit" function as well(named something other than exit due to 'exit' being a forbidden keyword, I used "leave()" for mine).

In the object, you can simply use the reference to the struct to call "run()" each step. As long as you define that function on your states, it won't matter what state you are in, it will simply "run()" which means you no longer need the switch statement.

When you create the struct, you also pass in the owner as an argument to the constructor and store that in a variable of the struct itself, so that you can easily access the owner's variables, and the instance itself(for moving around, etc...).

And each state's code can handle whatever is needed in that state. If you need to change states, you simply call the leave() function, and using the id/owner(often done in a with() statement), you assign a newly created state that you are switching to. Each state's code is responsible for switching to the next state.

If you wanted to, you could also simply return the new state from the run() function and then have the instance step event handle leaving the old state and assigning the value to the variable(only when it is supposed to change), but in my Jam entry I did it with the states themselves doing it.

Using the above idea, you can share variables on the instance(since you access them via the owner). You can also easily add states at any time you need, just requiring you to code the other states to know when to switch to that state.
 
You should read up on state machines. A machine not only knows what state it is in, but handles transitions between states as well.

Since you tagged this post 2.3+, I'd recommend you get familiar with structs. I used them on my Jam entry for the state machine, and it worked really well. Each state can be represented by a struct. When you start, you create the struct(and assign it to a state variable on your object instance). The constructor code for the struct not only initializes the needed variables, but it also serves as the "enter state" function. You would then create the "run" or "step" function for the state, and an "exit" function as well(named something other than exit due to 'exit' being a forbidden keyword, I used "leave()" for mine).

In the object, you can simply use the reference to the struct to call "run()" each step. As long as you define that function on your states, it won't matter what state you are in, it will simply "run()" which means you no longer need the switch statement.

When you create the struct, you also pass in the owner as an argument to the constructor and store that in a variable of the struct itself, so that you can easily access the owner's variables, and the instance itself(for moving around, etc...).

And each state's code can handle whatever is needed in that state. If you need to change states, you simply call the leave() function, and using the id/owner(often done in a with() statement), you assign a newly created state that you are switching to. Each state's code is responsible for switching to the next state.

If you wanted to, you could also simply return the new state from the run() function and then have the instance step event handle leaving the old state and assigning the value to the variable(only when it is supposed to change), but in my Jam entry I did it with the states themselves doing it.

Using the above idea, you can share variables on the instance(since you access them via the owner). You can also easily add states at any time you need, just requiring you to code the other states to know when to switch to that state.
Yes, once the code is up and working, refactoring into a full state machine sounds like a solid goal if it makes sense for this timer/the rest of the game.
 

jonjons

Member
You should read up on state machines. A machine not only knows what state it is in, but handles transitions between states as well.

Since you tagged this post 2.3+, I'd recommend you get familiar with structs. I used them on my Jam entry for the state machine, and it worked really well. Each state can be represented by a struct. When you start, you create the struct(and assign it to a state variable on your object instance). The constructor code for the struct not only initializes the needed variables, but it also serves as the "enter state" function. You would then create the "run" or "step" function for the state, and an "exit" function as well(named something other than exit due to 'exit' being a forbidden keyword, I used "leave()" for mine).

In the object, you can simply use the reference to the struct to call "run()" each step. As long as you define that function on your states, it won't matter what state you are in, it will simply "run()" which means you no longer need the switch statement.

When you create the struct, you also pass in the owner as an argument to the constructor and store that in a variable of the struct itself, so that you can easily access the owner's variables, and the instance itself(for moving around, etc...).

And each state's code can handle whatever is needed in that state. If you need to change states, you simply call the leave() function, and using the id/owner(often done in a with() statement), you assign a newly created state that you are switching to. Each state's code is responsible for switching to the next state.

If you wanted to, you could also simply return the new state from the run() function and then have the instance step event handle leaving the old state and assigning the value to the variable(only when it is supposed to change), but in my Jam entry I did it with the states themselves doing it.

Using the above idea, you can share variables on the instance(since you access them via the owner). You can also easily add states at any time you need, just requiring you to code the other states to know when to switch to that state.
can you post a small example of the struct, it seems confusing trying to picture it this way... How would a var that increments++ or -- would always start at zero when the strut begins
 

kburkhart84

Firehammer Games
can you post a small example of the struct, it seems confusing trying to picture it this way... How would a var that increments++ or -- would always start at zero when the strut begins
So, if the timer is just belonging to the state itself, then you would make the variable be part of the struct for that state. And the constructor function would simply set it to zero. If you need to access that value elsewhere for something, you can instead make it a variable of the object/instance.

I will post a couple of the states of my structs from my Jam entry. Anything in ALL CAPS is a #macro I defined elsewhere. Also, there are some function calls here that are part of my input and audio assets(fhAudio/fhInput) so don't try to find docs on those in the manual. Those don't matter anyway for the purpose of this example.

Code:
function bStateIdle(owner) constructor
{
    myOwner = owner;
    with(myOwner)
    {
        myState = BSTATE_IDLE;
        hspeed = 0;
        vspeed = 0;
    }
    
    static run = function()
    {
        //do nothing
    }
    static leave = function()
    {
        
    }
}
Code:
function bStateDrop(owner) constructor
{
    myOwner = owner;
    with(myOwner)
    {
        myState = BSTATE_DROPPING;
        vspeed = BOX_SPEED_DROP;
    }
    static run = function()
    {
        with(myOwner)
        {
            var spd = BOX_SPEED_DROP;
            if(fhInputActionCheckDown(FHINPUTACTION_Down))
                spd = 32;
            vspeed = spd;
            var inst = instance_place(x, y+spd, objSolid);
            if(inst == noone)
                inst = instance_place(x, y+spd, objSpikes);
            if(inst != noone)
            {
                if(inst.object_index == objPlatform || inst.object_index == objSpikes)
                {
                    pushAgainstDown();
                    
                    other.leave();
                    other.myStateCode = new bStateStill(id);
                    break;
                }
                //if adding a spring, add a case for it here to destroy the box
                if(inst.object_index == objBox)
                {
                    var otherType = inst.myType;
                    var stop = false;
                    switch(myType)
                    {
                        case BOX_CARDBOARD:
                            stop = true;
                            break;
                        case BOX_WOOD:
                            if((otherType == BOX_WOOD) || (otherType == BOX_METAL))
                                stop = true;
                            break;
                        case BOX_METAL:
                            if(otherType == BOX_METAL)
                                stop = true;
                            break;
                    }
                    if(stop)
                    {
                        pushAgainstDown();
                        other.leave();
                        other.myStateCode = new bStateStill(id);
                        break;
                    }
                    else
                    {
                        instance_destroy(inst);
                    }
                    break;
                }
                
                
            }
        }
    }
    static leave = function()
    {
        
    }
    static playLandSound = function()
    {
        with(myOwner)
        {
            if(myType == BOX_CARDBOARD)
                PlaySoundExt(SND_BOXLANDCARDBOARD);
            if(myType == BOX_METAL)
                PlaySoundExt(SND_BOXLANDMETAL);
            if(myType == BOXWOOD)
                PlaySoundExt(SND_BOXLANDWOOD);
        }
    }
}
So the "idle" state you see there simply sets the box speed to 0. Note that the constructor function takes the owner instance as the only argument, and it stores that for future usage. The idle state doesn't actually use it though. Note that the idle state also defines a run and a leave() function, even though they don't do anything. Final note on the idle state, the reason the run() function doesn't do anything is because the box in this state is actually being controlled by another object(a crane that drops the box). Therefore, the crane will actually handle making the box go to the dropping state.

Now, the code in the dropping state...when you first start that(by creating the struct with the constructor), note that it also stores the owner in one of the struct variables. Then, the run() function will actually use that owner value to know what box it belongs to, so that it drops that specific box, and check collisions using that specific box. It also does a couple other things. For example, when it is time for the box to stop dropping, it leaves the state(by calling its own leave() function), and it creates the next state on the box(the owner). Finally, it sets the variable on the owner to that new state as well. So once this code block is done, the next step, the run() function will be on the other state, even though it was in the same variable.

Now, I'll show you the create event of the box object, followed by the step event.
Code:
//create
myType = BOX_CARDBOARD;
myState = BSTATE_IDLE;
myStateCode = new bStateIdle(id);

//step
myStateCode.run();
if(myState == BSTATE_STILL && y < 120)
{
    instance_destroy();
}
See how simple those are by comparison? The create event simply sets a variable for the box type(I have 3 different boxes though they use the same object), and sets the state, both the variable with the macro and the actual struct. See how I add the 'id' variable to the struct creation? That gets stored in the owner variable of the struct. Then, see how the step even only needs a single line to call the run() function of the state. Note that the state could be ANY state I have defined for the box. Since the states themselves handle changing the 'myStateCode' variable to whatever state the box is in, the step event only has to call the run() function and doesn't actually care what it is doing. The only other code in that step event is checking for a specific case of the box location and state so it will be destroyed if needed.

**************

So, in your case...if you simply want the state to change based on the decrementing variable, you could make that just another variable in the struct for the state. Then, the run() function of that state would decrement it and once it is the right value, it would simply change state to the other struct. That other struct would create its own decrementing variable, which would be a different starting value from the first state going by your example. Finally, the object would just call run() on the variable that you are storing the state struct in, and the object itself has no need to directly know anything about the decrementing variables that are in the struct.

That's the beauty of using structs for this in fact. Each state stores only the values it needs to keep for its own tracking. The states CAN easily affect variables on the object as well in order to make it do whatever it needs, like falling, running, jumping, checking input, etc... The other cool thing is that each state is its own thing. If for example you have a state for a platformer character that is a STANDING state, and another that is for CROUCHING. Each state can check the jump button. The standing state would make it jump, but the crouching state could instead make it go down through the platform(seen in the Contra games for example).

You could also use a similar idea for different weapons. Each weapon can be a state of the actual gun object. They all check the shoot button for example, but one makes a spread shot when the button is hit, while another can check if the button is held down to do a charge shot. And the code for the two different things doesn't affect the others despite them both checking the same button.

If a character is falling for example(and you don't do space/double jump), then maybe you don't even check if the jump button is being hit, since the character can't jump while its falling.
 

jonjons

Member
thanks, it seems you already went ahead and typed the state in a function.

So, in your case...if you simply want the state to change based on the decrementing variable, you could make that just another variable in the struct for the state
yes this way worked... ive added a new var animReset = "a";
had to set it to "a" to skip using an extra variable_instance_get(id, name). Iam using a ds_grid GM by default sets it to 0 then 1,2,3,... when it reads from the function
GML:
function SK_AnimPlay(newAnim, _delay, _loop)
{
        anim_delay();
        var newAnimPass    = variable_instance_get(id, newAnim);

        if ( root !=  newAnimPass || animReset != "a")
        {
            animReset = "a";

            delay = 0;
            fk_imageindex = 0;
            delaySet = _delay;
            delay = delaySet;
            loop = _loop;
          
            root = newAnimPass;
            fk_imageNumber = array_length(root.Fnum)-1;
        }
        fk_imageindex = clamp(fk_imageindex, 0, fk_imageNumber);
}

function anim_costum_play( animVar )
{
    anim_delay2();
  
    if ( animReset != animVar )
    {
        animReset = animVar;
        arryGO = 0;
        delaySet2 = ds_grid_get(animVar, 2, arryGO);
        delay2 = delaySet2;
    }
  

    if ( delaySet2 != ds_grid_get(animVar, 2, arryGO) )
    {
        delaySet2 = ds_grid_get(animVar, 2, arryGO);
        delay2 = delaySet2;
    }
  

    arryGOsize = ds_grid_height(animVar)-1;
  

    if ( ds_grid_get(animVar, 0, arryGO) != 0  && root != ds_grid_get(animVar, 0, arryGO))
    {
        root = ds_grid_get(animVar, 0, arryGO);
    }
  
  
    if (  ds_grid_get(animVar, 1, arryGO) <=  array_length(root.Fnum)-1   )
    {
        fk_imageindex = ds_grid_get(animVar, 1, arryGO);
        fk_imageNumber = ds_grid_height(animVar)-1;
    }
    else if ( ds_grid_get(animVar, 1, arryGO) >= array_length(root.Fnum) )
    {
        arryGO = 0;
    }
}
 
Top