• 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!
  • Hello [name]! Thanks for joining the GMC. Before making any posts in the Tech Support forum, can we suggest you read the forum rules? These are simple guidelines that we ask you to follow so that you can get the best help possible for your issue.

Discussion My review of GMS2 (and my attempt to create a custom events system)

hugeen

Member
(english is not my native language)

Intro

10 years ago I created some short HTML5 games (JavaScript + Canvas for those who know).

For fun I started to redo them but with GMS 2 this time!

I have to say that I am impressed with a lot of the great features of GMS2, but others make me cringe!



The good stuff
  • The workspace is really excellent, I love it.
  • The different editors (Sprite, Room, Tileset,…) are also very good.



The less good stuff
  • The code editor is underwhelming, I stopped using it very quickly and started using VS Code instead.
  • Another problem, but I think it's just a bug (I am on a Mac and with an AZERTY keyboard):
    • When I hit cmd + Z, in any other app it’s for « Undo ». In GMS 2, it closes the current window in the Workspace.
    • When I hit cmd + A, in any other app it’s for « Select All ». In GMS 2, it closes GMS 2. (Yes :D)



The bad stuff

Events


To my surprise GMS 2 is not event based!

In the Little Town tutorials
the presenter says « everything in Game Maker studio 2 happens in an event ». I was really hyped!

But later, I realized that these are not events :(

These are just ordered / indexed callback functions with a label on them to recognize them in the interface, that's all!

To tell the truth, it is only semantics, it can still work if GMS 2 allows to make your own events.

I found that it was possible to connect to "User Events" but that it is impossible to name them and they are limited to the number of 16!

User Event 0
User Event 1
User Event 2

User Event 15
Seriously guys? It looks like 90s code!

These are not events, they are function slots!

I think this is my biggest disappointment by far.

But I am going to persist a little to try to appropriate GMS2 that seems promising to me despite that.




...

EDIT

Tutorials and code conventions

I watched several tutorials on the official GameMaker Studio YouTube channel, and i have to say they full of bad practices!

For instance :

Code:
var _move = key_right - key_left
hsp = _move * walkup
Please use readable variable names!

Here is my version:

Code:
var move = key_right - key_left
horizontal_speed = move * walk_speed
It's easier to read and understand, isn't it?

There is no naming convention in GML ?

It's necessary to choose:
  • walk_speed
  • walkSpeed
  • walkspeed

And then stick to it at least throughout your project!
 
Last edited:

Nocturne

Friendly Tyrant
Forum Staff
Admin
There is no naming convention in GML ?
There's no naming convention in most languages? I mean, sure, there are general practices that are taught, BUT there is nothing stopping any programmer using any convention they want to name variables or format their code. If there was we wouldn't have the eternal discussion over whether CamelCase is better than snake_case or whether Altmans is better than Whitesmiths, etc... this is absolutely a question of personal choice, and you can't tell someone "YOU MUST NAME YOUR VARIABLES LIKE THIS".

If you want to know what is expected when using GML to program, then the manual implicitly outlines what is considered "good practice" in the various programming sections and examples for the functions.

Oh, and "hsp" as a variable for horizontal speed IS a convention practically. If you check the forums you'll find that just about everyone that works with GML uses the convention of "hsp" and "vsp" ... you can't expect every language you learn to conform to your own expectations of what is acceptable. ;)
 

hugeen

Member
I don't care which convention is the best, what matters to me is that there is one.

For "hsp", it can mean so many different things, it unnecessarily confuses the brain.
I personally think that abbreviations of any kind should be avoided regardless of the coding language.

It's obviously not good for beginners, but it's not even good for yourself when you come back on your own script 2 weeks later!
 
Your reply doesn't make sense. If you want a variable named a certain way, name it that way? Even when I was an absolute beginner, I would adjust variable names to things I thought were better suited to my brain, rather than just blindly copying from the tutorial and getting mad because it wasn't using the name I wanted to use...This seems like a super pedantic point that has no actual bearing on whether GMS is good or not at all and it comprises like half the review...
 

hugeen

Member
Your reply doesn't make sense. If you want a variable named a certain way, name it that way? Even when I was an absolute beginner, I would adjust variable names to things I thought were better suited to my brain, rather than just blindly copying from the tutorial and getting mad because it wasn't using the name I wanted to use...This seems like a super pedantic point that has no actual bearing on whether GMS is good or not at all and it comprises like half the review...
I think you're right, of course I am not copying blindly the tutorial and I am not mad just disappointed.

But I realize that my review is a little bit unfair on this point :)


(I could delete it from my review, but now that we have talked about it the following messages would not make sense.)
 

GMWolf

aka fel666
I found that it was possible to connect to "User Events" but that it is impossible to name them and they are limited to the number of 16!

Seriously guys? It looks like 90s code!
User events are pretty much legacy now.

Check out methods instead, they were added recently and are much more powerful and ergonomic.

Of course if you want to use them like events you will need to do a little reflection to check that the instance has a method with that name. (I've suggested multiple times that they add syntactic sugar for duck typing style programming)
 

Mr Magnus

Viking King
that it is impossible to name them
Small nitpick: you can provide descriptions that show up after the event by doing

GML:
///@description A quick brown fox event
at the top of the event.

1627214114800.png

However that's a bit moot given we have methods now. Like, you can literally go

Code:
jump = function(){
    ///Jump function here
}

getHurt = function(amount){
    ///Hurt function here
}

timesUp = function(){
    ///Time is up function here
}
in the create event of any object and then go

Code:
///When some counter reaches zero

with(oEnemy){
    timesUp();
}

//or in a collision event

other.getHurt(10);

// or whenever you need jumping

player.jump();
These are functionally equivalent to user events AND you can have as many as you need. Scripts also used to serve this function better: needed a "user event" with a name? Plop it in a script, as scripts can either take the affected instance in, or can just use the scope of the instance that called it.


There is no naming convention in GML ?
There is, it's snake case. You'll notice all_the_built_in_functions_are_styled_like_this()

However it is not enforced upon the user, because that would be horrendous and a terrible idea. Name me a single reputable language that will yell at you for not adhering to whatever naming style that specific language developer prefers.
 

GMWolf

aka fel666
Plop it in a script, as scripts can either take the affected instance in, or can just use the scope of the instance that called it.
Not quite the same. It doesn't achieve polymorphism, or have different instances do different things with the same function call. For it to be the same you would have to initialize an instance or object variable with the script name, and execute it through script_execute.
 

hugeen

Member
Code:
jump = function(){
    ///Jump function here
}

getHurt = function(amount){
    ///Hurt function here
}

timesUp = function(){
    ///Time is up function here
}
in the create event of any object and then go

Code:
///When some counter reaches zero

with(oEnemy){
    timesUp();
}

//or in a collision event

other.getHurt(10);

// or whenever you need jumping

player.jump();
Following your answer I looked at the manual more in depth and it gave me an idea.

I created a script named "event_capabilities"

GML:
function add_event_capabilities () {
    events = ds_map_create()

    get_listeners_for = function (event_name) {
        if (!ds_map_exists(events, event_name)) {
            var listeners = []
            ds_map_set(events, event_name, listeners)
        }
        return events[? event_name]
    }

    add_listener = function (event_name, listener) {
        var listeners = get_listeners_for(event_name)
        array_push(listeners, listener)
        return listener
    }

    trigger_event = function (event_name) {
        var listeners = get_listeners_for(event_name)
        var count     = array_length(listeners)
        for (var i = 0; i < count; i++) {
            listeners[i]()
        }
    }
}
You just need to call it in the create of an object to activate custom events features on this object

GML:
add_event_capabilities()
add_listener("created", function () {
    show_message("object created")
})
trigger_event("created")

So it is possible to do things like

GML:
enemy.add_listener("died", function () {
    // add to score
    // play sound
    // spawn new enemy
    // whatever
})

what do you think about that ?
 
Last edited:

hugeen

Member
Use a struct instead of a ds_map. It can do all the same things and you don't have to worry about its destruction.

Thanks !

Here is the updated version with struct (and some minor changes).

GML:
function add_event_capabilities () {
    if (variable_instance_exists(id, "all_listeners")) {
        return
    }

    all_listeners = {}

    get_listeners_for = function (event_name) {
        if (!variable_struct_exists(all_listeners, event_name)) {
            variable_struct_set(all_listeners, event_name, [])
        }
        return variable_struct_get(all_listeners, event_name)
    }

    on = function (event_name, listener) {
        var listeners = get_listeners_for(event_name)
        array_push(listeners, listener)
    }

    emit = function (event_name, args) {
        var listeners = get_listeners_for(event_name)
        var count     = array_length(listeners)
        for (var i = 0; i < count; i++) {
            listeners[i](args)
        }
    }
}

Usage :

GML:
add_event_capabilities()
on("created", function (args) {
    show_message(["object created", args])
})
emit("created", ["some", "arguments"])
 
Last edited:
Top