Jump to content


Structures


  • This topic is locked This topic is locked
70 replies to this topic

#1

  • Guests

Posted 06 February 2011 - 01:19 PM

So this is something that has to go in. I've been using structures since my earliest days of programming, and I can't believe Game Maker doesn't have it. Not having a structure system means your code ends up being more bloated and more complex than it needs to be, and means you end up creating more variables than you need to, forcing you to remember all the different variable names. Over and over since I've started using Game Maker I've found the need to simple structures, so we will (at some point) make sure these go in.

However... While we view it as vital, I'm interested in your opinion, not only if you see the need for them, but how you think they should be implemented. Here's how I would prefer them to work (although syntax is still to be fully worked out). While I'm currently avoiding TYPEs, it would be nice to define a more compact type for certain things as it would allow better memory management.

const   CLUBS = 0;
const   HEARTS = 1;
const   SPADES= 2;
const   DIAMONDS = 3;

struct  UndoSlot
{
   Rank,
   Suit,
   Stack,
   Active
};

MyArray[0] = struct_create( UndoSlot );

MyArray[0].Rank = 1;
MyArray[0].Suit = CLUBS;
MyArray[0].Stack = 3;
MyArray[0].Active = true;

This is obviously very open to change, but this is the general idea..... This would have saved me lots of code as I currently have to deal with multiple arrays, which isn't very nice at all.
(You'll also notice I want CODE constants... I hate having to define them in via the menu)

So... this is the idea. Do you have a better way of implementing it? Let me know!

#2 YellowAfterlife

YellowAfterlife

    GMC Member

  • Global Moderators
  • 3490 posts
  • Version:GM:Studio

Posted 06 February 2011 - 01:40 PM

Structs sound like a good idea, but maybe these should accept typical C++ - like definition?
struct

{

   (type) name,

   name,

   // ...

} structname;

  • 0

#3 sabriath

sabriath

    12013

  • GMC Member
  • 3147 posts

Posted 06 February 2011 - 02:10 PM

Yellow, GM is pretty much typeless, so you don't really need to put a type to the variables. (It isn't really typeless, but it's masked for beginners).


Here's an idea, to make it possibly easier for beginners...make it a new tree item (like sprites/sounds/fonts/objects, etc.)...."structures". When you create a new structure, the same code editor for scripts is used, but a slightly different convention.

The reason I suggest it this way is because 'scripts' and object code are run as the interpreter reaches them, which means those structures will not be known until it gets run (and then possibly be redefined EVERY time it runs). Having it separate from the codebase itself will allow it to be defined at compile-time instead (although the "compiler" could look for these things in scripts/code and make them global, but that can confuse beginners as it is).

I prefer the following myself:
//"stats" structure

var experience, nextexp, level;

experience = 0;
nextexp = 100;
level = 1;

proc gain
{
  experience += argument0;
  if(experience >= nextexp)
  {
    level++;
    nextexp *= 2;
  }
}

Since GM uses 'argument#' for args in scripts, there is no need to worry about adding more complications to the mix (but if you decide to add the ability of naming args, so be it). What I see the above doing is simply defining 3 variables within the structure and a procedure, which would allow this:

PlayerStat = structure_create(stats);
PlayerStat.gain(120); //yay, level up!



Technicals:

During parsing of structures (which should be relatively first), save the code position of the bytecode table to the name table for the structure and any 'vars' are noted within the structure and stored in the name table as well. If 'proc' is parsed, push code table, compile the definition and store the code within the name table for the procedure (using "this" as target for the variables inside which are also found in the name table for the structure), pop the code table back. Any other code found will be considered "initializer" code, simply target 'this' for any variables defined within it and when finished parsing, out a return bytecode.

After that, run through the name table for all procs, store the current code table position in the name table for the proc and push the code to that position. During the parsing of the rest of the application, struct_new() for it will call the initializer bytecode (stored in the name table at the beginning), any time a procedure is identified, call that position in the bytecode (also now stored in the table).

This would require your original 'collection' idea, where variables will be flagged for what it contains.



edit: oh, yeah, forgot. When calling the methods, 'push' the 'this' variable and make 'this' target the structure....and afterward 'pop' it back. That should have been obvious for compiler makers, but I forgot to mention in technicals.

Edited by sabriath, 06 February 2011 - 02:34 PM.

  • 5

#4 Zeddy

Zeddy

    Totally Radical Dude

  • GMC Member
  • 1789 posts
  • Version:GM8

Posted 06 February 2011 - 02:15 PM

I agree with this a lot, both the constant declaration and structures. Another thing I'm really missing is functions/methods. You can technically use scripts for this, but if you want a function that's implemented differently for different objects you'll either need a lot of differently-named scripts or a convoluted switch-scheme.

Edited by zeddidragon, 06 February 2011 - 02:15 PM.

  • 0

#5 ragarnak

ragarnak

    GMC Member

  • Retired Staff
  • 19468 posts
  • Version:GM8

Posted 06 February 2011 - 02:46 PM

So this is something that has to go in.

That would be a good idea, yes.

Here's how I would prefer them to work <snip>

I'm not sure how this how would this be an improvement over using a ds_list() .

Would those records be automatically released when the array (or data-structure) they are assigned to is removed (or destroyed) ? If not than I do not see any improvement over using a ds_list(). Sorry.

Currently I use ds_lists to create records. Fun when you are going just one level deep, painfull when you have several of them in a irregular data-tree and you have to destroy the whole thing.


By the way: I get the strong feeling that your "what about this?" pilot questions where not about version v8.1 to begin with. :mellow:

With the ammount and types of changes you've now asked us about it looks like that you, if not YoYoGames too, are already aiming at v9.0 or maybe at an even later version.

When you announced this particular subforum with its fractional version-number I really thought you guys where putting effort in a bit of bug-fixing and my previous mentioning in that direction might have been a bit too early (nope, not hasty). But as it now looks that hope was in vain ...
  • 0

#6 NakedPaulToast

NakedPaulToast

    GM Studio/Mac/Win

  • GMC Member
  • 7179 posts
  • Version:GM:Studio

Posted 06 February 2011 - 02:48 PM

You haven't addressed the scope of your const and struct definitions.

Perhaps something along the lines of:

       const INST_CONST = 0;    //instance scoped
var    const SCRIPT_CONST = 0;  //script scoped
global const GLOBAL_SCRIPT = 0; //globally scoped

struct  inst_invent             //instance scoped
{ 
   item, 
   number 
}; 

var struct  script_invent       //script scoped
{ 
   item, 
   number, 
}; 

global struct  global_invent    //globally scoped
{ 
   item, 
   number 
}; 

Edited by NakedPaulToast, 06 February 2011 - 02:51 PM.

  • 3

#7 Docopoper

Docopoper

    You are observant!

  • GMC Member
  • 1287 posts
  • Version:GM:Studio

Posted 06 February 2011 - 03:19 PM

if you'r adding structs, are you going to add enumerations as well? (I can't believe the spell checker knew that enumeration was a word!)

Off topic GM suggestion if you want to read:
Spoiler


Edited by Docopoper, 06 February 2011 - 03:30 PM.

  • 0

#8 kburkhart84

kburkhart84

    GMC Member

  • GMC Member
  • 1606 posts
  • Version:GM:Studio

Posted 06 February 2011 - 03:29 PM

You haven't addressed the scope of your const and struct definitions.

Perhaps something along the lines of:

       const INST_CONST = 0;    //instance scoped
var    const SCRIPT_CONST = 0;  //script scoped
global const GLOBAL_SCRIPT = 0; //globally scoped

struct  inst_invent             //instance scoped
{ 
   item, 
   number 
}; 

var struct  script_invent       //script scoped
{ 
   item, 
   number, 
}; 

global struct  global_invent    //globally scoped
{ 
   item, 
   number 
}; 


This makes the most sense to me.

I use contants a lot. I come from C++, where some books and people train you to use defines/contants for everything, and have nothing hardcoded. So I use them for bullet speeds, top speed, acceleration, everything for the most part, and it would be much more convenient to put it in code.

I like the idea of putting struct definitions in the tree though, but I would be happy if they came either in tree form or code form, or both.
  • 1

#9 Docopoper

Docopoper

    You are observant!

  • GMC Member
  • 1287 posts
  • Version:GM:Studio

Posted 06 February 2011 - 03:35 PM

The quote form the previous comment...


How can you have a scoped constant in GM's case? then you could just have the following:

if xx>0
 var const yy = 0;
else
 var const yy = 1;


so, how is yy in any way constant if it is not created during compile time?

Edited by Docopoper, 06 February 2011 - 05:03 PM.

  • 1

#10

  • Guests

Posted 06 February 2011 - 04:30 PM

I'll be discussing methods/functions at a later date.

ds_list() (and the rest) are still only 1 value per entry (like an array). Meaning you need multiple lists/arrays to store certain types of data. Having a structure and then storing THAT means you can store many bits of info per array entry.

I tend to prefer defining structures in code as it makes no sense to define them in the "tree-view" if you don't actually use code. In terms of having to have them defined, it's the same for lots of "code things". If you want to use a global, it has to have been set up before hand. This is no different. Define the struct before you need it (inside a CREATE I guess), then it never has to do it again. If it's defined again - lets say you do it inside a STEP event, then as long as it doesn't change, you shouldn't get an error.

enums. Yes, they would be nice too. If we did constants in code, enums would be easy as well. But would you prefer the C# enum, or C++ ones?

C#
   enum MyEnum
   {
     Tree = 1,
     Ball,
     Car,
   }
   value = MyEnum.Tree;

   enum MyEnum
   {
     Tree = 1,
     Ball,
     Car,
   }
   value = Tree;

Personally, I prefer the C# method as I like the enum structure name prefix. It stops silly collisions with other enums, allowing you to have many values the same. (i.e. an enum called Flag etc.)

In terms of scope... I had just figured that it would be the same as before. So yes, you could use global or var to scope them. I guess there is an argument to make them ALL global, but unless there's a massive speed up, I don't see the need to change it.

In terms of...
if xx>0
  var const yy = 0;
else
  var const yy = 1;

Yes... yy would be defined differently. But we can easily detect a variation in its value and throw an error. While you COULD make a constant simply an "unchanging value", I'd prefer to make it a true CONST (since you can optimise code compilation), so you can only specify it once. C# does #defines by forcing you to declare them at the TOP of the function. So once you start writing normal code, you can no longer create new constants. *shrug* Not sure. I think only allowing a single definition would be best.

Lastly... in terms of the 8.1 thing. We will be fixing bugs as well as doing new features, and yes... lots of this will relate to further down the line (i.e. not 8.1), but we hope many will come in before 9.0.

#11 Docopoper

Docopoper

    You are observant!

  • GMC Member
  • 1287 posts
  • Version:GM:Studio

Posted 06 February 2011 - 05:01 PM

C# method makes more sense for lack of ambiguity - and would probably also make more sense to beginners.

If you'r making constants definable in code, then what about constant switches? (Keep the dynamic ones too)
  • 0

#12 thatshelby

thatshelby

    GMC Member

  • GMC Member
  • 3823 posts
  • Version:GM8

Posted 06 February 2011 - 05:03 PM

I whole-heartedly agree. This means the games use less memory. Putting basically a whole array in a single variable is genius, and we need it as soon as possible.


EDIT:

Enums... Could someone explain them to me, briefly? Thanks..


I like all these more advanced language features coming to GML. It's much more of a learning tool if we have these.

Edited by Theophilus, 06 February 2011 - 05:08 PM.

  • 0

#13 NakedPaulToast

NakedPaulToast

    GM Studio/Mac/Win

  • GMC Member
  • 7179 posts
  • Version:GM:Studio

Posted 06 February 2011 - 05:07 PM

With regard to the Define Constants menu, I too hate it.

What I would like instead is a guaranteed "Main" like script that I can create and know that it executes at game startup. This would create a logical place to put my const, struct and any other initialization code.

Currently, the popular technique seems to be create a start-up room, with the sole purpose of running an initialization script, and then start the first game play room. Awkward.

Lastly... in terms of the 8.1 thing. We will be fixing bugs as well as doing new features, and yes... lots of this will relate to further down the line (i.e. not 8.1), but we hope many will come in before 9.0.


I'm concerned that the GM Windows (8.x) will diverge to much from GM4Mac (7.x). As it stands now, the preferred development platform for those with both is Windows, then use LGM to create a file format compatible source loadable with GM4MAC. The conversion between PNG and GIF is inconvenient, but the rest is really no big deal.

With these anticipated 8.x changes, the differences between Mac and Windows platforms will start to become so significant that porting to Mac will become less feasible.
  • 0

#14 Phantom107

Phantom107

    Engineer

  • GMC Member
  • 2590 posts
  • Version:GM:Studio

Posted 06 February 2011 - 05:11 PM

Sounds like an excellent addition.

I'm currently not experienced with variable definitions like that, but I'm learning the HLSL shader language so it should feel all familiar once you guys add it.
  • 0

#15 Nocturne

Nocturne

    Nocturne Games

  • Administrators
  • 16791 posts
  • Version:GM:Studio

Posted 06 February 2011 - 05:29 PM

I am an experienced GML programmer but have NO experience with any other language and so I can only say "eh?"... I have never heard of structures (nor enums) and so would have NO IDEA what to do with them, what they are for nor whether GM needs them or not. (Am I the only one in this boat, I wonder?)

So, if you are planning on introducing them I hope to god that you give a really good help file to match, with explanations and examples!
  • 3

#16 Docopoper

Docopoper

    You are observant!

  • GMC Member
  • 1287 posts
  • Version:GM:Studio

Posted 06 February 2011 - 05:42 PM

They're very easy to learn, I did a 2 week C# course and picked them up very quickly.

Enums are pretty much constants - but they have no value: ie you can set a var to an enum and check if it's that enum - but you cant get the value of it. I think thats right
Nope, not right - close though - see next post.

Structs are pretty much objects that can only hold variables and not run code. (very small)

Edited by Docopoper, 06 February 2011 - 06:01 PM.

  • 0

#17 amd42

amd42

    GMC Member

  • GMC Member
  • 269 posts
  • Version:GM8

Posted 06 February 2011 - 05:50 PM

I am an experienced GML programmer but have NO experience with any other language and so I can only say "eh?"... I have never heard of structures (nor enums) and so would have NO IDEA what to do with them, what they are for nor whether GM needs them or not. (Am I the only one in this boat, I wonder?)

Structs are basically like arrays. They store a collection of values, but instead of accessing each value with an index (0, 1, 2, etc.) you would access them with names that you give them (e.g. power, color, health, etc.). They're mostly to help you be more organized. For example, you could make and use a struct for a 3D point like this:

struct point_3d
{
    x;
    y;
    z;
};

point_3d my_point;
my_point.x = 3;    // Instead of my_point[0] = 3;
my_point.y = 5;    // Instead of my_point[1] = 5;
my_point.z = 7;    // Instead of my_point[2] = 7;

Enums (in C++ at least) let you quickly define a group of constants that have sequential values. You aren't required to use them; they just make things easier for you if you need to define a lot of constants and don't care too much about their values. For example, if you have an enum such as

enum Tiles
{
    Grass = 1,
    Sand,
    Wood,
    Stone
};

Then the constant "Grass" would be equal to 1, "Sand" would be equal to 2, "Wood" would be equal to 3, and "Stone" would be equal to 4.

Edited by amd42, 06 February 2011 - 05:55 PM.

  • 5

#18 Nocturne

Nocturne

    Nocturne Games

  • Administrators
  • 16791 posts
  • Version:GM:Studio

Posted 06 February 2011 - 05:55 PM

Interesting... Yes I can see how this could help a great deal when organising code. Thank you both for explaining a bit more...
  • 0

#19 111Studio

111Studio

    GMC Member

  • GMC Member
  • 258 posts
  • Version:GM:Studio

Posted 06 February 2011 - 06:02 PM

Structures are definitely a must. And a new constant system is definitely needed too.

I use constants a lot to decrease hard-coding as much as possible, but it gets pretty hellish trying to keep things organized in the Define Constants menu thing.

I would also like to see Enums implemented. Often I want to limit a variable to a few values but have to create my own code for throwing an error to make sure I don't accidentally set it out of bounds. Enums would be a great help.

As far as how structures are applied... I personally like the example implementation you presented, Mike. I use a lot of arrays and constants and use scripts to make accessing arrays more streamlined between objects and having a structure concept that can be implemented within one slot of an array would be wonderful.
  • 0

#20 Manuel777

Manuel777

    InvaderGames

  • GMC Member
  • 2847 posts
  • Version:GM:Studio

Posted 06 February 2011 - 06:12 PM

Sounds like an awesome idea to me!
ohp, and i vote for the C# style enums, it makes the whole thing easyer, both for the eye and the general understanding of the codes. ;)


Edit; i'm eating my fingernails waiting for GM9 :(

Edited by manuel777, 06 February 2011 - 06:15 PM.

  • 0




0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users