From 94cac38cc6288293ef2c0820ddecf448fa6500ab Mon Sep 17 00:00:00 2001 From: Stiffly Date: Tue, 13 Oct 2015 15:22:11 +0200 Subject: [PATCH] "Lightening" particle bugg fixed. Scale and alpha interpolation implemented through ScalarInterpolation-funtion --- include/Physics/CParticle.h | 4 +- include/Physics/CParticleEmitter.h | 4 + include/Physics/ECreateParticleSequence.h | 5 +- include/Physics/PhysicsSystem.h | 65 +- src/game/Game/LevelSystem.cpp | 10 +- src/game/Physics/PhysicsSystem.cpp | 1528 +++++++++++---------- 6 files changed, 835 insertions(+), 781 deletions(-) diff --git a/include/Physics/CParticle.h b/include/Physics/CParticle.h index faa8267..c0247f1 100755 --- a/include/Physics/CParticle.h +++ b/include/Physics/CParticle.h @@ -33,8 +33,10 @@ namespace Components struct Particle : public Component { + EntityID ParticleSystem; float Radius = 0.5f; - float LifeTime = 5.0f; + double TimeLived = 0; + double LifeTime = 5; ParticleFlags::Type Flags = static_cast( ParticleFlags::Water diff --git a/include/Physics/CParticleEmitter.h b/include/Physics/CParticleEmitter.h index 8b6029f..507114c 100755 --- a/include/Physics/CParticleEmitter.h +++ b/include/Physics/CParticleEmitter.h @@ -22,6 +22,10 @@ struct ParticleEmitter : public Component float Speed = 2.f; double LifeTime = 100; + //values to interpolate between. + std::vector RadiusValues; + std::vector AlphaValues; + //System variables float GravityScale = 1.0f; }; diff --git a/include/Physics/ECreateParticleSequence.h b/include/Physics/ECreateParticleSequence.h index 82731bc..8f27fcb 100644 --- a/include/Physics/ECreateParticleSequence.h +++ b/include/Physics/ECreateParticleSequence.h @@ -24,12 +24,15 @@ struct CreateParticleSequence : public Event float MaxCount = 0; glm::vec4 Color = glm::vec4(0); EntityID parent = 0; + // values to interpolate between. + std::vector RadiusValues; + std::vector AlphaValues; //Particle std::string SpriteFile = ""; double ParticleLifeTime = 3.f; ParticleFlags::Type Flags = static_cast(ParticleFlags::Powder | ParticleFlags::ParticleContactFilter | ParticleFlags::FixtureContactFilter); - float Radius = 1.f; + }; } diff --git a/include/Physics/PhysicsSystem.h b/include/Physics/PhysicsSystem.h index ec5b618..237ebe1 100755 --- a/include/Physics/PhysicsSystem.h +++ b/include/Physics/PhysicsSystem.h @@ -49,7 +49,7 @@ namespace dd class PhysicsSystem : public System { friend class ContractListener; - friend class DestructionListener; + //friend class DestructionListener; public: PhysicsSystem(World* world, std::shared_ptr eventBroker) @@ -107,6 +107,7 @@ namespace dd b2ParticleSystem* CreateParticleSystem(float radius, float gravityScale, int maxCount); void CreateParticleEmitter(EntityID entity); void UpdateParticleEmitters(double dt); //TODO: Remove them and particles if needed. + float ScalarInterpolation(float timeProgress, std::vector spectrum); EventRelay m_SetImpulse; bool SetImpulse(const Events::SetImpulse &event); @@ -131,36 +132,36 @@ namespace dd std::list m_Impulses; - class DestructionListener : public b2DestructionListener - { - public: - DestructionListener(PhysicsSystem* physicsSystem) - : m_PhysicsSystem(physicsSystem) { } - - void SayGoodbye(b2Joint*) {LOG_INFO("joint körs");}; - void SayGoodbye(b2Fixture*) {/*LOG_INFO("Fixture körs");*/}; - - void SayGoodbye(b2ParticleSystem* particleSystem, int32 index) override - { - LOG_INFO("Particle ded"); - - - const b2ParticleHandle* handle = particleSystem->GetParticleHandleFromIndex(index); - for (int i = 0; i < m_PhysicsSystem->m_ParticleEmitters.ParticleSystem.size(); i++) { - if(m_PhysicsSystem->m_ParticleEmitters.ParticleSystem[i] == particleSystem) { - std::unordered_map::iterator it = m_PhysicsSystem->m_ParticleHandleToEntities[i].find(handle); - if(it != m_PhysicsSystem->m_ParticleHandleToEntities[i].end()) { - EntityID id = it->second; - m_PhysicsSystem->m_World->RemoveEntity(id); - m_PhysicsSystem->m_ParticleHandleToEntities[i].erase(it); - LOG_INFO("Removing from list"); - } - } - } - } - private: - PhysicsSystem* m_PhysicsSystem; - }; +// class DestructionListener : public b2DestructionListener +// { +// public: +// DestructionListener(PhysicsSystem* physicsSystem) +// : m_PhysicsSystem(physicsSystem) { } +// +// void SayGoodbye(b2Joint*) {LOG_INFO("joint körs");}; +// void SayGoodbye(b2Fixture*) {/*LOG_INFO("Fixture körs");*/}; +// +// void SayGoodbye(b2ParticleSystem* particleSystem, int32 index) override +// { +// // LOG_INFO("Particle ded"); +// // +// // +// // const b2ParticleHandle* handle = particleSystem->GetParticleHandleFromIndex(index); +// // for (int i = 0; i < m_PhysicsSystem->m_ParticleEmitters.ParticleSystem.size(); i++) { +// // if(m_PhysicsSystem->m_ParticleEmitters.ParticleSystem[i] == particleSystem) { +// // std::unordered_map::iterator it = m_PhysicsSystem->m_ParticleHandleToEntities[i].find(handle); +// // if(it != m_PhysicsSystem->m_ParticleHandleToEntities[i].end()) { +// // EntityID id = it->second; +// // m_PhysicsSystem->m_World->RemoveEntity(id); +// // m_PhysicsSystem->m_ParticleHandleToEntities[i].erase(it); +// // LOG_INFO("Removing from list"); +// // } +// // } +// // } +// } +// private: +// PhysicsSystem* m_PhysicsSystem; +// }; class ParticleContactDisabler : public b2ContactFilter { @@ -198,7 +199,7 @@ namespace dd PhysicsSystem* m_PhysicsSystem; }; - DestructionListener* m_DestructionListener; + //DestructionListener* m_DestructionListener; ParticleContactDisabler* m_ParticleContactDisabler; ContactListener* m_ContactListener; }; diff --git a/src/game/Game/LevelSystem.cpp b/src/game/Game/LevelSystem.cpp index 6a6f1fd..9624d22 100755 --- a/src/game/Game/LevelSystem.cpp +++ b/src/game/Game/LevelSystem.cpp @@ -314,9 +314,12 @@ bool dd::Systems::LevelSystem::OnContact(const dd::Events::Contact &event) ep.EmittingAngle = glm::half_pi(); ep.Spread = 1.5f; ep.Position = transformComponentBrick->Position; - ep.Radius = 0.05; + //ep.Radius = 0.05; ep.SpriteFile = "Textures/Particles/FadeBall.png"; ep.Color = brickModel->Color + glm::vec4(0.3f); + ep.AlphaValues.push_back(1.f); + ep.AlphaValues.push_back(0.f); + ep.RadiusValues.push_back(0.05); ep.Speed = 50; EventBroker->Publish(ep); @@ -369,9 +372,12 @@ bool dd::Systems::LevelSystem::OnContact(const dd::Events::Contact &event) ep.EmittingAngle = glm::half_pi(); ep.Spread = 1.5f; ep.Position = transformComponentBrick->Position; - ep.Radius = 0.05; + //ep.Radius = 0.05; ep.SpriteFile = "Textures/Particles/FadeBall.png"; ep.Color = brickModel->Color + glm::vec4(0.3f); + ep.AlphaValues.push_back(1.f); + ep.AlphaValues.push_back(0.f); + ep.RadiusValues.push_back(0.05f); ep.Speed = 50; EventBroker->Publish(ep); diff --git a/src/game/Physics/PhysicsSystem.cpp b/src/game/Physics/PhysicsSystem.cpp index 94778d1..6eaa68a 100755 --- a/src/game/Physics/PhysicsSystem.cpp +++ b/src/game/Physics/PhysicsSystem.cpp @@ -1,745 +1,783 @@ -#include "PrecompiledHeader.h" -#include "Physics/PhysicsSystem.h" - - -void dd::Systems::PhysicsSystem::RegisterComponents(ComponentFactory* cf) -{ - cf->Register(); - //TODO: REGISTER PHYSICS COMPONENTS HERE -} - -void dd::Systems::PhysicsSystem::Initialize() -{ - std::random_device rd; - gen = std::mt19937(rd()); - m_DestructionListener = new DestructionListener(this); - m_ContactListener = new ContactListener(this); - m_PhysicsWorld = new b2World(m_Gravity); - m_ParticleContactDisabler = new ParticleContactDisabler(); - m_PhysicsWorld->SetContactListener(m_ContactListener); - m_PhysicsWorld->SetContactFilter(m_ParticleContactDisabler); - m_PhysicsWorld->SetDestructionListener(m_DestructionListener); - - InitializeWater(); - EVENT_SUBSCRIBE_MEMBER(m_SetImpulse, &PhysicsSystem::SetImpulse); - EVENT_SUBSCRIBE_MEMBER(m_EPause, &PhysicsSystem::OnPause); - EVENT_SUBSCRIBE_MEMBER(m_EStageCleared, &PhysicsSystem::OnStageCleared); - EVENT_SUBSCRIBE_MEMBER(m_ECreateParticleSequence, &PhysicsSystem::CreateParticleSequence); - EVENT_SUBSCRIBE_MEMBER(m_EContact, &PhysicsSystem::OnContact); -} - -void dd::Systems::PhysicsSystem::InitializeWater() -{ - float radius = 0.13f; - float gravityScale = 1.0f; - - b2ParticleSystemDef m_ParticleSystemDef; - m_ParticleSystemDef.radius = radius; - m_ParticleSystemDef.gravityScale = gravityScale; - m_ParticleSystemDef.density = 4.f; - - m_WaterParticleSystem = m_PhysicsWorld->CreateParticleSystem(&m_ParticleSystemDef); -} - -bool dd::Systems::PhysicsSystem::SetImpulse(const Events::SetImpulse &event) -{ - auto it = m_EntitiesToBodies.find(event.Entity); - if(it == m_EntitiesToBodies.end()) { - LOG_ERROR("Entity: %i, Tried to set an impulse on a body that does not exsist", event.Entity); - return false; - } - - b2Vec2 impulse; - impulse.x = event.Impulse.x; - impulse.y = event.Impulse.y; - - b2Vec2 point; - point.x = event.Point.x; - point.y = event.Point.y; - - Impulse i; - i.Body = it->second; - i.Vector = impulse; - i.Point = point; - - m_Impulses.push_back(i); - return true; -} - -void dd::Systems::PhysicsSystem::SyncEntitiesWithBodies() -{ - - for (auto i : m_EntitiesToBodies) { - EntityID entity = i.first; - b2Body* body = i.second; - - if (body == nullptr) { - LOG_ERROR("This body should not exist, please fix this"); - continue; - } - - auto transformComponent = m_World->GetComponent(entity); - if (! transformComponent) { - continue; - LOG_ERROR("RigidBody with no TransformComponent"); - } - - auto physicsComponent = m_World->GetComponent(entity); - if (! physicsComponent) { - continue; - LOG_ERROR("RigidBody with no PhysicsComponent"); - } - - - - if (m_World->GetEntityParent(entity) == 0) { //TODO: Make this work with childs too - b2Vec2 position; - position.x = transformComponent->Position.x; - position.y = transformComponent->Position.y; - float angle = glm::eulerAngles(transformComponent->Orientation).z; - body->SetTransform(position, angle); - body->SetLinearVelocity(b2Vec2(transformComponent->Velocity.x, transformComponent->Velocity.y)); - body->SetGravityScale(physicsComponent->GravityScale); - - b2Filter filter; - filter.categoryBits = physicsComponent->Category; - filter.maskBits = physicsComponent->Mask; - body->GetFixtureList()->SetFilterData(filter); - - if (physicsComponent->CollisionType == CollisionType::Type::Static) { - body->SetType(b2_staticBody); - } - else if (physicsComponent->CollisionType == CollisionType::Type::Dynamic) { - body->SetType(b2_dynamicBody); - } - else if (physicsComponent->CollisionType == CollisionType::Type::Kinematic) { - body->SetType(b2_dynamicBody); - } - } - } -} - -void dd::Systems::PhysicsSystem::SyncBodiesWithEntities() -{ - for (auto i : m_BodiesToEntities) { - b2Body* body = i.first; - EntityID entity = i.second; - - if (body == nullptr) { - LOG_ERROR("This body should not exist, please fix this"); - continue; - } - - auto transformComponent = m_World->GetComponent(entity); - if (! transformComponent) { - continue; - LOG_ERROR("RigidBody with no TransformComponent"); - } - - auto physicsComponent = m_World->GetComponent(entity); - if (! physicsComponent) { - continue; - LOG_ERROR("RigidBody with no PhysicsComponent"); - } - - auto parent = m_World->GetEntityParent(entity); - if (parent == 0) { - auto physicsComponent = m_World->GetComponent(entity); - - if (physicsComponent->Calculate) { //TODO: REPLACE THIS WITH PARTICLE COLLISION FILTERS - transformComponent->Position.x = transformComponent->Position.x + (transformComponent->Velocity.x * m_TimeStep); - transformComponent->Position.y = transformComponent->Position.y + (transformComponent->Velocity.y * m_TimeStep); - } else { - b2Vec2 position = body->GetPosition(); - transformComponent->Position.x = position.x; - transformComponent->Position.y = position.y; - - float angle = body->GetAngle(); - transformComponent->Orientation = glm::quat(glm::vec3(0, 0, angle)); - - b2Vec2 velocity = body->GetLinearVelocity(); - transformComponent->Velocity.x = velocity.x; - transformComponent->Velocity.y = velocity.y; - } - } - } -} - -void dd::Systems::PhysicsSystem::Update(double dt) -{ - if (m_Pause) { - return; - } - - if (m_Travelling) { - if (m_DistanceTravelled > 12.f) { - m_DistanceTravelled = 0; - m_Travelling = false; - } - - m_DistanceTravelled += 6.0f * dt; - } - m_Accumulator += dt; - - while(m_Accumulator >= m_TimeStep) - { - - UpdateParticleEmitters(dt); - SyncEntitiesWithBodies(); - - //Apply Impulses Must be done after SyncEntitiesWithBodies - for (auto i : m_Impulses) { - i.Body->ApplyLinearImpulse(i.Vector, i.Point, true); - } - m_Impulses.clear(); - - - //Update the PhysicsWorld - m_PhysicsWorld->Step(m_TimeStep, m_VelocityIterations, m_PositionIterations); - - SyncBodiesWithEntities(); - - - //water - b2Vec2 *positionBuffer = m_WaterParticleSystem->GetPositionBuffer(); - for (auto i : m_EntitiesToWaterParticleHandle){ - EntityID entity = i.first; - const b2ParticleHandle *particleH = i.second; - - - b2Vec2 positionB2 = positionBuffer[particleH->GetIndex()]; - glm::vec2 position = glm::vec2(positionB2.x, positionB2.y); - - EntityID entityParent = m_World->GetEntityParent(entity); - glm::vec3 parentTransform = glm::vec3(0.f); - if(entityParent) { - auto tp = m_World->GetComponent(entityParent); - parentTransform = tp->Position; - } - auto transform = m_World->GetComponent(entity); - - transform->Position = glm::vec3(position.x - parentTransform.x, position.y - parentTransform.y, 0); - } - - //Normal particles - for ( int e = 0; e < m_EntitiesToParticleHandle.size(); e++) { - b2Vec2 *positionBuffer = m_ParticleEmitters.ParticleSystem[e]->GetPositionBuffer(); - if(!positionBuffer) { - break; - } - for (auto i : m_EntitiesToParticleHandle[e]){ - EntityID entity = i.first; - const b2ParticleHandle *particleH = i.second; - - b2Vec2 positionB2 = positionBuffer[particleH->GetIndex()]; - glm::vec2 position = glm::vec2(positionB2.x, positionB2.y); - - EntityID entityParent = m_World->GetEntityParent(entity); - glm::vec3 parentTransform = glm::vec3(0.f); - if(entityParent) { - auto tp = m_World->GetComponent(entityParent); - parentTransform = tp->Position; - } - auto transform = m_World->GetComponent(entity); - - transform->Position = glm::vec3(position.x, position.y, transform->Position.z); - } - } - - m_Accumulator -= dt; - } -} - -void dd::Systems::PhysicsSystem::UpdateEntity(double dt, EntityID entity, EntityID parent) -{ - if (m_Travelling) { - auto transform = m_World->GetComponent(entity); - if (transform != nullptr) { - if (!transform->Sticky) { - transform->Position.y -= 6.0f * dt; - } - } else { - transform->Position.y -= 6.0f * dt; - } - } - auto particle = m_World->GetComponent(entity); - auto pTemplate = m_World->GetComponent(entity); - - - - if (particle && !pTemplate) { - particle->LifeTime -= dt; - if (particle->LifeTime <= 0) { - for (int i = 0; i < m_EntitiesToParticleHandle.size(); i++) { - const b2ParticleHandle* handle = m_EntitiesToParticleHandle[i][entity]; - std::unordered_map::iterator iter1; - std::unordered_map::iterator iter2; - iter1 = m_EntitiesToParticleHandle[i].find(entity); - iter2 = m_ParticleHandleToEntities[i].find(handle); - if (iter1 != m_EntitiesToParticleHandle[i].end()) { - m_EntitiesToParticleHandle[i].erase(iter1); - } - if (iter2 != m_ParticleHandleToEntities[i].end()) { - m_ParticleHandleToEntities[i].erase(iter2); - } - m_World->RemoveEntity(entity); - } - } - auto sprite = m_World->GetComponent(entity); - sprite->Color.w = particle->LifeTime; - } - - auto emitter = m_World->GetComponent(entity); - if (emitter) { - EntityID emitterParent = emitter->Parent; - if (emitterParent != 0) { - auto emitterTransform = m_World->GetComponent(entity); - auto parentTransform = m_World->GetComponent(emitterParent); - if (emitterTransform && parentTransform) { - emitterTransform->Position = parentTransform->Position; - } - } - } -} - -bool dd::Systems::PhysicsSystem::OnPause(const dd::Events::Pause &event) -{ - if (event.Type != "PhysicsSystem" && event.Type != "All") { - return false; - } - - if (m_Pause) { - m_Pause = false; - } else { - m_Pause = true; - } - return true; -} - -void dd::Systems::PhysicsSystem::OnEntityCommit(EntityID entity) -{ - auto physicsComponent = m_World->GetComponent(entity); - auto waterComponent = m_World->GetComponent(entity); - auto particleEmitterComponent = m_World->GetComponent(entity); - - if (physicsComponent && waterComponent) { - LOG_ERROR("Entity has both water and physics component, this is illegal. The police has been alerted."); - return; - } - if (physicsComponent && particleEmitterComponent) { - LOG_ERROR("Entity has both particle and physics component, this is illegal. The police has been alerted."); - return; - } - - if (physicsComponent) { - auto it = m_EntitiesToBodies.find(entity); - if(it == m_EntitiesToBodies.end()) { - CreateBody(entity); - } else { - LOG_ERROR("Tried to commit a body that already exists"); - } - } else if (waterComponent) { - CreateParticleGroup(entity); - } else if (particleEmitterComponent) { - CreateParticleEmitter(entity); - } -} - - -void dd::Systems::PhysicsSystem::OnEntityRemoved(EntityID entity) -{ - auto it = m_EntitiesToBodies.find(entity); - if(it != m_EntitiesToBodies.end()) { - it->second->GetWorld()->DestroyBody(it->second); - m_BodiesToEntities.erase(it->second); - m_EntitiesToBodies.erase(entity); - } - -} - - -bool dd::Systems::PhysicsSystem::OnStageCleared(const dd::Events::StageCleared &event) -{ - if (event.ClearedStage < 5) { - m_Travelling = true; - } - return true; -} - - -void dd::Systems::PhysicsSystem::CreateBody(EntityID entity) -{ - auto physicsComponent = m_World->GetComponent(entity); - if(!physicsComponent){ - LOG_ERROR("No PhysicsComponent in CreateBody"); - return; - } - - auto transformComponent = m_World->GetComponent(entity); - if(!transformComponent) { - LOG_ERROR("No TransformComponent in CreateBody"); - return; - } - - auto absoluteTransform = m_World->GetSystem()->AbsoluteTransform(entity); - - b2BodyDef bodyDef; - bodyDef.position.Set(absoluteTransform.Position.x, absoluteTransform.Position.y); - bodyDef.angle = -glm::eulerAngles(absoluteTransform.Orientation).z; - - if (physicsComponent->CollisionType == CollisionType::Type::Static) { - bodyDef.type = b2_staticBody; - } else if (physicsComponent->CollisionType == CollisionType::Type::Dynamic) { - bodyDef.type = b2_dynamicBody; - } else if (physicsComponent->CollisionType == CollisionType::Type::Kinematic) { - bodyDef.type = b2_dynamicBody; - } - - b2Body* body = m_PhysicsWorld->CreateBody(&bodyDef); - - b2Shape* pShape; - - auto rectangleComponent = m_World->GetComponent(entity); - if (rectangleComponent) { - b2PolygonShape* bShape = new b2PolygonShape(); - bShape->SetAsBox(rectangleComponent->Dimensions.x/2.f, rectangleComponent->Dimensions.y/2.f); - pShape = bShape; - } else { - auto circleComponent = m_World->GetComponent(entity); - if (circleComponent) { - pShape = new b2CircleShape(); - pShape->m_radius = circleComponent->Radius; - } - } - - b2FixtureDef fixtureDef; - fixtureDef.shape = pShape; - fixtureDef.filter.categoryBits = physicsComponent->Category; - fixtureDef.filter.maskBits = physicsComponent->Mask; - - - - fixtureDef.shape = pShape; - fixtureDef.density = physicsComponent->Density; - fixtureDef.restitution = 1.0f; - fixtureDef.friction = 0.0f; - body->CreateFixture(&fixtureDef); - - - delete pShape; - - body->SetGravityScale(physicsComponent->GravityScale); - m_EntitiesToBodies.insert(std::make_pair(entity, body)); - m_BodiesToEntities.insert(std::make_pair(body, entity)); -} - - -void dd::Systems::PhysicsSystem::CreateParticleGroup(EntityID e) -{ - auto transform = m_World->GetComponent(e); - if (!transform) { - LOG_ERROR("No Transform component in CreateParticleGroup"); - } - b2ParticleGroupDef pd; - b2PolygonShape shape; - auto water = m_World->GetComponent(e); - if (water) { - - shape.SetAsBox(transform->Scale.x/2.f, transform->Scale.y/2.f); - pd.shape = &shape; - pd.flags = b2_tensileParticle; - pd.position.Set(transform->Position.x, transform->Position.y); - t_ParticleGroup.push_back(m_WaterParticleSystem->CreateParticleGroup(pd)); - b2Vec2* t_ParticlePositions = m_WaterParticleSystem->GetPositionBuffer(); - for(int i = 0; i < m_WaterParticleSystem->GetParticleCount(); i++){ - { - auto t_waterparticle = m_World->CreateEntity(e); - auto transformChild = m_World->AddComponent(t_waterparticle); - - transformChild->Position = glm::vec3(t_ParticlePositions[i].x - transform->Position.x, t_ParticlePositions[i].y - transform->Position.y, -9.5f); - transformChild->Scale = glm::vec3(m_WaterParticleSystem->GetRadius())/transform->Scale; - m_World->CommitEntity(t_waterparticle); - - m_EntitiesToWaterParticleHandle.insert(std::make_pair(t_waterparticle, m_WaterParticleSystem->GetParticleHandleFromIndex(i))); - m_WaterParticleHandleToEntities.insert(std::make_pair(m_WaterParticleSystem->GetParticleHandleFromIndex(i), t_waterparticle)); - } - - } - - } -} - - -void dd::Systems::PhysicsSystem::UpdateParticleEmitters(double dt) -{ - std::vector emittersToDelete; - int pSizeTest = 0; //For debugging, delete this - int psListSize = 0; - for (int i = 0; i < m_ParticleEmitters.ParticleSystem.size(); i++) { - auto e = m_ParticleEmitters.ParticleEmitter[i]; - auto pt = m_ParticleEmitters.ParticleTemplate[i]; - auto ps = m_ParticleEmitters.ParticleSystem[i]; - pSizeTest += ps->GetParticleCount(); - psListSize++; - auto emitter = m_World->GetComponent(e); - auto particleTemplate = m_World->GetComponent(pt); - if(!emitter) { - LOG_INFO("ParticleEmitter Component is nil"); - continue; - } - if(!particleTemplate) { - LOG_INFO("ParticleTemplate Component is nil."); - continue; - } - auto emitterTransform = m_World->GetComponent(e); - emitterTransform->Orientation = glm::rotate(glm::quat(), 3.f, glm::vec3(0.f, 0.f, -1.f)); - - emitter->TimeSinceLastSpawn += dt; - emitter->LifeTime -= dt; - - if (emitter->LifeTime <= 0 || emitter->NumberOfTicks <= 0) { - emittersToDelete.push_back(e); - continue; - } - if(emitter->TimeSinceLastSpawn < emitter->SpawnRate || emitter->NumberOfTicks < 1) { - continue; - } - emitter->NumberOfTicks--; - emitter->TimeSinceLastSpawn -= emitter->SpawnRate; - auto templateTransform = m_World->GetComponent(pt); - b2ParticleDef particleDef; - for ( int j = 0; j < emitter->ParticlesPerTick; j++) { - particleDef.flags = particleTemplate->Flags; - //particleDef.color TODO: Implement this if we want color mixing and shit. - particleDef.lifetime = particleTemplate->LifeTime; - float eAngle = emitter->EmittingAngle; - float halfSpread = emitter->Spread / 2; - - std::uniform_real_distribution dis(eAngle - halfSpread, eAngle + halfSpread); - float pAngle = dis(gen); - std::uniform_real_distribution dis2(0.3, 1.5); - float speedMultiplier = dis2(gen); - glm::vec2 unitVec = glm::normalize(glm::vec2(glm::cos(pAngle), glm::sin(pAngle))); - glm::vec2 vel = unitVec * emitter->Speed * (float)dt * speedMultiplier * 0.5f; - particleDef.velocity = b2Vec2(vel.x, vel.y); - particleDef.position = b2Vec2(emitterTransform->Position.x, emitterTransform->Position.y); - - - auto particle = m_World->CloneEntity(pt, 0); - m_World->RemoveComponent(particle); - auto transform2 = m_World->GetComponent(particle); - - std::uniform_real_distribution dist(0, 1); - float zDistribution = dist(gen); - transform2->Position = glm::vec3(emitterTransform->Position.x, emitterTransform->Position.y, -9.5f + zDistribution); - transform2->Scale = glm::vec3(particleTemplate->Radius * 2.f / speedMultiplier, particleTemplate->Radius * 2.f / speedMultiplier, 1); - - - auto b2Particle = ps->CreateParticle(particleDef); - - auto b2ParticleHandle = ps->GetParticleHandleFromIndex(b2Particle); - m_EntitiesToParticleHandle[i].insert(std::make_pair(particle, b2ParticleHandle)); - m_ParticleHandleToEntities[i].insert(std::make_pair(b2ParticleHandle, particle)); - - - } - - } -// system("cls"); -// std::cout << "Particles living: " << pSizeTest << std::endl; -// std::cout << "particle systems: " << psListSize << std::endl; -// int entHandles = 0; -// for (int i = 0; i < m_EntitiesToParticleHandle.size(); i++) -// entHandles += m_EntitiesToParticleHandle[i].size(); -// std::cout << "Entities and handles: " << entHandles << std::endl; -// LOG_INFO("Particles living: %i", pSizeTest); -// LOG_INFO("Particle systems: %i", psListSize); -// int entHandles = 0; -// for (int i = 0; i < m_EntitiesToParticleHandle.size(); i++) -// entHandles += m_EntitiesToParticleHandle[i].size(); -// LOG_INFO("Entities and handles: %i", entHandles); - - - for (int i = 0; i < emittersToDelete.size(); i++) - { - EntityID ent = emittersToDelete[i]; - int key; - for(key = 0; key < m_ParticleEmitters.ParticleEmitter.size(); key++) { - if (m_ParticleEmitters.ParticleEmitter[key] == ent) { - break; - } - } - - if (m_ParticleEmitters.ParticleSystem[key]->GetParticleCount() == 0 && key <= m_ParticleEmitters.ParticleSystem.size()) { - m_World->RemoveEntity(ent); - m_PhysicsWorld->DestroyParticleSystem(m_ParticleEmitters.ParticleSystem[key]); - m_ParticleEmitters.ParticleSystem.erase(m_ParticleEmitters.ParticleSystem.begin() + key); - m_ParticleEmitters.ParticleEmitter.erase(m_ParticleEmitters.ParticleEmitter.begin() + key); - m_ParticleEmitters.ParticleTemplate.erase(m_ParticleEmitters.ParticleTemplate.begin() + key); - m_EntitiesToParticleHandle.erase(m_EntitiesToParticleHandle.begin() + key); - m_ParticleHandleToEntities.erase(m_ParticleHandleToEntities.begin() + key); - } - } - - - - int stp = 0; - for (auto ts : m_EntitiesToParticleHandle) - { - stp += ts.size(); - } -} - -bool dd::Systems::PhysicsSystem::CreateParticleSequence(const Events::CreateParticleSequence &event) -{ - //Creating Emitter - EntityID emitter = m_World->CreateEntity(); - - auto emitterTransform = m_World->AddComponent(emitter); - auto particleEmitter= m_World->AddComponent(emitter); - - if (event.parent != 0) { - particleEmitter->Parent = event.parent; - } - - emitterTransform->Position = event.Position; - particleEmitter->GravityScale = event.GravityScale; - particleEmitter->SpawnRate = event.SpawnRate; - particleEmitter->NumberOfTicks = event.NumberOfTicks; - particleEmitter->Speed = event.Speed; - particleEmitter->ParticlesPerTick = event.ParticlesPerTick; - particleEmitter->Spread = event.Spread; - particleEmitter->EmittingAngle = event.EmittingAngle; - particleEmitter->LifeTime = event.EmitterLifeTime; - - { - //Creating Particle Template - auto particle = m_World->CreateEntity(emitter); - auto particleTransform = m_World->AddComponent(particle); - auto sprite = m_World->AddComponent(particle); - auto particleComponent = m_World->AddComponent(particle); - m_World->AddComponent(particle); - - particleTransform->Position = emitterTransform->Position; - sprite->SpriteFile = event.SpriteFile; - sprite->Color = event.Color; - particleComponent->LifeTime = event.ParticleLifeTime; - particleComponent->Flags = event.Flags; - particleComponent->Radius = event.Radius; - } - m_World->CommitEntity(emitter); - return true; -} - -void dd::Systems::PhysicsSystem::CreateParticleEmitter(EntityID entity) -{ - auto childEntities = m_World->GetEntityChildren(entity); - if (childEntities.empty()) { - LOG_ERROR("Particle Emitter does not have any child. Please adopt one or this will not work."); - return; - } - int pf = 0; - dd::Components::Particle* particle; - EntityID childEntity; - for ( auto c : childEntities ) { - auto p = m_World->GetComponent(c); - auto particleTemplate = m_World->GetComponent(c); - if (!p) { - continue; - LOG_WARNING("ParticleEmitter's Child is not a particle."); - } - if(!particleTemplate) { - LOG_ERROR("ParticleEmitter's particleChild is not a template."); - continue; - } - if (pf != 0) { - LOG_WARNING("ParticleEmitter has more than one child that is a particleTemplate, only the first one is used."); - break; - } - childEntity = c; - particle = p; - pf++; - } - //TODO: Skicka med fler flaggor till particlesystemet; - - m_ParticleEmitters.ParticleSystem.push_back(CreateParticleSystem(particle->Radius, 0.f, 0)); - m_ParticleEmitters.ParticleEmitter.push_back(entity); - m_ParticleEmitters.ParticleTemplate.push_back(childEntity); -} - - -b2ParticleSystem* dd::Systems::PhysicsSystem::CreateParticleSystem(float radius, float gravityScale, int maxCount) -{ - std::unordered_map m1; - std::unordered_map m2; - m_EntitiesToParticleHandle.push_back(m1); - m_ParticleHandleToEntities.push_back(m2); - - b2ParticleSystemDef m_ParticleSystemDef; - m_ParticleSystemDef.maxCount = maxCount; - m_ParticleSystemDef.radius = radius; - m_ParticleSystemDef.gravityScale = gravityScale; - m_ParticleSystemDef.destroyByAge = true; - - return m_PhysicsWorld->CreateParticleSystem(&m_ParticleSystemDef); -} - -bool dd::Systems::PhysicsSystem::OnContact(const dd::Events::Contact &event) -{ - //Check if it is a brick colliding - auto brick = m_World->GetComponent(event.Entity1); - Components::Model* model; - - if (!brick) { - brick = m_World->GetComponent(event.Entity2); - if (!brick) { - return false; - } - else { - model = m_World->GetComponent(event.Entity2); - } - } - else { - model = m_World->GetComponent(event.Entity1); - } - Events::CreateParticleSequence e; - e.EmitterLifeTime = 4; - //- glm::atan(event.Normal.x, event.Normal.y - e.EmittingAngle = glm::half_pi(); - e.Spread = 0.5f; - e.NumberOfTicks = 1; - e.ParticleLifeTime = 1.f; - e.ParticlesPerTick = 15; - e.Position = glm::vec3(event.IntersectionPoint.x, event.IntersectionPoint.y, -10); - e.Radius = 0.2f; - e.SpriteFile = "Textures/Particles/Cloud_Particle.png"; - e.Color = model->Color + glm::vec4(0.5f); - e.Speed = 100; - EventBroker->Publish(e); - return true; -} - - -dd::Systems::PhysicsSystem::~PhysicsSystem() -{ - for (auto i = m_BodiesToEntities.begin(); i != m_BodiesToEntities.end(); i++) { - b2Body* body = i->first; - body->GetWorld()->DestroyBody(body); - //delete body; - } - m_BodiesToEntities.clear(); - m_EntitiesToBodies.clear(); - m_Impulses.clear(); - - //TODO:REMOVE PARTICLE SYSTEMS - - if (m_ContactListener != nullptr) { - delete m_ContactListener; - m_ContactListener = nullptr; - } - - if (m_PhysicsWorld != nullptr) { - delete m_PhysicsWorld; - m_PhysicsWorld = nullptr; - } -} +#include "PrecompiledHeader.h" +#include "Physics/PhysicsSystem.h" + + +void dd::Systems::PhysicsSystem::RegisterComponents(ComponentFactory* cf) +{ + cf->Register(); + //TODO: REGISTER PHYSICS COMPONENTS HERE +} + +void dd::Systems::PhysicsSystem::Initialize() +{ + std::random_device rd; + gen = std::mt19937(rd()); +// m_DestructionListener = new DestructionListener(this); + m_ContactListener = new ContactListener(this); + m_PhysicsWorld = new b2World(m_Gravity); + m_ParticleContactDisabler = new ParticleContactDisabler(); + m_PhysicsWorld->SetContactListener(m_ContactListener); + m_PhysicsWorld->SetContactFilter(m_ParticleContactDisabler); +// m_PhysicsWorld->SetDestructionListener(m_DestructionListener); + + InitializeWater(); + EVENT_SUBSCRIBE_MEMBER(m_SetImpulse, &PhysicsSystem::SetImpulse); + EVENT_SUBSCRIBE_MEMBER(m_EPause, &PhysicsSystem::OnPause); + EVENT_SUBSCRIBE_MEMBER(m_EStageCleared, &PhysicsSystem::OnStageCleared); + EVENT_SUBSCRIBE_MEMBER(m_ECreateParticleSequence, &PhysicsSystem::CreateParticleSequence); + EVENT_SUBSCRIBE_MEMBER(m_EContact, &PhysicsSystem::OnContact); +} + +void dd::Systems::PhysicsSystem::InitializeWater() +{ + float radius = 0.13f; + float gravityScale = 1.0f; + + b2ParticleSystemDef m_ParticleSystemDef; + m_ParticleSystemDef.radius = radius; + m_ParticleSystemDef.gravityScale = gravityScale; + m_ParticleSystemDef.density = 4.f; + + m_WaterParticleSystem = m_PhysicsWorld->CreateParticleSystem(&m_ParticleSystemDef); +} + +bool dd::Systems::PhysicsSystem::SetImpulse(const Events::SetImpulse &event) +{ + auto it = m_EntitiesToBodies.find(event.Entity); + if(it == m_EntitiesToBodies.end()) { + LOG_ERROR("Entity: %i, Tried to set an impulse on a body that does not exsist", event.Entity); + return false; + } + + b2Vec2 impulse; + impulse.x = event.Impulse.x; + impulse.y = event.Impulse.y; + + b2Vec2 point; + point.x = event.Point.x; + point.y = event.Point.y; + + Impulse i; + i.Body = it->second; + i.Vector = impulse; + i.Point = point; + + m_Impulses.push_back(i); + return true; +} + +void dd::Systems::PhysicsSystem::SyncEntitiesWithBodies() +{ + + for (auto i : m_EntitiesToBodies) { + EntityID entity = i.first; + b2Body* body = i.second; + + if (body == nullptr) { + LOG_ERROR("This body should not exist, please fix this"); + continue; + } + + auto transformComponent = m_World->GetComponent(entity); + if (! transformComponent) { + continue; + LOG_ERROR("RigidBody with no TransformComponent"); + } + + auto physicsComponent = m_World->GetComponent(entity); + if (! physicsComponent) { + continue; + LOG_ERROR("RigidBody with no PhysicsComponent"); + } + + + + if (m_World->GetEntityParent(entity) == 0) { //TODO: Make this work with childs too + b2Vec2 position; + position.x = transformComponent->Position.x; + position.y = transformComponent->Position.y; + float angle = glm::eulerAngles(transformComponent->Orientation).z; + body->SetTransform(position, angle); + body->SetLinearVelocity(b2Vec2(transformComponent->Velocity.x, transformComponent->Velocity.y)); + body->SetGravityScale(physicsComponent->GravityScale); + + b2Filter filter; + filter.categoryBits = physicsComponent->Category; + filter.maskBits = physicsComponent->Mask; + body->GetFixtureList()->SetFilterData(filter); + + if (physicsComponent->CollisionType == CollisionType::Type::Static) { + body->SetType(b2_staticBody); + } + else if (physicsComponent->CollisionType == CollisionType::Type::Dynamic) { + body->SetType(b2_dynamicBody); + } + else if (physicsComponent->CollisionType == CollisionType::Type::Kinematic) { + body->SetType(b2_dynamicBody); + } + } + } +} + +void dd::Systems::PhysicsSystem::SyncBodiesWithEntities() +{ + for (auto i : m_BodiesToEntities) { + b2Body* body = i.first; + EntityID entity = i.second; + + if (body == nullptr) { + LOG_ERROR("This body should not exist, please fix this"); + continue; + } + + auto transformComponent = m_World->GetComponent(entity); + if (! transformComponent) { + continue; + LOG_ERROR("RigidBody with no TransformComponent"); + } + + auto physicsComponent = m_World->GetComponent(entity); + if (! physicsComponent) { + continue; + LOG_ERROR("RigidBody with no PhysicsComponent"); + } + + auto parent = m_World->GetEntityParent(entity); + if (parent == 0) { + auto physicsComponent = m_World->GetComponent(entity); + + if (physicsComponent->Calculate) { //TODO: REPLACE THIS WITH PARTICLE COLLISION FILTERS + transformComponent->Position.x = transformComponent->Position.x + (transformComponent->Velocity.x * m_TimeStep); + transformComponent->Position.y = transformComponent->Position.y + (transformComponent->Velocity.y * m_TimeStep); + } else { + b2Vec2 position = body->GetPosition(); + transformComponent->Position.x = position.x; + transformComponent->Position.y = position.y; + + float angle = body->GetAngle(); + transformComponent->Orientation = glm::quat(glm::vec3(0, 0, angle)); + + b2Vec2 velocity = body->GetLinearVelocity(); + transformComponent->Velocity.x = velocity.x; + transformComponent->Velocity.y = velocity.y; + } + } + } +} + +void dd::Systems::PhysicsSystem::Update(double dt) +{ + if (m_Pause) { + return; + } + + if (m_Travelling) { + if (m_DistanceTravelled > 12.f) { + m_DistanceTravelled = 0; + m_Travelling = false; + } + + m_DistanceTravelled += 6.0f * dt; + } + m_Accumulator += dt; + + while(m_Accumulator >= m_TimeStep) + { + + UpdateParticleEmitters(dt); + SyncEntitiesWithBodies(); + + //Apply Impulses Must be done after SyncEntitiesWithBodies + for (auto i : m_Impulses) { + i.Body->ApplyLinearImpulse(i.Vector, i.Point, true); + } + m_Impulses.clear(); + + + //Update the PhysicsWorld + m_PhysicsWorld->Step(m_TimeStep, m_VelocityIterations, m_PositionIterations); + + SyncBodiesWithEntities(); + + + //water + b2Vec2 *positionBuffer = m_WaterParticleSystem->GetPositionBuffer(); + for (auto i : m_EntitiesToWaterParticleHandle){ + EntityID entity = i.first; + const b2ParticleHandle *particleH = i.second; + + + b2Vec2 positionB2 = positionBuffer[particleH->GetIndex()]; + glm::vec2 position = glm::vec2(positionB2.x, positionB2.y); + + EntityID entityParent = m_World->GetEntityParent(entity); + glm::vec3 parentTransform = glm::vec3(0.f); + if(entityParent) { + auto tp = m_World->GetComponent(entityParent); + parentTransform = tp->Position; + } + auto transform = m_World->GetComponent(entity); + + transform->Position = glm::vec3(position.x - parentTransform.x, position.y - parentTransform.y, 0); + } + + //Normal particles + for ( int e = 0; e < m_EntitiesToParticleHandle.size(); e++) { + b2Vec2 *positionBuffer = m_ParticleEmitters.ParticleSystem[e]->GetPositionBuffer(); + if(!positionBuffer) { + break; + } + for (auto i : m_EntitiesToParticleHandle[e]){ + EntityID entity = i.first; + const b2ParticleHandle *particleH = i.second; + + b2Vec2 positionB2 = positionBuffer[particleH->GetIndex()]; + glm::vec2 position = glm::vec2(positionB2.x, positionB2.y); + + EntityID entityParent = m_World->GetEntityParent(entity); + glm::vec3 parentTransform = glm::vec3(0.f); + if(entityParent) { + auto tp = m_World->GetComponent(entityParent); + parentTransform = tp->Position; + } + auto transform = m_World->GetComponent(entity); + auto particle = m_World->GetComponent(entity); + + transform->Position = glm::vec3(position.x, position.y, transform->Position.z); + transform->Scale = glm::vec3(particle->Radius * 2.f, particle->Radius * 2.f, 1); + } + } + + m_Accumulator -= m_TimeStep; + } +} + +void dd::Systems::PhysicsSystem::UpdateEntity(double dt, EntityID entity, EntityID parent) +{ + if (m_Travelling) { + auto transform = m_World->GetComponent(entity); + if (transform != nullptr) { + if (!transform->Sticky) { + transform->Position.y -= 6.0f * dt; + } + } else { + transform->Position.y -= 6.0f * dt; + } + } + auto particle = m_World->GetComponent(entity); + auto pTemplate = m_World->GetComponent(entity); + + + + if (particle && !pTemplate) { + particle->TimeLived += dt; + //Delete particles + if (particle->TimeLived >= particle->LifeTime - 0.1) { + for (int i = 0; i < m_EntitiesToParticleHandle.size(); i++) { + const b2ParticleHandle* handle = m_EntitiesToParticleHandle[i][entity]; + std::unordered_map::iterator iter1; + std::unordered_map::iterator iter2; + iter1 = m_EntitiesToParticleHandle[i].find(entity); + iter2 = m_ParticleHandleToEntities[i].find(handle); + if (iter1 != m_EntitiesToParticleHandle[i].end()) { + m_EntitiesToParticleHandle[i].erase(iter1); + } + if (iter2 != m_ParticleHandleToEntities[i].end()) { + m_ParticleHandleToEntities[i].erase(iter2); + } + m_World->RemoveEntity(entity); + } + } + //Update alpha + auto sprite = m_World->GetComponent(entity); + float timeProgress = particle->TimeLived / particle->LifeTime; + if (timeProgress > particle->LifeTime) { + timeProgress = particle->LifeTime; + } + auto emitter = m_World->GetComponent(particle->ParticleSystem); + if (emitter) { + sprite->Color.w = ScalarInterpolation(timeProgress, emitter->AlphaValues); + particle->Radius = ScalarInterpolation(timeProgress, emitter->RadiusValues); + } + } + + //Particlesystem relative to parent + auto emitter = m_World->GetComponent(entity); + if (emitter) { + EntityID emitterParent = emitter->Parent; + if (emitterParent != 0) { + auto emitterTransform = m_World->GetComponent(entity); + auto parentTransform = m_World->GetComponent(emitterParent); + if (emitterTransform && parentTransform) { + emitterTransform->Position = parentTransform->Position; + } + } + } +} + +float dd::Systems::PhysicsSystem::ScalarInterpolation(float timeProgress, std::vector spectrum) +{ + int alphaVecSize = spectrum.size(); + if (alphaVecSize == 0) { + return 0.01f; + } + if (alphaVecSize == 1) { + return spectrum[0]; + } + + float dValue = glm::abs(spectrum[0] - spectrum[1]); + if (spectrum[0] > spectrum[1]) { + dValue *= -1; + } + + float scalar = spectrum[0] + dValue * timeProgress; + + return scalar; +} + +bool dd::Systems::PhysicsSystem::OnPause(const dd::Events::Pause &event) +{ + if (event.Type != "PhysicsSystem" && event.Type != "All") { + return false; + } + + if (m_Pause) { + m_Pause = false; + } else { + m_Pause = true; + } + return true; +} + +void dd::Systems::PhysicsSystem::OnEntityCommit(EntityID entity) +{ + auto physicsComponent = m_World->GetComponent(entity); + auto waterComponent = m_World->GetComponent(entity); + auto particleEmitterComponent = m_World->GetComponent(entity); + + if (physicsComponent && waterComponent) { + LOG_ERROR("Entity has both water and physics component, this is illegal. The police has been alerted."); + return; + } + if (physicsComponent && particleEmitterComponent) { + LOG_ERROR("Entity has both particle and physics component, this is illegal. The police has been alerted."); + return; + } + + if (physicsComponent) { + auto it = m_EntitiesToBodies.find(entity); + if(it == m_EntitiesToBodies.end()) { + CreateBody(entity); + } else { + LOG_ERROR("Tried to commit a body that already exists"); + } + } else if (waterComponent) { + CreateParticleGroup(entity); + } else if (particleEmitterComponent) { + CreateParticleEmitter(entity); + } +} + + +void dd::Systems::PhysicsSystem::OnEntityRemoved(EntityID entity) +{ + auto it = m_EntitiesToBodies.find(entity); + if(it != m_EntitiesToBodies.end()) { + it->second->GetWorld()->DestroyBody(it->second); + m_BodiesToEntities.erase(it->second); + m_EntitiesToBodies.erase(entity); + } +} + + +bool dd::Systems::PhysicsSystem::OnStageCleared(const dd::Events::StageCleared &event) +{ + if (event.ClearedStage < 5) { + m_Travelling = true; + } + return true; +} + + +void dd::Systems::PhysicsSystem::CreateBody(EntityID entity) +{ + auto physicsComponent = m_World->GetComponent(entity); + if(!physicsComponent){ + LOG_ERROR("No PhysicsComponent in CreateBody"); + return; + } + + auto transformComponent = m_World->GetComponent(entity); + if(!transformComponent) { + LOG_ERROR("No TransformComponent in CreateBody"); + return; + } + + auto absoluteTransform = m_World->GetSystem()->AbsoluteTransform(entity); + + b2BodyDef bodyDef; + bodyDef.position.Set(absoluteTransform.Position.x, absoluteTransform.Position.y); + bodyDef.angle = -glm::eulerAngles(absoluteTransform.Orientation).z; + + if (physicsComponent->CollisionType == CollisionType::Type::Static) { + bodyDef.type = b2_staticBody; + } else if (physicsComponent->CollisionType == CollisionType::Type::Dynamic) { + bodyDef.type = b2_dynamicBody; + } else if (physicsComponent->CollisionType == CollisionType::Type::Kinematic) { + bodyDef.type = b2_dynamicBody; + } + + b2Body* body = m_PhysicsWorld->CreateBody(&bodyDef); + + b2Shape* pShape; + + auto rectangleComponent = m_World->GetComponent(entity); + if (rectangleComponent) { + b2PolygonShape* bShape = new b2PolygonShape(); + bShape->SetAsBox(rectangleComponent->Dimensions.x/2.f, rectangleComponent->Dimensions.y/2.f); + pShape = bShape; + } else { + auto circleComponent = m_World->GetComponent(entity); + if (circleComponent) { + pShape = new b2CircleShape(); + pShape->m_radius = circleComponent->Radius; + } + } + + b2FixtureDef fixtureDef; + fixtureDef.shape = pShape; + fixtureDef.filter.categoryBits = physicsComponent->Category; + fixtureDef.filter.maskBits = physicsComponent->Mask; + + + + fixtureDef.shape = pShape; + fixtureDef.density = physicsComponent->Density; + fixtureDef.restitution = 1.0f; + fixtureDef.friction = 0.0f; + body->CreateFixture(&fixtureDef); + + + delete pShape; + + body->SetGravityScale(physicsComponent->GravityScale); + m_EntitiesToBodies.insert(std::make_pair(entity, body)); + m_BodiesToEntities.insert(std::make_pair(body, entity)); +} + + +void dd::Systems::PhysicsSystem::CreateParticleGroup(EntityID e) +{ + auto transform = m_World->GetComponent(e); + if (!transform) { + LOG_ERROR("No Transform component in CreateParticleGroup"); + } + b2ParticleGroupDef pd; + b2PolygonShape shape; + auto water = m_World->GetComponent(e); + if (water) { + + shape.SetAsBox(transform->Scale.x/2.f, transform->Scale.y/2.f); + pd.shape = &shape; + pd.flags = b2_tensileParticle; + pd.position.Set(transform->Position.x, transform->Position.y); + t_ParticleGroup.push_back(m_WaterParticleSystem->CreateParticleGroup(pd)); + b2Vec2* t_ParticlePositions = m_WaterParticleSystem->GetPositionBuffer(); + for(int i = 0; i < m_WaterParticleSystem->GetParticleCount(); i++){ + { + auto t_waterparticle = m_World->CreateEntity(e); + auto transformChild = m_World->AddComponent(t_waterparticle); + + transformChild->Position = glm::vec3(t_ParticlePositions[i].x - transform->Position.x, t_ParticlePositions[i].y - transform->Position.y, -9.5f); + transformChild->Scale = glm::vec3(m_WaterParticleSystem->GetRadius())/transform->Scale; + m_World->CommitEntity(t_waterparticle); + + m_EntitiesToWaterParticleHandle.insert(std::make_pair(t_waterparticle, m_WaterParticleSystem->GetParticleHandleFromIndex(i))); + m_WaterParticleHandleToEntities.insert(std::make_pair(m_WaterParticleSystem->GetParticleHandleFromIndex(i), t_waterparticle)); + } + + } + + } +} + + +void dd::Systems::PhysicsSystem::UpdateParticleEmitters(double dt) +{ + std::vector emittersToDelete; + int pSizeTest = 0; //For debugging, delete this + int psListSize = 0; + for (int i = 0; i < m_ParticleEmitters.ParticleSystem.size(); i++) { + auto e = m_ParticleEmitters.ParticleEmitter[i]; + auto pt = m_ParticleEmitters.ParticleTemplate[i]; + auto ps = m_ParticleEmitters.ParticleSystem[i]; + pSizeTest += ps->GetParticleCount(); + psListSize++; + auto emitter = m_World->GetComponent(e); + auto particleTemplate = m_World->GetComponent(pt); + if(!emitter) { + LOG_INFO("ParticleEmitter Component is nil"); + continue; + } + if(!particleTemplate) { + LOG_INFO("ParticleTemplate Component is nil."); + continue; + } + auto emitterTransform = m_World->GetComponent(e); + emitterTransform->Orientation = glm::rotate(glm::quat(), 3.f, glm::vec3(0.f, 0.f, -1.f)); + + emitter->TimeSinceLastSpawn += dt; + emitter->LifeTime -= dt; + + if (emitter->LifeTime <= 0 || emitter->NumberOfTicks <= 0) { + emittersToDelete.push_back(e); + continue; + } + if(emitter->TimeSinceLastSpawn < emitter->SpawnRate || emitter->NumberOfTicks < 1) { + continue; + } + //Create new particle + emitter->NumberOfTicks--; + emitter->TimeSinceLastSpawn -= emitter->SpawnRate; + auto templateTransform = m_World->GetComponent(pt); + + for ( int j = 0; j < emitter->ParticlesPerTick; j++) { + b2ParticleDef particleDef; + particleDef.flags = particleTemplate->Flags; + //particleDef.color TODO: Implement this if we want color mixing and shit. + particleDef.lifetime = particleTemplate->LifeTime; + float eAngle = emitter->EmittingAngle; + float halfSpread = emitter->Spread / 2; + + std::uniform_real_distribution dis(eAngle - halfSpread, eAngle + halfSpread); + float pAngle = dis(gen); + std::uniform_real_distribution dis2(0.3, 1.5); + float speedMultiplier = dis2(gen); + glm::vec2 unitVec = glm::normalize(glm::vec2(glm::cos(pAngle), glm::sin(pAngle))); + glm::vec2 vel = unitVec * emitter->Speed * (float)dt * speedMultiplier * 0.5f; + particleDef.velocity = b2Vec2(vel.x, vel.y); + particleDef.position = b2Vec2(emitterTransform->Position.x, emitterTransform->Position.y); + + + auto particle = m_World->CloneEntity(pt, 0); + m_World->RemoveComponent(particle); + auto particleTransform = m_World->GetComponent(particle); + + + std::uniform_real_distribution dist(0, 1); + float zDistribution = dist(gen); + particleTransform->Position = glm::vec3(emitterTransform->Position.x, emitterTransform->Position.y, -9.5f + zDistribution); + particleTransform->Scale = glm::vec3(particleTemplate->Radius * 2.f / speedMultiplier, particleTemplate->Radius * 2.f / speedMultiplier, 1); + particleTransform->Velocity = glm::vec3(vel.x, vel.y, 0); + + + auto b2ParticleIndex = ps->CreateParticle(particleDef); + auto b2ParticleHandle = ps->GetParticleHandleFromIndex(b2ParticleIndex); + + m_EntitiesToParticleHandle[i].insert(std::make_pair(particle, b2ParticleHandle)); + m_ParticleHandleToEntities[i].insert(std::make_pair(b2ParticleHandle, particle)); + } + + } +// system("cls"); +// std::cout << "Particles living: " << pSizeTest << std::endl; +// std::cout << "particle systems: " << psListSize << std::endl; +// int entHandles = 0; +// for (int i = 0; i < m_EntitiesToParticleHandle.size(); i++) +// entHandles += m_EntitiesToParticleHandle[i].size(); +// std::cout << "Entities and handles: " << entHandles << std::endl; +// LOG_INFO("Particles living: %i", pSizeTest); +// LOG_INFO("Particle systems: %i", psListSize); +// //int entHandles = 0; +// for (int i = 0; i < m_EntitiesToParticleHandle.size(); i++) +// entHandles += m_EntitiesToParticleHandle[i].size(); +// LOG_INFO("Entities and handles: %i", entHandles); + + + for (int i = 0; i < emittersToDelete.size(); i++) + { + EntityID ent = emittersToDelete[i]; + int key; + for(key = 0; key < m_ParticleEmitters.ParticleEmitter.size(); key++) { + if (m_ParticleEmitters.ParticleEmitter[key] == ent) { + break; + } + } + + if (m_ParticleEmitters.ParticleSystem[key]->GetParticleCount() == 0 && key <= m_ParticleEmitters.ParticleSystem.size() - 1) { + m_World->RemoveEntity(ent); + m_PhysicsWorld->DestroyParticleSystem(m_ParticleEmitters.ParticleSystem[key]); + m_ParticleEmitters.ParticleSystem.erase(m_ParticleEmitters.ParticleSystem.begin() + key); + m_ParticleEmitters.ParticleEmitter.erase(m_ParticleEmitters.ParticleEmitter.begin() + key); + m_ParticleEmitters.ParticleTemplate.erase(m_ParticleEmitters.ParticleTemplate.begin() + key); + m_EntitiesToParticleHandle.erase(m_EntitiesToParticleHandle.begin() + key); + m_ParticleHandleToEntities.erase(m_ParticleHandleToEntities.begin() + key); + emittersToDelete.clear(); + } + } +} + +bool dd::Systems::PhysicsSystem::CreateParticleSequence(const Events::CreateParticleSequence &event) +{ + //Creating Emitter + EntityID emitter = m_World->CreateEntity(); + + auto emitterTransform = m_World->AddComponent(emitter); + auto particleEmitter= m_World->AddComponent(emitter); + + if (event.parent != 0) { + particleEmitter->Parent = event.parent; + } + + emitterTransform->Position = event.Position; + particleEmitter->GravityScale = event.GravityScale; + particleEmitter->SpawnRate = event.SpawnRate; + particleEmitter->NumberOfTicks = event.NumberOfTicks; + particleEmitter->Speed = event.Speed; + particleEmitter->ParticlesPerTick = event.ParticlesPerTick; + particleEmitter->Spread = event.Spread; + particleEmitter->EmittingAngle = event.EmittingAngle; + particleEmitter->LifeTime = event.EmitterLifeTime; + particleEmitter->AlphaValues = event.AlphaValues; + particleEmitter->RadiusValues = event.RadiusValues; + { + //Creating Particle Template + auto particle = m_World->CreateEntity(emitter); + auto particleTransform = m_World->AddComponent(particle); + auto sprite = m_World->AddComponent(particle); + auto particleComponent = m_World->AddComponent(particle); + m_World->AddComponent(particle); + particleTransform->Position = emitterTransform->Position; + sprite->SpriteFile = event.SpriteFile; + sprite->Color = event.Color; + particleComponent->LifeTime = event.ParticleLifeTime; + particleComponent->Flags = event.Flags; + particleComponent->Radius = event.RadiusValues[0]; + particleComponent->ParticleSystem = emitter; + } + m_World->CommitEntity(emitter); + return true; +} + +void dd::Systems::PhysicsSystem::CreateParticleEmitter(EntityID entity) +{ + auto childEntities = m_World->GetEntityChildren(entity); + if (childEntities.empty()) { + LOG_ERROR("Particle Emitter does not have any child. Please adopt one or this will not work."); + return; + } + int pf = 0; + dd::Components::Particle* particle; + EntityID childEntity; + for ( auto c : childEntities ) { + auto p = m_World->GetComponent(c); + auto particleTemplate = m_World->GetComponent(c); + if (!p) { + continue; + LOG_WARNING("ParticleEmitter's Child is not a particle."); + } + if(!particleTemplate) { + LOG_ERROR("ParticleEmitter's particleChild is not a template."); + continue; + } + if (pf != 0) { + LOG_WARNING("ParticleEmitter has more than one child that is a particleTemplate, only the first one is used."); + break; + } + childEntity = c; + particle = p; + pf++; + } + //TODO: Skicka med fler flaggor till particlesystemet; + + m_ParticleEmitters.ParticleSystem.push_back(CreateParticleSystem(particle->Radius, 0.f, 0)); + m_ParticleEmitters.ParticleEmitter.push_back(entity); + m_ParticleEmitters.ParticleTemplate.push_back(childEntity); +} + + +b2ParticleSystem* dd::Systems::PhysicsSystem::CreateParticleSystem(float radius, float gravityScale, int maxCount) +{ + std::unordered_map m1; + std::unordered_map m2; + m_EntitiesToParticleHandle.push_back(m1); + m_ParticleHandleToEntities.push_back(m2); + + b2ParticleSystemDef m_ParticleSystemDef; + m_ParticleSystemDef.maxCount = maxCount; + m_ParticleSystemDef.radius = radius; + m_ParticleSystemDef.gravityScale = gravityScale; + m_ParticleSystemDef.destroyByAge = false; + + return m_PhysicsWorld->CreateParticleSystem(&m_ParticleSystemDef); +} + +bool dd::Systems::PhysicsSystem::OnContact(const dd::Events::Contact &event) +{ + //Check if it is a brick colliding with ball + auto brick = m_World->GetComponent(event.Entity1); + Components::Model* model; + auto ball = m_World->GetComponent(event.Entity2); + if (!brick) { + brick = m_World->GetComponent(event.Entity2); + if (!brick) { + return false; + } + else { + model = m_World->GetComponent(event.Entity2); + } + } + else if (!ball) { + ball = m_World->GetComponent(event.Entity1); + if (!ball) { + return false; + } + } + else { + + model = m_World->GetComponent(event.Entity1); + } + Events::CreateParticleSequence e; + e.EmitterLifeTime = 4; + //- glm::atan(event.Normal.x, event.Normal.y + e.EmittingAngle = glm::half_pi(); + e.Spread = 0.5f; + e.NumberOfTicks = 1; + e.ParticleLifeTime = 1.f; + e.ParticlesPerTick = 15; + e.Position = glm::vec3(event.IntersectionPoint.x, event.IntersectionPoint.y, -10); + e.RadiusValues.push_back(0.2); + e.RadiusValues.push_back(1); + e.SpriteFile = "Textures/Particles/Cloud_Particle.png"; + e.Color = model->Color + glm::vec4(0.5f); + e.AlphaValues.push_back(1.f); + e.AlphaValues.push_back(0.f); + e.Speed = 100; + EventBroker->Publish(e); + return true; +} + + +dd::Systems::PhysicsSystem::~PhysicsSystem() +{ + for (auto i = m_BodiesToEntities.begin(); i != m_BodiesToEntities.end(); i++) { + b2Body* body = i->first; + body->GetWorld()->DestroyBody(body); + //delete body; + } + m_BodiesToEntities.clear(); + m_EntitiesToBodies.clear(); + m_Impulses.clear(); + + //TODO:REMOVE PARTICLE SYSTEMS + + if (m_ContactListener != nullptr) { + delete m_ContactListener; + m_ContactListener = nullptr; + } + + if (m_PhysicsWorld != nullptr) { + delete m_PhysicsWorld; + m_PhysicsWorld = nullptr; + } +}