Adventure Game Studio

AGS Support => Beginners' Technical Questions => Topic started by: arj0n on Thu 19/06/2014 16:57:39

Title: [solved] looking for something like a data collection
Post by: arj0n on Thu 19/06/2014 16:57:39
So, this is the situation in short:

I have:
1. a set of sprites in the sprite editor.
2. a random selected sprite (int spritenum) (this happens in the global script, in the always_execute function).
3. a gui that shows the random selected sprite for x seconds.
4. a menu where you can activate/dis-activate categories (about 20)

What I'm looking for is this:
for each category I do know the collection of sprites that does fit within each category.
Now, after a random sprite has been selected, I'd like to check if this specific chosen sprite does exist in each category.

if so (the category does contain this random sprite number): show sprite
if not (the category does not contain this random sprite number): choose another random sprite

So, is there something like a data collection I can create where you can store a bunch of, in this case, numbers and check the random sprite (int spritenum) against such data collection?
Title: Re: looking for something like a data collection
Post by: Joe on Thu 19/06/2014 18:38:44
What about usign arrays?

//10 sprites per category for example
#define MAX_SPRITES_PER_CATEGORY 10
//As far as I know bidimensional arrays ar not implemented in AGS so the best option would be:
int sprites[20*MAX_SPRITES_PER_CATEGORY];

//You would have to fill it manually at some point in the script (game_start maybe).
int category=0;
sprites[category*MAX_SPRITES_PER_CATEGORY]=23;//23 would be the fisrt spriteID in category 0
sprites[category*MAX_SPRITES_PER_CATEGORY+1]=45;//45 would be the 2nd spriteID in category 0
sprites[category*MAX_SPRITES_PER_CATEGORY+2]=63;
//...
category=2;
sprites[category*MAX_SPRITES_PER_CATEGORY]=65;
//...

//and then wherever you want to check if the sprite is in the wanted category:
int i=0;
bool found=false;
while(i<MAX_SPRITES_PER_CATEGORY)
{
    if(sprites[selected_category*MAX_SPRITES_PER_CATEGORY+i]==randomly_chosen_sprite)
        found=true;
    i++;
}
if(found==true)
    your_show_sprite_function();//
else
    choose_another_sprite();//or wherever you have scripted
   



EDIT: I posted a better solution below!!
Title: Re: looking for something like a data collection
Post by: arj0n on Thu 19/06/2014 20:07:06
Thanx Joe! I'll check this out tomorrow.

questions:
Any reason spriteID 23 is written out twice for category 0?

EDIT:
After having a good look at it: this seems to be exactly what I was looking for, thanx again!
Title: Re: looking for something like a data collection
Post by: Joe on Thu 19/06/2014 20:37:15
No problem!

1Q) The reason for having a 'max sprites...' is that it's the easiest way. You can define it as 100 or 1000... On modern PC's you won't ever have memory overflows issues.
2Q) No sorry, just copied the line and forgot to modify it.

Nevertheless, looking at your 1stQ I've thought an easier way where you don't need to define a max_sprites_per_category:


int sprite_category[MAX_AGS_SPRITES];//this array will store the category number instead of the sprite ID
//NOTE: I don't know if MAX_AGS_SPRITES is already defined in AGS

//at game_start
int i=0;
while(i<MAX_AGS_SPRITES)
{
    sprite_category[i]=-1;//Fill the whole array with -1 which will mean null category
    i++;                  //The reason for doing this is that there will surely be some sprite IDs which will not be used for the category purpose
                         
}
//then fill the array manually:
sprite_category[23]=1;//The sprite whose ID is 23 is in category 1;
sprite_category[31]=1;//The sprite whose ID is 31 is in category 1;
sprite_category[11]=2;//The sprite whose ID is 11 is in category 2;
//...

//and then whenever you want to check if the sprite is in the wanted category:
if(sprite_category[randomly_chosen_spriteID]==selected_category)
    your_show_sprite_function();
else
    choose_another_sprite();
   
Title: Re: looking for something like a data collection
Post by: arj0n on Thu 19/06/2014 21:40:06
Looks perfect, thanx.
Title: Re: looking for something like a data collection
Post by: arj0n on Fri 20/06/2014 18:26:26
Drat, can't seem to implement your code.
Would probably need to rewrite the whole part I already have...

So, the whole thing was already working except for 1 thing:
As you can see in Line 80 and 81, I now have to write out an 'if' statement for each available category. (written out to of them now: exterior & nature)
I guess there's a way better way to do such a check for all categories.
The categories are set from line 182. (again, only exterior & nature)

This is what I already have (sorry for the not so well done coding of me...):

Code (ags) Select

// main global script file
bool menu_is_shown; //if menu is shown, stop running the gui with images
int countdown;
int ran; //randomizer
bool playlist_Exterior = true; //for enable/Disable category Exterior (in the menu)
bool playlist_Nature = true; //for enable/Disable category Nature (in the menu)
int prevsprite;int prevsprite;//to store the previous sprite to avoid showing 1 sprite twice

struct Sprite { //struct with arrays as categories for each sprite
  String name;
  bool cat_Nature;
  bool cat_Interior;
  bool cat_Exterior;
  import void Copy(int spriteID);
};
Sprite sprites[14]; //set number of sprites


function repeatedly_execute_always(){
//set Sprite Info
sprites[0].name = "info0";
sprites[1].name = "info1";
sprites[2].name = "info2";
sprites[3].name = "info3";
sprites[4].name = "info4";
sprites[5].name = "info5";
sprites[6].name = "info6";
sprites[7].name = "info7";
sprites[8].name = "info8";
sprites[9].name = "info9";
sprites[10].name = "info10";
sprites[11].name = "info11";
sprites[12].name = "info12";
sprites[13].name = "info13";

//set multiple categories per sprite on/off:
sprites[0].cat_Exterior = true;
sprites[1].cat_Exterior = true;
sprites[2].cat_Exterior = true;
sprites[3].cat_Exterior = false;
sprites[4].cat_Exterior = false;
sprites[5].cat_Exterior = false;
sprites[6].cat_Exterior = true;
sprites[6].cat_Nature = true;
sprites[7].cat_Exterior = true;
sprites[7].cat_Nature = true;
sprites[8].cat_Exterior = true;
sprites[8].cat_Nature = true;
sprites[9].cat_Exterior = true;
sprites[9].cat_Nature = false;
sprites[10].cat_Exterior = false;
sprites[10].cat_Nature = false;
sprites[11].cat_Exterior = false;
sprites[12].cat_Exterior = false;
sprites[13].cat_Exterior = false;

if (countdown > 0)
  {
  countdown--; // decrease countdown by 1 and reloop
  }
else if (menu_is_shown == true) //do nothing when menu is shown and reloop
  {
  //reloop   
  } 
else if (countdown == 0)
  {
    Bblitz.Visible=false;//set gui button invisible
    Lblitznfo.Visible=false;//set gui label invisible
    ran=Random((12)+1); //pick a random sprite
 
    if ((ran < 6) || (ran == prevsprite))//reloop if random selected sprite_id is 5 or lower or current random sprite is same previous random sprite
      {
        //reloop 
      }
    else if (ran >= 6) //random selected sprite_id is 6 or higher, sprite_id 0 to 6 aren't used
      {
        Bblitz.Visible=false;//set gui button invisible 
        int spritenum = (ran);

        if (((sprites[(spritenum)].cat_Exterior==true) && (playlist_Exterior==true)) &&
            ((sprites[(spritenum)].cat_Nature==true) && (playlist_Nature==true)))  //go if sprite cat exterior is true en playlistexterior is choosen in menu
         {
          prevsprite =(ran);
          Bblitz.NormalGraphic=(ran); //set button normalgrahp with random sprite within range
          Bblitz.X = ((1024 - Game.SpriteWidth[ran])/2);//center gui button that shows sprite
          Bblitz.Visible=true; //set gui buttonvisible
          Lblitznfo.Visible=true;//set gui label visible
          Lblitznfo.Text = (sprites[(spritenum)].name); //the sprite information shown on the label on the gui
          countdown=60;//reset countdown (40=1sec)
         }
      }
  }
}

//These are buttons in the menu to set a category on or of:
function Bcatexterior_OnClick(GUIControl *control, MouseButton button)
{
if (Bcatexterior.Text == "exterior is on"){
     Bcatexterior.Text = "exterior is off";
     playlist_Exterior = false;
}
else if (Bcatexterior.Text == "exterior is off"){
     Bcatexterior.Text = "exterior is on";
     playlist_Exterior = true;
}
}

function Bnature_OnClick(GUIControl *control, MouseButton button)
{
if (Bnature.Text == "nature is on"){
     Bnature.Text = "nature is off";
     playlist_Nature = false;
}
else if (Bnature.Text == "nature is off"){
     Bnature.Text = "nature is on";
     playlist_Nature = true;
}
}
Title: Re: looking for something like a data collection
Post by: Joe on Fri 20/06/2014 19:34:37
1st of all. Why initalize sprites in rep_ex func?? I think you should initialize them in game_start function.

I could appreciate that 1 sprite can have several categories and you can also have more than one category selected. Am I wrong?

In that case I wouldn't create several properties for handling categories.
I would do the foloowing:

//Declare each category as binary code. Note they can only be powers of 2
#define NATURE   1 //00000001
#define EXTERIOR 2 //00000010
#define INTERIOR 4 //00000100
#define RELAX    8 //00001000

struct Sprite { //struct with arrays as categories for each sprite
  String name;
  int category;
  import void Copy(int spriteID);
};

//Also define only 1 variable for your playlist_category
int playlist_category;

//then at game _start:
sprites[0].category = EXTERIOR;
sprites[1].category = EXTERIOR;
sprites[2].category = EXTERIOR;
sprites[6].category = EXTERIOR | NATURE;//this will result 00000011 which will mean exterior+nature
sprites[6].category = EXTERIOR | NATURE;
//...

//Whenever you select 1 category:
playlist_category=NATURE|INTERIOR;//Or what ever you have selected

//Whenever you want to compare(your 80 and 81 lines):
if(sprites[spritenum].category & playlist_category) //Note it's only one & and not 2 since it's bitwise operation
                                                    //This condition will return true if any of the sprite categories fits with any of the playlist categories
{
//...your stuff
}


Title: Re: looking for something like a data collection
Post by: arj0n on Fri 20/06/2014 20:46:57
Code (ags) Select
//Whenever you select 1 category:
playlist_category=NATURE|INTERIOR;//Or what ever you have selected


That's for when you click a category button in the menu, I suppose?
If so, I can never know what other categories has been set, so I can't create a combi like NATURE|INTERIOR.

But it wouldn't surprise me if I completely misunderstoot this specific line of code of yours.

In my case multiple categories can be set on or off.

And yes, I complete misplaced parts of the code in rep_exec instead of the game_start function.
That wasn't a smart move indeed.
Title: Re: looking for something like a data collection
Post by: Joe on Fri 20/06/2014 21:16:49
You intrepeted it just right. I'll try to fit that line in your code:


function Bcatexterior_OnClick(GUIControl *control, MouseButton button)
{
  if (Bcatexterior.Text == "exterior is on"){
     Bcatexterior.Text = "exterior is off";
     playlist_category ^= EXTERIOR; //This will toggle EXTERIOR bit ...
  }
  else if (Bcatexterior.Text == "exterior is off"){
     Bcatexterior.Text = "exterior is on";
     playlist_category |= EXTERIOR; //this will add the EXTERIOR bit without modifying other bits so you can have combiantions
  }
}
Title: Re: looking for something like a data collection
Post by: arj0n on Fri 20/06/2014 21:49:26
I think this looks like the solution I was looking for.
But I don't know why line 5 & 9 from your code gives me a parse error:

GlobalScript.asc(635): Error (line 635): PE04: parse error at 'playlist_category'


I'm not really familiar with using operators like XOR this way :(
Title: Re: looking for something like a data collection
Post by: Joe on Fri 20/06/2014 22:08:37
Maybe its not supported in AGS, try this mode:

Code (ags) Select

playlist_category = playlist_category ^ EXTERIOR;

playlist_category = playlist_category | EXTERIOR;


EDIT: If you dont feel good with using this AND, OR, XOR operators and need an explanation of their operating mode please tell, I think I can explain it in detail.
Title: Re: looking for something like a data collection [solved]
Post by: arj0n on Fri 20/06/2014 22:17:21
Yup, you nailed it, much appriciated!!
Title: Re: looking for something like a data collection
Post by: arj0n on Fri 20/06/2014 22:40:44
Quote from: Joe on Fri 20/06/2014 22:08:37
If you dont feel good with using this AND, OR, XOR operators and need an explanation of their operating mode please tell, I think I can explain it in detail.
Yeh, I'm not really familiar with these bitwise operators, so it would be quite helpful for me to see an explanation of their operating mode.
Very kind of you.
Title: Re: looking for something like a data collection
Post by: Gurok on Fri 20/06/2014 23:39:50
Quote from: Joe on Fri 20/06/2014 21:16:49
You intrepeted it just right. I'll try to fit that line in your code:


function Bcatexterior_OnClick(GUIControl *control, MouseButton button)
{
  if (Bcatexterior.Text == "exterior is on"){
     Bcatexterior.Text = "exterior is off";
     playlist_category ^= EXTERIOR; //This will toggle EXTERIOR bit ...
  }
  else if (Bcatexterior.Text == "exterior is off"){
     Bcatexterior.Text = "exterior is on";
     playlist_category |= EXTERIOR; //this will add the EXTERIOR bit without modifying other bits so you can have combiantions
  }
}


Support for yer' new fangled assignment operators is hopefully coming in the next release. For now, yeah, you need to use the long form.
Title: Re: looking for something like a data collection
Post by: Joe on Sat 21/06/2014 01:12:12
Quote from: Gurok on Fri 20/06/2014 23:39:50
Support for yer' new fangled assignment operators is hopefully coming in the next release. For now, yeah, you need to use the long form.
Nice to know.

Quote from: Arj0n on Fri 20/06/2014 22:40:44
Yeh, I'm not really familiar with these bitwise operators, so it would be quite helpful for me to see an explanation of their operating mode.
Very kind of you.

I guess you can understand logic operations, anyway here is a link for reference: http://en.wikibooks.org/wiki/Digital_Circuits/Logic_Operations
Bitwise operations are made bit by bit. If you type:
result=var1|var2;
It will do the OR operation between var1's first bit and var2's first bit and the result will be stored in result's 1st bit and so on with the rest of bits

An example:
00101101 = var1
10101000 = var2
============ OR
10101101 = result

In our case we want to be able to store several categories in 1 variable so if we type:
sprites[10].category = EXTERIOR | NATURE | INTERIOR;

The operation would be the following:

00000010
00000001
00000100
====== OR
00000111

Note im just typing 8 bits but they are actually 32. So you can store your 20 categories.

Also when we are checking if our sprite fits with any of the selected categories:

if(sprites[spritenum].category & playlist_category)

Let's guess spritenum=10 so the category value is 00000111. If the playlist_category value is for example 00001100 (INTERIOR + RELAX) the condition should return true (note any value !=0 is considered as true) since INTERIOR category is selected. The operation would be the following:

00000111
00001100
======= AND
00000100 -------> this is !=0 so it's true as we expected

However if the playlist_category value was 00001000 then the operation should return false:

00000111
00001000
======= AND
00000000 -------> 0 = false since none of the sprite categories fit with the selected categories

The XOR operation used in the selection is for toggling the corresponding bit. Actually you can use the XOR operator in both cases (selection and deselection) since it will always toggle the bit. The only reason I used the OR operator in the selection part was to make sure the bit is set to 1. But I really dont think there would be any problem if you use the XOR operator.

Hope you understand my testament ;)



Title: Re: [solved] looking for something like a data collection
Post by: arj0n on Mon 23/06/2014 14:32:28
Wow, thanx for the comprehensive testament Joe!
I'm gonna have a good read now first :)

EDIT:
While reading it I do remember I've actually already been through this bitwise operations material some years ago for software testing techniques.
But it's good to read such a clear explanation like yours.
I'm gonna save your testament in a text file on my hd now for sure :)