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?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
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.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.
60FPS, and it runs at 960x540.I don't really see anything in HLD that pushes 'GMS to the limits' though to be honest. 640 x 480 at 30 FPS ???
Other than 2MiB RAM + 1MiB VRAM, maximum sprite size of 256x256, complete lack of shaders etc...Any insights into how that is, exactly? It doesn't look like anything the PS1 wouldn't be able to handle...
Perhaps with a blank room. But HLD has, y'know, sprites and AI and physics and everything that makes it a game.If I couldn't keep a stable 3000 FPS at that resolution, I'd be feeling like I had failed.
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.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.
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.Convenient? Sure. Extremely poor practice? Definitely
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).Perhaps ability to make custom data types would be too much to ask for at the moment...
And that is why GML uses handles for virtually everything. Create an Instnace? get an ID.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.
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.
Apologies.... I shall once again hide my bollocks.Read more carefully next time, and you won't have to summon any bollocks. Like Lewa says, neither of us were talking about pointers.
Perhaps another accessor, such as:we are open to talking about faster / better ways of accessing buffers
//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
//before:
buffer_poke(buff, buffer_tell(buff) - 12, buffer_u32, 25);
//with accessors
buff[* buff[*] - 12, buffer_u32] = 25;
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.Perhaps another accessor, such as:
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.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: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.
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.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.
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.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.
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. =)Other than 2MiB RAM + 1MiB VRAM, maximum sprite size of 256x256, complete lack of shaders etc...
Thank you, sir. =)Apologies.... I shall once again hide my bollocks.
No worries.Apologies.... I shall once again hide my bollocks.
Well, fair enough. I still would prefer having true data types (as well as proper OOP).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
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.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!".
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.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.
This. Very much this.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.
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 public-only variables which can be accessed from everywhere
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:no weird bugs due to wrong parameters passed into a function
#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
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.no weird hacks with GMS instances to create own data structures
How is this different from script resources if you don't mind me asking? "Tied to a class" is not a reason...data abstraction (functions which are tied to classes)
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, ...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
Don't do things in ways the system wasn't meant to do ityou start to realize that you are working against the system.
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.Want a struct-like structure? Use a map. It's fairly identical.
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.How is this different from script resources if you don't mind me asking? "Tied to a class" is not a reason...
I agree the argument of "GML being for smaller projects/games" is a miss, too.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!
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.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.
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. =)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, ...
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. =)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.
I do agree that i could've structured my code a bit differently in order to improve the readability as much as possible.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!
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.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?
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.)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 )
An assert is certainly a step in the right direction, but in no way the same thing as explizit types.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:
Use this script like so: assert(is_real(argument0), "Expected real, got nonsense");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
Problem solved
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.)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, data and code seperation. (In addition to overloading, extensions, not being able to create interfaces, etc...)How is this different from script resources if you don't mind me asking? "Tied to a class" is not a reason...
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.)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!
Easier said then done especially considering all the stuff i mentioned above.Don't do things in ways the system wasn't meant to do it
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 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.
Me... for appending data.Who uses buffer_seek_end?
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.no one has ever attempted what I am currently achieving with GMS
Well there is the whole accuracy thing.As for the whole data type thing... I just don't see the appeal.
Thank you @rwkay!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
Floor() can be wonky with doubles since 2 may actually be 1.9999454. I've seen this a handful of times.Just floor() your equations.
Doubles have a 52-bit mantissa. Signed 64-bit integers have a 63-bit mantissa. floor() will not bring the missing 11 bits back.Just floor() your equations.
Still, I think some forme of namespacing should be the next biggest update for GML.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.
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...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.
str_fruit = "apple";
show_message(str_fruit[$ 4]); // output: l
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.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 {...}
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.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.
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.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.
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 haveStill, I think some forme of namespacing should be the next biggest update for GML..
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.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.
Private means other objects and scripts would not be able to access and change that variable.What value does making them private have?
This still stands though, because it will make scripts a little useless...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.
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....)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.
scr = scr_very_long_name;
x = scr();
//outside of object
n = obj.scr();
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: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.
music_play( music_track, fade_out, wait )
global.system.playMusic = [ music_track, fade_out, wait ]
if playMusic != undefined { perform_my_long_script_name( playMusic ) }
So i did sorry, Not always down too read all text when on my phone ^^Lol, @Fel666. You may have misread me.
I actually have been working on GM paradigms for a long time now.Or even worse, a reluctance to learn or build GML-specific paradigms.
Thank you for this, it is actually really helpful.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.
So I have been thinking about this for a few days. What gets me, s we have Data Types listed in the manual.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
Real myNumber = 5;
But perhaps a bit of static analysis would be nice.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.
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.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.
In no way am I asking to change internals. Moreso, just exposing a bit of what you already have.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
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
Full roadmap: https://help.yoyogames.com/hc/en-us/articles/231719448-RoadMapthis 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::
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.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
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.
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.
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.@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.
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.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.
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.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.
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.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.