Jump to content

  • Log In with Google      Sign In   
  • Create Account

We're offering banner ads on our site from just $5!

1. Details HERE. 2. GDNet+ Subscriptions HERE. 3. Ad upload HERE.


What is your opinion and how would you do a structure that has multyple functionalities


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
11 replies to this topic

#1 BaneTrapper   Members   -  Reputation: 1231

Like
0Likes
Like

Posted 03 May 2014 - 04:20 PM

Hello.

I was thinking how to make a structure know its functionalities in my 2d top down game.

The first thought i had is make bit flags and turn on and off what the structure does:
For example:

enum StructureFunctions{

        SFStorage = 0x01,//Used to drop resources
        SFRest = 0x02,//Used to sleep at night
        SFTownHall = 0x04,//Used to get actions from
        SFBarrack = 0x08,//Used for training/ getting battle/scout/guard actions for day
        SFOnWater = 0x10,//This structure is on water
        SFOnLand = 0x20,//This structure is on land
        SFOperationable = 0x40,//Uses people to operate, instead of automatic
        SFProduces = 0x80,//Produces resources

    };
class Structure
{
public:
       int Functions;
};
 
//Somewhere in cpp
Structure Farm;
Structure FishingDocks;
Structure Church;
Structure Barrack;
 
Farm.Functions = SFProduces | SFOperationable | SFOnLand | SFStorage;
FishingDocks.Functions = SFProduces | SFOperationable | SFOnLand | SFOnWater | SFStorage;
Church.Functions = SFRest | SFOnLand | SFProduces;
Barrack.Functions = SFRest | SFBarrack | SFOnLand;

The big question is:
I require more flag states, and i never worked with them so i got no experience in that field except tutorials and examples i saw.

How do i make specific structures have attributes as such that would be efficient?

I need to be able to make a object of structure and the structure stats with base value "Is on land", then i will add crafting table intro the structure i will turn "Crafting" on for that structure, if i add barrel intro it i will add "Storage"

Then when i require something as

//A unit just finished harvesting wood, find a place to drop resources
for(all structures)
{
    if(Structure.Function has Storage)
        //Check if storage has space left
        //Check if storage can take type the unit is carrying (Barrel, is made for liquid or small type objects as fish, not for wood storage)
}
//A unit has decided to go rest
for(all structures)
{
    if(Structure.Function has Rest)
        //If not occupied
}

Have you done anything like this before? would you be willing to trow some ideas this way?

If you didn't do something like this before? would you be willing to trow some ideas this way.


Current projects:
The Wanderer, 2d turn based rpg style game

www.gamedev.net/topic/641117-check-up-the-wanderer/


Sponsor:

#2 Servant of the Lord   Crossbones+   -  Reputation: 20377

Like
3Likes
Like

Posted 03 May 2014 - 05:05 PM

Slightly non-standard (de-jure), but with most compilers implementing it the same way (de-facto), you could use anonymous structs in a union holding bitfields.

union StructureFlags
{
     uint32_t bits = 0; //Holds all the bits, for when you save/load the game.
     struct
     {
          bool locatedOnWater : 1; //Use only a single bit.
          bool locatedOnLand : 1;
          bool canSleepHere : 1;
          bool canOperate : 1;
          
     };
};

struct Structure
{
     std::string displayName = "Unnamed";
     StructureFlags flags;
     int remainingHealth = 100;

     int numberOfPeopleInside = 0;
     
     int foodProductionPerMinute = 0;
     int ironProductionPerMinute = 0;
     int woodProductionPerMinute = 0;
};

bools normally use more than a single bit, but if you use bit fields, you can compact multiple of them into the same bytes.

You can read more of bit fields here.

 

If you want to continue using enums and bit flags, which is also a great option and more commonly done (and better supported), your function:

if(Structure.Function has Storage)

Goes like this:

if(Structure.Function & SFStorage)

Note that you use a single &, not a double &&.


It's perfectly fine to abbreviate my username to 'Servant' rather than copy+pasting it all the time.
All glory be to the Man at the right hand... On David's throne the King will reign, and the Government will rest upon His shoulders. All the earth will see the salvation of God.
Of Stranger Flames - [indie turn-based rpg set in a para-historical French colony] | Indie RPG development journal

[Fly with me on Twitter] [Google+] [My broken website]

[Need web hosting? I personally like A Small Orange]


#3 BaneTrapper   Members   -  Reputation: 1231

Like
0Likes
Like

Posted 03 May 2014 - 08:34 PM

Slightly non-standard (de-jure), but with most compilers implementing it the same way (de-facto), you could use anonymous structs in a union holding bitfields.

union StructureFlags
{
     uint32_t bits = 0; //Holds all the bits, for when you save/load the game.
     struct
     {
          bool locatedOnWater : 1; //Use only a single bit.
          bool locatedOnLand : 1;
          bool canSleepHere : 1;
          bool canOperate : 1;
          
     };
};

struct Structure
{
     std::string displayName = "Unnamed";
     StructureFlags flags;
     int remainingHealth = 100;

     int numberOfPeopleInside = 0;
     
     int foodProductionPerMinute = 0;
     int ironProductionPerMinute = 0;
     int woodProductionPerMinute = 0;
};

bools normally use more than a single bit, but if you use bit fields, you can compact multiple of them into the same bytes.

You can read more of bit fields here.

 

If you want to continue using enums and bit flags, which is also a great option and more commonly done (and better supported), your function:

if(Structure.Function has Storage)

Goes like this:

if(Structure.Function & SFStorage)

Note that you use a single &, not a double &&.

That is quite useful, i did not even know such a thing existed.

Well this pretty much solves every problem i had cool.png thanks, not the first time you helped big time, i will make sure to get big flashy thank you in my game!


Current projects:
The Wanderer, 2d turn based rpg style game

www.gamedev.net/topic/641117-check-up-the-wanderer/


#4 BaneTrapper   Members   -  Reputation: 1231

Like
0Likes
Like

Posted 04 May 2014 - 05:55 AM

I cant figure out how to use it simple as

//This is the syntax i want to use to set the flags.
objFarm = SFStorage | SFRest;//The objFarm in main will now have these two flags set on
 
enum StructureFunctions

{

    SFStorage = 0x01,//Used to drop resources

    SFRest = 0x02,//Used to sleep at night

    SFTownHall = 0x04,//Used to get actions from

    SFBarrack = 0x08,//Used for training/ getting battle/scout/guard actions for day

    SFOnWater = 0x10,//This structure is on water

    SFOnLand = 0x20,//This structure is on land

    SFOperationable = 0x40,//Uses people to operate, instead of automatic

    SFProduces = 0x80,//Produces resources

};



struct holder

{

    holder();

    bool a : 1;

    bool b : 1;

    bool c : 1;

};

holder::holder()

{

    a = 0;

    b = 0;

    c = 0;

}



int main()

{

    holder objFarm;

    objFarm = SFStorage & SFRest;
//...

}

And a line like this for the operator =

holder operator=(StructureFunctions strucFunc);

dosent allow me to write code like

//Case 1
objFarm = SFStorage & SFRest;

But i can

//Case 2
objFarm = SFStorage;

Which is understandable to me why it does that, but how would i be able to assign the values like in case 1. what do i need to do?


Current projects:
The Wanderer, 2d turn based rpg style game

www.gamedev.net/topic/641117-check-up-the-wanderer/


#5 dr01d3k4   Members   -  Reputation: 427

Like
2Likes
Like

Posted 04 May 2014 - 08:49 AM

I think the problem is because when you try to use a bitwise operator on two enum values, it returns an int. I searched on google and found this stackoverflow post about using bitwise operators with enums. eidolon's solution was to override the operator for your enum, so it'd look like this:

inline StructureFunctions operator|(StructureFunctions a, StructureFunctions b) {
	return static_cast<StructureFunctions>(static_cast<int>(a) | static_cast<int>(b));
}



inline StructureFunctions operator&(StructureFunctions a, StructureFunctions b) {
	return static_cast<StructureFunctions>(static_cast<int>(a) & static_cast<int>(b));
}

Edit: I just realized that using these operators could return a number not defined by a member of the enum. I don't know how enums in C++ work though so I don't know if this is a problem or not. There were some answers on the stack overflow question saying to use int, rather than StructureFunctions as the type of your variables using it.


Edited by dr01d3k4, 04 May 2014 - 08:55 AM.

Falling block colour flood game thing I'm making: http://jsfiddle/dr01d3k4/JHnCV/


#6 Servant of the Lord   Crossbones+   -  Reputation: 20377

Like
5Likes
Like

Posted 04 May 2014 - 11:37 AM

Sorry, I didn't explain fully.
 
Use the | to bitwise 'OR' two flags together.
Use the & to bitwise 'AND' two flags together.
 

This is similar to how || and && work on bools, except it works on a bit level. (bitwise operators)

 

These aren't specifically designed for holding flags - they are used for manipulating bits in bytes and can be used for whatever purpose.

We can manipulate the bits to use the bits as separate flags, which is what we are doing here (and why it's slightly more confusing at first than what should be a simple task - it's a general-purpose tool).

objFarm = SFStorage | SFRest; //Add two flags together.

if(objFarm & SFStorage)
{
   //...The farm has 'SFStorage' on it.
}

objFarm |= SFProduction; //Add another flag into it.

objFarm &= ~(SFProduction); //Remove a flag.
objFarm &= ~(SFProduction|SFStorage); //Remove multiple flags.

objFarm = SFRest; //Remove every flag, and add 'SFRest'.

Note: For this to work, the flags must each have their own bit, and can't overlap with other flags' bits. This means they must have the values 1, 2, 4, 8, 16, 32, etc... (which is why the hexadecimal values you are using go 0x01, 0x02, 0x04, etc...).

 

1 = 00001

2 = 00010

4 = 00100

etc...


Edited by Servant of the Lord, 04 May 2014 - 11:40 AM.

It's perfectly fine to abbreviate my username to 'Servant' rather than copy+pasting it all the time.
All glory be to the Man at the right hand... On David's throne the King will reign, and the Government will rest upon His shoulders. All the earth will see the salvation of God.
Of Stranger Flames - [indie turn-based rpg set in a para-historical French colony] | Indie RPG development journal

[Fly with me on Twitter] [Google+] [My broken website]

[Need web hosting? I personally like A Small Orange]


#7 BeerNutts   Crossbones+   -  Reputation: 2981

Like
1Likes
Like

Posted 05 May 2014 - 12:08 PM

I personally would avoid the bit flags.  Unless you're going to be hurting for space because you have 100,000, or a million objects, then I'd suggest just using something simple, like a set, and I'd suggest you load all these attributes via a data file.

 

For example, you could have a json data file like this:

{"Structures" :
 {
  "Farm" :
   ["Produces", "Operationable", "OnLand", "Storage"],
  "FishingDocks" :
   ["Produces", "Operationable", "OnLand", "OnWater", "Storage"]
 } 
}

 

Then in your code, you can just do this:

 
// load the objects into a simple structure like this
class Structure
{
  public:
    std::string Name;
    std::set<std::string> Attributes;
}
 
std::vector<Structure> Structures;
 
// use a json library, jsoncpp or jansson, to load the structures and attributes
 
// Now just look for each attribute in your list of Structures
for (uint32_t i = 0; i < Structures.size(); ++i) {
  if (structures[i].Attributes.find("Produces") {
    // do producing thing
  }
}
 

 

Of course, all of this looks a lot like a component based entity system.  So, it might be easier to use a library already created to handle this kind of thing for you.  While I have a partially completed library, I think entitiyx looks good.

 

Either way, good luck, and have fun.


My Gamedev Journal: 2D Game Making, the Easy Way

---(Old Blog, still has good info): 2dGameMaking
-----
"No one ever posts on that message board; it's too crowded." - Yoga Berra (sorta)

#8 BaneTrapper   Members   -  Reputation: 1231

Like
1Likes
Like

Posted 05 May 2014 - 12:08 PM

Sorry, I didn't explain fully.
 
Use the | to bitwise 'OR' two flags together.
Use the & to bitwise 'AND' two flags together.
 

This is similar to how || and && work on bools, except it works on a bit level. (bitwise operators)

 

These aren't specifically designed for holding flags - they are used for manipulating bits in bytes and can be used for whatever purpose.

We can manipulate the bits to use the bits as separate flags, which is what we are doing here (and why it's slightly more confusing at first than what should be a simple task - it's a general-purpose tool).

objFarm = SFStorage | SFRest; //Add two flags together.

if(objFarm & SFStorage)
{
   //...The farm has 'SFStorage' on it.
}

objFarm |= SFProduction; //Add another flag into it.

objFarm &= ~(SFProduction); //Remove a flag.
objFarm &= ~(SFProduction|SFStorage); //Remove multiple flags.

objFarm = SFRest; //Remove every flag, and add 'SFRest'.

Note: For this to work, the flags must each have their own bit, and can't overlap with other flags' bits. This means they must have the values 1, 2, 4, 8, 16, 32, etc... (which is why the hexadecimal values you are using go 0x01, 0x02, 0x04, etc...).

 

1 = 00001

2 = 00010

4 = 00100

etc...

For some reason following line was not allowed by the compiler i had error. I hope it was a mistake on my part.

objFarm = SFStorage | SFRest; //Add two flags together.

That is why you see in the following i used ampersand i couldn't get it to compile. I will try to write it again and see what i got.

int main()
{
    holder objFarm;
    objFarm = SFStorage & SFRest;

But all in all, bit fields are great!, i did not know they even existed until this post!
And id really like to control them with enum types.

 

 

 

I personally would avoid the bit flags.  Unless you're going to be hurting for space because you have 100,000, or a million objects, then I'd suggest just using something simple, like a set, and I'd suggest you load all these attributes via a data file.

 

For example, you could have a json data file like this:

 

{"Structures" :
 {
  "Farm" :
   ["Produces", "Operationable", "OnLand", "Storage"],
  "FishingDocks" :
   ["Produces", "Operationable", "OnLand", "OnWater", "Storage"]
 } 
}

 

Then in your code, you can just do this:

 

 
// load the objects into a simple structure like this
class Structure
{
  public:
    std::string Name;
    std::set<std::string> Attributes;
}
 
std::vector<Structure> Structures;
 
// use a json library, jsoncpp or jansson, to load the structures and attributes
 
// Now just look for each attribute in your list of Structures
for (uint32_t i = 0; i < Structures.size(); ++i) {
  if (structures[i].Attributes.find("Produces") {
    // do producing thing
  }
}
 

 

Of course, all of this looks a lot like a component based entity system.  So, it might be easier to use a library already created to handle this kind of thing for you.  While I have a partially completed library, I think entitiyx looks good.

 

Either way, good luck, and have fun.

Those libraries are great, worth bookmarking, thanks.

But the reason i don't load from external file the structures is because they are dynamic, i don' know a farm is farm.

To know if X posses a farm i check if he has Land(Grow crops, trees...) or livestock and a building(with tools inside for cultivating land, livestock inside...).

There fore i decide what a building is depending on what is inside on fly.


Edited by BaneTrapper, 05 May 2014 - 12:16 PM.

Current projects:
The Wanderer, 2d turn based rpg style game

www.gamedev.net/topic/641117-check-up-the-wanderer/


#9 EarthBanana   Members   -  Reputation: 974

Like
2Likes
Like

Posted 05 May 2014 - 12:32 PM

It seems like you are trying to implement a component system - I agree that you don't really need bit fields to do that - why don't you do something like make a base struct called Component (or something similar) and then make all of your other structs inherit from that struct?

 

In your objects you could do something like have a vector of pointers to Component structs.. then you can add and remove components dynamically

 

You could either create virtual serialize and deserialize functions in your base component struct that inheriting structs must define for writing and reading their contents to and from file - or if you make all parts of your struct components constant sized (ie no std::string or pointers or anything like that) you could directly read and write them to file as lump memory blocks ( outFile.write((char*) myComponent, sizeof(MyComponent)) )

 

Just an idea



#10 Lactose!   GDNet+   -  Reputation: 3625

Like
1Likes
Like

Posted 05 May 2014 - 01:00 PM


For some reason following line was not allowed by the compiler i had error. I hope it was a mistake on my part.
objFarm = SFStorage | SFRest; //Add two flags together.
That is why you see in the following i used ampersand i couldn't get it to compile. I will try to write it again and see what i got.

This works if objFarm is an int. I'm not quite sure what you're wanting to achieve with your holder struct, but you add an "int type" field or something, and then do

objFarm.type = SFStorage | SFRest;



#11 BeerNutts   Crossbones+   -  Reputation: 2981

Like
2Likes
Like

Posted 05 May 2014 - 01:16 PM


But the reason i don't load from external file the structures is because they are dynamic, i don' know a farm is farm.
To know if X posses a farm i check if he has Land(Grow crops, trees...) or livestock and a building(with tools inside for cultivating land, livestock inside...).
There fore i decide what a building is depending on what is inside on fly.

 

OK, I understand.  You really should look at component based systems.  That's what you have here.

 

Instead of manually checking

if (Entity.Has(SomeComponent)) DoThis()

you should have it done manually, meaning, you have a system that is automatically executed when an entity has specific components.

 

Good luck.


My Gamedev Journal: 2D Game Making, the Easy Way

---(Old Blog, still has good info): 2dGameMaking
-----
"No one ever posts on that message board; it's too crowded." - Yoga Berra (sorta)

#12 Servant of the Lord   Crossbones+   -  Reputation: 20377

Like
6Likes
Like

Posted 05 May 2014 - 01:58 PM

Here is a compilable C++ example using bitflags:

#include <iostream>
using namespace std;

namespace SF
{
	enum Enums {None, CanStore = 1, CanRest = 2, CanTrain = 4, OnWater = 8, OnLand = 16, CanProduce = 32, CanOperate = 64, OnWaterAndLand = OnWater|OnLand};
}

typedef unsigned int StructFlags;

int main()
{
	StructFlags structureFlags = SF::None;
	
	structureFlags |= SF::CanStore;
	
	structureFlags |= (SF::CanOperate | SF::CanProduce);
	
	structureFlags |= SF::OnWaterAndLand;
	
	if(structureFlags & SF::CanStore)
		std::cout << "This building can store stuff." << std::endl;
		
	if(structureFlags & SF::CanOperate)
		std::cout << "This building requires people to operate it." << std::endl;
	
	//  |--- Notice the '!' to negate the result.
	//  v
	if( !(structureFlags & SF::CanTrain))
		std::cout << "This building can NOT train people." << std::endl;
	
	if(structureFlags & SF::OnWaterAndLand)
	{
		std::cout << "This building is on both water and land." << std::endl;
	}
	else if(structureFlags & SF::OnWater)
	{
		std::cout << "This building is only on water." << std::endl;
	}
	else if(structureFlags & SF::OnLand)
	{
		std::cout << "This building is only on land." << std::endl;
	}
	else
	{
		std::cout << "This building is not on water or land." << std::endl;
	}
	
	return 0;
}

[Execute it and play around with it] - ideone.com
 
 
I wouldn't use component-based design for this situation. Just because objects have components, that doesn't mean they need to be built out of components.
Component-based design (also called ECS - entity component systems) is useful for many games, but in this situation he's asking for flags to branch his logic. Most ECS architectures are designed for graphics components, physic components, logic components, and so on. What's he's doing is dozens of Logic component, Logic component, Logic component, Logic component. That makes it closer to a finite-state machine that a component-based architecture. wink.png 
 
It's not the correct fit in my opinion, and if he looked into component based design, it'd lead him on a wild goose chase to implement or learn how to use something that solves a problem he's not currently having. mellow.png 
 
Example: ALL his structures will have appearances. ALL his structures will have locations on the map. There's no need for components in this situation. It's not different pieces of the engine being composed together. Just because it's composable at runtime doesn't mean we need to make it into components.

 
ECS architectures are really cool and I'm really excited about them. tongue.png I personally feel that they'll stick around as one of our most-used architectures, at least where games are concerned - but they shouldn't be applied everywhere.
 
In this case, I think the OP was actually correct that this best fits the idea of flags. Whether those flags are implemented using bools, std::set<std::string>, std::bitsets, bitflag enums, or any of another implementation, it doesn't particularly matter.
 
If we take the OP's structure:

        SFStorage = 0x01,//Used to drop resources
        SFRest = 0x02,//Used to sleep at night
        SFTownHall = 0x04,//Used to get actions from
        SFBarrack = 0x08,//Used for training/ getting battle/scout/guard actions for day
        SFOnWater = 0x10,//This structure is on water
        SFOnLand = 0x20,//This structure is on land
        SFOperationable = 0x40,//Uses people to operate, instead of automatic
        SFProduces = 0x80,//Produces resources

 
What we actually see is that the flags are all logic-based, and fit into several categories:

[where they can be located] (SFOnLand, SFOnWater)

[what they can do] (SFStorage, SFRest, SFBarrack, SFTownhall(?))

[whether they produce or not] (SFProduces)

[what they require] (SFOperationable)

 

I feel the simplest way to describe the structures would be to design the class around those categories:

//If using C++11, this should be an 'enum class'
namespace GroundType
{
	//Since there are only three states, I wouldn't use bitflags here.
	enum Enum {Water, Land, WaterAndLand};
}

//Even if using C++11, this *shouldn't* be an 'enum class'.
namespace Action
{
	//I'm using bitflags here, plain ol' bools would also work just fine.
	enum Enum {None, CanStore, CanRest, CanTrain, CanShelterInside};
};
typedef unsigned int Actions;

struct Stats
{
	int currentHealth;
	int maxHealth;
	
	int defense;
	int rangedDefense;
};

struct Production
{
	int actionPoints; //For town-halls, for example.
	int iron;
	int copper;
	int food;
	int wood;
	//...etc...
};

struct Structure
{
	std::string name; //For example, "Town hall".
	std::string description; //"The place where villagers come to hang out after a hard day's work."
	
	Stats stats;
	GroundType groundType; //The type of ground the structure can exist on.
	
	//Per turn, or per minute, or whatever. Non-producing structures just produce '0'. No flag needed.
	Production production;
	
	//No flags needed for operation.
	int numPeopleOperating;
	int minPeopleRequiredToOperate;
	
	//The actions the player can use this building for.
	Actions actions;
};

Edited by Servant of the Lord, 05 May 2014 - 09:47 PM.

It's perfectly fine to abbreviate my username to 'Servant' rather than copy+pasting it all the time.
All glory be to the Man at the right hand... On David's throne the King will reign, and the Government will rest upon His shoulders. All the earth will see the salvation of God.
Of Stranger Flames - [indie turn-based rpg set in a para-historical French colony] | Indie RPG development journal

[Fly with me on Twitter] [Google+] [My broken website]

[Need web hosting? I personally like A Small Orange]





Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS