• 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!

OFFICIAL GMS 2.3.0 BETA ANNOUNCEMENT

Status
Not open for further replies.
L

looreenzoo86

Guest
Here #169776 and I haven't received access yet :(((
I would like to try to understand the criterion used for the priority for access to the beta...
 
D

Deleted member 45063

Guest
Here #169776 and I haven't received access yet :(((
I would like to try to understand the criterion used for the priority for access to the beta...
It has been mentioned throughout the thread that it is first-come, first-served, so I'm guessing they just stopped issuing access before your ticket number got picked :/
 

Bruchpilot

Member
Here #169776 and I haven't received access yet
*adjusts glasses*
According to my calculations they have handed out about 300 - 350 Beta invites within a week, and taking into account the ticket numbers (there's of course a lot of unknowns, because it's just the regular ticket counter, so non-beta-request tickets count up too) and assuming they continue to do so in a comparable pace, I would guess you're up in about 1 - 1.5 weeks.

This could of course be completely wrong on all levels, though ;)
 

Zhanghua

Member
What's the different between the codes below?
Code with Error message show the "Why do you call me????"!!!!!
GML:
function basic() constructor{  static function val(){ throw("You should call me!!!!!!"); }  }
function overload1(): basic() constructor{}
function overload2(): basic() constructor{  static function val(){ throw("Why do you call me????"); } }
Code with Normal message..... show the "You should call me!!!!!!"
GML:
function basic() constructor{ static val = function(){ throw("You should call me!!!!!!"); }  }
function overload1(): basic() constructor{}
function overload2(): basic() constructor{ static val = function(){ throw("Why do you call me????"); } }
The test code................
GML:
function test(){
    var test1 = new overload1();
    test1.val();
}
 
Last edited:

FrostyCat

Redemption Seeker
What's the different between the codes below?
Code with Error message show the "Why do you call me????"!!!!!
GML:
function ICondition() constructor{  static function val(){ throw("You should call me!!!!!!"); }  }
function IConditionEle(): ICondition() constructor{}
function OConditions_Err(): ICondition() constructor{  static function val(){ throw("Why do you call me????"); } }
Code with Normal message..... show the "You should call me!!!!!!"
GML:
function ICondition() constructor{ static val = function(){ throw("You should call me!!!!!!"); }  }
function IConditionEle(): ICondition() constructor{}
function OConditions_Err(): ICondition() constructor{ static val = function(){ throw("Why do you call me????"); } }
The test code................
GML:
function test(){
    var test1 = new IConditionEle();
    test1.val();
}
From what I've observed during the beta, function declarations in function name(...) { ... } form get pulled to the top level to become scripts, while those in name = function(...) { ... } form stay localized where they are. So your first sample starts with one implementation and then overwrites it with another down the line, while the second sample has two distinct implementations.

One important note to keep in mind when exploring OOP in GMS 2.3 is to STOP thinking of it as static-type OOP found in C++/C#/Java. It is a duck-typed, JS-like kind of OOP.
 

Zhanghua

Member
From what I've observed during the beta, function declarations in function name(...) { ... } form get pulled to the top level to become scripts, while those in name = function(...) { ... } form stay localized where they are. So your first sample starts with one implementation and then overwrites it with another down the line, while the second sample has two distinct implementations.

One important note to keep in mind when exploring OOP in GMS 2.3 is to STOP thinking of it as static-type OOP found in C++/C#/Java. It is a duck-typed, JS-like kind of OOP.
Yes, during the test, I find the same named inner functions overwrite the upper each other.

But the inner method variable type is overload rightly.
 

Zhanghua

Member
From what I've observed during the beta, function declarations in function name(...) { ... } form get pulled to the top level to become scripts, while those in name = function(...) { ... } form stay localized where they are. So your first sample starts with one implementation and then overwrites it with another down the line, while the second sample has two distinct implementations.

One important note to keep in mind when exploring OOP in GMS 2.3 is to STOP thinking of it as static-type OOP found in C++/C#/Java. It is a duck-typed, JS-like kind of OOP.
GML:
function basic() constructor{
    function val(){ throw("You should call me!!!!!!"); }
}

function overload1(): basic() constructor{
}

function overload2(): basic() constructor{
     function val(){ throw("Why do you call me????"); }
}

function basic2() constructor{
    function a(){
        function val(){ throw("what the f111111111"); }
    }
}

function val(){ throw("what the f22222222"); }


function test(){
    var test1 = new overload1();
    show_debug_message( test1.val() );
}
It will show the basic2's "what the f111111111" while not the latest outside val() which throws "what the f22222222"
 

FrostyCat

Redemption Seeker
Your f1 version is at a deeper nesting level than your f2 version, so f1 may end up being evaluated by the compiler later than f2 and give the result you saw.

Look, just stop declaring constructor methods using function name(...) { ... } already, and use name = function(...) { ... } which is known to work. This isn't PHP.
 

Miradur

Member
@FrostyCat / @Yal

So in my opinion, GameMaker is very well suited for beginners who do not have much programming experience. So you usually start with DnD. But now the legitimate question arises why a game engine from the 21st century doesn't support ramps, although a game from 1991 already did this(Sonic). Or is it officially approved that you have to buy missing standard features, buy and fix obvious bugs yourself (or buy something that fixes it)? Why you defend this model is now clear to me, it's about money and the prestige of being better than others. But YoYo certainly thinks as a company and since they live to a large extent from new customers, they surely see it a little bit differently than you (at least I hope so).

Good business my friends,
Miradur
 

Niften

Member
@FrostyCat / @Yal

So in my opinion, GameMaker is very well suited for beginners who do not have much programming experience. So you usually start with DnD. But now the legitimate question arises why a game engine from the 21st century doesn't support ramps, although a game from 1991 already did this(Sonic). Or is it officially approved that you have to buy missing standard features, buy and fix obvious bugs yourself (or buy something that fixes it)? Why you defend this model is now clear to me, it's about money and the prestige of being better than others. But YoYo certainly thinks as a company and since they live to a large extent from new customers, they surely see it a little bit differently than you (at least I hope so).

Good business my friends,
Miradur
If you don't want to make your own system, you can still get it working within minutes with a quick tutorial, Google search, or marketplace download, there's no need to berate the engine because it doesn't have everything you need built-in
 

FrostyCat

Redemption Seeker
@FrostyCat / @Yal

So in my opinion, GameMaker is very well suited for beginners who do not have much programming experience. So you usually start with DnD. But now the legitimate question arises why a game engine from the 21st century doesn't support ramps, although a game from 1991 already did this(Sonic). Or is it officially approved that you have to buy missing standard features, buy and fix obvious bugs yourself (or buy something that fixes it)? Why you defend this model is now clear to me, it's about money and the prestige of being better than others. But YoYo certainly thinks as a company and since they live to a large extent from new customers, they surely see it a little bit differently than you (at least I hope so).

Good business my friends,
Miradur
That's because GMS 2 is a general-purpose engine, not a genre-specific drop-and-go engine. Making ramps is a narrow need specific to the platformer genre, and one that isn't difficult to handle if you check out tutorials like this. And to boot, tile collisions is a top recommended result on that video. It's GameMaker, not PlatformerMaker.

Stop it with this fraidy-cat "I-am-a-beginner" talk line already. Given that YoYo hasn't imploded yet from not getting new users, the only conclusion I can make is that most revenue-generating beginners YoYo has been receiving over the years are running circles around you in terms of intellectual courage. They look into things they aren't comfortable with and learn from them. You just sit here with your beginner hat and whine about how the GM world should revolve around you.
 
One important note to keep in mind when exploring OOP in GMS 2.3 is to STOP thinking of it as static-type OOP found in C++/C#/Java. It is a duck-typed, JS-like kind of OOP.
For those of us who've only used GML, would you be able to briefly explain what you mean by this? I googled but the explanations are either super vague or jump right into code-heavy examples and it's hard to tell if YoYo's execution of this stuff is the exact same as other languages or if trying to learn from Java tutorials is just going to throw me off (like how GameMaker's "objects" are different from other languages "objects" etc)

And for you or anyone else: I'm still trying to understand what kind of situations a person would decide to use or not use "static" in their function declarations in actual application for a game, I think I understand static variables but it seems like you would pretty much always want to use static functions, but if anyone could provide an example of a scenario where you'd want to use a static function and use a non-static function in like, a Mario game or Pac-Man or RPG or something, that would be a huge help!

I feel like having function, constructor AND static, 3 new keywords that all seem to work together in various combinations for various results, is probably the most confusing leap for someone who's just been using normal GML scripts for years so it's hard to grasp at first and figure out "ok what kind of situations would I want to use these different combinations if I'm making a game instead of just doing programming concept exercises?" So any help would be awesome!
 

FrostyCat

Redemption Seeker
For those of us who've only used GML, would you be able to briefly explain what you mean by this? I googled but the explanations are either super vague or jump right into code-heavy examples and it's hard to tell if YoYo's execution of this stuff is the exact same as other languages or if trying to learn from Java tutorials is just going to throw me off (like how GameMaker's "objects" are different from other languages "objects" etc)
Learning OOP from Java will teach you the static-typed variety of OOP, which is the most commonly taught. Static-type means every value has a developer-specified type that strictly determines whether A counts as B (e.g. if you declare int foo = 5;, you cannot turn around and put a string in foo later), and OOP means there are reusable units of code (classes) that have their own formally associated properties and actions.

GML 2020 has duck-typed OOP. It's still OOP because the reusable units (class constructors) have formally associated properties and actions. But duck-type means there is no developer-specified type that the compiler takes as canon, instead the presence of certain actions determines whether A counts as a B. A duck has a swim(), quack() and walk() method, and anything implementing all 3 will count as a duck. There is no formal compiler-level type enforcement. In contrast, with static typing, only instances created from the duck class or its children can count as a duck, just having all 3 of the named methods wouldn't be enough and will cause the compiler to stop if you try to use such as a class as a duck.

The closest equivalent I know of to GML 2020 OOP is the model used by JS, while the kind in C++/C#/Java is the polar opposite in many ways. It's fine and actually valuable to learn from the static-typed OOP model, but you can't be fundamentalist about it. You have to think over what are actually OOP (fields and methods) and what are just shibboleths of static-typing that don't apply in GML 2020 OOP (abstract, interface, virtual, etc.)

And for you or anyone else: I'm still trying to understand what kind of situations a person would decide to use or not use "static" in their function declarations in actual application for a game, I think I understand static variables but it seems like you would pretty much always want to use static functions, but if anyone could provide an example of a scenario where you'd want to use a static function and use a non-static function in like, a Mario game or Pac-Man or RPG or something, that would be a huge help!

I feel like having function, constructor AND static, 3 new keywords that all seem to work together in various combinations for various results, is probably the most confusing leap for someone who's just been using normal GML scripts for years so it's hard to grasp at first and figure out "ok what kind of situations would I want to use these different combinations if I'm making a game instead of just doing programming concept exercises?" So any help would be awesome!
In GML 2020, using static means you want every instance built from the constructor to have the exact same implementation of the marked function. There are times when you want individual instances to have varying implementations, where you would NOT use static.

For example, this tick-based delayer class:
GML:
function Delayer(_action, _ticks) constructor {
    action = _action;
    ticks = _ticks;

    static tick = function() {
        if (--ticks == 0) action();
    };
}
Create:
GML:
nextRoomAction = new Delayer(function() {
    room_goto_next();
}, room_speed*2);
Step:
GML:
nextRoomAction.tick();
Every instance of this Delayer class ticks the same way, so tick uses static. But the action being performed varies between instances, so it is NOT static.

In summary:
  • function denotes a subroutine.
  • constructor marks a function as something that can be used with new to create lightweight instances.
  • static marks a property/method such that all instances get the same starting implementation from the constructor. Without it, each instance starts with its own independent copy. Only the constructor has write access to a static property/method, not other methods in the constructor or anything external --- attempts to write by other sources later result in a non-static property/method.
Update 2020-05-12: Changed wording to reflect a reply from YoYo about the behaviour of static.
 
Last edited:

Khao

Member
Got my beta email about 8 hours ago! Since you guys love to know, I had the ticket #169326. Applied the first day, but I remember I did so several hours late (8:13:57 PM GMT+1, if that's helpful).

Can't wait to try the new features. I'm a fundamentally paranoid person so I'm kinda anxious to know if my game's gonna work in this version correctly, hahaha. Won't do a full conversion until 2.3 is officially released but it can't hurt to know what to expect.

EDIT: Okay, literally nothing in my game works any differently than in the live version, so that's fantastic!
 
Last edited:

Karlstens

Member
@FrostyCat / @Yal

So in my opinion, GameMaker is very well suited for beginners who do not have much programming experience. So you usually start with DnD. But now the legitimate question arises why a game engine from the 21st century doesn't support ramps, although a game from 1991 already did this(Sonic). Or is it officially approved that you have to buy missing standard features, buy and fix obvious bugs yourself (or buy something that fixes it)? Why you defend this model is now clear to me, it's about money and the prestige of being better than others. But YoYo certainly thinks as a company and since they live to a large extent from new customers, they surely see it a little bit differently than you (at least I hope so).

Good business my friends,
Miradur
My dude, you are in the wrong thread writing to the wrong audience about the wrong problems.

Take time out from these forums. Go to Youtube - type “GMS Slopes”, then come back and post your new slopey skills in your own slopey thread when you have the slopes to show us.
 
Last edited:

Zhanghua

Member
@FrostyCat

How to operate the out variable in the inner nested-function?

GML:
function basic2() constructor{
    static abc = 0;
    static val = function(){
        abc++;
        show_debug_message(abc);
    }
}

function test(){
    var test1 = new basic2();
    var test2 = new basic2();
 
    test1.val();// output 1
    test2.val();// output 1 but want to print 2
}
 

FrostyCat

Redemption Seeker
@FrostyCat

How to operate the out variable in the inner nested-function?

GML:
function basic2() constructor{
    static abc = 0;
    static val = function(){
        abc++;
        show_debug_message(abc);
    }
}

function test(){
    var test1 = new basic2();
    var test2 = new basic2();

    test1.val();// output 1
    test2.val();// output 1 but want to print 2
}
I traced this mentally and also expected 1 and 2 (since both test1 and test2 should in theory share the same abc and increment it once each), but like you I also saw 1 for both. You can report this as a topic on the hidden beta forum (you should have a link to that as part of your invitation), and ask if this behaviour is intended functionality or a bug.
 

Zhanghua

Member
I traced this mentally and also expected 1 and 2 (since both test1 and test2 should in theory share the same abc and increment it once each), but like you I also saw 1 for both. You can report this as a topic on the hidden beta forum (you should have a link to that as part of your invitation), and ask if this behaviour is intended functionality or a bug.
:oops:I used the account of my friend, my id is 196514 and still for waiting.
Could you post this issue to the beta forum stuff or maybe they have realized this?
 

xDGameStudios

GameMaker Staff
GameMaker Dev.
GML:
function basic() constructor{
    function val(){ throw("You should call me!!!!!!"); }
}

function overload1(): basic() constructor{
}

function overload2(): basic() constructor{
     function val(){ throw("Why do you call me????"); }
}

function basic2() constructor{
    function a(){
        function val(){ throw("what the f111111111"); }
    }
}

function val(){ throw("what the f22222222"); }


function test(){
    var test1 = new overload1();
    show_debug_message( test1.val() );
}
It will show the basic2's "what the f111111111" while not the latest outside val() which throws "what the f22222222"
This is a bug that already been reported. It as to do with the fact that:
scoped functions with the same name as global functions are ignored when called inside the scope and are replaced by the global function call.
This is a bug that is being addressed.

it's called: "[BUG] Unable to overwrite globally defined functions" in the beta forums!
 

Zhanghua

Member
@xDGameStudios

That issue can be avoideded and understood。

But this bug is a headache without any solution right now.
GML:
function basic2() constructor{
    static abc = 0;
    static val = function(){
        abc++;
        show_debug_message(abc);
    }
}

function test(){
    var test1 = new basic2();
    var test2 = new basic2();

    test1.val();// output 1
    test2.val();// output 1 but want to print 2
}
 

xDGameStudios

GameMaker Staff
GameMaker Dev.
@xDGameStudios

That issue can be avoideded and understood。

But this bug is a headache without any solution right now.
GML:
function basic2() constructor{
    static abc = 0;
    static val = function(){
        abc++;
        show_debug_message(abc);
    }
}

function test(){
    var test1 = new basic2();
    var test2 = new basic2();

    test1.val();// output 1
    test2.val();// output 1 but want to print 2
}
This is actually NOT a bug.. that's how static is supposed to work... when you create the struct (using new) you are making the abc variable static but as soon as you call the val() function that specific instance gets a copy of the static one and changes the value.
if you want to make a change to static variable value you need to do so in the constructor itself...

GML:
function basic2() constructor{
    // this ASSIGNMENT is run only once (the first time you create the struct)
    static abc = 0;
    // this runs for every single instance
    abc++;
  
    show_debug_message(abc);
}

a = new basic2() // 1
b = new basic2() // 2
c = new basic2() // 3
d = new basic2() // 4

show_debug_message(a.abc ) // 4
show_debug_message(b.abc ) // 4
show_debug_message(c.abc ) // 4
show_debug_message(d.abc ) // 4
 

Zhanghua

Member
This is actually NOT a bug.. that's how static is supposed to work... when you create the struct (using new) you are making the abc variable static but as soon as you call the val() function that specific instance gets a copy of the static one and changes the value.
if you want to make a change to static variable value you need to do so in the constructor itself...

GML:
function basic2() constructor{
    // this ASSIGNMENT is run only once (the first time you create the struct)
    static abc = 0;
    // this runs for every single instance
    abc++;
 
    show_debug_message(abc);
}

a = new basic2() // 1
b = new basic2() // 2
c = new basic2() // 3
d = new basic2() // 4

show_debug_message(a.abc ) // 4
show_debug_message(b.abc ) // 4
show_debug_message(c.abc ) // 4
show_debug_message(d.abc ) // 4
But this will prevent the member function to operate the member variables.......
 

Zhanghua

Member
The new syntax passes the simple IOP's SINGLETON and Composite Mode test, Good Job YOYO!
GML:
function DebugBox(){
    static _inst = noone;
    if( noone == _inst ){
        _inst = function(){};
        _inst.Err_Interface = function(){ throw("Invalide Interface Call"); }
        _inst.Err_InvalidType = function(){ throw("Invalide Type"); }
    }
    return _inst;
}
#macro DBG_BOX DebugBox()


function ICondition() constructor{
    static val = function(){ DBG_BOX.Err_Interface(); }
}


function IConditionEle():ICondition() constructor{
    _checkresult  = false;
    _triggercheck = true;
    
    static reset = function(){ _triggercheck = true; }
    static val = function(){
        if( _triggercheck ){
            _triggercheck = false;
            _checkresult = check();
        }
        return _checkresult;
    }
    
    static check = function(){ DBG_BOX.Err_Interface(); }
}

function IConditions():ICondition() constructor{
    _eles = [];
    _chks = [];
    
    static pushcondition = function(ele,chk){
        _eles[array_length(_eles)] = ele;
        _chks[array_length(_chks)] = chk;
    }
}

function OConditionsAND():IConditions() constructor{
    static val = function(){
        var ret = true;
        for( var i=0; i<array_length(_eles); ++i ){
            if( _eles[i].val() != _chks[i] ){ ret = false; break; }
        }
        return ret;
    }
}

function OConditionsOR():IConditions() constructor{
    static val = function(){
        var ret = false;
        for( var i=0; i<array_length(_eles); ++i ){
            if( _eles[i].val() == _chks[i] ){ ret = true; break; }
        }
        return ret;
    }
}


function OConditionEleManager() constructor{
    _eles = [];
    
    static pushele = function(ele){
        if( string_pos(instanceof(ele),"IConditionEle")  != 0 ){ return DBG_BOX.Err_InvalidType(); }
        _eles[array_length(_eles)] = ele;
    }
    
    static reset_eles = function(){
        for( var i=0; i<array_length(_eles); ++i ){
            _eles[i].reset();
        }
        show_debug_message(array_length(_eles));
    }
}

function OConditionEle1():IConditionEle() constructor{
    static check = function(){
        return false;
    }
}

function OConditionEle2():IConditionEle() constructor{
    static check = function(){
        return true;
    }
}

function test(){
    var mana = new OConditionEleManager();
    var a = new OConditionEle1();
    var b = new OConditionEle2();
    mana.pushele(a);
    mana.pushele(b);
    mana.reset_eles();
    
    var CondAnd1 = new OConditionsAND();
    var CondOR1  = new OConditionsOR()
    
    CondAnd1.pushcondition(a,false);
    CondAnd1.pushcondition(b,true);
    
    CondOR1.pushcondition(a,true);
    CondOR1.pushcondition(b,false);
    CondOR1.pushcondition(CondAnd1,true);
    
    
    show_message(CondOR1.val());
}
 

FrostyCat

Redemption Seeker
But this bug is a headache without any solution right now.
GML:
function basic2() constructor{
    static abc = 0;
    static val = function(){
        abc++;
        show_debug_message(abc);
    }
}

function test(){
    var test1 = new basic2();
    var test2 = new basic2();

    test1.val();// output 1
    test2.val();// output 1 but want to print 2
}
I got a reply. Here it is:
The read of the first abs comes from the static but when it is written a member variable is written so the static value of abc remains at 0, because test1 gets a variable added called abc that has the value 1 and then test2 reads the static variable (set to 0) of abc and then that is incremented and test2 gets a variable called abc that has the value 1.
Only the constructor function itself can write to the static member variable.

if you did
GML:
show_debug_message( test1 );
show_debug_message( test2 );
before and after your invocations of .val() then you would see those changes mentioned above.

This is not a bug and is intended behaviour.
Russell
So not only is there a shared quality to the static keyword, past the point of the constructor there is also a copy-on-write quality to it. The best practice would be to treat static methods/properties as read-only, not just as singular.
But this will prevent the member function to operate the member variables.......
It won't. Member functions can operate normally on other non-static fields. The member functions themselves are not changed in the process.
 

Zhanghua

Member
GML:
function demo(n) constructor{
    abc = [n];
    static push = function(){
        abc[0]++;
    }

    static show = function(){
        return abc[0];
    }
}


function test(){
    var a = new demo(2);//a.abc=[2]
    var b = new demo(5);//b.abc=[5]

    a.push(); show_debug_message(a.show());//a.abc=[3]
    a.push(); show_debug_message(a.show());//a.abc=[4]
    b.push(); show_debug_message(b.show());//b.abc=[6]
    b.push(); show_debug_message(b.show());//b.abc=[7]
}
GML:
function demo(n) constructor{
    static abc = [n];
    static push = function(){
        abc[@ 0]++;
    }

    static show = function(){
        return abc[0];
    }
}


function test(){
    var a = new demo(2);//abc=[2]
    var b = new demo(5);//abc=[2]

    a.push(); show_debug_message(a.show());//abc=[3]
    a.push(); show_debug_message(a.show());//abc=[4]
    b.push(); show_debug_message(b.show());//abc=[5]
    b.push(); show_debug_message(b.show());//abc=[6]
}

TKS @FrostyCat @xDGameStudios
 
Last edited:
This is probably a dumb question but can you put other code up at the top like this:
GML:
function basic2() constructor{
    // this ASSIGNMENT is run only once (the first time you create the struct)
    static abc = 0;
    // this runs for every single instance
    abc++;
    // CAN OTHER CODE GO HERE?? LIKE:
    with (obj_someObj) {
        if (image_xscale > 0.5) {image_alpha = 0.1;}
        show_message("something");
    }
    surf = surface_create(blah blah);
    surface_set_target(surf);
    draw_set_color(c_green);
    draw_text(x, y, "blah");
    surface_reset();
    surface_destroy(surf);
    // etc...

    static val = function() {
        abc++;
        show_debug_message(abc);
    }
}
...so that all that code runs when you first make a New() from the constructor...or when you make a constructor is it purely just assigning values to variables like how defining enums is limited? I don't know what you would use this for, I'm just curious lol I assume a normal function would be fine but for a constructor...?
 

FrostyCat

Redemption Seeker
Any code can belong in a constructor, not only variable assignments. It just needs to be in-scope for the task at hand.
 

Azenris

Member
I really wish default variables existed instead of the argument stuff :(

I was messing around with shader stack using structs. keep all the uniforms and stuff together. Might be useful :p

GML:
// --------------------------

global.shader_stack = ds_stack_create();

function shader_stack_push( _shader )
{
    ds_stack_push( global.shader_stack, _shader );

    _shader.use();
}

function shader_stack_pop()
{
    var num = argument_count > 0 ? argument[ 0 ] : 1;

    repeat ( num )
        ds_stack_pop( global.shader_stack );

    if ( not ds_stack_empty( global.shader_stack ) )
    {
        ds_stack_top( global.shader_stack ).use();
    }
    else
    {
        shader_reset();
    }
}

// --------------------------

function s_shader() constructor
{
    static shader = undefined;

    static use = function()
    {
        show_debug_message( "Implementation required in dervied class" );
    };
}

function s_shader_red( _strength ) : s_shader() constructor
{
    static shader = shader_red;
    static uniform_strength = shader_get_uniform( shader, "u_strength" );

    strength = _strength;

    static use = function()
    {
        shader_set( shader );
        shader_set_uniform_f( uniform_strength, strength );
    };
}

// --------------------------

global.my_red_shader = new s_shader_red( 1.0 );
global.my_dim_red_shader = new s_shader_red( 0.5 );

GML:
shader_stack_push( global.my_red_shader );

// draw

shader_stack_push( global.my_dim_red_shader );

// draw

shader_stack_pop( 2 );
 

Nocturne

Friendly Tyrant
Forum Staff
Admin
I really wish default variables existed instead of the argument stuff :(
You don't need to use the argument stuff... you can do this:

GML:
function my_func( _value ) {
_value = is_undefined(_value) ? 10 : _value;
}
So any argument that is in the function, but doesn't actually get used will be passed through as undefined, which you can then check for and so keep using named arguments.
 

Azenris

Member
You don't need to use the argument stuff... you can do this:

GML:
function my_func( _value ) {
_value = is_undefined(_value) ? 10 : _value;
}
So any argument that is in the function, but doesn't actually get used will be passed through as undefined, which you can then check for and so keep using named arguments.
Still a bit more verbose than

GML:
function my_func( _value = 10 ) {
}
But yeah, that is probably more clear than using the argument stuff. ty
 
Are functions just definable as any other value?
Like, in Lua I can do something like this
Code:
--Like this
function model_load_obj (path)
    local function split_line (str)
        --Do stuff
    end
    
end

--Or this
function model_load_obj (path)
    local split_line = function (str)
        --Do stuff
    end
    
end
Can I do that in GM2.3 either like
GML:
//Like this
function model_load_obj (path)
{
    var function split_line (str)
    {
        //Do stuff
    }
}

//Or this
function model_load_obj (path)
{
    var split_line = function (str) {
        // do stuff
    }
}
 

xDGameStudios

GameMaker Staff
GameMaker Dev.
Are functions just definable as any other value?
Like, in Lua I can do something like this
Code:
--Like this
function model_load_obj (path)
    local function split_line (str)
        --Do stuff
    end

end

--Or this
function model_load_obj (path)
    local split_line = function (str)
        --Do stuff
    end

end
Can I do that in GM2.3 either like
GML:
//Like this
function model_load_obj (path)
{
    var function split_line (str)
    {
        //Do stuff
    }
}

//Or this
function model_load_obj (path)
{
    var split_line = function (str) {
        // do stuff
    }
}
if model_load_obj is only an actual function that you run using:
model_load_obj(path);

Then the correct syntax is:
GML:
function model_load_obj (path)
{
    // This exists inside the function call scope
    var split_line = function (str) {
        // do stuff
    }

    // You can use it like so (inside the function call)
    var s = split_line(path);
}

var model = model_load_obj("Path/To/File.txt");
if you remove the var keyword from the function inside the function call, like so:

GML:
function model_load_obj (path)
{
    // This exists both inside and ouside the function call scope (after it has been called)
    split_line = function (str) {
        // do stuff
    }

    // You can still use it like so
    var s = split_line(path);
}

var model = model_load_obj("My/Path/To/File.txt");
// as the definition was not made local using the 'var' keyword it now exists outside after you call the function

split_line("Blah");

###### ANOTHER EXAMPLE ######
Lets look a more specific example. Imagine you have this function defined inside a script file:

GML:
function MyFunction()
{
    var t = get_timer();
    get_age = function()
    {
        return age;
    }
}
if you call it inside an object:
objMyFirstObject --> [CREATE EVENT]
GML:
age = 10;
MyFunction();
Now this object has two instance variables:
age -> which is a number with value 10
get_age -> which is a method (note that I didn't say function.. because it is BOUND to this instance).

NOTE: t is local to the function so it won't exist outside it.

So you can then do this:
objMyFirstObject --> [CREATE EVENT]
GML:
MyFunction();

show_debug_message(get_age()); // 10
(place the object inside the room) As you can see the function gets called and it gets the right value :)

What do I mean by being BOUND to that instance?!?
What I mean is that is you pass the method reference to another object:

objMySecondObject --> [CREATE EVENT]
GML:
// lets create a variable name with the same name:
age = 100;

// lets get the method reference
otherObjGetAge = objMyFirstObject.get_age;

show_debug_message(otherObjGetAge()); // 10 <-- this is the value from the other instance
// this is because what you are actually doing is:
show_debug_message(objMyFirstObject.get_age());
(place both objects inside the room) as you can see even though the function returns the variable age it returns the one from where it is bound to.

Now lets try a interesting thing:
objMySecondObject --> [CREATE EVENT]
GML:
// lets create a variable name with the same name:
age = 100;

// lets get the method reference
otherObjGetAge = objMyFirstObject.get_age;

show_debug_message(otherObjGetAge()); // 10 <-- this is the value from the other instance
// because what you are actually doing is:
show_debug_message(objMyFirstObject.get_age());

// lets call our first function here too (this will create a 'get_age' method bound to THIS instance)
MyFunction();

show_debug_message(get_age()); // 100 <-- this is the age value from this instance
 
Last edited:

Zhanghua

Member
GML:
function demo(n) constructor{
    static abc = [n];
    static push1 = function(){
        abc[@ 0]++;
    }

    static push2 = function(){
        abc[0] += 2;
    }
 
    static show = function(){
        show_debug_message(abc);
    }
}


function test(){
    var a = new demo(2);//public.abc = [2], a.abc is the public one.
    var b = new demo(5);//public.abc = [2], b.abc is the public one and will not be initialed again

    a.push1();//public abc[0] = 2+1, a.abc is the public one.
    a.show();// show pulic abc = [3]
    a.push2();//private a.abc[0] = public abc[0] + 2; a has his private abc now, the abc below is not the pulic one and be initialed from the public.
    a.show();// show private a.abc = [5]
    a.push1();//private a.abc[0]++
    a.show();// show private a.abc = [6]
    a.push2();//private a.abc[0]+=2
    a.show();// show private a.abc = [8]
 
    b.push1();//public abc[0] = 3+1, , b.abc is the public one.
    b.show();// show pulic abc = [4]
    b.push2();//private b.abc[0] = public.abc[0] + 2; b has his private abc now, the abc below is not the pulic one and be initialed from the public.
    b.show();// show private b.abc = [6]
    b.push1();//private b.abc[0]++
    b.show();// show private b.abc = [7]
    b.push2();//private b.abc[0]+=2
    b.show();//show private b.abc = [9]
}
My Conclusion:
If struct only has public static member, it will operate the public one.
Once struct has it's own member, it will operate his private one and be initialed from the public.
 
Last edited:
Status
Not open for further replies.
Top