Sign in to follow this  

[C++]Loading Entity into manager

This topic is 2657 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

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 location
void 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[i].Get_Name() == name)
{
//set position
Type[i].SetPosition(sx, sy);
//set state to Active
Type[i].Set_State(ES_ACTIVE);

float total_cost = 0;

//find its path


Pather.SolvePath(sx, sy, Map.pathEnd.x, Map.pathEnd.y, Type[i].path, total_cost);

//Assign image damn it
if(Type[i].img != NULL)
{
Type[i].SetImage( *Type[i].img );
}

//Test to see if it worked
/*
cout << Type[i].Get_Name().c_str() << endl;
cout << Type[i].Get_State() << endl;
cout << Type[i].GetPosition().x << ", " << Type[i].GetPosition().y << endl;
*/



entity_list.push_back(Type[i]);

//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[i].Get_Name().c_str() << endl;
cout << entity_list[i].Get_State() << endl;
cout << entity_list[i].GetPosition().x << ", " << entity_list[i].GetPosition().y << endl<< endl;

}
//entity_list[0] = Type[i];

//add to the list
//entity_list.push_back(Type[i]);
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 Class
class 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]

Share this post


Link to post
Share on other sites
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 :]

Share this post


Link to post
Share on other sites
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 Constructor
Entity::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]

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
sorry it took me so long to respond, been busy,

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



//Base Class Objects
class 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[i] << "\n\n";

string cfg_loc = cfg_location + List[i] + "/";


//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[i].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 location
void 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!

Share this post


Link to post
Share on other sites
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. :)

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites

This topic is 2657 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this