예제 #1
0
void PhysicsSystem::update(GameComponents& components, Entities const& entities, float dt) {
    std::vector<Contact> contacts;
    std::vector<StaticContact> static_contacts;
    std::vector<Collider*> colliders(entities.size());
    int collider_index = 0;
    
    float top = 600.0f;
    float bottom = 40.0f;
    
    // find contacts
    for (Entities::const_iterator it0 = entities.begin(); it0 != entities.end(); ++it0) {
        Entity entity0 = *it0;
        Collider* collider0 = &components.get<ColliderComponent>(entity0);
        collider0->touching.clear();
        colliders[collider_index++] = collider0;
        
        static_contacts.push_back({
            top - collider0->position(1) - collider0->radius,
            Mth::make_cvector(0.0f, 1.0f),
            collider0,
            entity0,
            0.0f
        });
        static_contacts.push_back({
            collider0->position(1) - bottom - collider0->radius,
            Mth::make_cvector(0.0f, -1.0f),
            collider0,
            entity0,
            0.0f
        });
        
        Entities::const_iterator it1 = it0; ++it1;
        for (; it1 != entities.end(); ++it1) {
            Entity entity1 = *it1;
            Collider* collider1 = &components.get<ColliderComponent>(entity1);
            
            if ((collider0->group == CG_PB && collider1->group == CG_PB) ||
                (collider0->group == CG_EB && collider1->group == CG_EB) ||
                (collider0->group == CG_PB && collider1->group == CG_EB) ||
                (collider0->group == CG_EB && collider1->group == CG_PB) ||
                (collider0->group == CG_P && collider1->group == CG_PB) ||
                (collider0->group == CG_PB && collider1->group == CG_P) ||
                (collider0->group == CG_E && collider1->group == CG_EB) ||
                (collider0->group == CG_EB && collider1->group == CG_E)) {
                continue;
            }
            
            Mth::CVector<float, 2> d = collider1->position - collider0->position;
            
            Contact c {
                Mth::length(d) - collider0->radius - collider1->radius,
                Mth::normal(d),
                collider0,
                collider1,
                entity0,
                entity1,
                0.0f
            };
            
            contacts.push_back(c);
        }
    }
    
    // solve contacts
    int iterations = 4;
    for (int i = 0; i < iterations; ++i) {
        for (auto& contact : static_contacts) {
            float relative_velocity = Mth::dot(-contact.collider->velocity, contact.normal);
            float remove_impuls = contact.distance / dt + relative_velocity;
            float new_impuls = std::min(contact.impuls + remove_impuls, 0.0f);
            float impuls_change = new_impuls - contact.impuls;
            contact.impuls = new_impuls;
            contact.collider->velocity += contact.normal * impuls_change;
        }
        
        for (auto& contact : contacts) {
            float relative_velocity = Mth::dot(contact.collider1->velocity - contact.collider0->velocity, contact.normal);
            float remove = contact.distance / dt + relative_velocity;
            float remove_impuls = remove / 2.0f;
            float new_impuls = std::min(contact.impuls + remove_impuls, 0.0f);
            float impuls_change = new_impuls - contact.impuls;
            
            contact.impuls = new_impuls;
            contact.collider0->velocity += contact.normal * impuls_change;
            contact.collider1->velocity -= contact.normal * impuls_change;
            
            if (i == iterations-1) {
                if (new_impuls < 0.0f) {
                    contact.collider0->touching.push_back(contact.entity1);
                    contact.collider1->touching.push_back(contact.entity0);
                }
            }
        }
    }
    
    // evaluate simulation
    for (Collider* collider : colliders) {
        collider->position += collider->velocity * dt;
        collider->velocity = Mth::make_cvector(0.0f, 0.0f);
    }
}
예제 #2
0
파일: scene.cpp 프로젝트: Commnets/QGAMES
// ---
void QGAMES::Scene::drawOn (QGAMES::Screen* s, const QGAMES::Position& p)
{
	assert (_activeMap);

	if (!_entitiesPerLayer.empty ())
	{
		// This means, there are entities that has to be drawn in an specific layer.
		// So it starts to iterate over the layers, 
		// drawing them, and the entities (or characters) in each
		// and also keeping control which one are drawn in each layer
		// to avoid they to be drawing on top of all layers.
		// At this point on the code, we don't still know which entities are in each layer
		std::vector <int> ePainted; // The entities that are being painted in its specific layer...
		QGAMES::Layers l = _activeMap -> layers (); // Let's go to iterate per layer...
		for (QGAMES::Layers::const_iterator i = l.begin (); i != l.end (); i++)
		{
			(*i) -> drawOn (s, p); // First of all the layer is drawn..
			QGAMES::EntitiesPerLayer::const_iterator j;
			// Is there something in this specific layer to be drawn?.
			if ((j = _entitiesPerLayer.find ((*i) -> name ())) != _entitiesPerLayer.end ())
			{
				// The list of the entities and characteres to be drawn...
				std::vector <int> es = (*j).second;
				// ...then the entities are drawn (if they have been defined in the layer)
				for (Entities::const_iterator k1 = _entities.begin (); 
					k1 != _entities.end (); k1++)
				{
					bool eFound = false;
					for (std::vector <int>::const_iterator l = es.begin (); 
							l != es.end () && !eFound; l++)
					{
						if ((*k1).second ->id () == (*l))
						{
							eFound = true;
							ePainted.push_back ((*l));
						}
					}

					if (eFound)
						(*k1).second -> drawOn (s); // The entities are drawn where they are...
				}

				// ...and the characters too (if they have been defined in the layer as well)
				for (Entities::const_iterator k2 = _characteres.begin (); 
					k2 != _characteres.end (); k2++)
				{
					bool eFound = false;
					for (std::vector <int>::const_iterator l = es.begin (); 
							l != es.end () && !eFound; l++)
					{
						if ((*k2).second ->id () == (*l))
						{
							eFound = true;
							ePainted.push_back ((*l));
						}
					}

					if (eFound)
						(*k2).second -> drawOn (s); // The entities are drawn where they are...
				}
			}
		}

		// Entities and characteres are put into the same structure
		// ...and ordered to be painted...
		Entities eTP = _entities; 
		eTP.insert (_characteres.begin (), _characteres.end ()); // Add the characters...
		eTP = orderEntitiesToDraw (eTP); // Order the set...
		for (Entities::const_iterator k3 = eTP.begin (); 
			k3 != eTP.end (); k3++)
		{
			bool eFound = false;
			for (std::vector <int>::const_iterator l = ePainted.begin (); 
					l != ePainted.end () && !eFound; l++)
				if ((*k3).second ->id () == (*l))
					eFound = true;
			if (!eFound) // If the entity was not drawn before...
				(*k3).second -> drawOn (s); // Every entity is drawn where it is...
		}
	}
	else
	{
		// This means that there are no specific entities per layer...
		_activeMap -> drawOn (s, p); // It is possible to alter where the map is drawn...
		Entities eTP = _entities;
		eTP.insert (_characteres.begin (), _characteres.end ()); // Add the characters...
		eTP = orderEntitiesToDraw (eTP); // Order everything...
		for (Entities::const_iterator i = eTP.begin (); i != eTP.end (); i++)
			(*i).second -> drawOn (s); // ...but the entities are drawn where they are...
	}
}