/* orxonox - the future of 3D-vertical-scrollers Copyright (C) 2004 orx This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. ### File Specific: main-programmer: Patrick Boenzli co-programmer: ... */ #define DEBUG_SPECIAL_MODULE DEBUG_MODULE_COLLISION_REACTION #include "cr_object_damage.h" #include "cr_physics_full_walk.h" #include "cr_physics_ground_walk.h" #include "collision.h" #include "collision_event.h" #include "collision_filter.h" #include "collision_tube.h" #include "cr_defs.h" #include "cr_engine.h" #include "debug.h" namespace CoRe { ObjectListDefinition(CREngine); /** * standard constructor */ CREngine::CREngine () : BaseObject() { this->registerObject(this, CREngine::_objectList); this->setName("CREngine"); this->init(); } /** * the singleton reference to this class */ CREngine* CREngine::singletonRef = NULL; /** @brief standard deconstructor */ CREngine::~CREngine () { CREngine::singletonRef = NULL; if( this->collisionsUnused.size() != CR_MAX_COLLISIONS) PRINTF(0)("CollisionReaction Error: Collision cache size missmatch: %i of %i\n", this->collisionsUnused.size(), CR_MAX_COLLISIONS); if( this->collisionEventsUnused.size() != CR_MAX_COLLISION_EVENTS) PRINTF(0)("CollisionReaction Error: CollisionEvent cache size missmatch: %i of %i\n", this->collisionEventsUnused.size(), CR_MAX_COLLISION_EVENTS); this->reset(); CollisionIterator it1 = this->collisionsUnused.begin(); for(; it1 < this->collisionsUnused.end(); it1++) delete *it1; CollisionEventIterator it2 = this->collisionEventsUnused.begin(); for(; it2 < this->collisionEventsUnused.end(); it2++) delete *it2; this->collisionsUnused.clear(); this->collisionEventsUnused.clear(); } /** * inits the CREngine to a working state */ void CREngine::init() { // precaching: // create a list of Collisions and CollisionEvents for fast object recycling purposes for( int i = 0; i < CR_MAX_COLLISIONS; i++) this->collisionsUnused.push_back(new Collision()); for( int i = 0; i < CR_MAX_COLLISION_EVENTS; i++) this->collisionEventsUnused.push_back(new CollisionEvent()); // push the collision reaction object on the list in the right order // physical reactions this->_reactionList[CREngine::CR_PHYSICS_MOMENTUM] = NULL; this->_reactionList[CREngine::CR_PHYSICS_STEP_BACK] = NULL; this->_reactionList[CREngine::CR_PHYSICS_GROUND_WALK] = new CRPhysicsGroundWalk(); this->_reactionList[CREngine::CR_PHYSICS_FULL_WALK] = new CRPhysicsFullWalk(); this->_reactionList[CREngine::CR_PHYSICS_DAMAGE] = NULL; // object based reactions this->_reactionList[CREngine::CR_OBJECT_DAMAGE] = new CRObjectDamage(); this->_reactionList[CREngine::CR_OBJECT_PICKUP] = NULL; // misc reactions this->_reactionList[CREngine::CR_VERTEX_TRAFO] = NULL; this->_reactionList[CREngine::CR_SPECIAL_CALLBACK] = NULL; } /** * @returns an instance to a collision object. instead of creating new object this ones can be resycled */ Collision* CREngine::popCollisionObject() { if( !this->collisionsUnused.empty()) { this->collisionsUsed.push_back(this->collisionsUnused.back()); this->collisionsUnused.pop_back(); return this->collisionsUsed.back(); } else { PRINTF(0)("There is no Collision Object left in the precache table, fatal error will cause segfault, change CR_MAX_COLLISIONS\n"); assert(false); return NULL; } } /** * @return an instanco of a CollisionEvent object. instead of creating a new object this ones can be used and resycled */ CollisionEvent* CREngine::popCollisionEventObject() { if( !this->collisionEventsUnused.empty()) { this->collisionEventsUsed.push_back(this->collisionEventsUnused.back()); this->collisionEventsUnused.pop_back(); return this->collisionEventsUsed.back(); } else { PRINTF(0)("There is no Collision Object left in the precache table, fatal error will cause segfault, change CR_MAX_COLLISION_EVENTS\n"); assert(false); return NULL; } } /** * handles all collisions in registered in this tube */ void CREngine::handleCollisions() { // for all collisions: CollisionIterator ci = CollisionTube::getInstance()->begin(); for(; ci < CollisionTube::getInstance()->end(); ci++) { for( int i = CREngine::CR_PHYSICS_MOMENTUM; i < CREngine::CR_NUMBER; i++) { if( _reactionList[i] == NULL) continue; // PRINTF(0)("CR CHECK: collision between: %s, %s\n", (*ci)->getEntityA()->getClassName().c_str(), (*ci)->getEntityB()->getClassName().c_str()); // check if entity A or B is subscibed for this event bool aReact = (*ci)->getEntityA()->isReactive(*(*ci)->getEntityB(), (CREngine::ReactionType)i); bool bReact = (*ci)->getEntityB()->isReactive(*(*ci)->getEntityA(), (CREngine::ReactionType)i); // store this information (*ci)->setEntityACollide(aReact); (*ci)->setEntityBCollide(bReact); // and execute the reaction if( aReact || bReact) { this->_reactionList[i]->reactToCollision(*ci); //PRINTF(0)("executing reaction: %s, between %s - %s\n", this->_reactionList[i]->getClassName().c_str(), (*ci)->getEntityA()->getClassName().c_str(), (*ci)->getEntityB()->getClassName().c_str()); } } (*ci)->reset(); } this->reset(); } /** * flushes all the collision lists and puts them to their initial state */ void CREngine::reset() { CollisionIterator it1 = this->collisionsUsed.begin(); for(; it1 < this->collisionsUsed.end(); it1++) this->collisionsUnused.push_back(*it1); CollisionEventIterator it2 = this->collisionEventsUsed.begin(); for(; it2 < this->collisionEventsUsed.end(); it2++) this->collisionEventsUnused.push_back(*it2); this->collisionsUsed.clear(); this->collisionEventsUsed.clear(); CollisionTube::getInstance()->reset(); } void CREngine::debug() { } }