#include "PrecompiledHeader.h" #include "TankSteeringSystem.h" #include "World.h" void Systems::TankSteeringSystem::RegisterComponents( ComponentFactory* cf ) { cf->Register([]() { return new Components::TankSteering(); }); cf->Register([]() { return new Components::TowerSteering(); }); cf->Register([]() { return new Components::BarrelSteering(); }); } void Systems::TankSteeringSystem::Initialize() { EVENT_SUBSCRIBE_MEMBER(m_ECollision, &Systems::TankSteeringSystem::OnCollision); for (int i = 0; i < 4; i++) { m_TankInputControllers[i] = std::shared_ptr(new TankSteeringInputController(EventBroker, i + 1)); } } void Systems::TankSteeringSystem::Update(double dt) { for (int i = 0; i < 4; i++) { m_TankInputControllers[i]->Update(dt); } } void Systems::TankSteeringSystem::UpdateEntity(double dt, EntityID entity, EntityID parent) { auto tankSteeringComponent = m_World->GetComponent(entity); if(!tankSteeringComponent) return; auto playerComponent = m_World->GetComponent(entity); if (!playerComponent) return; if (playerComponent->ID == 0) return; auto inputController = m_TankInputControllers[playerComponent->ID - 1]; Events::TankSteer eSteering; eSteering.Entity = entity; eSteering.PositionX = inputController->PositionX; eSteering.PositionY = inputController->PositionY; eSteering.Handbrake = inputController->Handbrake; EventBroker->Publish(eSteering); auto towerSteeringComponent = m_World->GetComponent(tankSteeringComponent->Turret); auto barrelSteeringComponent = m_World->GetComponent(tankSteeringComponent->Barrel); if(towerSteeringComponent) { auto transformComponent = m_World->GetComponent(tankSteeringComponent->Turret); glm::quat orientation = glm::angleAxis(towerSteeringComponent->TurnSpeed * inputController->TowerDirection * (float)dt, towerSteeringComponent->Axis); transformComponent->Orientation *= orientation; } if(barrelSteeringComponent) { auto tankTransform = m_World->GetComponent(entity); auto transformComponent = m_World->GetComponent(tankSteeringComponent->Barrel); auto absoluteTransform = m_World->GetSystem()->AbsoluteTransform(tankSteeringComponent->Barrel); glm::quat orientation = glm::angleAxis(barrelSteeringComponent->TurnSpeed * inputController->BarrelDirection * (float)dt, barrelSteeringComponent->Axis); transformComponent->Orientation *= orientation; if(inputController->Shoot && m_TimeSinceLastShot[tankSteeringComponent->Barrel] > 0.5) { EntityID clone = m_World->CloneEntity(barrelSteeringComponent->ShotTemplate); auto templateAbsoluteTransform = m_World->GetSystem()->AbsoluteTransform(barrelSteeringComponent->ShotTemplate); auto cloneTransform = m_World->GetComponent(clone); cloneTransform->Position = templateAbsoluteTransform.Position; cloneTransform->Orientation = absoluteTransform.Orientation * cloneTransform->Orientation; Events::SetVelocity eSetVelocity; eSetVelocity.Entity = clone; eSetVelocity.Velocity = tankTransform->Velocity + absoluteTransform.Orientation * (glm::vec3(0.f, 0.f, -1.f) * barrelSteeringComponent->ShotSpeed); EventBroker->Publish(eSetVelocity); m_TimeSinceLastShot[tankSteeringComponent->Barrel] = 0; auto clonePhysicsComponent = m_World->GetComponent(clone); //1,670m/s //25kg Events::ApplyPointImpulse ePointImpulse ; ePointImpulse.Entity = entity; ePointImpulse.Position = absoluteTransform.Position; ePointImpulse.Impulse = glm::normalize(absoluteTransform.Orientation * glm::vec3(0, 0, 1)) * clonePhysicsComponent->Mass * 6.f * 1670.f; EventBroker->Publish(ePointImpulse); } m_TimeSinceLastShot[tankSteeringComponent->Barrel] += dt; } } bool Systems::TankSteeringSystem::OnCollision( const Events::Collision &e ) { if(m_World->ValidEntity(e.Entity1) && m_World->ValidEntity(e.Entity2)) { auto tankShell1 = m_World->GetComponent(e.Entity1); auto tankShell2 = m_World->GetComponent(e.Entity2); EntityID shellEntity = 0; Components::TankShell* shellComponent; EntityID otherEntity = 0; if (tankShell1) { shellEntity = e.Entity1; otherEntity = e.Entity2; shellComponent = tankShell1; } else if (tankShell2) { shellEntity = e.Entity2; otherEntity = e.Entity1; shellComponent = tankShell2; } else { return false; } if(m_World->GetComponent(shellEntity)) return false; auto physicsComponents = m_World->GetComponentsOfType(); auto shellTransform = m_World->GetComponent(shellEntity); //auto otherTransform = m_World->GetComponent(otherEntity); for (auto &physComponent : *physicsComponents) { EntityID physicsEntity = std::dynamic_pointer_cast(physComponent)->Entity; auto physEntityTransform = m_World->GetComponent(physicsEntity); float distance = glm::distance(physEntityTransform->Position, shellTransform->Position); if (distance <= shellComponent->ExplosionRadius) { // DO STUFF! :D float radius = shellComponent->ExplosionRadius; float strength = (1.f - pow(distance / radius, 2)) * shellComponent->ExplosionStrength; glm::vec3 direction = glm::normalize(physEntityTransform->Position - shellTransform->Position); Events::ApplyPointImpulse e; e.Entity = physicsEntity; e.Impulse = direction * strength; e.Position = physEntityTransform->Position; EventBroker->Publish(e); auto health = m_World->GetComponent(physicsEntity); if(health) { Events::Damage d; d.Entity = physicsEntity; d.Amount = (1.f - pow(distance / radius, 2)) * shellComponent->Damage; EventBroker->Publish(d); } m_World->RemoveEntity(shellEntity); } } //if(tankShell1) //{ // LOG_DEBUG("%i collided with %i", e.Entity1, e.Entity2); // auto transform = m_World->GetComponent(e.Entity1); // //m_World->GetSystem()->CreateExplosion(transform->Position, 1, 60, "Textures/Sprites/NewtonTreeDeleteASAPPlease.png", glm::angleAxis(glm::pi()/2, glm::vec3(1,0,0)), 40, glm::pi(), 0.5f); // glm::vec3 pointOfImpact = transform->Position; // { // auto ent = m_World->CreateEntity(); // LOG_DEBUG("Created trigger entity %i", ent); // auto transform = m_World->AddComponent(ent); // transform->Position = pointOfImpact; // auto trigger = m_World->AddComponent(ent); // trigger->TriggerOnce = true; // auto frameTimer = m_World->AddComponent(ent); // frameTimer->Frames = 100; // auto explosion = m_World->AddComponent(ent); // explosion->MaxVelocity = 50.f; // explosion->Radius = 30.f; // { // auto shape = m_World->CreateEntity(ent); // auto transformshape = m_World->AddComponent(shape); // auto sphere = m_World->AddComponent(shape); // sphere->Radius = 30.f; // m_World->CommitEntity(shape); // } // m_World->CommitEntity(ent); // } // // m_World->RemoveEntity(e.Entity1); //} //if(tankShell2) //{ // LOG_DEBUG("%i collided with %i", e.Entity1, e.Entity2); // auto transform = m_World->GetComponent(e.Entity2); // //m_World->GetSystem()->CreateExplosion(transform->Position, 1, 60, "Textures/Sprites/NewtonTreeDeleteASAPPlease.png", glm::angleAxis(glm::pi()/2, glm::vec3(1,0,0)), 40, glm::pi(), 0.5f); // glm::vec3 pointOfImpact = transform->Position; // { // auto ent = m_World->CreateEntity(); // LOG_DEBUG("Created trigger entity %i", ent); // auto transform = m_World->AddComponent(ent); // transform->Position = pointOfImpact; // auto trigger = m_World->AddComponent(ent); // trigger->TriggerOnce = true; // auto frameTimer = m_World->AddComponent(ent); // frameTimer->Frames = 100; // auto explosion = m_World->AddComponent(ent); // explosion->MaxVelocity = 50.f; // explosion->Radius = 30.f; // { // auto shape = m_World->CreateEntity(ent); // auto transformshape = m_World->AddComponent(shape); // auto sphere = m_World->AddComponent(shape); // sphere->Radius = 30.f; // m_World->CommitEntity(shape); // } // m_World->CommitEntity(ent); // } // m_World->RemoveEntity(e.Entity2); //} } return true; } void Systems::TankSteeringSystem::TankSteeringInputController::Update( double dt ) { PositionX = m_Horizontal; PositionY = m_Vertical; TowerDirection = m_TowerDirection; BarrelDirection = m_BarrelDirection; Shoot = m_Shoot; } bool Systems::TankSteeringSystem::TankSteeringInputController::OnCommand(const Events::InputCommand &event) { if (event.PlayerID != this->PlayerID) return false; float val = event.Value; // Tank if (event.Command == "horizontal") { m_Horizontal = val; } else if (event.Command == "vertical") { m_Vertical = -val; } else if (event.Command == "handbrake") { Handbrake = val > 0; } // Turret if(event.Command == "tower_rotation") { m_TowerDirection = -val; } else if(event.Command == "barrel_rotation") { m_BarrelDirection = val; } else if (event.Command == "shoot") { m_Shoot = val > 0; } else if(event.Command == "EnableCollisions") { Events::EnableCollisions e; e.Layer1 = 1; e.Layer2 = 2; EventBroker->Publish(e); } else if(event.Command == "DisableCollisions") { Events::DisableCollisions e; e.Layer1 = 1; e.Layer2 = 2; EventBroker->Publish(e); } return true; }