Jump to content


Structures


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

#21 slayer 64

slayer 64

    GMC Member

  • GMC Member
  • 3300 posts
  • Version:GM8.1

Posted 06 February 2011 - 06:20 PM

why even have structures? game maker has object oriented programming. just use instances of objects to store data. they are perfect for storing data in variables, and storing build in functions in events.
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;
structures. objects. same dam thing.
look, it's even less typing.
clubs=0
hearts=1
spades=2
diamonds=3

MyArray[0]=instance_create(0,0,undoSlot)
MyArray[0].rank=1
MyArray[0].suit=clubs
MyArray[0].stack=3
MyArray[0].active=1

  • 1

#22 gm_user_tronic

gm_user_tronic

    GMC Member

  • GMC Member
  • 45 posts
  • Version:GM7

Posted 06 February 2011 - 06:41 PM

will this break old sources?

I'm with Slayer, you can easily use objects as variable storage
  • 0

#23 Manuel777

Manuel777

    InvaderGames

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

Posted 06 February 2011 - 06:42 PM

@Slayer; I guess the benefit of having structures is not the sintax or how easyer it is to write, its the amount of memory you are using to store the data..
An instance for storing a structure doesnt see like a nice deal trough, imagine if you need to make many, MANY structures; you will be using tons of resources to do something that doesnt require them :)

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

  • 0

#24 Erik Leppen

Erik Leppen

    GMC Member

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

Posted 06 February 2011 - 06:48 PM

This is completely new to me as I have never programmed in any other language than GML and Basic. At first sight it looks overly complicated, but as long as it's all optional I'm fine with it. Also, same concern as yoyotronic: I just hope the current way of doing things keeps working. If that's the case, one could slowly get used to this concept of structures. It'd be a good opportunity to learn some more programming concepts. But on the other hand I have always liked the simplicity of GML.

And yes, constants should be defineable in code. The current constants window is a big mess in my newest game (147 constants, most of which just indices of things).
  • 0

#25 Docopoper

Docopoper

    You are observant!

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

Posted 06 February 2011 - 07:01 PM

Slayer:

If you like using objects so much then why do you use data structures so much in your games? Because it is way faster.
  • 1

#26 111Studio

111Studio

    GMC Member

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

Posted 06 February 2011 - 07:19 PM

Objects contain built in information that is not necessary to a structure. x and y coordinates, speed variables, gravity, etc. Sure, not very much for one instance, but what happens when you have tons? Structures allow you to do the same thing and create *only* what you *need*. Plus, accessing them is just way more feasible in Mike's example code than using instance ids stored in an array to access the variables.
  • 0

#27 slayer 64

slayer 64

    GMC Member

  • GMC Member
  • 3300 posts
  • Version:GM8.1

Posted 06 February 2011 - 07:38 PM

If you like using objects so much then why do you use data structures so much in your games? Because it is way faster.

that is exactly the problem with instances. 10,000 instances of an object are slow because game maker is doing who knows what. but 10,000 values in a data structure list is fast because nothing is being looped. nothing is happening. it's just data sitting there. make the background thinking in instances optional.
  • 1

#28 Docopoper

Docopoper

    You are observant!

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

Posted 06 February 2011 - 07:52 PM


If you like using objects so much then why do you use data structures so much in your games? Because it is way faster.

that is exactly the problem with instances. 10,000 instances of an object are slow because game maker is doing who knows what. but 10,000 values in a data structure list is fast because nothing is being looped. nothing is happening. it's just data sitting there. make the background thinking in instances optional.


so, why did you suggest to use instances then?
  • 1

#29 slayer 64

slayer 64

    GMC Member

  • GMC Member
  • 3300 posts
  • Version:GM8.1

Posted 06 February 2011 - 07:57 PM

so, why did you suggest to use instances then?

because game maker should use the object oriented programming it already has instead of using outdated methods from other languages.
  • 0

#30

  • Guests

Posted 06 February 2011 - 08:39 PM

Outdated? Really? Structures (in some form or another) are in most languages, it helps you access things in "packet" size chunks, memory/file layouts or simply helps you organise your data without any real overheads. They've been around since early assembler days, and I haven't seen anything that can replace them. Structs are still in modern languages like C# because it lets you access specific memory patterns that classes can not.

To us... Structs are far more very memory friendly, and don't impact Game Makers other subsystems (the looping through 200K instances thing is a real danger). Yes, we could change lots of this stuff; and probably will, but if an instance is active (since it's storing active data), then it has to be processed for events and the like. Now while we have plans to limit all this, these won't appear till GM9 or later, and even then instances will be far more memory intensive than structs.

So... while structs do behave somewhat similar to objects/instances in terms of storing data, you won't have functions/events associated with them, and they will use far, FAR less memory.

This won't break any old code. It's a new addition, so nothing in the past has used it.

As to the issue regarding upgrades to GML for windows and not GM4Mac.... Yes, good point, well made. We'll talk about this and see what we can come up with. Thanks.

#31 Robert3DG+

Robert3DG+

    VR Games

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

Posted 06 February 2011 - 09:12 PM

This all sounds really interesting Mr. Dailly. It's neat to have someone like you with Yoyo. I also read your blog and saw that you gave a thumbs up to sound instancing. Awesome :D

If structures won't break the source of previous games then I think it will be a neat new addition. I'd love to learn something new code wise.

Are you allowed to discuss about how fast work on GM 8.1 is going?

Edited by Robert3DG+, 06 February 2011 - 09:13 PM.

  • 0

#32 databot

databot

    admin of moonlight games

  • New Member
  • 309 posts

Posted 06 February 2011 - 09:21 PM

I hugely agree with the need for Structs and would love to see something like sabriath's suggestion with the ability to put code in the structs, it would much of the complex code I've written for things such as inventories, XML tree parsing much, much nicer and quicker (1 lookup of a struct verus several DS_ calls).
  • 0

#33 thaaks

thaaks

    GMC Member

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

Posted 06 February 2011 - 09:28 PM

Structs are still in modern languages like C# because it lets you access specific memory patterns that classes can not.

I think that's pretty much the only reason for their existence in C# - to allow dll calls and callbacks...
I'm with Slayer 64 and think that objects would make much more sense as their concept is already well known in GM.

All the performance issues you mention are just due to the way GM works right now. Currently objects have their event handling, step and draw events and so on. They are all checked each step for their events, are updated and drawn which of course costs precious amounts of time in the game loop.

But in every other OO language the base "Objects" are stupid data containers with some methods to retrieve or modify their data. You have subclasses that will add more and more functionality.
So if GM would start to become real OO under the hood you could have "simple stupid" Objects which are not much more than data structures.
One possible subclass would be a GameObject identical to the objects as we know them now with all their builtin variables, events and so on.

You could get there but it's a loooong way :rolleyes:

So assuming you decide to stay with structures the "old fashioned" way ;) : what about their scope? Are they treated like globals? Any script must know how all structs look like to modify them without throwing syntax errors. This would imply "precompiling" or scanning all scripts (or do some two phase compile step) and check for struct definitions and store them inside GM to make them accessable everywhere. Or you have some (as already mentioned) "init the game" script where all constants, structures and globals can be defined...
  • 2

#34 gnysek

gnysek

    GMC Member

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

Posted 06 February 2011 - 09:31 PM

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'm using ds_map for something like structures now:

(It's a script which reads images params which should be set along with sprite_add*, it uses 39dll for reading file)

global.resources = ds_map_create();
var _total,i;
_total = readint();
for( i=0; i<_total; i+=1) {
    var _name,_map;
    _name = readstring();
    _map = ds_map_create();
    ds_map_add( _map, 'transparent', readbyte() );
    ds_map_add( _map, 'imgnum', readbyte() );
    ds_map_add( _map, 'xorig', readint() );
    ds_map_add( _map, 'yorig', readint() );
    ds_map_add( global.resources, _name, _map );
}

So you can now achieve structures, but, it's of course much harder. The only advantage with them is that you can dynamically change number of entries in ds_map, beacause in array when you set t[999] = x, you will have 1000 keys in array until variable isn't destroyed, and you cannot make smaller (stupid thing is GM that you also can't count array elements, and you need to store it in another variable).

For example when I'm making online game, where sometimes plays 10 players, sometimes 100, but server need to be online all day, I need to define array players[99] (I'm keeping references for instances (id) in this array), but when there is average 20 players during day and only simetimes there will be 100, indexes >19 will be empty in this array, so I'm just wasting memory. It's the biggest problem with "for" loop, because I need to check whole table even if there will be one player.
Advantage with structs is that it will be possible to DON'T create any objects for those players, because all data can be keept in structure and treated by one, main object in game.

So - structures are OK, but think what to do with arrays to better handle them (resizing, or at least counting). Or maybe about associative arrays. Otherwise I will still use ds_map to keep structures as values, and player names as keys to have better control on them.
  • 0

#35 LSnK

LSnK

    NaN

  • GMC Member
  • 1188 posts

Posted 06 February 2011 - 09:31 PM

Structs would be a very nice addition. I assume these would be usable in other structs, containers and arrays as well?

Please make them easy to store, like the ds_ containers. While I'm on the subject, that goes for instances too.
  • 0

#36

  • Guests

Posted 06 February 2011 - 09:43 PM

I think that's pretty much the only reason for their existence in C# - to allow dll calls and callbacks...
I'm with Slayer 64 and think that objects would make much more sense as their concept is already well known in GM.


Actually, there's some other subtle reasons/uses for them. Classes are always passed by ref, structs aren't. It's pretty subtle, but storage reasons aside, you can see some fairly handy reasons for keeping them.

Aside from that... would I, in a perfect world make stucts instances? Not sure I would. I also like them being VERY simple. That's is you can't attach functions/properties to them. You need simple mappings, and who knows... in the future you might be able to map a struct to some raw file you've loaded in, which would allow you simple (and fast) access to some underlying binary data. That seems like a worthwhile reason to keep them for the future too.

EDIT:

Wow...I can't begin to tell you how slow your ds_map() accessors are :). Besides, there's nothing saying you can't then store your structure object in a ds_map() or something, but it would mean many times less accessing to get your data. Basically, you'd just make a single struct, and add THAT to your global.resources map. This is far, FAR quicker to run, and would use a lot less memory. Win, win in my book.

And yes, serialising would be nice down the line.... For everything, not just structs.

Also yes, I don't see any issue (currently) with structs inside structs. But that may or may not be possible. I don't know as yet.

#37 ~Dannyboy~

~Dannyboy~

    ~hoqhuue(|~

  • GMC Member
  • 2144 posts
  • Version:GM8

Posted 06 February 2011 - 09:58 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 
}; 

Sorry for going off on a tangent. But I've often wished that "instance scope" was not the default. I often forget to add the "var" keyword, and as such the code is silently broken, no errors are shown to let me know I've exposed this variable to the whole instance. I realise it would confuse a lot of current users, but I would like to see variables in "script scope" by default and require a "globalvar/localvar" or "global./local." prefix (one of these syntaxes should go...) to have it's scope extended. This way if I forget the prefix I will get an error and be able to fix it.

As for the syntax of structs, I'm fairly easy so long as the syntax is consistent with the other collections and so long as we don't have to explicitly state the type of the variable as being a struct. That is, please don't make variables staticly typed by default, make them take what ever type is on the right hand side of the assignment. Static typing should be explicit and an optional feature.
  • 0

#38 Smarty

Smarty

    GMC Member

  • Retired Staff
  • 7262 posts
  • Version:GM:Studio

Posted 06 February 2011 - 10:06 PM

Structs would really be of benefit to me - for a particular daunting job, I'm stuck with using maps referencing maps and lists, and it's a hassle to work with. It's slow, too.

I haven't seen one important feature mentioned yet though - we'd definitely require methods to save and load struct data. I do foresee some challenges to overcome, for example as to what should happen if the loaded data doesn't match the struct defined within the game, or when it only covers part of the struct.

Edited by Smarty, 06 February 2011 - 10:10 PM.

  • 0

#39 LSnK

LSnK

    NaN

  • GMC Member
  • 1188 posts

Posted 06 February 2011 - 10:12 PM

Silent scope-related errors

The source of error here is ambiguity in the code editor. I think a better solution would be to highlight variables differently depending on their scope. At least, some option which will list all affected variables along with their scope.
  • 0

#40 ParodyKnaveBob

ParodyKnaveBob

    theUndiscovered

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

Posted 06 February 2011 - 10:30 PM

Thank you, Mr. Dailly, for this subforum and its posts. (I only wish I knew of this sooner. I've been away for awhile. I wouldn't mind adding some different input to a couple of the other threads.)

I want to say I like the idea of adding structures (my first real look at them), and of allowing constants to be defined in code, but as ..I'll say a novice-to-intermediate programmer, I have some concerns. I have a nice ability to ramble, thus I'll try to keep it pointed in this post. $:^ ]

I like defining constants the way GM8 defines them -- but perhaps only because I don't know the alternative. GM6- didn't have this, but with GM7+, I can now softcode a lot yet have color-coded highlights to super-quickly visually distinguish between mere variables and a constant. (I usually go for the all-caps naming scheme, but on some stuff, it's just annoying -- for one example, using custom color constants is more awkward with c_blue c_orange C_LEO_BLUE C_MIKEY_ORANGE c_black etc. and less awkward with c_blue c_orange_ c_leo_blue c_mikey_orange c_black etc.)

I hear about intellisense, but I'm curious how well it might work to, say, 1. write a script that does plenty of nifty stuff, including defining certain constants for any given instance that calls the script, then 2. call this script from an object's Create Event and 3. refer to these object- (or even instance- ) specific constants in another event (such as End Step or Draw Event). Is it seriously easy enough to implement a GML-created constant with color coding elsewhere? I think it was Smarty in another thread who mentioned a concept similar to this, which I'll illustrate with a simplified example:

// object's Create Event
const c_favorite = choose(c_blue,c_red,c_orange,c_purple);
// object's Mouse Event for Left Pressed
if (image_blend == c_white) {
  image_blend = c_favorite;
} else {
  image_blend = c_white;
}
My basic question is, using this example, would/could this actually color-code the text "c_favorite" in some GML embedded into the Mouse Event? And if this code is instead in a script, and the script gets called from the event, would/could it still receive that nice color-coding? (It doesn't seem very easy to me, but I'm nowhere nearly as advanced as people like Smarty--however, to my ears, my concern sounds the same as Smarty's.)

"Real world" application: My memory may be foggier than I thought, but in my "9 to 5," when I define a constant in PHP, it doesn't get color-coded in other PHP files, even though these other scripts and subscripts obviously use said constants.

--

why even have structures? game maker has object oriented programming. just use instances of objects to store data. they are perfect for storing data in variables, and storing build in functions in events.


The disadvantages have already been lain out. I'll let them stand for me.

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;
structures. objects. same [PKB snip] thing.
look, it's even less typing.
clubs=0
hearts=1
spades=2
diamonds=3

MyArray[0]=instance_create(0,0,undoSlot)
MyArray[0].rank=1
MyArray[0].suit=clubs
MyArray[0].stack=3
MyArray[0].active=1

Oh my. I believe your example just sold me on structures more than anyone else's. My mind said, "You mean, I can

define a few lines of text for a structure

instead of

designing an entire object (with all its built-in overhead of variables, events, etc.) and strategically placing one or more instances of it into whichever appropriate rooms, taking care to account for order-of-instance-creation to prevent uninitialized errors,

and use the same easy code?" Yes. I believe I'll take

// initialize somewhere
struct undo_slot {
  rank,
  suit,
  stack,
  active
};
card_slot[0] = struct_create(undo_slot);

card_slot[0].rank = 1;
card_slot[0].suit = CLUBS;
card_slot[0].stack = 3;
card_slot[0].active = true;

over

// SET UP AN ENTIRE o_ctrl_card_slot OBJECT
solid = false;
visible = false;
// ETC.
// ETC.
// YET ANOTHER OBJECT IN MY TREE IN THE o_ctrl FOLDER, IF NOT WITH MORE SUBFOLDER-ING
/* FEEL TERRIBLE KNOWING I'M WASTING *SO* MANY VARIABLES AND EVENTS AND SO FORTH
   ON SOMETHING THAT'S REALLY NOT MUCH MORE THAN A FANCIFIED ARRAY               */
card_slot[0] = instance_create(0,0,undo_slot);

card_slot[0].rank = 1;
card_slot[0].suit = CLUBS;
card_slot[0].stack = 3;
card_slot[0].active = true;

any day.

And on another quickie note, Mr. slayer, it wasn't eternally condemned. There's no need to curse it. $:^ J

--

On Dannyboy's "Silent scope-related errors" issue and LSnK's response: ~nodnod~ I could see this remedied a lot even if only the temporary var scope got a different highlight (from the point it's defined, downward). That'd be convenient and nifty.

--

An additional note to Mike, syntax and scope:

struct card_type {
  suit,
  face
}

...looks more-or-less fine, but what happens when scope gets involved?

var stuff, things;
var struct card_type {
  suit,
  face
}

For consistency with defining other variables' scopes using var or globalvar, what are the advantages and disadvantages to these kinds of syntaxes?

var stuff, card_type, things;

struct card_type {
  suit,
  face
}

// VS.

var stuff, struct card_type, things;

struct card_type {
  suit,
  face
}

// VS.

var stuff, struct card_type {suit,face}, things;
The last seems pretty logical, especially if defining more than one structure...
struct card_type {suit,face}, vehicle_stat {make,model,year,manual,paint,etc};

// SAME CODE, DIFFERENTLY WRITTEN

struct card_type {
  suit,
  face
}, vehicle_stat {
  make,
  model,
  year,
  manual,
  paint,
  etc
}
...which would then lead to the question of scope definitions...
var card_type, vehicle_stat;
struct card_type {}, vehicle_stat {};

// OR

var card_type, vehicle_stat;

struct card_type {
  // ...
}

struct vehicle_stat {
  // ...
}

// OR

var struct card_type {
  // ...
}, vehicle_stat {
  // ...
}

// OR

var struct card_type {
  // ...
}

var struct vehicle_stat {
  // ...
}
...which then leads me to wonder about making it look more GML-syntaxy. For example,
var card_type, vehicle_stat;
card_type = struct_create(suit,face);
vehicle_stat = struct_create(make,model,year,manual,paint,etc);
...or (come to think of it) would using a function limit it to only 16 arguments? (Hmmmmmmmmmm... Perhaps include a couple struct_* functions which only go up to 16 args, whereas the "standard" struct syntax would allow arbitrary? Kind of like how the Execute Script Action only allows 5 arguments, whereas calling my_script() from any Action (such as Execute Code) gives you up to 16. And, kind of like how users have the option to write argument2+argument7 or argument[2]+argument[7].)

Just some thoughts, really...

--

Regards,

Edited by ParodyKnaveBob, 06 February 2011 - 11:26 PM.

  • 0




0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users