I actually found a pretty good website recently that helped me.
http://afloatingpoint.blogspot.com/
This lets you test for derivations and whatnot. Personally I would detatch my physics code so that the component is simply a pointer to some data and that the index of that data can easily be indexed.
You could go GameComponent->PhysicsComponent (abstract)->BoxCollider ... etc. Then you just need to go with
Entity->GetComponent<PhysicsComponent>()
to get the collider, or if you want a specific one you can check to see if you have
Entity->GetComponent<BoxCollider>()
Also on your physics code you don't want to recheck specific pairings so your for loop could be different for a nice speed up. Also it is unlikely you want your callbacks to happen RIGHT when the collision happens. Maybe but I'd let my physics code finish up first so you don't destroy the cache and that way if you raycast or whatever all the colliders are resituated where they need to be.
/*
Want a continuous block of colliders for processing.
Makes processing much faster.
*/
vector<AABB> m_aabbColliders;
vector<AABBCollider*> m_aabbComponents;
Queue<Collision> m_collisionQueue;
Collision collision;
//No comparison necessary because when i is zero it evaluates as false
for(auto i = m_aabbColliders.size();i;--i)
{
//No need to check i or greater then i because all collisions
//combinations in that part of the list have been checked.
//Since j will never equal i we can ignore having the if(j == i) clause here.
for(auto j = i - 1;j < 0;--j)
{
//Physics Code
if(Physics::AABBvAABBCollision(m_aabbColliders[i],m_aabbColliders[j],&collision))
{
collision.first = m_aabbComponents[i];
collision.second m_aabbComponents[j];
m_CollisionQueue.push_back(collision);
}
}
}
//Let the physics engine deal with collisions before you take call backs.
//To resituate collided objects.
//Collisions are DONE now deal with callbacks to pass that info to
//Entities that need to know.
Message collisionMessage;
for(auto i = m_collisionQueue.size();i;--i)
{
collisionMessage = Message(m_collisionQueue.pop());
collisionMessage.asCollision().first->SendMessage(MessageType::Collision,collisionMessage);
//Maybe swap first and second here depending on
//if you want your engine to have the collision message
//have first be itself always or something.
collisionMessage.asCollision().second->SendMessage(MessageType::Collision,collisionMessage);
}
//DamageComponent Code
void DamageComponent::RecieveMessage(MessageType type,const Message& msg)
{
switch(type)
{
case MessageType::Collision:
Message dmg = Message(dmg_amount);
msg.asCollision().second->SendMessage(MessageType::DealtDamage,dmg);
break;
}
}
void HealthComponent::RecieveMessage(MessageType type,const Message& msg)
{
switch(type)
{
case MessageType::DealtDamage:
this->ChangeHealth(-msg.asInt());
break;
}
}
void HealthComponent::ChangeHealth(int amount)
{
if(m_health != m_maxHealth && m_health + amount >= m_maxHealth)
{
m_health = m_maxHealth;
SendMessage(MessageType::HealthFilled);
}
else
{
m_health += amount;
if(m_health > m_maxHealth) m_health = m_maxHealth;
}
if(m_health <= 0)
{
Message msg = Message(playerComponent);
SendMessage(MessageType::PlayerDeath,msg);
}
}
//On the Player script you can have it recieve the event then remove itself from queues and setup respawn and all that other stuff.
As you can see this can get really interconnected but still be completely encapsulated in individual components.