structs are like your own defined variable type.
That sounds boring. Let's make it sound half as amazing as it is.
Before we begin: In this, I'll brutally use "." instead of "->". Purists are well in their right to criticise, but I believe learning one new thing in this post is enough for now.
So, you probably noticed something in gamestudio. When you act on entities, with the
me or
you-pointer, then you can suddenly do all KINDS of crazy stuff. Like this:
my.skill1 = 10;
set(my.flag1,TRANSLUCENT);
And that's cool, isn't it? Can't do that with your variable.
var myentitiy;
myentity.skill1 = 10; //NOPE! Won't work.
"Yeah, but", you say, "that's cause it's a
pointer. I know its not the same as a variable, you dummy.
Alright, okay. But you know what's also a pointer? This guy here:
And, guess what, can't do these things on that one:
mybmap.skill1 = 10; //NOPE! That won't work
"Yeah, well...", you now say, perhaps already scratching your head, "'cause that's like, a different... kind of pointer. For a bmap. The other one was for entities."
And now, BAM, you got it.
BMAP and ENTITY are super-different, right? The one thing holds 100 skills, and flags, and got crazy stuff going on, like flags.
The other one doesn't NEED that stuff - instead, it has other stuff.
They are supposed to serve different
purposes, and thats why their
structure differs. Now, I want you to put on your explorer's helmet and open the "atypes.h"-file in your "include"-folder. Then, search for "typedef struct ENTITY". You'll find this
typedef struct ENTITY {
C_LINK link;
char *type; // entity file name
var x,y,z; // position of the entity
var pan,tilt,roll; // euler angles
var scale_x,scale_y,scale_z; // scale factors, 0..255
long flags; // entity flags
var frame; // frame number for sprites & models
var next_frame; // interpolation target frame for models
var skin; // skin texture number for models
var ambient; // -100..+100
var albedo; // 0..100, light reflectivity
var alpha; // 0..100, transparency, default 50
var lightrange; // dynamic light range in quants
var blue,green,red; // dynamic light color, 0..255
long emask; // event enable flags
long eflags; // hull and status flags
var min_x,min_y,min_z;
var max_x,max_y,max_z; // bounding box for entity->entity collisions
var trigger_range;
var push;
var floor_dist; // distance to the floor (if not UNLIT)
long smask; // nosend_... flags
var client_id; // client # that has created this entity
// or view pointer for a layer entity
var skill[100]; // entity skills
var pose; // current bones pose number
MATERIAL* material; // entity material
var u,v; // texture offsets
var group; // collision group
long flags2; // sky flags
char *attachname;
EVENT event; // event function
EVENT local; // client side function
var layer; // layer for 2D entities and skies
long vmask; // mask for suppressing mesh groups
char *string1,*string2; // strings
float fRadius; // visual bounding radius
long path_index; // path of the entity
void* model; // mesh/skin info pointer
struct ENTITY* shadow; // shadow sprite or model
struct ENTITY* parent; // parent entity
BMAP* lightmap; // external lightmap (f.i. for terrains)
void* body; // physX actor
var clipfactor; // visual clipping factor
} ENTITY;
Holy cow! That's a lot of stuff. And all of these, you can access by going
my.<something>
BMAP is comparably simple
typedef struct BMAP {
C_LINK link;
long width,height; // original size of the bitmap
long bytespp; // original bytes per pixel (1..4)
void *ptr; // internal use
byte *pixels; // ptr to palettized, 565, 4444, 888 or 8888 coded original image
long flags; // see BMPF_... above
void *d3dtex; // LPDIRECT3DTEXTURE9 (usually a different format than the original image)
float u1,v1,u2,v2; // texture pixel bounds
long u,v; // cutout start size
long refcount; // for implicitely created bmaps
long finalwidth,finalheight,finalbytespp;
long pitch,finalpitch;
long miplevels;
long finalformat;
void *finalbits; // bitmap content when locked, otherwise NULL
} BMAP;
and that, to, you can use, but you tend to do that indirectly using the bmap_-functions.
Okay, so, here's the point. In your dream game, who knows what you want to have. Mystical armor to find? Space alien species to attack? Strange alcohol to buy? Who's to say. So, in an engine, you'll want FLEXIBILITY. Structs allow you to have all kind of strange things in one neat package, that is easy and simple to access. Once the code is (properly) written, it's easy to ADD things to your package. For instance, if you HAD armor:
typedef struct ARMOR {
var defense;
char element;
} ARMOR;
And you add it to your game
ARMOR* armorlisttofind;
int amountofarmorstofind;
...
armorlisttofind = (ARMOR*) sys_malloc(amountofarmorstofind * sizeof(ARMOR));
Then you don't have to change lots of stuff once you realized you messed up and forgot the most important bit of information of armor.
typedef struct ARMOR {
var defense;
char element;
var howpinkitis; //0: slightly pink, 10:SUPER pink!!
} ARMOR;
The other stuff stays, but now in the rest of the game, you can access that bit of info
void NPCdialog() {
if(playerarmor.howpinkitis>8) {
Textbox("Oh Snap you're awesome!");
} else {
Textbox("Go away you suck");
}
}
structs give you the ability to add your own type of information containers, suited to your needs, and relatively adaptable for changes later down the road. They can be stuffed together in arrays and worked together on groups, which is infinitely better than handling thousands of
"first_armor_defense", "first_armor_howpinkitis", "first_armor_element", "second_armor_defense", "second_armor_howpinkitis", ...
variables. They are great, and should be your friend, and it's an outrage of how easy it is to miss their usefulness and strength at first.
Technically, as far as I understand, they "just" reserve a chunk of memory and the different elements you have in them are stored one after another. But you don't have to worry about that, the engine does that for you. Because it loves you - if you love structs.
If you don't, it's not so into you.