Skip to content

Commit

Permalink
Add Collision system for handling custom events upon collisions.
Browse files Browse the repository at this point in the history
squashed commits:
Implementation of custom collision events. Some questionable design choices within. (Untested)

Updated collision system to new structure. Now uses CollisionHandlerComponent and CollisionSystem. Manifolds used instead of global callback.

Fixed previous compile error - a new one has taken it's place (uintptr_tr not defined)

Basic working state achieved. m_collisionCallbackKey assignment from lua does not seem to take effect.

Also storage and load still needs implementing, and agentabsorber system needs refactoring.

Storage and load implemented.
AgentAbsorber system & component refactored to use this system.
Acceptance tests performed

Collision filters added, not fully functional

Collision functionality nearly updated.
Needs cleanup, testing and integration with agentabsorber.

Working CollisionFilter class.

Attempt at exposing CollisionFilter to lua. Not successful.

Fixes to improve usage of CollisionFilter. Now uses Collision struct instead of typedef to pair of entityIds.
Better model for exposure to lua (still doesn't quite work).
Cleaned up documentation and header includes.

Fixed minor compile error

Collision system finalized.
- Added a member to Collision to represent the duration of collision represented since last clearCollisions().
  This member will allow more fine grained control of collision handling (damage every 0.5 second, etc).
- Cleaned up documentation and debugging code.

Renamed CollisionHandlerComponent to CollisionComponent.
Added removeCollisionGroup to CollisionComponent.
Added constructor taking a collision group to CollisionComponent

Refactoring of CollisionSystem. Stopped using mutable keyword in collision class and instead uses unordered map.
Added a vector<collision*> mirroring the contents of the unordered_map to allow iteration in lua.

Changed to using boost::map_values for iteration.

Rebased onto master.
Fixed setup.lua
Various relevant fixes.
Code is currently not functioning due to strange bug.

Implementation of custom collision events. Some questionable design choices within. (Untested)

Updated collision system to new structure. Now uses CollisionHandlerComponent and CollisionSystem. Manifolds used instead of global callback.

Fixed previous compile error - a new one has taken it's place (uintptr_tr not defined)

Basic working state achieved. m_collisionCallbackKey assignment from lua does not seem to take effect.

Also storage and load still needs implementing, and agentabsorber system needs refactoring.

Fix typo in Lua script

The previous version crashed because the game state passed to
CollisionFilter's constructor was nil in Lua and consequently
nullptr in C++.

Simplify GameState::findSystem

No need for complicated iteration. Also, dynamic_cast can only
throw an exception if a reference type is cast, not for pointer
types.

Refactor signature handling of CollisionFilter

Returning a pair of references is a little tricky because it's
not obvious how the std::pair template will handle it. Returning
a reference to a pair, however, is more predictable.

Use static initializers when possible

Minor refactoring

* Use typedefs (i.e. CollisionFilter::Signature) instead of repeating
the type
* Use emplace when possible, it's more readable than constructing
  the collection item manually
* Rename permutation -> combination

Do not register collision filter in Implementation constructor

At that point, the m_impl field of the CollisionFilter is not
initialized yet (because the Implementation object is not
fully constructed). The CollisionSystem asks the filter for
its signature, which is saved in the m_impl object. Since this
doesn't point to anything useful yet, it crashes.

Added CollisionFilter.init and CollisionFilter.shutdown to allow users to create their CollisionFilters in constructors.
Removed debugging code.

Minor refactorings for CollisionFilter and CollisionSystem

Removed typedefs in collision_filter.cpp.

Removed minor error in rebasing
  • Loading branch information
jjonj committed Nov 19, 2013
1 parent 0f2fc5f commit c4c3169
Show file tree
Hide file tree
Showing 17 changed files with 903 additions and 45 deletions.
11 changes: 9 additions & 2 deletions res/scripts/microbe_stage/microbe.lua
Original file line number Diff line number Diff line change
Expand Up @@ -74,10 +74,15 @@ function Microbe.createMicrobeEntity(name)
rigidBody.properties.linearFactor = Vector3(1, 1, 0)
rigidBody.properties.angularFactor = Vector3(0, 0, 1)
rigidBody.properties:touch()

local reactionHandler = CollisionComponent()
reactionHandler:addCollisionGroup("microbe")

local components = {
AgentAbsorberComponent(),
OgreSceneNodeComponent(),
MicrobeComponent(),
reactionHandler,
rigidBody
}
for _, component in ipairs(components) do
Expand All @@ -93,6 +98,7 @@ Microbe.COMPONENTS = {
microbe = MicrobeComponent.TYPE_ID,
rigidBody = RigidBodyComponent.TYPE_ID,
sceneNode = OgreSceneNodeComponent.TYPE_ID,
collisionHandler = CollisionComponent.TYPE_ID
}


Expand Down Expand Up @@ -391,7 +397,8 @@ function MicrobeSystem:__init()
AgentAbsorberComponent,
MicrobeComponent,
OgreSceneNodeComponent,
RigidBodyComponent
RigidBodyComponent,
CollisionComponent
},
true
)
Expand All @@ -401,7 +408,7 @@ end

function MicrobeSystem:init(gameState)
System.init(self, gameState)
self.entities:init(gameState)
self.entities:init(gameState)
end


Expand Down
8 changes: 6 additions & 2 deletions res/scripts/microbe_stage/setup.lua
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,9 @@ local function setupEmitter()
)
rigidBody.properties:touch()
entity:addComponent(rigidBody)
local reactionHandler = CollisionComponent()
reactionHandler:addCollisionGroup("emitter")
entity:addComponent(reactionHandler)
-- Scene node
local sceneNode = OgreSceneNodeComponent()
sceneNode.meshName = "molecule.mesh"
Expand Down Expand Up @@ -278,6 +281,7 @@ local function createMicrobeStage(name)
UpdatePhysicsSystem(),
RigidBodyOutputSystem(),
BulletToOgreSystem(),
CollisionSystem(),
-- Graphics
OgreAddSceneNodeSystem(),
OgreUpdateSceneNodeSystem(),
Expand All @@ -301,5 +305,5 @@ end

GameState.MICROBE = createMicrobeStage("microbe")
GameState.MICROBE_ALTERNATE = createMicrobeStage("microbe_alternate")

Engine:setCurrentGameState(GameState.MICROBE)
Engine:setCurrentGameState(GameState.MICROBE)
4 changes: 4 additions & 0 deletions src/bullet/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,9 @@ add_sources(
${CMAKE_CURRENT_SOURCE_DIR}/script_bindings.h
${CMAKE_CURRENT_SOURCE_DIR}/update_physics_system.cpp
${CMAKE_CURRENT_SOURCE_DIR}/update_physics_system.h
${CMAKE_CURRENT_SOURCE_DIR}/collision_system.cpp
${CMAKE_CURRENT_SOURCE_DIR}/collision_system.h
${CMAKE_CURRENT_SOURCE_DIR}/collision_filter.cpp
${CMAKE_CURRENT_SOURCE_DIR}/collision_filter.h
)

129 changes: 129 additions & 0 deletions src/bullet/collision_filter.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
#include "collision_filter.h"
#include <luabind/iterator_policy.hpp>
#include "engine/game_state.h"
#include "scripting/luabind.h"



using namespace thrive;

struct CollisionFilter::Implementation {

Implementation(
const std::string& collisionGroup1,
const std::string& collisionGroup2
) : m_signature(collisionGroup1, collisionGroup2)
{
}

CollisionMap m_collisions;

Signature m_signature;

CollisionSystem* m_collisionSystem = nullptr;

};


luabind::scope
CollisionFilter::luaBindings() {
using namespace luabind;
return class_<CollisionFilter>("CollisionFilter")
.def(constructor<const std::string&, const std::string&>())
.def("init", &CollisionFilter::init)
.def("shutdown", &CollisionFilter::shutdown)
.def("collisions", &CollisionFilter::collisions, return_stl_iterator)
.def("clearCollisions", &CollisionFilter::clearCollisions)
;
}


CollisionFilter::CollisionFilter(
const std::string& collisionGroup1,
const std::string& collisionGroup2
) : m_impl(new Implementation(collisionGroup1, collisionGroup2))
{
}

CollisionFilter::~CollisionFilter(){}

void
CollisionFilter::init(
GameState* gameState
) {
m_impl->m_collisionSystem = gameState->findSystem<CollisionSystem>();
m_impl->m_collisionSystem->registerCollisionFilter(*this);
}

void
CollisionFilter::shutdown() {
m_impl->m_collisionSystem->unregisterCollisionFilter(*this);
m_impl->m_collisionSystem = nullptr;
}

const CollisionFilter::CollisionIterator
CollisionFilter::collisions() {
return m_impl->m_collisions | boost::adaptors::map_values;
}


void
CollisionFilter::addCollision(
Collision collision
) {
CollisionMap::iterator foundCollision = m_impl->m_collisions.find(CollisionId(collision.entityId1, collision.entityId2));
if (foundCollision != m_impl->m_collisions.end())
foundCollision->second.addedCollisionDuration += collision.addedCollisionDuration; //Add collision time.
else
{
CollisionId key(collision.entityId1, collision.entityId2);
m_impl->m_collisions.emplace(key, collision);
}

}


typename CollisionFilter::CollisionIterator::iterator
CollisionFilter::begin() const {
return (m_impl->m_collisions | boost::adaptors::map_values).begin();
}


typename CollisionFilter::CollisionIterator::iterator
CollisionFilter::end() const {
return (m_impl->m_collisions | boost::adaptors::map_values).end();
}


void
CollisionFilter::clearCollisions() {
m_impl->m_collisions.clear();
}


const CollisionFilter::Signature&
CollisionFilter::getCollisionSignature() const {
return m_impl->m_signature;
}


size_t
CollisionFilter::IdHash::operator() (
const CollisionId& collisionId
) const {
std::size_t hash1 = std::hash<EntityId>()(collisionId.first);
std::size_t hash2 = std::hash<EntityId>()(collisionId.second);
// Hash needs to be symmetric so that hash(entityId1, entityId2) == hash(entityId2, entityId1)
return hash1 ^ hash2;
}


bool
CollisionFilter::IdEquals::operator() (
const CollisionId& lhs,
const CollisionId& rhs
) const{
// Equality needs to be symmetric for collisions
return (lhs.first == rhs.first && lhs.second == rhs.second) ||
(lhs.first == rhs.second && lhs.second == rhs.first);
}
172 changes: 172 additions & 0 deletions src/bullet/collision_filter.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
#pragma once

#include <boost/range/adaptor/map.hpp>

#include "bullet/collision_system.h"

#include <iostream>
#include <string>

#include <unordered_set>
#include <utility>


namespace luabind {
class scope;
}

namespace thrive {

class Collision;
class CollisionSystem;

/**
* @brief Filters for collisions that contain specific collision groups
*
* Collision filter makes it easy for systems and other peices of code to get easy
* access to the right collisions
*
*/

class CollisionFilter {

public:

using CollisionId = std::pair<EntityId, EntityId>;

using Signature = std::pair<std::string, std::string>;

struct IdHash {
std::size_t
operator() (
const CollisionId& collisionId
) const;
};

struct IdEquals {
bool
operator() (
const CollisionId& lhs,
const CollisionId& rhs
) const;
};

using CollisionMap = std::unordered_map<CollisionId, Collision, IdHash, IdEquals>;
using CollisionIterator = boost::range_detail::select_second_mutable_range<CollisionMap>;

/**
* @brief Constructor
*
* @param collisionGroup1
* The first collision group to monitor
*
* @param collisionGroup2
* The second collision group to monitor
*
*/
CollisionFilter(
const std::string& collisionGroup1,
const std::string& collisionGroup2
);

/**
* @brief Destructor
*/
~CollisionFilter();

/**
* @brief Initialized the collision filter
*
* @param gameState
* The gamestate the filter belongs in.
*/
void
init(
GameState* gameState
);

/**
* @brief Shuts down the filter.
*/
void
shutdown();

/**
* @brief Lua bindings
*
* Exposes the following \b constructors:
* - CollisionFilter(const std::string&, const std::string&)
* - CollisionFilter::init(GameState*)
* - CollisionFilter::shutdown()
* - CollisionFilter::collisions()
* - CollisionFilter::clearCollisions()
*/
static luabind::scope
luaBindings();

/**
* @brief Returns the collisions that has occoured
*
* Is only reset when clearCollisions() is called
*/
const CollisionIterator
collisions();

/**
* @brief Clears the collisions
*/
void
clearCollisions();

/**
* @brief Adds a collision
*
* @param collision
* Collision to add
*/
void
addCollision(Collision collision);

/**
* @brief Iterator
*
* Equivalent to
* \code
* collisions().cbegin()
* \endcode
*
* @return An iterator to the first collision
*/
typename CollisionIterator::iterator
begin() const;

/**
* @brief Iterator
*
* Equivalent to
* \code
* collisions().cend()
* \endcode
*
* @return An iterator to the end of the collisions
*/
typename CollisionIterator::iterator
end() const;

/**
* @brief Returns the signature of the collision filter
*
* @return
* A pair of the two collision group strings.
*/
const Signature&
getCollisionSignature() const;

private:

struct Implementation;
std::unique_ptr<Implementation> m_impl;

};

}
Loading

0 comments on commit c4c3169

Please sign in to comment.