#include "PrecompiledHeader.h" #include "Game/BallSystem.h" dd::Systems::BallSystem::~BallSystem() { } void dd::Systems::BallSystem::RegisterComponents(ComponentFactory *cf) { } void dd::Systems::BallSystem::Initialize() { EVENT_SUBSCRIBE_MEMBER(m_Contact, &BallSystem::Contact); EVENT_SUBSCRIBE_MEMBER(m_ELifeLost, &BallSystem::OnLifeLost); EVENT_SUBSCRIBE_MEMBER(m_EMultiBallLost, &BallSystem::OnMultiBallLost); EVENT_SUBSCRIBE_MEMBER(m_EResetBall, &BallSystem::OnResetBall); EVENT_SUBSCRIBE_MEMBER(m_EMultiBall, &BallSystem::OnMultiBall); EVENT_SUBSCRIBE_MEMBER(m_EStickyPad, &BallSystem::OnStickyPad); EVENT_SUBSCRIBE_MEMBER(m_EInkBlaster, &BallSystem::OnInkBlaster); EVENT_SUBSCRIBE_MEMBER(m_EPause, &BallSystem::OnPause); EVENT_SUBSCRIBE_MEMBER(m_EActionButton, &BallSystem::OnActionButton); //OctoBall { auto ent = m_World->CreateEntity(); std::shared_ptr transform = m_World->AddComponent(ent); transform->Position = glm::vec3(-0.f, 50.26f, -10.f); transform->Scale = glm::vec3(0.3f, 0.3f, 0.3f); transform->Velocity = glm::vec3(0.f, 0.f, 0.f); auto model = m_World->AddComponent(ent); model->ModelFile = "Models/Test/Ball/Sid.obj"; std::shared_ptr circleShape = m_World->AddComponent(ent); circleShape->Radius = 0.4f; std::shared_ptr ball = m_World->AddComponent(ent); ball->Speed = 5.f; ball->Waiting = true; std::shared_ptr physics = m_World->AddComponent(ent); std::shared_ptr ballTemplate = m_World->AddComponent(ent); physics->CollisionType = CollisionType::Type::Dynamic; physics->Category = CollisionLayer::Type::Ball; physics->Mask = static_cast(CollisionLayer::Type::Pad | CollisionLayer::Type::Brick | CollisionLayer::Type::Wall | CollisionLayer::LifeBuoy); physics->Calculate = true; transform->Sticky = true; m_World->CommitEntity(ent); SetBall(ent); auto ent2 = CreateBall(); auto transform2 = m_World->GetComponent(ent2); transform2->Position = glm::vec3(-0.f, 0.26f, -10.f); transform2->Velocity = glm::vec3(0.0f, -10.f, 0.f); } for (int i = 0; i < Lives(); i++) { CreateLife(i); } } void dd::Systems::BallSystem::Update(double dt) { if (Lives() < 0) { SetLives(3); Events::GameOver e; EventBroker->Publish(e); } ResolveContacts(); } void dd::Systems::BallSystem::UpdateEntity(double dt, EntityID entity, EntityID parent) { //TODO: When the ball collides with 2 bricks on the same frame it is reflected and then reflected again, make it reflect only once like a list or something? auto ballComponent = m_World->GetComponent(entity); if (IsPaused()) { if (ballComponent != nullptr) { auto transform = m_World->GetComponent(entity); if (!ballComponent->Paused) { ballComponent->Paused = true; ballComponent->SavedSpeed = transform->Velocity; transform->Velocity = glm::vec3(0, 0, 0); } } return; } else { if (ballComponent != nullptr) { auto transform = m_World->GetComponent(entity); if (ballComponent->Paused) { transform->Velocity = ballComponent->SavedSpeed; ballComponent->Paused = false; } } } auto templateCheck = m_World->GetComponent(entity); if (templateCheck != nullptr){ return; } if (ballComponent != nullptr) { if (ReplaceBall()) { SetReplaceBall(false); m_Waiting = true; ballComponent->Waiting = true; } if (ballComponent->Waiting) { if (m_Waiting == false) { ballComponent->Waiting = false; auto transform = m_World->GetComponent(entity); transform->Velocity = glm::normalize(glm::vec3(0.5f, 1, 0.f)) * ballComponent->Speed; if (ballComponent->Sticky) { transform->Velocity = ballComponent->SavedSpeed; m_StickyCounter--; std::cout << m_StickyCounter << std::endl; if (m_StickyCounter > 0) { m_Sticky = true; } ballComponent->Sticky = false; } } else if (!ballComponent->Sticky) { auto transform = m_World->GetComponent(entity); transform->Velocity = glm::vec3(0.f, 0.f, 0.f); transform->Position = glm::vec3(0.0f, -3.f, -10.f); transform->Orientation = glm::quat(); return; } } auto transformBall = m_World->GetComponent(entity); if (glm::abs(transformBall->Velocity.y) < 2) { if (transformBall->Velocity.y > 0) { transformBall->Velocity.y = 2; } else { transformBall->Velocity.y = -2; } } if (transformBall->Position.y < -EdgeY() - 4 || transformBall->Position.y > EdgeY() + 4) { if (MultiBalls() != 0) { m_World->RemoveEntity(entity); Events::MultiBallLost e; EventBroker->Publish(e); } else if (Lives() == PastLives()) { Events::ResetBall be; EventBroker->Publish(be); Events::LifeLost e; e.Entity = entity; EventBroker->Publish(e); return; } } //Removing this made the wall collisions work again /*else if (transformBall->Position.x > EdgeX()) { if (transformBall->Velocity.x > 0) { glm::vec2 reflectedVelocity = glm::reflect(glm::vec2(transformBall->Velocity.x, transformBall->Velocity.y), glm::vec2(1, 0)); transformBall->Velocity = glm::vec3(reflectedVelocity, 0.f); } } else if (transformBall->Position.x < -EdgeX()) { if (transformBall->Velocity.x < 0) { glm::vec2 reflectedVelocity = glm::reflect(glm::vec2(transformBall->Velocity.x, transformBall->Velocity.y), glm::vec2(-1, 0)); transformBall->Velocity = glm::vec3(reflectedVelocity, 0.f); } } else if (transformBall->Position.y > EdgeY()) { if (transformBall->Velocity.y > 0) { glm::vec2 reflectedVelocity = glm::reflect(glm::vec2(transformBall->Velocity.x, transformBall->Velocity.y), glm::vec2(0, 1)); transformBall->Velocity = glm::vec3(reflectedVelocity, 0.f); } }*/ } if (Lives() != PastLives()) { auto life = m_World->GetComponent(entity); if (life != nullptr) { if (life->Number + 1 == PastLives()) { m_World->RemoveEntity(entity); SetPastLives(Lives()); } } } if (ballComponent != nullptr) { auto transform = m_World->GetComponent(entity); glm::vec2 dir = glm::normalize(glm::vec2(transform->Velocity.x, transform->Velocity.y)); glm::vec2 up = glm::vec2(0.f, 1.f); float angle = glm::acos(glm::dot(dir, up)) * glm::sign(dir.x); transform->Orientation = glm::rotate(glm::quat(), angle, glm::vec3(0.f, 0.f, -1.f)); } } bool dd::Systems::BallSystem::OnPause(const dd::Events::Pause &event) { if (event.Type != "BallSystem" && event.Type != "All") { return false; } if (IsPaused()) { SetPause(false); } else { SetPause(true); } return true; } void dd::Systems::BallSystem::OnEntityCommit(EntityID entity) { } void dd::Systems::BallSystem::OnEntityRemoved(EntityID entity) { } bool dd::Systems::BallSystem::Contact(const Events::Contact &event) { Components::PowerUp* power1 = m_World->GetComponent(event.Entity1); Components::PowerUp* power2 = m_World->GetComponent(event.Entity2); if (power1 != nullptr || power2 != nullptr) { return false; } Components::Ball* ballComponent1 = m_World->GetComponent(event.Entity1); Components::Ball* ballComponent2 = m_World->GetComponent(event.Entity2); Components::Ball* ballComponent; if (ballComponent1 != nullptr && ballComponent2 != nullptr) { return false; } EntityID ballEntity, otherEntitiy; //Which is the ball? if (ballComponent1 != nullptr) { ballEntity = event.Entity1; otherEntitiy = event.Entity2; ballComponent = ballComponent1; } else if (ballComponent2 != nullptr) { ballEntity = event.Entity2; otherEntitiy = event.Entity1; ballComponent = ballComponent2; } else { return false; } auto ballTransform = m_World->GetComponent(ballEntity); glm::vec2 ballVelocity = glm::vec2(ballTransform->Velocity.x, ballTransform->Velocity.y); if (m_World->GetProperty(otherEntitiy, "Name") == "Pad") { auto padTransform = m_World->GetComponent(otherEntitiy); Events::HitPad e; e.Ball = ballEntity; e.Pad = otherEntitiy; EventBroker->Publish(e); // Events::HitLag el; // el.Time = 0.1f; //el.Type = "All"; // EventBroker->Publish(el); float x = (ballTransform->Position.x - padTransform->Position.x) * XMovementMultiplier(); float y = glm::cos((abs(x) / (1.6f)) * glm::pi() / 2.f) + 1.f; ballComponent->Combo = 0; if (m_InkBlaster) { m_InkBlaster = false; ballComponent->Sticky = true; ballComponent->StickyPlacement = glm::vec3(0, 0.5f, 0); ballTransform->Velocity = glm::vec3(0.f, 0.f, 0.f); } else if (m_Sticky) { m_Sticky = false; m_Waiting = true; ballComponent->Sticky = true; ballComponent->Waiting = true; ballComponent->StickyPlacement = ballTransform->Position - padTransform->Position; ballComponent->SavedSpeed = glm::normalize(glm::vec3(x, y, 0.f)) * ballComponent->Speed; ballTransform->Velocity *= -1; return true; } ballTransform->Velocity = glm::normalize(glm::vec3(x, y ,0.f)) * ballComponent->Speed; Events::ComboEvent ec; ec.Combo = ballComponent->Combo; ec.Ball = ballEntity; EventBroker->Publish(ec); //std::cout << "Combo: " << ballComponent->Combo << std::endl; } // Lifebuoy should always reflect the ball upwards else if (m_World->GetProperty(otherEntitiy, "Name") == "Lifebuoy"){ ballTransform->Velocity = glm::vec3(ballTransform->Velocity.x, abs(ballTransform->Velocity.y), ballTransform->Velocity.z); } else { auto it = m_Contacts.find(ballEntity); if (it == m_Contacts.end()) { std::list normalList; normalList.push_back(event.Normal); m_Contacts[ballEntity] = normalList; } else { std::list normalList = it->second; normalList.push_back(event.Normal); m_Contacts[ballEntity] = normalList; } } return true; } void dd::Systems::BallSystem::ResolveContacts() { for (auto c : m_Contacts) { EntityID entity = c.first; std::list contactNormals = c.second; glm::vec2 finalNormal = glm::vec2(0.f); for (auto it = contactNormals.begin(); it != contactNormals.end(); it++) { finalNormal = finalNormal + (*it); } finalNormal = glm::normalize(finalNormal); auto transform = m_World->GetComponent(entity); glm::vec2 velocity = glm::vec2(transform->Velocity.x, transform->Velocity.y); glm::vec2 reflectedVelocity = glm::reflect(velocity, finalNormal); auto ballComponent = m_World->GetComponent(entity); reflectedVelocity = glm::normalize(reflectedVelocity) * ballComponent->Speed; transform->Velocity = glm::vec3(reflectedVelocity, 0.f); } m_Contacts.clear(); } EntityID dd::Systems::BallSystem::CreateBall() { auto ent = m_World->CloneEntity(Ball()); m_World->RemoveComponent(ent); return ent; } void dd::Systems::BallSystem::CreateLife(int number) { auto life = m_World->CreateEntity(); std::shared_ptr transform = m_World->AddComponent(life); transform->Position = glm::vec3(-1.5f + number * 0.15f, -2.f, -5.f); transform->Scale = glm::vec3(0.1f, 0.1f, 0.1f); transform->Sticky = true; std::shared_ptr lifeNr = m_World->AddComponent(life); lifeNr->Number = number; auto model = m_World->AddComponent(life); model->ModelFile = "Models/Test/Ball/Sid.obj"; m_World->CommitEntity(life); } bool dd::Systems::BallSystem::OnLifeLost(const dd::Events::LifeLost &event) { SetLives(Lives() - 1); return true; } bool dd::Systems::BallSystem::OnMultiBallLost(const dd::Events::MultiBallLost &event) { SetMultiBalls(MultiBalls() - 1); //std::cout << MultiBalls() << std::endl; if (MultiBalls() < 0) { auto ent = CreateBall(); SetMultiBalls(0); } return true; } bool dd::Systems::BallSystem::OnResetBall(const dd::Events::ResetBall &event) { SetReplaceBall(true); return true; } bool dd::Systems::BallSystem::OnMultiBall(const dd::Events::MultiBall &event) { auto ent1 = CreateBall(); auto ent2 = CreateBall(); auto transform1 = m_World->GetComponent(ent1); auto transform2 = m_World->GetComponent(ent2); auto ball1 = m_World->GetComponent(ent1); auto ball2 = m_World->GetComponent(ent2); ball1->Waiting = false; ball2->Waiting = false; auto padTransform = event.padTransform; float x1 = padTransform->Position.x/* - 2*/, x2 = padTransform->Position.x/* + 2*/; if (x1 < -m_EdgeX) { x1 = m_EdgeX - 0.2; } if (x2 > m_EdgeX) { x2 = -m_EdgeX + 0.2; } transform1->Position = glm::vec3(x1, -5.5, -10); transform2->Position = glm::vec3(x2, -5.5, -10); transform1->Velocity = glm::normalize(glm::vec3(5, 5 ,0.f)) * ball1->Speed; transform2->Velocity = glm::normalize(glm::vec3(-5, 5 ,0.f)) * ball2->Speed; SetMultiBalls(MultiBalls() + 2); //std::cout << MultiBalls() << std::endl; return true; } bool dd::Systems::BallSystem::OnStickyPad(const dd::Events::StickyPad &event) { m_Sticky = true; m_StickyCounter = 5; return true; } bool dd::Systems::BallSystem::OnInkBlaster(const dd::Events::InkBlaster &event) { m_InkBlaster = true; return true; } bool dd::Systems::BallSystem::OnActionButton(const dd::Events::ActionButton &event) { m_Waiting = false; return true; }