[C++]Loading Entity into manager

Started by
6 comments, last by CrazyCdn 13 years, 7 months ago
mkay, so, Im working on an entity manager, where all the different types of entities are loaded from individual folders that contains their images/sounds/and INI configuration files. But when i use my entityManager.Spawn(...) function, the new object is not initialized properly, the Spawn function takes 3 parameters,
a String that is the name of the object you want to create, and x/y values at where you want them to spawn in screen coordinates. My guess is something is going out of scope.
It begins looping through my 'Type' object (which is a vector of entities), which contains a list of all the different type of Entities, when it finds one that's name is the same as the parameters, it sets the Type object its currently on position and sets it to active and other game specific stuff. I then proceed to push the current Type object into another vector called entity_list. this is the actual vector i use to loop through and draw to screen/Update Logic for.

the problem lies here, because when i use the spawn function, the entity_list.size grows, but all the objects' variables are 0, and it has no image.
now the Type vector works fine, i checked it but when its pushed on the other vector I think it goes out of scope, any suggestions on how to fix this?


here is my spawn function
//Spawn an entity at a locationvoid Entity_Factory::Spawn(string name, float sx, float sy){	//Loop through all of the different entity types we have	for(int i = 0; i < Type.size(); i++)	{		//Iff the name of what we want is the same as 		//as the current type, spawn it		if(Type.Get_Name() == name)		{			//set position			Type.SetPosition(sx, sy);			//set state to Active			Type.Set_State(ES_ACTIVE);			float total_cost = 0;			//find its path			Pather.SolvePath(sx, sy, Map.pathEnd.x, Map.pathEnd.y, Type.path, total_cost);			//Assign image damn it			if(Type.img != NULL)			{				Type.SetImage( *Type.img );			}			//Test to see if it worked			/*			cout << Type.Get_Name().c_str() << endl;			cout << Type.Get_State() << endl;			cout << Type.GetPosition().x << ", " << Type.GetPosition().y << endl;			*/					entity_list.push_back(Type);//Testing purposes, All the values are 0 except for Get Name//Which is somehow the name its suppose to be ("chomps")			for(int i = 0; i < entity_list.size(); i++ )			{				cout << entity_list.Get_Name().c_str() << endl;				cout << entity_list.Get_State() << endl;				cout << entity_list.GetPosition().x << ", " << entity_list.GetPosition().y << endl<< endl;			}			//entity_list[0] = Type;			//add to the list			//entity_list.push_back(Type);			cout << entity_list.size() << endl << endl;				break;		}	}}//EoF



And my Entity Managing class

#ifndef _ENTITY_FACTORY_H#define _ENTITY_FACTORY_H#include <SFML/Graphics.hpp>#include <vector>#include "factory.h"#include "entity.h"enum Entity_State{	ES_NONE = 0,	ES_ACTIVE,	ES_DEAD};//All important Entity system Classclass Entity_Factory : public Factory{public:	Entity_Factory();	~Entity_Factory();		//Spawn an entity by its name at a certain location	void Spawn(string, float, float);	//Draw all of the Entities	void Draw();	//Update all entity Logic	void Update_Logic();			std::vector < Entity > Type;private:		bool Load_TypeIntoList( string );	//we have a Type 	//and entity list	//all things of the entity list will basicly be an instance	//of something from the Type list	//tried to use a pointer to a temporary entity	//to push onto the entityList, didn't work either	Entity * tempEntity;//	Entity entity_list[200];	std::vector < Entity > entity_list;};//only use the single instance entityManager, (makes exporting the class to scripts easy)extern Entity_Factory entityManager;#endif


Any help would be MUCH appreciated I've been stuck on this for a while now :/

[Edited by - BlackShark33 on August 27, 2010 10:26:51 AM]
-Jawshttp://uploading.com/files/eff2c24d/TGEpre.zip/
Advertisement
I haven't done any deep analysis of your code, but if I were to postulate as to the root of your problem, I imagine it has to do with copy-construction and destruction of the Entity objects, since you're storing them by value in the vectors. Could you post the code of your Entity class?

Also, [ source ] [ /source ] tags (minus spaces) are your friend, wrap that code up :]
Free speech for the living, dead men tell no tales,Your laughing finger will never point again...Omerta!Sing for me now!
does changing

entity_list.push_back(Type);

to

entity_list.push_back(Entity(&Type));

do anything?
Roger that, lets run like hell!
Quote:Original post by SirLuthor
I haven't done any deep analysis of your code, but if I were to postulate as to the root of your problem, I imagine it has to do with copy-construction and destruction of the Entity objects, since you're storing them by value in the vectors. Could you post the code of your Entity class?

Also, [ source ] [ /source ] tags (minus spaces) are your friend, wrap that code up :]



sure,
entity.h

class Entity :	public Objects{public:	Entity() {}	//copy constructor	Entity(const Entity&);	//Get Entity Properties	bool Get_Config(std::string);		std::string * script_location;		//Path for AI entities to follow	std::vector< void* > path;private:		//damage it can deal	int damage;};



and entity.cpp
#include <iostream>using namespace std;#include "cfg_reader.h"#include "image_manager.h"#include "script_manager.h"#include "app.h"#include "entity.h"//Copy ConstructorEntity::Entity(const Entity &other){	damage = other.damage;	name = other.name;	script_location = other.script_location;	img = other.img;	}//EoF/* Get the Ammo Configuration file and load properties */bool Entity::Get_Config(string resource_dir){		//grab and create the nessisary directories	string image_location = resource_dir + string("image.png");	string cfg_location = resource_dir + string("properties.cfg");	string script_name = App::getInstance().Resources_Dir["scripts"];	//string snd_location = folder_location + string("fire.wav");	cout << "Loading Entity folder: " << resource_dir << endl;	cout << "Config from: " << cfg_location << endl;	cout << "Image from: " << image_location << endl;	//cout << "Gun sound from: " << snd_location << endl;//Now Grab the firing sound for the gun	//if(!Load_Sounds(s_fire, SND_fire, snd_location)) { return false; }//Grab particle Config		cfg_reader cfg(cfg_location, true);//Get all of the properties			name = cfg.Get_Info("info:name", "Default");			damage = cfg.Get_Info("info:damage", 10);			script_name += cfg.Get_Info("info:script_driver", "NULL");		//Animation related information			tile_size.x = cfg.Get_Info("animation:tile_width", 32);			tile_size.y = cfg.Get_Info("animation:tile_height", 32);					this->SetOrigin(this->tile_size.x/2, this->tile_size.y/2);				//cout << "Particle Image from: " << image_location << "\n\n";			//Load Particle Image used for each type			img = gImageManager.getResource( image_location );			if(img == NULL) { return false; }						SetImage( *img );			//Load scripts			script_location = gScriptManager.getResource( script_name );			if(script_location == NULL)			{				cout << "Script Failed to load\n";			}	return true;}//EoF



Also Dave, i tried it but it didn't like converting a pointer to an object

[Edited by - BlackShark33 on August 27, 2010 11:47:30 AM]
-Jawshttp://uploading.com/files/eff2c24d/TGEpre.zip/
Post the code for your Objects class - Entity derives from it, and it seems that quite a few important member variables (specifically img) come from the Objects class. I'm also curious to see where exactly you're loading entity types into your Type list - I assume you're calling that function once for every class that's derived from Entity, right?


Meanwhile, two tips: pass strings as const references by default: spawn(const std::string& name). There's no need for the function to receive a copy of the string, so a reference would be appropriate. But it shouldn't modify the string either, so to guarantee this, it should be marked as const.

Also, since you're mapping names to objects, a dictionary would be a much better data structure choice than a vector. Thus, std::map<std::string, Entity> Type.
Create-ivity - a game development blog Mouseover for more information.
sorry it took me so long to respond, been busy,

warning, the object class is pretty messy at the moment,

//Base Class Objectsclass Objects : public sf::Sprite{	public:			 Objects();			 //Update Tiles for the Object based of 			 //Classes Parameters			 int Tile_Update();			 int Get_State() { return state; }			 void Set_State(int sState) { state = sState; }			 //Velocity Setters n' getters			 sf::Vector2f Get_Velocity() { return velocity; }			 void Set_Velocity(sf::Vector2f new_velocity) { velocity = new_velocity; }			 void Set_Velocity(float x_vel, float y_vel)			 {				 velocity.x = x_vel;				 velocity.y = y_vel;			 }			//Get/Set Name			std::string Get_Name() { return name; }			void Set_Name(std::string new_name) { name = new_name; }			 //Get/Set speed			virtual float Get_Speed() { return speed; }			virtual void Set_Speed(float new_speed) { speed = new_speed; }						//Handle Rotation and Angle of Object			 float Get_Angle() { return angle; }			 void Rotate_Angle( float sAngle )			 {				 Set_Angle(angle += sAngle);			 }			 void  Set_Angle(float sAngle) 			 { 				 angle = sAngle; 				 //Clamp value to the 0 - 360 range				 if(angle > 359) { angle = 0; }				 else if(angle < 0) { angle = 359; }				 SetRotation(angle);			 }			 //Get Counter/Frame			 float Get_Counter() { return counter; }			 int   Get_Frame() { return frame; }				 bool Is_OnScreen();			 //Get/Set's Tile_Size			 sf::Vector2f Get_TileSize() { return tile_size; }			 void Set_TileSize(sf::Vector2f new_size) { tile_size = new_size; }			 void Set_TileSize( int width, int height) 			 {				 tile_size.x = width;				 tile_size.y = height;			 }			 //Get Render Windowz!!!			// static sf::RenderWindow* Get_RenderWindow();			 //static void Set_RenderWindow(sf::RenderWindow& App);			 sf::Vector2f velocity, tile_size;             float speed;			 float max_speed;                      Directions h_direction, v_direction;			 			 //Get object properties from cnfig file			 //Each derived class can implement this on their own			// virtual bool Get_Properties(std::string cfg_loc) = 0;            			 //Must be public or else			 //bullets don't work properly			sf::Image *img;			float angle;	protected:		//Get App reference		//static sf::RenderWindow *p_App;		int state;							 		//sf::Image Image;		//Name of object		std::string name;		//- for animations        int frame;        float counter;				};


Like I said, very icky,
as for were types are loaded,

//Load Types into the List (needed since we inheret from factory)bool Entity_Factory::Load_TypeIntoList(const string& cfg_location){	Type.clear();	//Loop through and load each Type	for(int i = 0; i < List.size(); i++)	{		cout << "Type Name: " << List << "\n\n";					string cfg_loc = cfg_location + List + "/";			//and Configurations			if(! tempEntity->Get_Config(cfg_loc)) 			{				cout << "Entity Type: " << cfg_loc << " failed to load.\n";				return false;			}			//add to type vector			tempEntity->SetImage(*tempEntity->img);			Type[tempEntity->Get_Name()] = tempEntity;			//cout << Type[tempEntity.Get_Name()].Get_Name() << endl;		//	Type.SetImage(*tempEntity->img);	//entity_list.reserve(100);	}	return true;}//EoF


and the Get_Config() Member function is
/* Get the Ammo Configuration file and load properties */bool Entity::Get_Config(string resource_dir){		//grab and create the nessisary directories	string image_location = resource_dir + string("image.png");	string cfg_location = resource_dir + string("properties.cfg");	string script_name = App::getInstance().Resources_Dir["scripts"];	//string snd_location = folder_location + string("fire.wav");	cout << "Loading Entity folder: " << resource_dir << endl;	cout << "Config from: " << cfg_location << endl;	cout << "Image from: " << image_location << endl;	//cout << "Gun sound from: " << snd_location << endl;//Now Grab the firing sound for the gun	//if(!Load_Sounds(s_fire, SND_fire, snd_location)) { return false; }//Grab particle Config		cfg_reader cfg(cfg_location, true);//Get all of the properties			name = cfg.Get_Info("info:name", "Default");			damage = cfg.Get_Info("info:damage", 10);			script_name += cfg.Get_Info("info:script_driver", "NULL");		//Animation related information			tile_size.x = cfg.Get_Info("animation:tile_width", 32);			tile_size.y = cfg.Get_Info("animation:tile_height", 32);							//cout << "Particle Image from: " << image_location << "\n\n";			//Load Particle Image used for each type			img = gImageManager.getResource( image_location );			if(img == NULL) { return false; }						SetImage( *img );			//Load scripts			script_location = gScriptManager.getResource( script_name );			if(script_location == NULL)			{				cout << "Script Failed to load\n";			}	return true;}//EoF


also, I took your advice on using maps' (cant believe I didn't think of this earlier) and changed the spawn function to use it, among other things,


//Spawn an entity at a locationvoid Entity_Factory::Spawn(const string& name, float sx, float sy){	if(Type[name] == NULL)	{		cout << " OH NULL!\n";		}			entity_list.push_back(*Type[name]);		//	entity_list.push_back(Type[name]);			Entity &temp = entity_list.back();			entity_list.back().SetPosition(sx, sy);			//set state to Active			entity_list.back().Set_State( ES_ACTIVE );			entity_list.back().SetImage(*temp.img);			entity_list.back().SetOrigin(temp.tile_size.x/2, temp.tile_size.y/2);			float total_cost = 0;			//find its path			Pather.SolvePath(sx, sy, Map.pathEnd.x, Map.pathEnd.y,  entity_list.back().path, total_cost);		//	cout << entity_list.size() << endl << endl;}//EoF


Now it 'sort' of works, but if I spawn one object, and then another, the first one disappears, ok, so the first one is replaced, that's simple enough to understand, but when i click to spawn more, i can spawn 2 chomp enemies now, and if i try to spawn another, the first 2 disappears, and now i can spawn 3 of them, but on the 4th one, the other three disappear and etc.

i have a little demo of what im talking about here,

www.blackshark.nukelol.com/Citedel/Citadel_pre_003.zip
built with VS2010 so might need the run time libraries

Sorry to kind of just throw this all at you guys, this one is killing me, I thought this would be the easy part of my game to do :/

any help is vastly appreciated!
-Jawshttp://uploading.com/files/eff2c24d/TGEpre.zip/
Still hard to tell without, I guess, seeing more of the code (I couldn't run the game due to missing .dll's). Have you tried debugging, or at the very least, tracing some debug information to a console or log?

I would read up on the Rule of three, and on the differences between 'shallow' and 'deep' copies if I were you. This may not be the source of the problem, but you'll want to understand these things regardless. Personally, I wouldn't store entities by value - each time your std::vector resizes itself, it'll copy it's content around. It tends to make certain things harder to deal with, and if you're not taking the rule of three into account properly, it'll mess things up eventually. I sometimes make the copy-constructor and assignment operators private just to mark objects as non-copyable.


As for your code, there's a couple of questionable things in there. First of all, from the files I've seen, this seems to be a tower defense game, right? If it is, then I wonder why you're building a 'generic' entity system...

Wouldn't it be more practical to just create a Tower, Projectile and Creep class? And perhaps a TowerType, ProjectileType and CreepType class to store type-specific data in? For each type, you would create a *Type instance, set it's values according to it's config file, and for each actual object, you'd create an instance of the right class, and give it a reference/pointer to the appropriate *Type instance. This 'flyweight pattern' nicely separates type and instance data.


As for the Objects class, the name is too generic, but it's functionality seems too specific (velocity, speed?) or misplaced (tiles, name?). Even Entity is still a rather generic name. I'm not sure why this Objects class is even in-between there - are there other classes inheriting from it besides Entity?

I also noticed how this hierarchy inherits from a sprite class. I would argue that not all game objects are necessarily visible, and that some game objects are displayed with multiple sprites, or other kinds of visual effects. Game objects aren't sprites - but they can be visualized towards the player with sprites. I would use composition (sprites as member variables) over inheritance here.


I hope this helps you pinpoint the problem, as well as giving you some food for thought. :)
Create-ivity - a game development blog Mouseover for more information.
I just woke up and did a brief glance at your code (wow is it hard to read), but a few things to test and narrow down.

Can you do
Entity test, copytest;// Populate test here:copytest = test;cout << copytest.Name(); //think it had a Name()?


Now a few general observations:

Why are you doing this?
if(Type[name] == NULL)

If Type is now a map, use the find function. The code will read a lot cleaner. And if Type is a map now (you state it but never post the changed code) the above will likely never hit. If a map doesn't find a member as you're doing above, it automatically adds in a new key value (this case, name).

What is the point of this line, you never use it again:
Entity &temp = entity_list.back();

It's not far below the above line in the spawn function.

Just some ideas.

"Those who would give up essential liberty to purchase a little temporary safety deserve neither liberty nor safety." --Benjamin Franklin

This topic is closed to new replies.

Advertisement