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

Question - Code Data types...

xot

GMLscripter
GMC Elder
My GTX 970 is the bottleneck. The bandwidth required to do a modest 7-tap, 3-texture, 2-pass post-processing effect hits its limits around 2K fps. GameMaker is sitting idle 98% of the time.
 
You simply couldn't do that with a project remotely like HLD. A virtually empty project with two 640x480 passes by simple shaders doesn't even hit a stable 2000 fps on this reasonably powerful workstation
Any insights into how that is, exactly? It doesn't look like anything the PS2 wouldn't be able to handle...it still seems really strange to me that it dropped down to like 10fps on my old computer. If it wasn't because of GM, was HLD really just so poorly optimized?
 

Juju

Member
Funny thing though. I asked the dev of HLD if the released version of the game was actually built using GMS. But, he avoided the question.
It was made in GMS. Also, there is no "the dev". There were a dozen people on the main staff for HLD, and approximately twenty people have contributed code/audio/art to the project.
I don't really see anything in HLD that pushes 'GMS to the limits' though to be honest. 640 x 480 at 30 FPS ???
60FPS, and it runs at 960x540.
Any insights into how that is, exactly? It doesn't look like anything the PS1 wouldn't be able to handle...
Other than 2MiB RAM + 1MiB VRAM, maximum sprite size of 256x256, complete lack of shaders etc...
PS1 programmers went to extremes to get games looking as good as they did. Even then, most games looked like dog sick, especially the early games before they had worked out the quirks in the architecture.
If I couldn't keep a stable 3000 FPS at that resolution, I'd be feeling like I had failed.
Perhaps with a blank room. But HLD has, y'know, sprites and AI and physics and everything that makes it a game.

The main blockages in HLD are the graphics pipeline, the AI, and the collision system. About four months after I joined, we swapped over to the new fast system (after a lot of bug testing) so that's much better than it was at launch. The AI is complex and requires a great deal of speculative collision checks, due to the prevalence of moving platforms and bottomless pits, and that's always been a sticky part of the codebase. As someone mentioned elsewhere, the audio system is novel - there's 3 hours of music and ambience, all streamed in and out of the game. GM handles this flawlessly, though the code our end does bork every now and again.

The graphics pipeline has two major hurdles: 1) 960x540 screenspace shaders + sprite shaders that are running all the time 2) the sheer number of instances. Inside even modestly-sized rooms, there are hundreds of tiny little details that are all depth-sorted, placed by hand, and animated carefully for a specific look and mood. When you've got 149 2048x2048 texture pages - that's 2.2GB uncompressed - the number of texture swaps you're doing to draw the scene becomes very hard to manage. We had a major bug about halfway through the 60FPS conversion where certain cutscenes ran awfully... we had forgotten to prefetch a single texture when the room loaded. HLD is running that close to the edge.

Nothing near the magnitude of HLD has been seriously attempted in GMS, and nothing has ever been successfully released. That is by definition pushing the engine.

I can think of three things that would improve the performance of Hyper Light Drifter and none of these are predicated on improving GML itself. However, for general usage, I would like to see some kind of method analogue - I think it fits GameMaker's style, I think it makes organisation easier, I think it is accessible and natural to learn. Having access to datatypes will lift the ceiling on certain kinds of games and data management strategies so I broadly support their inclusion, though I'm not sure I'd be using it all the time. I have less positive feelings towards pointers and private/public variables because they're stepping into the territory of diminishing returns.

Finally, that devs here are offhandedly tearing down other people's work because they're trying to prove a point is shameful. You know the extraordinary lengths that every single one of us go to. GameMaker removes so so many of the barriers for game development and that is what makes it special. By trying to judge someone's work as a "failure" and not "proper programming" without any knowledge of the details, you're putting barriers back up. This is bad for any community, but it is especially poisonous for GameMaker. I wish we had more prevalent advanced use, I want the ceiling to go higher, but we cannot hope to support that without an unshakeable foundation of welcoming inexperienced developers.
 

GMWolf

aka fel666
Sorry to go back to old points, but:
Simple explanation: Data types allow for larger projects and faster calculations. A 10,000 x 10,000 ds_grid/array currently takes 2.3 gigabytes. Since there are no data types, this size is non-negotiable and makes large grids unrealistic. If we had simple 0-255 int's, that 10,000 x 10,000 grid could be as small as 100 megabytes, or 4% the size that ds_grids currently are.
Try using java, C# or even c++. You will find that you use just as much memory because of objects. Just a pointer/address to an object is 32bits (64 if compiled to x64). Then you have all the object interface etc adding more bloat.
The solution is either C and some clever pointer code, Or the exact same code refactored to use GM buffers.
The real solution is not to store all that in Ram. If you have to, then you are probably doing something a little off.

Convenient? Sure. Extremely poor practice? Definitely
If this where java, c#, then yes. In GM, i would say that is good practice (in a way): It allows for concise and clear code.
other examples: Before many features where added to java, for instance, It was good practice to use reflection everywhere. With interfaces and and annotations, There are now better alternatives for many applications.
In GM, people think relying on script names is poor practice. I say 'nay', There are no interfaces or annotations in GM, reflection is fine.
Some peeps frown upon the use of execute_script and storing script ID's to call them. Again, Java, C# have classes and lambda expressions, You dont need that. But in C, much of the better code actually uses these sorts of ideas. And there is no reason you shouldnt use them in GML either.
There are plenty more things that are bad practice in some languages, but that are fine in GML.
Infact, I think that the people behind GML (Mike, especially) Are probably big fans of C programming. The more i use and learn C, the more parallels i find between my GML code and C code. (And i love it).

Perhaps ability to make custom data types would be too much to ask for at the moment...
You can already create those. Its a bit laborious, but you have to create the interface through scripts (ie, vector_create, vector_add, vector_destory, etc) and then choose an implementation .I like Arrays with enums, And, for larger DS's, I like to give the user a handle rather than the array back, storing the array in a map. (This is safer, and closer to existing GML DS's bahaviour).

They take up a drastically smaller amount of space when being passed around then data structures and object instances. The allowing of pointers, yes, would open up users to making mistakes and having pointer errors, but it would promote one of the most important concepts of game programming: memory efficiency.
And that is why GML uses handles for virtually everything. Create an Instnace? get an ID.
Create a ds_list, get an other ID.
Thats rather nice as its efficient, and (somewhat) safer than pointer.
On top of that, I dont htink pointers make much sense when you are talking about an interpreted language. I doubt YYG are simulating a machine with ram and adresses. Its much more likely that they had a hashmap of names to values.
I also suspect that the YYC generates code that also uses maps, etc. When developing my own interpreters and compilers, I found that to be the easier and safer option.
 

Mike

nobody important
GMC Elder
However, i was talking about data types, type safety as well as explicit typing. (Not pointers.) And those problems definitely don't apply to those topics.
Read more carefully next time, and you won't have to summon any bollocks. Like Lewa says, neither of us were talking about pointers. :p
Apologies.... I shall once again hide my bollocks.

I think unless your explicitly needing 64bit types, then doubles aren't terrible. Also, internally to the VM if you AND something, it does become an INT or an INT64 etc and gets handled like that, but yes - you certainly don't get casting errors etc if you accidentally add on a float etc.

And as to games running badly... as @xot said, any engine can be made to do that. In fact, because GameMaker is SO accessible folk who may not be the worlds greatest coders (not talking HLD here), they could make your brand new computer run like crap, and then blame the engine. If you code your game properly, and optimise properly, then your game will run across most platforms easily. Just depends on your coding ability....

Not sure HLD push it to the limits....they did things in odd ways sometimes to achieve the effect they wanted, I would have done things differently and it might have LOOKED a little different, but run much better. They had their own reasons for doing things in the way they did. We helped them out, but we weren't about to rewrite their code. Could we have made it run much faster? Yes, but that's not what we're paid to do so.....
 
Last edited:

mMcFab

Member
Whoops, I think @Mike accidentally quoted me into this!
I think the top quote was from @Lewa, just to clarify.

Otherwise, I don't really have anything major to add, but if I was desperate to reduce bloat by using a specific data type in GameMaker (and maybe to move it around or something), I'd probably just use a buffer and structure it nicely. Referencing "variables" in a buffer with buffer_peek could be a pain given the rigid structure you'd need to use, but then I don't think I need/want data types anyway. Maybe I'd find specific types for data structures (lists, maps etc.) rather than numerical ID's useful, but otherwise I'm not feeling it.
 

rwkay

GameMaker Staff
GameMaker Dev.
OK I can shut the speculation within this conversation down by saying we are not looking to type variables in GML for storage reasons, variables in GML will ALWAYS be 16bytes as they currently are as we have to store meta data on the storage for the variables (including storing what the type of the variable is).

If you require typed storage use buffers, we are open to talking about faster / better ways of accessing buffers (which are essentially pointers with offsets), this includes functions and syntax changes to allow access buffers to be more aesthetic and easier from GML.

We are also open to talking about hints to the compiler to say this variable should only ever be an int/float/single and it is free to optimise, but it will NOT affect the storage of those variables within arrays, data structures (i.e. ds_list, ds_map etc), this will help with error checking and allow the compiler to perform some better optimisation at runtime.

Russell
 

GMWolf

aka fel666
we are open to talking about faster / better ways of accessing buffers
Perhaps another accessor, such as:

Code:
//Creae buffers like usual
var buff = buffer_create(16384, buffer_fixed, 2);

//Writing to buffer
buffer_write(buff, buffer_s16, 8); //Current call
buff[* buffer_s16] = 8; //write a s16 atcurrent seek pos

//reading from buffer
x = buffer_read(buff, buffer_s16);
x = buff[* buffer_s16]; //read an s16 at current seek pos

//poking buffer
buffer_poke(buff, 3, buffer_u8,  24);
buff[* 3,  buffer_u8] = 24; //poke a u8 at position 3

//peeking buffer
y = buffer_peek(buff, 2, buffer_u32)
y = buff[* 2, buffer_u32] //peek a u32 at position 2

//seeking buffer
buffer_seek(buff, buffer_seek_start, 0);
buff[*] = 0; //Place seek at position 0 from seek_start

buffer_seek(buff, buffer_seek_relative, 4);
buff[*] += 4; //Move seek by 4 bytes //isnt this great?

//get buffer seek pos
var pos = buffer_tell(buff);
var pos = buff[*]; //same notation as when changing seek. Much nicer that way :)

//Following are ideas that are less usefull, but still cool.
//I dont think those are essential at all. Jus more ideas to write down.
var size = buff[*?]; //Gets the size of the buffer
var adress = buff[*&]; //gets the address.
var byte = buff[**]; //Gets the byte (u8) value at seek
var byte = buff[** 5]; //Gets the byte (u8) value at position 5
buff[**] = 1; //setts the byte value at seek to 1
buff[** 8] = 5; //sets the byte value at position 8 to 5
buff[*:, buffer_u16] = 0; //Fills buffer with u16 0s
buff[* 4:16, buffer_u32] = 5; //Fills all between 4 and 16 with u32 5s
buff[** :] = 0; //Fills all bytes to 0
buff[** 20:120] = 1; //Fill all bytes between 20 and 120 to 1
BTW, any plans for GML formating on the forums? I dont like having this script running...

This is especially nice for seeking: As you dont have both buffer_tell and buffer_seek to mess around with seek position. just the p[*] notation.

It would also be nice to have a typed buffer that can only take one type. I often use buffers to store a bunch of ints. Compiler would probably be able to optimize for that rather well.

Example of why this is nice:
Code:
//before:
buffer_poke(buff, buffer_tell(buff) - 12, buffer_u32, 25);
//with accessors
buff[* buff[*] - 12, buffer_u32] = 25;
[edit] still adding ideas. At this point, mostly handy shortcuts.
 
Last edited:

GMWolf

aka fel666
Not sure why assessors would matter, they just go through the normal calls behind the scenes, and you can read/write or peek/poke types to them already.
Well, We have them for lists, maps and arrays. Why not buffers? I can see using them, especially to seek. (current buffer_seek takes too many args. Who uses buffer_seek_end?) buff[*] = 0 is much easier.

I added a couple things to my previous post. I think being able to do buff[*] += 15; would be really quite nice.

Sure, it doest help with performance, but some people may like this kind of notation better. just like more and more people are using list and map accessors.

[edit] Added even more random bits. To be clear, I think it would be nice to have the basic opperations. The other adresses, size, and byte things are much less needed.
 
Last edited:

Alice

Darts addict
Forum Staff
Moderator
Not sure why assessors would matter, they just go through the normal calls behind the scenes, and you can read/write or peek/poke types to them already.
I think what Fel was getting at was what has been emphasized here:

If you require typed storage use buffers, we are open to talking about faster / better ways of accessing buffers (which are essentially pointers with offsets), this includes functions and syntax changes to allow access buffers to be more aesthetic and easier from GML.
And I've got to agree, putting some syntactic sugar around buffers (whether the one proposed by Fel or something else; dunno if his solution is optimal or something better can be used) would be pretty nice. That addition wouldn't introduce a new way to make code more efficient (because the functionality wouldn't change), but it would probably encourage it and make writing highly-performing code generally easier.
 
It was made in GMS. Also, there is no "the dev". There were a dozen people on the main staff for HLD, and approximately twenty people have contributed code/audio/art to the project.
But there's only one who did a bunch of interviews and made millions of dollars, right? He's probably referring to that one, hahah. :p
Other than 2MiB RAM + 1MiB VRAM, maximum sprite size of 256x256, complete lack of shaders etc...
Yeah, I upgraded that to PS2 about two seconds after posting. I was definitely exaggerating a bit too much at first, hahah. Sorry about that. To be clear, I don't think that HLD was a bad game, or that the small indie team who worked on it did a bad job. I just think it could have run much faster than it did, either through more optimized programming, or through more careful use of art assets. I understand that when working with a small team and limited budget, it's not possible to do everything perfectly, though. I think Heart Machine probably focused their efforts in the right places - the game sold well enough, and most people loved it. Definitely a huge success, even if I think it ran a little slow. =)
Apologies.... I shall once again hide my bollocks.
Thank you, sir. =)
Honestly, GM already runs fast enough for what I'm making. I'm more interested in improvements that'll make my code easier to organize and read. It's why I keep on asking for scoped methods and variables. I'm only interested in type-casting because I'm assuming it'd make it easier for the IDE and intellisense to catch my programming errors for me, and because I'd like to see GM attract more advanced programmers, because I think it'd be good for your company and for the engine. I'm a good designer, but I won't pretend to know anything at all about programming. I enjoy GM's ease of use, and my suggestions are only to make keeping track of my large project easier.
 
Last edited:

Lewa

Member
Apologies.... I shall once again hide my bollocks.
No worries. :)

OK I can shut the speculation within this conversation down by saying we are not looking to type variables in GML for storage reasons, variables in GML will ALWAYS be 16bytes as they currently are as we have to store meta data on the storage for the variables (including storing what the type of the variable is).

If you require typed storage use buffers, we are open to talking about faster / better ways of accessing buffers (which are essentially pointers with offsets), this includes functions and syntax changes to allow access buffers to be more aesthetic and easier from GML.

We are also open to talking about hints to the compiler to say this variable should only ever be an int/float/single and it is free to optimise, but it will NOT affect the storage of those variables within arrays, data structures (i.e. ds_list, ds_map etc), this will help with error checking and allow the compiler to perform some better optimisation at runtime.

Russell
Well, fair enough. I still would prefer having true data types (as well as proper OOP).
I already said everything i had to say. In the end, it's up to you guys to decide in what direction you want to go. (And i'm not going to argue with that.) :)


Regarding to the whole "pushing GM to its limits":
I think "pushing" an engine to it's limits can be a very subjective thing. More often than no i see people only looking at graphical stuff when it comes to "pushing" an engine. (at least here on the GMC.)
In my opinion, the graphical stuff doesn't nessecarily tell anything about how far something was pushed (it can be a factor, but it isn't everything). GM does support shaders. So most of the stuff seen in other engines can be also done in GM. (granted, you are a bit limited when it comes to the underlying graphics API, so things like Geometry shaders, instancing,etc... aren't possible.)

The interesting part is how far a game pushes the internally available systems to it's limits (or how much of the capabilitys of an engine is used in the game).
In my eyes there is a difference between a game which uses a few shaders to look like a triple AAA game and a game which looks simpler but takes advantage of all the features which the engine has to offer or tries to push some of them internally to the "limits" (be it the soundsystem, networking for a complex multiplayer, HTTP functionality, etc...) which would be more representative of what the engine has to offer.
Same goes for GML. Due to the absence of OOP and proper data abstraction you can only go so far with the complexity of your codebase before you start screwing yourself over due to the limitations of the language. So by "pushing" Game Maker to it's limits i also consider games which go above and beyound implementing stuff into their games which push the GML code to the limits (in terms of complexity.)

(At least for me, if i look at other engines i'm not only looking at the graphical capabilities but also at all the other features like networking, collission detection, (scripting-) language, performance (multi-threading), audio features, multiplatform support, etc...)
 
Last edited:

FrostyCat

Redemption Seeker
Why? It does the job... Been using GM for years now and I've never once to thought to myself "Damn, but it's a shame that variable is a double precision floating point number!".
For people who need to implement standardized cryptographic/hashing/PRNG algorithms in 64-bit fixed point arithmetic, or people who run across YYC bugs that involve unwanted casting of numeric handles, they're all saying the same thing you never said.

"Damn, but it's a shame that variable is a double precision floating point number!"

I've only seen one or two games that really push GM to it's limits (HLD for example) and when that happened YoYo Games added in streamed audio, texture prefetching and fast collisions (amongst other things). They didn't add in different data types because that wasn't the issue. In GMS2 we've been given layers and an improved render pipeline using DX11 as well as a load of other things under the hood and performance has increased again, and again without data types. I can understand the argument for different types when it comes to shifting huge amounts of information around using things like data structures, but in general I feel that most GMS users don't really care about these micro optimisations and wouldn't benefit from them anyway - all they want to do is get their head down and work on their game, which GML permits them to do incredibly quickly and without any fuss.

So, all of GameMaker's optimisations come from other things that aren't anything to do with the language itself (directly) and I would think that until we get people regularly pushing the limits of what GMS can do we shouldn't even be considering making this kind of change to the language as it impacts everyone and YYG have to consider the whole (incredibly wide) range of users and not just those that have some other programming background or that consider themselves "power" users. If you really want it, then make a quality game that pushes the limits and requires it and then petition YYG, just like Vlambeer or other devs have done. ;)
Using "game letter grades" or project grandeur of existing projects as the only measure of pushing limits is a shallow way to justify how GM will be used.

Let's take the HTTP functions as an example. For the first 2 years of their existence, practically nobody used them because every use case but simple downloading is beyond GMS 1.2's limits (i.e. no support for headers). It began to be used to its potential only after http_request() was added.

Introducing classes as a type is a boon to data-driven games and deep AIs (as opposed to the action-oriented majority), not the least of which is simplifying the handling of serialized game states. On the data-driven and deep AI front, people who have a genuine use case for classes do all sorts of workarounds to emulate using maps and arrays, and we're speaking up because we're tired of it. On the MMO front, people who knew what they're doing were driven to write state management in other OO languages (along with the rest of the server), because of this and GM's inability to scale and run headless.

Once you start looking at "pushing limits" from function-specific views, you can clearly see that GM isn't allowing us to push limits on those fronts. So stop it with the "we won't build it because we haven't seen people come close to using it" excuse. Quite often people don't come close to pushing it because they smell the inherent limitations GM placed upon them ahead of time, and went with something else that pushes better instead.

People may still not come even after you build it, but people definitely won't come if you never build it.
 

Lewa

Member
Introducing classes as a type is a boon to data-driven games and deep AIs (as opposed to the action-oriented majority), not the least of which is simplifying the handling of serialized game states. On the data-driven and deep AI front, people who have a genuine use case for classes do all sorts of workarounds to emulate using maps and arrays, and we're speaking up because we're tired of it. On the MMO front, people who knew what they're doing were driven to write state management in other OO languages (along with the rest of the server), because of this and GM's inability to scale and run headless.

Once you start looking at "pushing limits" from function-specific views, you can clearly see that GM isn't allowing us to push limits on those fronts. So stop it with the "we won't build it because we haven't seen people come close to using it" excuse. Quite often people don't come close to pushing it because they smell the inherent limitations GM placed upon them ahead of time, and went with something else that pushes better instead.
This. Very much this.
You guys have no idea how much i would have benefited from proper OO language features. (Back then, around 3 years ago when i started my project i never realised in what a mess the codebase would end up to be, including all the headaches associated with it.)
Proper OOP... no public-only variables which can be accessed from everywhere (access modifiers), no weird bugs due to wrong parameters passed into a function (type safety), no weird hacks with GMS instances to create own data structures (GM instances do have an overhead and you have to be carefull with functions like instance_destroy(), activate, deactivate, etc...), proper code and data abstraction (functions which are tied to classes), etc...

After the experience developing such a project in GMS i realised how limiting this can be. GML is completely fine for smaller projects/games. (It is clearly designed for that.)
But once you start having a bigger codebase or do more complex stuff (having lots of subsystems which have to communicate with each other,...) you start to realize that you are working against the system.
I'm probably (with the handfull of other people) the vocal minority here, but still. (Someone has to speak up. :p )
 
Last edited:

Jobo

Member
GMC Elder
If your code is a mess, it's not the language's fault - it's exclusively yours. I have no problems writing organized and documented code and game systems in GameMaker Language. Every time you write messy code, you learn from it... I've written plenty of messy code in my time - sometimes purposefully because I just don't care, and sometimes because I just don't know the language I'm using well enough; but it's never the language's fault if you write messy code. After all, you're the one with the keyboard! :)

I do like object-oriented programming... A lot! But 1) it has a lot of downsides in my opinion, and 2) I don't think it's within the scope of GameMaker Language, and 3) You can solve all the problems you bring up without extending GML. Remember when you were a beginner, and you appreciated the simplicity of GameMaker Language? Why take that away from current beginners just because you're not a beginner anymore?

no public-only variables which can be accessed from everywhere
How would you benefit from not being able to access certain variables? How would your ability to write code benefit from this? Access modifiers are a compile-time thing and nothing more. There is nothing at runtime in any language as far as I am aware that says "no, you can't access that." - it's all in the compiler. So instead of polluting GameMaker Language with access modifiers, why don't you just not access those variables? My naming conventions have "public" variables as "my_variable" and "internal" variables as "__my_variable" (the number of underscores depend on my mood and how internal I think it is ;))

no weird bugs due to wrong parameters passed into a function
You write the code, you write the bugs. Agreed that strong typing aids in finding these errors, but if you want to ensure you get the right types passed into a function I suggest adding an assert() script that looks like the following:
Code:
#define assert(expr, message)
if(os_get_config() != "debug") return; // only run this in a debug configuration
if(!expr) show_error(message, true); // assertion failed, show error
Use this script like so: assert(is_real(argument0), "Expected real, got nonsense");
Problem solved :)

no weird hacks with GMS instances to create own data structures
If you misuse a language, you have to accept the trade-offs of doing so. If you don't like doing weird hacks like this, then don't do them. Want a struct-like structure? Use a map. It's fairly identical.

data abstraction (functions which are tied to classes)
How is this different from script resources if you don't mind me asking? "Tied to a class" is not a reason...

GML is completely fine for smaller projects/games. (It is clearly designed for that.)
But once you start having a bigger codebase or do more complex stuff
Say that to the developers of: Hyper Light Drifter, Blackhole, Crashlands, Defenders of Ekron, Death's Gambit, Gunpoint, Hotline Miami, Spelunky, Memoranda, Savant Ascent, Wanderlust, ...
And so many more... I could go on for hours - and these are just some of the few that I know of!

you start to realize that you are working against the system.
Don't do things in ways the system wasn't meant to do it :)
 

Alice

Darts addict
Forum Staff
Moderator
Want a struct-like structure? Use a map. It's fairly identical.
In principle, it mostly is (though map lookup might take a bit more time, I guess? Having to calculate the hash and stuff; though it won't matter for most projects, probably). However, in syntax there's still that nasty barrier of not being able to use chained accessors. Once we get these, operating on nested structures shouldn't be an issue.

How is this different from script resources if you don't mind me asking? "Tied to a class" is not a reason...
All script resource share the same name, and often one might want to use the same function name for different implementations in different objects. I feel that would be a natural extension of the User Defined events we have now.
Though with the return of variable_whatever_exists/get_set functions emulating methods functionality should be significantly easier. In particular, in absence of a specific method one can just assume the object should do nothing.

Say that to the developers of: Hyper Light Drifter, Blackhole, Crashlands, Defenders of Ekron, Death's Gambit, Gunpoint, Hotline Miami, Spelunky, Memoranda, Savant Ascent, Wanderlust, ...
And so many more... I could go on for hours - and these are just some of the few that I know of!
I agree the argument of "GML being for smaller projects/games" is a miss, too.
Instead, I think the issue is with GML having "blind spots" for specific projects or tasks; sometimes, some things are just more of a pain than their should be. The type checking is one of the most glaring - unless I know the type of structure from elsewhere, I cannot tell data structures apart from each other, or apart from regular integers. Because of that, in particular, I cannot handle an arbitrary JSON structure where the same item could be a list or a map, because I can't tell these apart.

Seriously, though, why ds_map/list_is_map/list/primitive isn't a thing yet? Clearly, the data is there, because GM must know how to destroy structures; yet, we cannot access it ourselves. That limitation is really frustrating sometimes...
 
If your code is a mess, it's not the language's fault - it's exclusively yours. I have no problems writing organized and documented code and game systems in GameMaker Language.
What games have you made? Not being a jerk, since I know you're a good programmer. I'm legitimately curious what you've made in GM, though.
Say that to the developers of: Hyper Light Drifter, Blackhole, Crashlands, Defenders of Ekron, Death's Gambit, Gunpoint, Hotline Miami, Spelunky, Memoranda, Savant Ascent, Wanderlust, ...
A lot of those are great games, but I don't think any of them would qualify as overly complex when compared with the better Unreal 4 games out there. I do agree that GM can handle the projects most of us (including myself) would like to create here, though. =)

All script resource share the same name, and often one might want to use the same function name for different implementations in different objects. I feel that would be a natural extension of the User Defined events we have now.
Though with the return of variable_whatever_exists/get_set functions emulating methods functionality should be significantly easier. In particular, in absence of a specific method one can just assume the object should do nothing.
Yes, named user events that show up along with instance variables in the intellisense would be incredible. Please make this happen, @Mike! Just showing variable names has saved me a ton of headaches already. Having named events too would be amazing. =)
 

Lewa

Member
If your code is a mess, it's not the language's fault - it's exclusively yours. I have no problems writing organized and documented code and game systems in GameMaker Language. Every time you write messy code, you learn from it... I've written plenty of messy code in my time - sometimes purposefully because I just don't care, and sometimes because I just don't know the language I'm using well enough; but it's never the language's fault if you write messy code. After all, you're the one with the keyboard! :)
I do agree that i could've structured my code a bit differently in order to improve the readability as much as possible.
However, this would require you (as the developer) to know all the downsides of such a language (in this case, no type safety, no class methods, no access modifiers, no ability to create object without the overhead of GM instances, etc...)
and write with those limitations in mind, essentially requiring you to learn GML specific "workarounds" for language features (even if you have experience in other languages) which exist in other programming languages. (And this is more often than not even less convenient compared to the same stuff in proper OO languages.)

As an example:
> Access modifiers: You will have to make sure that you NEVER overwrite (or even touch) a private variable outside of the instance in which it was created.
> Methods: you would need to create scripts representing said methods and (in order to organize them somehow) come up with a naming sheme in order to find them easily in the ressource tree. like scr_player_getLives(): Oh, and good luck with refractoring. (Also then you have the problem that you can't set access modifiers to those scripts.) Also, method overloading or overwriting is a pain in the a**.
> Type safety: You can't tell if you accidentally pass a wrong value type as a parameter into the functions. (And i"l get to it why this is "inconvenient" a bit later.)

I do like object-oriented programming... A lot! But 1) it has a lot of downsides in my opinion, and 2) I don't think it's within the scope of GameMaker Language, and 3) You can solve all the problems you bring up without extending GML. Remember when you were a beginner, and you appreciated the simplicity of GameMaker Language? Why take that away from current beginners just because you're not a beginner anymore?
OOP does in certain scenarios have it's downsides. But there is a reason why the object oriented approach to programming was invented in the first place.
In addition to that: I never said that i want to make the language more complicated. I want to make it better for both sides: Beginners and advanced users alike. There are definitely ways to implement GML in such a way so that it makes both sides happy.

How would you benefit from not being able to access certain variables? How would your ability to write code benefit from this? Access modifiers are a compile-time thing and nothing more. There is nothing at runtime in any language as far as I am aware that says "no, you can't access that." - it's all in the compiler. So instead of polluting GameMaker Language with access modifiers, why don't you just not access those variables? My naming conventions have "public" variables as "my_variable" and "internal" variables as "__my_variable" (the number of underscores depend on my mood and how internal I think it is ;))
All comes down to code and data seperation. As an example, let's say you want to write a class which stores some form of data (be it a chunk system, a linkedlist, or whatever.) Sometimes you want to declare variables (state variables, etc...) inside this class in order to implement certain functionality or optimize the code. (You could store the size of a datastructure as an int and return it everytime if you call the appropiate method instead of iterating through the datastructure everytime in order to safe performance. Of course you need to make sure that you update this integer everytime you modify the datastructure.)

No other system (besides the datastructure class itself) should be able to modify the value of the integer. Making sure to not touch the variable outside of the class is fine and dandy, but it doesn't prevent you from accidentaly doing so. This issue of not "enforcing" certain things upon the developer becomes especially appareant if you work in a team of multiple programmers which work on the same codebase together.

You write the code, you write the bugs. Agreed that strong typing aids in finding these errors, but if you want to ensure you get the right types passed into a function I suggest adding an assert() script that looks like the following:
Code:
#define assert(expr, message)
if(os_get_config() != "debug") return; // only run this in a debug configuration
if(!expr) show_error(message, true); // assertion failed, show error
Use this script like so: assert(is_real(argument0), "Expected real, got nonsense");
Problem solved :)
An assert is certainly a step in the right direction, but in no way the same thing as explizit types.
It can be tedious to open the script and look what exact type parameters it allows you to pass in. (Every modern IDE shows you what parameters and overloads of this method are available for you to use in the specific scope you're in.)
And again, no overloading, overwriting, etc...

If you misuse a language, you have to accept the trade-offs of doing so. If you don't like doing weird hacks like this, then don't do them. Want a struct-like structure? Use a map. It's fairly identical.
Again, it doesn't solve the underlying problem. Yes, it's possible to use a map as a struct. But it's not the same as a proper struct (or object) and thus forces you to find other ways to do operations on this "struct" or access its content. (Not to mention the overhead of a map compared to a simple struct.)

How is this different from script resources if you don't mind me asking? "Tied to a class" is not a reason...
Again, data and code seperation. (In addition to overloading, extensions, not being able to create interfaces, etc...)
First of, you wouldn't have the possibility of function name collissions (Namespace!) if you download something from the marketplace. (Because scripts wouldn't be globally accessible from everywhere.)
Instead they would be tied to the class itself. In addition, by simply opening a class you would be able to tell immediately what exact methods it has. (And you wouldn't have to search the appropiate scripts in the ressource tree to see what it has to offer in terms of functionality.)
And again, overloading: Not possible. Extending/overwriting methods: Not possible. Making methods private (which shouldn't be accessible for the outside but were created to reduce code duplication and make the code inside the class more readable): Not possible.

Say that to the developers of: Hyper Light Drifter, Blackhole, Crashlands, Defenders of Ekron, Death's Gambit, Gunpoint, Hotline Miami, Spelunky, Memoranda, Savant Ascent, Wanderlust, ...
And so many more... I could go on for hours - and these are just some of the few that I know of!
I can't speak for the developers of those games. I don't know how they structured their games nor how the code looks like (or how complex it is.)


Don't do things in ways the system wasn't meant to do it :)
Easier said then done especially considering all the stuff i mentioned above. :p


I agree the argument of "GML being for smaller projects/games" is a miss, too.
Instead, I think the issue is with GML having "blind spots" for specific projects or tasks; sometimes, some things are just more of a pain than their should be. The type checking is one of the most glaring - unless I know the type of structure from elsewhere, I cannot tell data structures apart from each other, or apart from regular integers. Because of that, in particular, I cannot handle an arbitrary JSON structure where the same item could be a list or a map, because I can't tell these apart.
I agree. It's not that GML isn't a proper programming language. It just has this limitations which can be very annoying (and restrictive) to work with.


I'll now stop discussing this further. (Don't want to derail the topic and risk getting shot by Mike. :p )
 
Last edited:

Mike

nobody important
GMC Elder
I think the issue isn't features because you "can't" to it any other way, it's features to make it easier, or quicker to do. I don't think anyone would disagree with that. I've wanted structures for ages, but I can make do with grids/arrays and enums as entries. Method calls I'm not as fussed about. I'll either use old "C" style calls where I pass an ID in, or I'll do a with before calling so it's attached to the instance "like" a method. Would method syntax speed things up, sure. Does it stop me? no.

As to doing encryption or whatever. Buffers will help with this a lot, and if you are really stuck then you can pass a buffer directly into a DLL and do whatever you need to - although, you can do everything in GML if you want to, it's just a little more long winded.

I've not found anything I can't do, just things I wish were a little easier or quicker to do.

I don't do much 64bit stuff, so doubles never usually hurt, and the few times I have, I can do software maths on ints to work it out - not the end of the world, but yeah... more memory, and a bit more hassle. Some of these will come, but I don't really think you "Need" specific types or class definitions.... but methods, stucts etc. would make a huge difference and I do hope we get them one day.

GML has changed a lot over the years already, from simple things like ++/-- to being able to data structure accessors and passing arrays into scripts properly - remember, you couldn't even do that before! I don't think it unreasonable to think it'll stop changing now, but we'll do it in a way that preserves the look and feel of the language so it remains accessible.
 
R

renex

Guest
Who uses buffer_seek_end?
Me... for appending data.

no one has ever attempted what I am currently achieving with GMS
Attempted? Certainly. Achieved? Well, me, personally, not much - I keep hitting instruction limits on shaders and giving up on entire projects because of dumb design flaws requiring too much refactor.

As for the whole data type thing... I just don't see the appeal. My only problem with GM's doubles was the passing worry that a loop counter used a double to count. Well, that's going to get sorted in the future, and it shouldn't even matter anyway unless you're looping loops of loops of loops of loops. I hit a number size limit on one game once and decided to solve the problem forever, so I made a scalable basic arithmethic system using strings. That turned out to be horribly slow so I ported it to arrays.

So this brings me to a neat thing I had been meaning to ask for a while. I liked being able to treat strings as byte arrays in C, and that'd be really neat to see in GM. I like to make projects with lots of custom data formats for external editors and dealing with these things is often a huge hassle, often making me resort to very slow string iterators or explosive formats like json, which is not ideal. I know there is already a function to get and set the string byte at position, so a string accessor would probably take very little effort to implement.
 

GMWolf

aka fel666
As for the whole data type thing... I just don't see the appeal.
Well there is the whole accuracy thing.
When dealing with ints, its perfectly fine to use ==. When dealing with floats, much less so.
Also, integer division can lead to some rather nice code. I always assumed it would be a nuisance untill i actually used it and found many good uses for it.
 
A

Ariak

Guest
If you require typed storage use buffers, we are open to talking about faster / better ways of accessing buffers (which are essentially pointers with offsets), this includes functions and syntax changes to allow access buffers to be more aesthetic and easier from GML.
Russell
Thank you @rwkay!
I generally like the idea of being able to use a buffer should integers really be neccessary - and i've done so in the past.
Increasing access speed and implementing a buffer accessor for cleaner looking code would be greatly apprecitated! It is strange to see that grids are faster than buffers with the YYC in GMS 1.x, when they require one coordinate more and also store any kind of value which is not predefined before access.

Upgrading buffers doesn't add complexity for beginners to GML/coding in general whilst acknowledging the problem and resulting nuissances for more advanced users [without outright implementing data type casting].
 
Last edited by a moderator:

Lewa

Member
Just wanted to show you guys a real-world example as to how cluttered the script ressource tree can get with time:
(Be careful, large picture!)

Now, i don't know how big the ressource tree in other GM games get, but this amount shown above (for me atleast) does become a big problem when it comes to overview and navigation of the code.
It just isn't funny anymore.
Navigating through that is a chore. Nowadays i pretty much exclusively use the "find ressource" option (CTRL + R) in GM in order to quickly open up a script without having to navigate through the tree. (Given that i know the name of the script.)

It's true that i'm also responsible for not organizing the code in a better way. I probably should've stuck with some form of method based naming sheme where for each object a subfolder is created in the script ressouce tree in which i place it's "methods". It's a bit too late for that now.

(But this doesn't mean that i didn't try to organize the games structure in any way.)
I indeed have subsystems in the game which i tried to seperate from each other. (Collission system, audio system, levelloader, MapEditor controller, Replay system, etc...)
I also used the user defined events to simulate methods. (Especially the GUI components like buttons and textboxes and renderable objects like the world geometry and players, etc...)
The big issue is that once all those system start to interact with each other (and you don't set fixed rules as to how those objects can interact with each other right from the beginning of development) it can become very confusing and hard to track.
Things that are straightforward in other languages do require jumping hoops in Game Maker in order to achieve some form of abstraction and seperation.

Hope some of you understand my point of view and the statements which i've made regarding this topic.
 
Last edited:

Mike

nobody important
GMC Elder
GMS2 has resource "views", you can have one view that has all this, and another that cuts out whatever you don't need for each specific task.

They are also not bound to resource type so you can sort, remove things however you like.
 

GMWolf

aka fel666
GMS2 has resource "views", you can have one view that has all this, and another that cuts out whatever you don't need for each specific task.

They are also not bound to resource type so you can sort, remove things however you like.
Still, I think some forme of namespacing should be the next biggest update for GML.
Any other additions simply worsten the problem, or are impractical to add without namespacing. So i thnk it really should be a priority.
It will break projects (probably), but come on YYG, its getting ridiculous!

I think you have realized that the most important feature for a language is the libraries people built. And you cleverly buit a marketplace for those.
But without namespacing, i really dont like importing peoples code, simply because of the clutter it causes and more importantly, having to resolve naming clashes really quite often.
 
P

ParodyKnaveBob

Guest
So this brings me to a neat thing I had been meaning to ask for a while. I liked being able to treat strings as byte arrays in C, and that'd be really neat to see in GM. I like to make projects with lots of custom data formats for external editors and dealing with these things is often a huge hassle, often making me resort to very slow string iterators or explosive formats like json, which is not ideal. I know there is already a function to get and set the string byte at position, so a string accessor would probably take very little effort to implement.
Actually, this is an idea. You can use string variables as arrays in Javascript. Perhaps a GML accessor could harken to BASIC and go something like...

Code:
str_fruit = "apple";
show_message(str_fruit[$ 4]); // output: l
That assumes for char and not byte. I suppose [$ could be used for char and [$$ for byte. Yes, I recall the [! fiasco. Something besides $ could be used (e.g. [% [%% I suppose), or there could be a big warning (like for [! before) to leave a space.

No big deal, but convenient...
(gotta keep it on topic)
...for uh string data types yeah.
 
M

mdbussen

Guest
I'm not going to wade into the data typing debate (it has both positives and negatives) but I WOULD like to see some optional way to designate variables as "private", explicitly for the purpose of protecting me from myself! It could just be an optional keyword that "beginners" could ignore; there doesn't need to be a corresponding "public" type declaration.

You write the code, you write the bugs. Agreed that strong typing aids in finding these errors, but if you want to ensure you get the right types passed into a function I suggest adding an assert() script that looks like the following {...}
This is kind of a silly argument. People are putting forth suggestions to try and improve the functionality of the language (in their opinion). You can't just handwave suggestions away by saying "If you write perfect code you won't have any problems". The reason people are asking for datatyping is because it is a very useful feature to help ensure that the programmer is using the correct data in the correct way. With non-typed languages it is very easy to write code that you THINK is doing one thing and then find out much later through painful debugging that you had been using a variable in the wrong way, but GML in all of its non-typed glory had decided to just continue merrily along where a typed language would have at least warned you that maybe this wasn't QUITE what you were intending.

Still, I think some forme of namespacing should be the next biggest update for GML.
Any other additions simply worsten the problem, or are impractical to add without namespacing. So i thnk it really should be a priority.
It will break projects (probably), but come on YYG, its getting ridiculous!

I think you have realized that the most important feature for a language is the libraries people built. And you cleverly buit a marketplace for those.
But without namespacing, i really dont like importing peoples code, simply because of the clutter it causes and more importantly, having to resolve naming clashes really quite often.
Rather than namespacing, having an ability to declare functions/variables as "private" would nicely allow for you to no longer worry about potential collisions. The asset becomes an API where the only things that are exposed are the things that should be exposed.
 
Last edited by a moderator:

GMWolf

aka fel666
Rather than namespacing, having an ability to declare functions/variables as "private" would nicely allow for you to no longer worry about potential collisions. The asset becomes an API where the only things that are exposed are the things that should be exposed.
I was thinking more for scripts. Besides, Making variables private doesnt solve much: instead of wierdness, you get compile errors, And you loose the ability to write your object interface in scripts.
 

Mike

nobody important
GMC Elder
Still, I think some forme of namespacing should be the next biggest update for GML..
Don't disagree, and we've wanted it for a while, but its a sizable task and we just didn't have the time to do it. So - for now, we're stuck with what we have
 

Hyomoto

Member
Rather than namespacing, having an ability to declare functions/variables as "private" would nicely allow for you to no longer worry about potential collisions. The asset becomes an API where the only things that are exposed are the things that should be exposed.
All variables are private. If you have two instances, they can both have the same named variables and be different objects. What value does making them private have? To prevent you from var-ing a temporary version? To borrow from @Fel666, private variables don't solve anything. At best it allows you to write your code in a lazy and frightening manner. GML is interesting in that you can easily write bad code in it, and you can easily write good code in it, and it demands neither. Forcing, or even just allowing you to cover up your bad habits and poor planning by permitting you to have them in the first place is hardly an improvement. Bad habits are bad habits regardless of whether or not code allows you to have them.

Most GML guys, and I suspect many other language users, take to specific naming conventions if this is really a problem. For variables you want to have the same name for some reason, you can either split them up between objects: screen.width, object.width, or just use different names screenWidth, objectWidth. Those are both better solutions than just allowing you to type width and have it mean something different depending on location. I personally use wordWord convetions for normal variables, word_word_word conventions for macros, and _word for temporary variables. It's a personal style, but it means I have no troubles with overlapping variables, ever. And it's literally that easy to solve.
 

GMWolf

aka fel666
Actually Hyomoto...
What value does making them private have?
Private means other objects and scripts would not be able to access and change that variable.

To borrow from @Fel666, private variables don't solve anything
This still stands though, because it will make scripts a little useless...

At best it allows you to write your code in a lazy and frightening manner.
Forcing, or even just allowing you to cover up your bad habits and poor planning by permitting you to have them in the first place is hardly an improvement.
Actually making some variables private is considered very good practice and un-lazy. Unfortunately private variables simply make little sense outside of OO languages. (Imagine C structs had private member fields....)

People often mistake GM for an object oriented language. If we get right down to it, it misses a couple features for it to be truly that.
Rather, I would say GMObjects are closer to structs, with a couple function pointers the engine can call.
In that regard, private variables would make little sense. Besides, private variables will not solve the problem of name clashing anyways.

We already have scoping for variables anyways, and its mostly fine. You can generally import an object with little to no problems.

However, we have no 'scope' or namespace for scripts. Its not uncommon for scripts to be imported and to have similar if not equal names. The big problem with that is that the solution so far has been to include massive names.

Now @Mike said it wasn't happening anytime soon. But a good solution to the problem would be one @YellowAfterlife proposed (here)
Being able to store scripts in variables and calling them as follows:
Code:
scr = scr_very_long_name;
x = scr();
//outside of object
n = obj.scr();
This would allow use to define long script names, perhaps prefixed with the object name, and then define them with shorted names in the object.
Think of C structs with function pointers as members. This has been used a lot to emulate objects to great success. But does not inforce OO concepts on functional programmers.
 

Hyomoto

Member
@Fel666 - Well, then that's where we disagree. Object-oriented programming is really just a bottom-up approach, and that you can achieve in most languages despite the lack of 'true' object-oriented structures. True OO is to me, well to quote from Paul Graham's Hundred-year language essay:
I don't predict the demise of object-oriented programming, by the way. Though I don't think it has much to offer good programmers, except in certain specialized domains, it is irresistible to large organizations. Object-oriented programming offers a sustainable way to write spaghetti code. It lets you accrete programs as a series of patches. Large organizations always tend to develop software this way, and I expect this to be as true in a hundred years as it is today.
It has it's uses, especially when you have a lot of hands stirring the pot it's easier to just say, "this is my spoon" than to try and figure out if someone is already using yours. But in that case, I'd also say you are right that namespacing is the proper solution to that problem and anything else would just be a workaround, and it's one that benefits most users in some way. However, I would also propose that some of this script clashing could be fixed without it. Something I've been playing with a lot recently is the removal of scripts for things I'd normally use them for. So, instead of doing something like:
Code:
music_play( music_track, fade_out, wait )
I instead do:
Code:
global.system.playMusic = [ music_track, fade_out, wait ]
I'm sure this is not always the solution, but there are probably times where it can be the solution and may be the preferable one since it is a type of namespacing as the only flaw in using improper scope is the music won't play. I could even rename the variable or rewrite the entire underlying code and the only bug is the music wouldn't play. This is what I think of when I consider a bottom up approach. The object that handles my music code is in no way reliant on the objects that make use of it, it has no idea they exist and it doesn't care, it only listens for changes and responds to them. In fact, if I wanted to use a script but reduce the size of my large script name I could always put this into the object:
Code:
if playMusic != undefined { perform_my_long_script_name( playMusic ) }
As I said, maybe this isn't always the solution but GML is a unique language like any other and while we can take cues from other places, it's also important to ask what we can achieve in the language we have and question what proper implementation in it may look like. There are some people who are insistent that PC's are better because they have constantly changing and more powerful hardware while I've always argued consoles are probably responsible for most the major advances we've had in graphic rendering because they do not. I won't argue against specific implementation, as you've said this can benefit both OO and functional programmers and I love playing with new stuff. I just question whether or not these things are really solutions or hackarounds to a perceived shortcoming. Or even worse, a reluctance to learn or build GML-specific paradigms.
 

GMWolf

aka fel666
@Hyomoto
I never said OO wasn't a good thing. I love OO. I use it every day.

Unfortunately, GM is not an inherently OO language. And so we need extra constructs to build up OO patterns.

No matter how much you love OO, it won't change the fact GM simply doesn't work that way.

[edit] Yeah, missread. was on phone (see below)
 
Last edited:

GMWolf

aka fel666
Lol, @Fel666. You may have misread me.
So i did :) sorry, Not always down too read all text when on my phone ^^

Well, I kind of agree with you: It is sort of a hack around. But these sorts of 'hacks' have been working just fine for C programmers.
I also beleive it is the best solution for GML. It works with current syntax and would prove to be a very powerful tool.

Or even worse, a reluctance to learn or build GML-specific paradigms.
I actually have been working on GM paradigms for a long time now.
And yet, even though i have come up with many paradigms to work with GM (array structs, indirection scripts, etc), I still feel like GML is not doing much to help me.
Having script syntactic sugar like @YellowAfterlife suggested would greatly help im many, many ways. No longer would you have to write long, unmaintainable indirection scripts.

I dont think it would be a quick short term solution. This is a very powerfull tool that allows many functional languages to still be relevant today. And i beleibe code quality and maintainability could be greatly improved if such a feature was added.

Infact, With this addition, GML would not really need all the OO features everyone (myslef including) have been asking for a while. GML would be able to keep its simplicity, but still allow for rather complex structures.
 
S

Storyteller

Guest
GMS2 has resource "views", you can have one view that has all this, and another that cuts out whatever you don't need for each specific task.

They are also not bound to resource type so you can sort, remove things however you like.
Thank you for this, it is actually really helpful.

OK I can shut the speculation within this conversation down by saying we are not looking to type variables in GML for storage reasons, variables in GML will ALWAYS be 16bytes as they currently are as we have to store meta data on the storage for the variables (including storing what the type of the variable is).

If you require typed storage use buffers, we are open to talking about faster / better ways of accessing buffers (which are essentially pointers with offsets), this includes functions and syntax changes to allow access buffers to be more aesthetic and easier from GML.

We are also open to talking about hints to the compiler to say this variable should only ever be an int/float/single and it is free to optimise, but it will NOT affect the storage of those variables within arrays, data structures (i.e. ds_list, ds_map etc), this will help with error checking and allow the compiler to perform some better optimisation at runtime.

Russell
So I have been thinking about this for a few days. What gets me, s we have Data Types listed in the manual.
I tried using them in them as such
Code:
Real myNumber = 5;
and the error I got was 'unnecessary use of word...'. Not, unexpected word, but unnecessary.
Reading your post, it seems adding data types to the compiler is a no-go, its just too tightly ingrained in the underlying engine to fix 'any time soon if ever'.

So what about the editor? Could we get maybe a 'Strict' keyword at the top of a file or code block?
even Strict { some code;} like try-catch blocks.
In the Editor, not the compiler, this would allow the use of the existing data types as qualifiers in statements, and do a little syntax checking, thus throwing a warning at the programmer if they call a variable that had been given a 'type'.

While not ideal and still open to some runtime/compile time errors, for those that ar writing code it would lead to more succinct and well defined code. It would help prevent and catch errors on the developer side, with far less tedium than using 'is_a_such_n_such()' functions.

Again, not ideal, but would lead to well formed code, is only implemented in the editor, and would be a fine compromise somewhere in there. No compiler code would be touched.

I for one, am not comfortable enough yet to start using buffers, I think a lot of new coders might be put off by them. This would be a bit of a middle ground to help experienced coders spot bugs, and help new coders get in the practices of writing well formed manageable code.

If you guys can't do this, i it possible to write editor scripts so we can implement this or other features ourselves?

Anyway, I'm sure there are downsides to this, but it is a start. My $0.02
 

rwkay

GameMaker Staff
GameMaker Dev.
Well I can tell you that you got the error for unnecessary use of word as 'Real' is not a keyword so the syntax checker in the IDE considers it to be a variable name and using it at that position is not wrong... but it is unnecessary (and it will do nothing) so it is telling you that.

The way in which variables work in GML is intrinsic to the engine and the runtime, it is not going to change any time soon.

Russell
 

GMWolf

aka fel666
The way in which variables work in GML is intrinsic to the engine and the runtime, it is not going to change any time soon.
But perhaps a bit of static analysis would be nice.
Think of typescript. In the end, it ends up being ducktyped JavaScript. But it still offers all the comfort of a typed language.
 

rwkay

GameMaker Staff
GameMaker Dev.
We are planning on more analysis during compilation to make the code generation better but intrinsically variables (as stored in objects) will be 16 bytes, though even now we can store numbers as integers if we work out they are never needed to be floating point numbers and we can store various data types in them.

Now local variables within a script they can be any type we like (as they are not stored in long term object storage) and we will have a more focused analysis in the future on what they are over the execution lifetime of the script. This is more amenable to optimisation - but we are balancing the effort required to do this with the relative use of local variables as the code that we are seeing does not really use them much, while the effort to do this optimisation is huge, currently we are focusing on adding in language features (see Roadmap coming soon).

Russell
 
S

Storyteller

Guest
But perhaps a bit of static analysis would be nice.
Think of typescript. In the end, it ends up being ducktyped JavaScript. But it still offers all the comfort of a typed language.
this is basically what Im talking about. There are syntax and compiler error panes. Im not in any way talking about changing the internals of GML, just an option to give us some syntax errors where we want them to help us keep things straight.

Well I can tell you that you got the error for unnecessary use of word as 'Real' is not a keyword so the syntax checker in the IDE considers it to be a variable name and using it at that position is not wrong... but it is unnecessary (and it will do nothing) so it is telling you that.

The way in which variables work in GML is intrinsic to the engine and the runtime, it is not going to change any time soon.

Russell
In no way am I asking to change internals. Moreso, just exposing a bit of what you already have.

Consider the following, and I apologize if I have the grammar here off a bit, but you should see my meaning::
Code:
somevar = 12; //this is a number
othervar = "happy" //this is a string

if (isReal(somevar) = 12 { do some stuff;} //this will go
if(isString(somevar) = "happy" {do other stuff;} //this wont
We have just noted the type of a variable and checked that type. This is already done in the compiler. What we are asking for, is to make this more intuitive and less tedious. Doing this for every variable will get real old, real quick. It is 'unusual'. A lot of things in GML are 'unusual', especially coming from other languages, things just don't quite work like you'd expect. That's okay, every language has it's idiosyncrasies.

Tedious type checking is a pain. we want some method to at least warn us, if we are making a blunder. Type safety can be a good or bad thing. What we are asking for here (at least me) is an editor level check, that does not require such verbose notation, and the need to jump back and forth looking at comments to see if that was the variable type to use. Making that more automated, is a good thing.

As you mentioned an upcoming roadmap, I can't wait to see it. In fact, I will try not to post any suggestions until I see it, as it may be redundant.

That said, you might consider a 'strict' keyword, that allows some notation of typing, and checking that type (or at least displaying it somehow) in the editor, that will not interfere with the compiler.

Something you said, is that GM object variables are 16 bytes, and include the type of variable used. If you have that information anyway, can it be exposed in the editor?

It seems adding a 'strict typing' could use what is already there and either expose that information in the IDE, like in the autocomplete box (instead of variable, variable - real/string/boolean/etc).

Further, using the 'strict' keyword (if you add such a thing), might just perform the 'isReal' under the hood for us.

I look forward to the roadmap. :cool:
 
S

Shadow Gamer

Guest
this is basically what Im talking about. There are syntax and compiler error panes. Im not in any way talking about changing the internals of GML, just an option to give us some syntax errors where we want them to help us keep things straight.



In no way am I asking to change internals. Moreso, just exposing a bit of what you already have.

Consider the following, and I apologize if I have the grammar here off a bit, but you should see my meaning::
Code:
somevar = 12; //this is a number
othervar = "happy" //this is a string

if (isReal(somevar) = 12 { do some stuff;} //this will go
if(isString(somevar) = "happy" {do other stuff;} //this wont
We have just noted the type of a variable and checked that type. This is already done in the compiler. What we are asking for, is to make this more intuitive and less tedious. Doing this for every variable will get real old, real quick. It is 'unusual'. A lot of things in GML are 'unusual', especially coming from other languages, things just don't quite work like you'd expect. That's okay, every language has it's idiosyncrasies.

Tedious type checking is a pain. we want some method to at least warn us, if we are making a blunder. Type safety can be a good or bad thing. What we are asking for here (at least me) is an editor level check, that does not require such verbose notation, and the need to jump back and forth looking at comments to see if that was the variable type to use. Making that more automated, is a good thing.

As you mentioned an upcoming roadmap, I can't wait to see it. In fact, I will try not to post any suggestions until I see it, as it may be redundant.

That said, you might consider a 'strict' keyword, that allows some notation of typing, and checking that type (or at least displaying it somehow) in the editor, that will not interfere with the compiler.

Something you said, is that GM object variables are 16 bytes, and include the type of variable used. If you have that information anyway, can it be exposed in the editor?

It seems adding a 'strict typing' could use what is already there and either expose that information in the IDE, like in the autocomplete box (instead of variable, variable - real/string/boolean/etc).

Further, using the 'strict' keyword (if you add such a thing), might just perform the 'isReal' under the hood for us.

I look forward to the roadmap. :cool:
Full roadmap: https://help.yoyogames.com/hc/en-us/articles/231719448-RoadMap





On another note, I totally agree with a bunch of the people here about optional explicit data types for memory/performance increases. Doesn't even have to be by-the-bit or by sign type, just:
Code:
int enemiesPresent = 0; //classified as a signed integer with 64 bits
enemiesPresent = 0; //Still works to ensure compatibility and ease of use

string lastenemyName = "bob"; //classified as string (Not sure how the byte array method of dealing with strings would work, but I prefer the char array method of Python)
lastenemyName = "bob"; //Still works to ensure compatibility and ease of use

//and then floats, doubles, etc.
//Also, I disagree with a few others that booleans should be their own types, unless that type is an unsigned 8-bit integer (just to save space). I do greatly appreciate the allowance of using bools in operations, and removing that would be removing a large versatile component of GML.
Though, I guess that isn't probable from what the mods said here. Honestly, any way to make our games take up less memory or perform arithmetic faster is a welcome addition.

@FrostyCat, I know you mentioned the lack of headless export holding back the scalability of GM earlier. Might want to take a look at this: https://www.change.org/p/yoyo-games-game-maker-studio-2-headless-support
Sebastian is a pretty important developer that solely uses GMS, so he might have some clout.


Other than that, keep up the good work, Yoyo! I've seen the roadmap and I really like where you're going with this. I am very, very, very impressed with all the IDE and GML changes you guys are planning, you are one of the few large corporations I see actively listening to their base. I'm especially liking the planned foreach loop, the garbage collector, inlined functions, and the particle+tilemap improvements.
 

FrostyCat

Redemption Seeker
@FrostyCat, I know you mentioned the lack of headless export holding back the scalability of GM earlier. Might want to take a look at this: https://www.change.org/p/yoyo-games-game-maker-studio-2-headless-support
Sebastian is a pretty important developer that solely uses GMS, so he might have some clout.
You are putting words into my mouth backwards. I said even if headless runs existed, the lack of scalability and support for simultaneity elsewhere would hold back its potential.
This "running headless is the only thing in the way" myth is a common fallacy.

GML doesn't suddenly become practical for online multiplayer servers even if it can run headless. GMS 2 is still single-threaded and incapable of multiple simultaneous room states, so you still won't get very far anyways without re-engineering both.

If you know another language that can do both, use it --- GML probably won't get there in time.
And about that petition you linked to, show me where exactly a YoYo staff member promised to add headless executables for reaching 1000 signatures. Only Millennials would think online petitions like this have any clout, and even then not the ones with any business or workplace sense. My bet is that he's making up crap to serve his own propaganda and to make himself look important.

Yes, there could be a point to headless runs if scalability is addressed. But no, I am not going to sign the petition of someone putting words into YoYo's mouth, nor one suggested by somebody putting words into mine, and especially not one that fits both bills.
 
S

Shadow Gamer

Guest
You are putting words into my mouth backwards. I said even if headless runs existed, the lack of scalability and support for simultaneity elsewhere would hold back its potential.

And about that petition you linked to, show me where exactly a YoYo staff member promised to add headless executables for reaching 1000 signatures. Only Millennials would think online petitions like this have any clout, and even then not the ones with any business or workplace sense. My bet is that he's making up crap to serve his own propaganda and to make himself look important.

Yes, there could be a point to headless runs if scalability is addressed. But no, I am not going to sign the petition of someone putting words into YoYo's mouth, nor one suggested by somebody putting words into mine, and especially not one that fits both bills.
Ah, sorry, I must have misread. I thought the comment about headless and pushing capabilities were related in #65. I see now they were not. I kind of have to agree with you though, headless isn't going to fix much.

I don't claim to have started or been involved in the process of creating that petition or any of its promises, and I certainly do not back up any of those promises.

Again, I didn't make the petition. Nor am I asking you to sign it, or am I endorsing it. I simply thought you might be interested in it, due to a misinterpretation of what I read. If you were interested, great. If you weren't, which was the case, that is fine as well. There was no intent of putting words in your mouth involved, just a desire to share something I thought may have matched your interests (which as you said, it did not). If you would like, I can ask him if he can put proof of the "promise" on the page, but in all honesty with the current signature count and the extraneous nature of headless executables in general I don't think it is necessary.
 
K

kevins_office

Guest
I know i am late to the party however i found this while searching for answers. I have a real world situation where having the ability to declare data types is needed. I am using GMS2 and pushing its abilities. For an RTS style game I created a top down 2.5D procedurally generated infinite map using perlin noise which loads as chunks using tilemaps. The perlin noise decides on terrain and then i use bitwise auto tiling to create the tilemaps. This creates an open world allowing the player to move anywhere into positive and negative x/y.

Because the world is not locked into a room size it is a challenge to do pathfinding. I first tried using mp_grid_path() but to have any sort of tile based collisions i needed to fill out mp_grid. I take the two path points A / B and create a mp_grid over that area of the map with a 200 * tilesize margin to allow for navigating around obstacles. Now i have to create two for loops going over tilemaps x/y getting tile ID's to know which cells to flag with mp_grid_add_cell(). This process was extremely slow causing the game to freeze up for a second or two each time. So i went searching for another solution.

My best idea was to create my own pathfinding which could take tilemap tile ID's into consideration while plotting a path instead of having to pre-populate a full grid loop over the entire xy of all tilemaps. I learned A* and coded it in GML and it worked. I benchmarked it against mp_grid_path to see if what i had was efficient. Using rough numbers... For a path which took mp_grid_path 200µs it took my A* 30,000µs so i went debugging to find out why. Long story short, the code in my A* which looks up tile ID's and scores cells and finds a path was less than 200µs being faster than mp_grid_path. The bulk of the time of the 30,000µs was spent just to create and destroy the five (aprox 500 x 500) 2D arrays needed to hold values while A* scoring.

I looked for suggestions on discord and tried the following...

Switching from 2D arrays to ds_grids. No speed improvement as ds_grids take the exact same time to create and destroy.

Using less arrays by combining numbers into a single array like G and H score values (G * 100000 + H) which then i had to div and mod back out. I found the added work with div and mod was slower than the time to create the extra arrays so i went back to having five arrays.

Instead of temp arrays being created when needed. I tried keeping instance arrays around to avoid creation and destroy times. Because grid size is dynamic depending on where the path point A and B were going to be, i created five 1,000 x 1,000 2D arrays. Then when making a path which only required a 500 x 500 grid i would for loop only 0 to 500 setting values to 0. Not only was this three times slower than just creating new 2D arrays it also sucked up over a gig of memory holding those arrays around as instance variables.

Then someone said use buffers. I created scripts that used buffers like a fake 2D array with offsetting peek and poke to get / set values. Started benchmarking and at first was excited. When it took 11,000µs to create five 2D arrays i could create the same sized fake arrays in buffers as buffer_u8 in only 300µs, or buffer_u16 in 500µs. I thought i had a solution. I was wrong, come to find out buffer access time is slower. It took 5 times longer to assign values in a buffer with poke than assigning values to an array.

This experience did open my eyes to why my A* which has to create arrays is much slower than mp_grid_path. Because even though YYG thinks we can do anything needed with loose typing, they themselves were able to use strict types when creating GMS2 which means under the hood their mp_grid_path doesn't need to create buffer_f64 (8 bytes) arrays. They have the ability to create buffer_u8 (1 byte) arrays. Because GMS2 does not offer me any other options and im stuck with hugely bloated variables there is no way i can improve performance in my game. Im not 12 making a Mario clone in my bedroom. I am trying to be a serious dev and wrongly assumed GMS2 was a tool that could create a top notch indie game. Now i see why the GMS2 user base is mostly beginners making platformer clones, anything else more complex becomes difficult and lacks the ability to really optimize.

Some people make the comment "If you want a real language then why not go use that language." I didn't choose GMS2 for the GML, heck it would be nice if GMS2 used C# like Unity3D or anything else than PHP, err i mean GML. I choose GMS2 for the IDE, for the interface, for the prototyping tools. Sure i could use Java but then i wouldn't have the nice prototyping IDE that is GMS2. And honestly i do like GML, even though it lacks some built in features other langs have, like split string, and i can easily create my own functions for those things. But i have hit a hard limitation that can not be worked around in GML's current form.

I like the ideas suggested before, allow users to declare variables with a data type, but if a variable isn't declared it defaults to real data type as training wheels for newbies. You know kind of like the, you should use ; to terminate a line of code, but if you don't we will do it for you internally. I also wish that you had to declare instance variables. You have to declare globals with global.* , you have to declare locals with var, but you don't have to declare instance which means if i typo a variable name a few hundred lines of code down the page, nothing tells me hey this isn't a variable you just used, instead it silently just makes it a new instance variable so now there are two different variables, and when the bugs start good hunting. Just a simple "inst myVar = 0;" would be awesome. And don't start with the newbies cant handle syntax rules, because they already learned how to use "var myVar = 0;". And isn't that what DnD is for? For getting newbies into using GMS2? Adding too many training wheels into GML syntax is redundant and hinders turning those newbies into better programmers.

So if i was able to catch the attention of any YYG employees, help. How can i improve my A* to get the same kind of performance you get in mp_grid_path? Because 30,000µs for pathfinding when a step is only 16,000µs (60fps) sucks especially if you need to make more than one path in a step.
 
Last edited by a moderator:

Simon Gust

Member
I know i am late to the party however i found this while searching for answers. I have a real world situation where having the ability to declare data types is needed. I am using GMS2 and pushing its abilities. For an RTS style game I created a top down 2.5D procedurally generated infinite map using perlin noise which loads as chunks using tilemaps. The perlin noise decides on terrain and then i use bitwise auto tiling to create the tilemaps. This creates an open world allowing the player to move anywhere into positive and negative x/y.

Because the world is not locked into a room size it is a challenge to do pathfinding. I first tried using mp_grid_path() but to have any sort of tile based collisions i needed to fill out mp_grid. I take the two path points A / B and create a mp_grid over that area of the map with a 200 * tilesize margin to allow for navigating around obstacles. Now i have to create two for loops going over tilemaps x/y getting tile ID's to know which cells to flag with mp_grid_add_cell(). This process was extremely slow causing the game to freeze up for a second or two each time. So i went searching for another solution.

My best idea was to create my own pathfinding which could take tilemap tile ID's into consideration while plotting a path instead of having to pre-populate a full grid loop over the entire xy of all tilemaps. I learned A* and coded it in GML and it worked. I benchmarked it against mp_grid_path to see if what i had was efficient. Using rough numbers... For a path which took mp_grid_path 200µs it took my A* 30,000µs so i went debugging to find out why. Long story short, the code in my A* which looks up tile ID's and scores cells and finds a path was less than 200µs being faster than mp_grid_path. The bulk of the time of the 30,000µs was spent just to create and destroy the five (aprox 500 x 500) 2D arrays needed to hold values while A* scoring.

I looked for suggestions on discord and tried the following...

Switching from 2D arrays to ds_grids. No speed improvement as ds_grids take the exact same time to create and destroy.

Using less arrays by combining numbers into a single array like G and H score values (G * 100000 + H) which then i had to div and mod back out. I found the added work with div and mod was slower than the time to create the extra arrays so i went back to having five arrays.

Instead of temp arrays being created when needed. I tried keeping instance arrays around to avoid creation and destroy times. Because grid size is dynamic depending on where the path point A and B were going to be, i created five 1,000 x 1,000 2D arrays. Then when making a path which only required a 500 x 500 grid i would for loop only 0 to 500 setting values to 0. Not only was this three times slower than just creating new 2D arrays it also sucked up over a gig of memory holding those arrays around as instance variables.

Then someone said use buffers. I created scripts that used buffers like a fake 2D array with offsetting peek and poke to get / set values. Started benchmarking and at first was excited. When it took 11,000µs to create five 2D arrays i could create the same sized fake arrays in buffers as buffer_u8 in only 300µs, or buffer_u16 in 500µs. I thought i had a solution. I was wrong, come to find out buffer access time is slower. It took 5 times longer to assign values in a buffer with poke than assigning values to an array.

This experience did open my eyes to why my A* which has to create arrays is much slower than mp_grid_path. Because even though YYG thinks we can do anything needed with loose typing, they themselves were able to use strict types when creating GMS2 which means under the hood their mp_grid_path doesn't need to create buffer_f64 (8 bytes) arrays. They have the ability to create buffer_u8 (1 byte) arrays. Because GMS2 does not offer me any other options and im stuck with hugely bloated variables there is no way i can improve performance in my game. Im not 12 making a Mario clone in my bedroom. I am trying to be a serious dev and wrongly assumed GMS2 was a tool that could create a top notch indie game. Now i see why the GMS2 user base is mostly beginners making platformer clones, anything else more complex becomes difficult and lacks the ability to really optimize.

Some people make the comment "If you want a real language then why not go use that language." I didn't choose GMS2 for the GML, heck it would be nice if GMS2 used C# like Unity3D or anything else than PHP, err i mean GML. I choose GMS2 for the IDE, for the interface, for the prototyping tools. Sure i could use Java but then i wouldn't have the nice prototyping IDE that is GMS2. And honestly i do like GML, even though it lacks some built in features other langs have, like split string, and i can easily create my own functions for those things. But i have hit a hard limitation that can not be worked around in GML's current form.

I like the ideas suggested before, allow users to declare variables with a data type, but if a variable isn't declared it defaults to real data type as training wheels for newbies. You know kind of like the, you should use ; to terminate a line of code, but if you don't we will do it for you internally. I also wish that you had to declare instance variables. You have to declare globals with global.* , you have to declare locals with var, but you don't have to declare instance which means if i typo a variable name a few hundred lines of code down the page, nothing tells me hey this isn't a variable you just used, instead it silently just makes it a new instance variable so now there are two different variables, and when the bugs start good hunting. Just a simple "inst myVar = 0;" would be awesome. And don't start with the newbies cant handle syntax rules, because they already learned how to use "var myVar = 0;". And isn't that what DnD is for? For getting newbies into using GMS2? Adding too many training wheels into GML syntax is redundant and hinders turning those newbies into better programmers.

So if i was able to catch the attention of any YYG employees, help. How can i improve my A* to get the same kind of performance you get in mp_grid_path? Because 30,000µs for pathfinding when a step is only 16,000µs (60fps) sucks especially if you need to make more than one path in a step.
Or, you could take on the challenge and get past the barriers like the ones that are determined. A* is not the only kind of pathfinding. Think outside the box, what do you have on your arsenal and what do you need.
 
Top