Code Search for Developers
 
 
  

EntityManager.cpp from palisma2d at Krugle


Show EntityManager.cpp syntax highlighted

/**
**************************************************************************************
*Palisma - Secrets of the Illuminati is an open-source 2D RPG                        *
*Copyright (C) 2006, Tony Sparks                                                     *
*                                                                                    *
*This library is free software; you can redistribute it and/or                       *
*modify it under the terms of the GNU Lesser General Public                          *
*License as published by the Free Software Foundation; either                        *
*version 2.1 of the License, or (at your option) any later version.                  *
*                                                                                    *
*This library is distributed in the hope that it will be useful,                     *
*but WITHOUT ANY WARRANTY; without even the implied warranty of                      *
*MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU                   *
*Lesser General Public License for more details.                                     *
*                                                                                    *
*You should have received a copy of the GNU Lesser General Public                    *
*License along with this library; if not, write to the Free Software                 *
*Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA      *
**************************************************************************************
*/
#include "StdAfx.h"
#include "EntityManager.h"


#include "../shared/stringutil.h"
#include "../shared/vector.h"
#include "../shared/QuadTree.h"
#include "../render/viewmanager.h"
#include "../kernel.h"

extern Kernel* g_kernel;


// id counter
unsigned int EntityManager::m_idcounter = 1;
// our singleton
EntityManager* EntityManager::instance = new EntityManager;
/**
====================================
EntityManager
====================================
*/
EntityManager::EntityManager(void)
{
    m_player = NULL;
    m_playerCreated = false;

    // temp
    m_scene = NULL;
    quadTree = NULL;
}

/**
=====================
Create an entity 
=====================
*/
IEntity* EntityManager::CreateEntity( const std::string &entName )
{
    // allocate mem for the new Entity
    IEntity* ent = new IEntity;
    // Set the new ents name
    ent->SetName ( entName );
    // Register it with the manager
    RegisterEntity( ent );
    return ent;
}


/**
=====================
Create the player
Only creates one per game instance
=====================
*/
Player*   EntityManager::CreatePlayer(const std::string &pName)
{
    if ( !m_playerCreated )
    {
        m_player = new Player;
        m_player->SetName( pName );
        // the player has the special id of 0
        m_player->SetID( 0 );
        RegisterEntity( m_player );

        // player has been created
        m_playerCreated = true;
    }
    return m_player;
}

/** Create a weapon */
IWeapon*  EntityManager::CreateWeapon(const std::string &wName )
{
    IWeapon* weapon = new IWeapon;
    weapon->SetName( wName );
    // Register it with the manager
    RegisterEntity( weapon );

    return weapon;
}

/**
============================
Get the player
============================
*/
Player* EntityManager::GetPlayer()
{
    // return the player
    return m_playerCreated ? m_player : NULL;
}


/**
==================================
Update each entity
==================================
*/
void EntityManager::Update(long dt) 
{
    ICamera* cam = g_kernel->GetRenderer()->GetCamera(0);
    
    CleanDeadEntities();
    // current time
    float time = g_kernel->GetTime();
    type_ents::iterator it = entities.begin();
    static bool first = true;
    for(; it != entities.end(); it++)
    {
        IEntity* ent = (*it);
        ent->m_flags &= ~EF_NOTONSCREEN;        // clear flags for this update
        ent->m_flags &= ~EF_UPDATE;


        // make sure the entity is on screen
        if ( !cam->Contains( ent->m_world.x, ent->m_world.y+32 ) && !first ) { //-8,+32
            ent->m_flags |= EF_NOTONSCREEN;
            continue;
        }

        if ( time > ent->m_nextUpdate && m_scene ) // temp scene check!
        {
            ent->m_flags |= EF_UPDATE;
            bool popped = quadTree->Pop( ent );
            ent->Update(dt);
            Move( ent, dt );

            Vector2f v( float(ent->m_world.x - m_scene->GetX()), float(ent->m_world.y - m_scene->GetY()) );
            // update the screen coords and collision box
            ent->UpdateScreenCoord( v );
 
            // update the QuadTree
            if ( popped || first ) 
            {
                quadTree->Put( ent );
            }
        }
    }
    first = false;
    
}

/**
===============================
Move each entity -
TODO apply collision detection
===============================
*/
bool EntityManager::Move(IEntity* ent, long deltaTime)
{
    // entity is not moving
    if ( !ent->m_velocity.Length() )
        return false;

    float dt = deltaTime/1000.0f;

    // apply gravity -- NEEDS SOME WORK
    if ( !ent->ArrivedToLocation() && ent->m_heightAboveGround )
    {   
        ent->m_gravity += (9.8f * dt);
        ent->m_heightAboveGround -= ent->m_gravity*dt;
        if ( ent->m_heightAboveGround <= 0 )
        {
            ent->m_heightAboveGround = 0;
            ent->m_gravity = 0;
        }
    } 
    else
    {
        ent->m_heightAboveGround = 0;
        ent->m_gravity = 0;
        if ( ent->m_flags & EF_MOVED )
        {
            ent->m_velocity.ZeroOut();
            ent->m_flags &= ~EF_MOVED; // we are done moving
            ent->UpdateCollisionBounds( ent->m_world.x, ent->m_world.y );   // dirty hack for throwing things in the portal
            return false;
        }
    }
    // get the amount of pixels to move
    double xmove = (double)ent->m_velocity.x * (double)ent->m_baseVelocity.x * dt;
    double ymove = (double)ent->m_velocity.y * (double)ent->m_baseVelocity.y * dt;

    // apply gravity
    ymove += ent->m_gravity;
    // get the current map
    Scene* scene = m_scene; // use m_scene here since this is temporary!!!

    // check collisions
    MoveX( ent, xmove, ymove, scene );
    MoveY( ent, xmove, ymove, scene );

    // test to see if we hit a trigger
    scene->InvokeTrigger( ent, ent->m_world.x, ent->m_world.y + ent->GetBounds().height/2 );

    // move the camera for the player
    if ( ent->IsPlayer() )
    {
        // get the world camera
        ICamera* cam = g_kernel->GetRenderer()->GetCamera(0);

        // center the camera around the player
        scene->CenterCamera( cam, ent->m_world );
    }
    return true;

}


/** Move X coord of an ent */
void EntityManager::MoveX(IEntity *ent, float xmove, float ymove, Scene* scene)
{
    int xToMove = 0;
    while( xmove )
    {
        // move one pixel
        // and test collision
        if ( xmove > 1 )
        {
            xToMove = 1.0f;
            xmove--;
        } 
        else if ( xmove < -1 )
        {
            xToMove = -1.0f;
            xmove++;
        }
        else
        {
            xToMove = xmove;
            xmove = 0.0f;
        }

        // move ent 1 pixel ahead
        ent->m_world.x += xToMove;

        // check collision
        if ( scene->Collide( ent->m_world.x, ent->m_world.y + ent->GetBounds().height/2, ent->GetBounds() ) ||
             CheckCollision( ent, ent->m_world.x, ent->m_world.y ) )  
        {
            ent->m_world.x -= xToMove;
            ent->UpdateCollisionBounds( ent->m_world.x, ent->m_world.y );
            return;
        }

    }

}

/** Move Y coord of an ent */
void EntityManager::MoveY(IEntity *ent, float xmove, float ymove, Scene* scene)
{
    int yToMove = 0;
    while( ymove )
    {
        // move one pixel
        // and test collision
        if ( ymove > 1 )
        {
            yToMove = 1.0f;
            ymove--;
        } 
        else if ( ymove < -1.0f )
        {
            yToMove = -1.0f;
            ymove++;
        } 
        else
        {
            // we hit 1 pixel
            yToMove = ymove;
            ymove = 0;
        }

        // move ent 1 pixel ahead
        ent->m_world.y += yToMove;

        // check collision
        if ( scene->Collide( ent->m_world.x, ent->m_world.y + ent->GetBounds().height/2, ent->GetBounds() ) ||
             CheckCollision( ent, ent->m_world.x , ent->m_world.y ) )
        {
            ent->m_world.y -= yToMove;
            ent->UpdateCollisionBounds( ent->m_world.x, ent->m_world.y );
            return;
        }

    }
}

/** Find Entity by Name */
IEntity* EntityManager::Find( const std::string &name )
{
    type_ents::iterator it = entities.begin();
    for(; it != entities.end(); it++)
    {
        // we found the entity
        if ( (*it)->GetName() == name )
            return (*it);
    }
    return NULL;
}


/** Find Entity by id */
IEntity* EntityManager::Find( int id )
{
    type_ents::iterator it = entities.begin();
    for(; it != entities.end(); it++)
    {
        // we found the entity
        if ( (*it)->GetID() == id)
            return (*it);
    }
    return NULL;

}

/** Remove the entity without deleting it */
void EntityManager::RemoveWithoutDeleting(IEntity* ent)
{
    type_ents::iterator it = entities.begin();
    for(; it != entities.end(); it++)
    {
        // we found the entity
        if ( (*it) == ent) {
            quadTree->Pop( ent );
            entities.erase( it );
            return;
        }
    }
}

/** Check collision between entities 
 *  O(n) operation - very slow
 */
bool EntityManager::CheckCollision(IEntity* ent, float x, float y)
{
    ent->UpdateCollisionBounds( x, y );
    typedef std::vector< IEntity* > List;
    //typedef std::map<int, IEntity* > List;
    
    List list;
    quadTree->GetObjects( ent->GetBounds(), list );
    List::iterator it = list.begin();

    for (; it != list.end(); ++it )
    {
        IEntity* other = (*it);

        
        // don't collide with yourself
        if ( ent == other ) {
            continue;
        }

        // entity is being erased
        if ( other->CanRemove() )
            continue;

        // if this entity is being carried
        // do not col test
        if ( other->GetState() == "CARRIED" || other->GetState() == "THROWN" || ent->GetState() == "THROWN" )
            continue;

        if ( ent->GetBounds().Intersects( other->GetBounds() ) )
        {
            ent->CollideWith( other );
            other->CollideWith( ent );
            return true;
        }
    }
    return false;
}


/** Prune the entity List */
void EntityManager::CleanDeadEntities()
{
    type_ents::iterator it = entities.begin();
    while( it != entities.end() )
    {
        IEntity* ent = (*it);

        // release any free entities
        if ( ent->CanRemove() )
        {
            g_kernel->GetConsole()->Print(  ("Trying to Delete: " + ent->GetName() ).c_str() );
            g_kernel->GetConsole()->Print(  "Before: %d", quadTree->Size() );
            if ( !quadTree->Pop( ent ) ) 
            {
                g_kernel->GetConsole()->Print(  "Could not Pop the entity, continuing!" );
                continue;
            }
            g_kernel->GetConsole()->Print(  "After: %d", quadTree->Size() );
            // remove its models
            ViewManager::GetInstance()->RemoveView( ent->GetID() );
            // We only delete the first entity that needs to 
            // be removed -- is there a better way, without
            // creating a linklist?
            g_kernel->GetConsole()->Print( "--Deleting from EntityManager:: Releasing %d  bytes", sizeof( (*ent) ) );

            delete ent;
            it = entities.erase( it );
        }
        else
        {
            ++it;
        }
    }
}


/** Find the first entity in a given region 
 *  O(n) operation - very slow
 */
IEntity* EntityManager::FindInRegion( Rect &region, IEntity* ignoreMe )
{
    //type_ents::iterator it = entities.begin();
    //for(; it != entities.end(); it++)
    //{
    //    IEntity* other = (*it);
    //    // ignore this entity (usually the caller entity)
    //    if ( other == ignoreMe )
    //        continue;
    //    // test bounds
    //    if ( other->GetBounds().Intersects( region ) )
    //    {
    //        return other;
    //    }
    //}
    //return NULL;
    if ( quadTree )
    {
        typedef std::vector< IEntity* > List;
        //typedef std::map<int, IEntity* > List;
        
        List list;
        quadTree->GetObjects( region, list );
        List::iterator it = list.begin();
        for (; it != list.end(); ++it )
        {
            g_kernel->GetConsole()->Print( ((*it)->GetName()).c_str() );
            if ( (*it) == ignoreMe )
                continue;
            if ( region.Intersects( (*it)->GetBounds() ) )
                return (*it);
        }
    }
    return NULL;
}

/** HACK--How to register the Map with entities?
    Reference: Currently I register the scene
    when we load a new Scene, look at InGameStateView::LoadScene()
    with the EntityManager, this is horrible and NEEDS fixing.
  */
void    EntityManager::SetScene(Scene* scene) 
{ 
    m_scene = scene; 
    if ( quadTree ) delete quadTree;
    int w = 0, h = 0;
    m_scene->TileToWorld( m_scene->GetMaxX(), m_scene->GetMaxY(), w, h );
    quadTree = new QuadTree<IEntity*>( 16,16, w, h  );
}

/** Register the entity */
void EntityManager::RegisterEntity( IEntity* ent ) { 
    ent->SetID ( m_idcounter++ );
    AddEntity( ent );
};

EntityManager::~EntityManager(void)
{
    // delete this instance
	if ( instance ) {
		delete instance;
		instance = NULL;
	}

    // delete each entity
    type_ents::iterator it = entities.begin();
    for(; it != entities.end(); it++)
    {
        if ( (*it) )
            delete (*it);
    }

    // delete the player
    if ( m_playerCreated )
    {
        if ( m_player )
            delete m_player;
    }

    if ( quadTree ) delete quadTree;

}




See more files for this project here

palisma2d

The University of Wisconsin-Parkside Developers Union first product. More info to come. Code name Palisma.

Project homepage: http://code.google.com/p/palisma2d/
Programming language(s): C,C++
License: gpl2

  DialogModel.cpp
  DialogModel.h
  DialogState.cpp
  DialogState.h
  Enemy.cpp
  Enemy.h
  EntityController.cpp
  EntityController.h
  EntityEvents.cpp
  EntityEvents.h
  EntityFactory.cpp
  EntityFactory.h
  EntityManager.cpp
  EntityManager.h
  EntityStates.cpp
  EntityStates.h
  Event.h
  HUD.cpp
  HUD.h
  IEntity.cpp
  IEntity.h
  IWeapon.cpp
  IWeapon.h
  InGameState.cpp
  InGameState.h
  Inventory.cpp
  Inventory.h
  MissionHolder.cpp
  MissionHolder.h
  Player.cpp
  Player.h
  PlayerConfig.cpp
  PlayerConfig.h
  PlayerController.cpp
  PlayerController.h
  QuestImporter.cpp
  QuestImporter.h
  ReadMe.txt
  Scene.cpp
  Scene.h
  Shotgun.cpp
  Shotgun.h
  State.h
  StateFactory.cpp
  StateFactory.h
  StateMachine.cpp
  StateMachine.h
  Tile.cpp
  Tile.h
  Weather.cpp
  Weather.h
  stdafx.cpp
  stdafx.h