diff --git a/Games/RType/Source/Core/Boss/BP_Boss.cpp b/Games/RType/Source/Core/Boss/BP_Boss.cpp index ea2ccd95..b96d1be5 100644 --- a/Games/RType/Source/Core/Boss/BP_Boss.cpp +++ b/Games/RType/Source/Core/Boss/BP_Boss.cpp @@ -48,7 +48,7 @@ void BP_Boss::BeginPlay(void) auto Box = GetComponent("BoxCollision"); if (Box) { - Box->SetHiddenInGame(false); + Box->SetHiddenInGame(true); Box->SetBoxExtent(FVector3f(1.5f, 2.5f, 1.5f)); } } diff --git a/Games/RType/Source/Core/Monsters/BP_Monster.cpp b/Games/RType/Source/Core/Monsters/BP_Monster.cpp index 750a1509..22e8dfa2 100644 --- a/Games/RType/Source/Core/Monsters/BP_Monster.cpp +++ b/Games/RType/Source/Core/Monsters/BP_Monster.cpp @@ -101,7 +101,7 @@ void BP_Monster::BeginPlay(void) if (Box) { FLogger::Debug("[BP_MONSTER] Setting up box collision component"); - Box->SetHiddenInGame(false); + Box->SetHiddenInGame(true); Box->SetBoxExtent(FVector3f(0.25f, 0.25f, 0.25f)); FTransform transform = Box->GetLocalTransform(); Box->SetLocalTransform(transform); diff --git a/Games/RType/Source/Core/Player/BP_Player.cpp b/Games/RType/Source/Core/Player/BP_Player.cpp index dd358b56..2850eb6e 100644 --- a/Games/RType/Source/Core/Player/BP_Player.cpp +++ b/Games/RType/Source/Core/Player/BP_Player.cpp @@ -32,6 +32,22 @@ BP_Player::BP_Player(UInt32 playerColor) ), true ) + , ServerBeam( + *this, + "ServerBeam", + ERPCType::Server, + std::bind(&BP_Player::RPC_ServerBeam, this), + true + ) + , MulticastBeam( + *this, + "MulticastBeam", + ERPCType::Multicast, + std::bind( + &BP_Player::RPC_MulticastBeam, this, std::placeholders::_1 + ), + true + ) , m_lastVelocity(FVector2f::Zero) , m_lastFiredTime(0.0f) , m_lastPosition(FVector3::Zero) @@ -62,7 +78,7 @@ void BP_Player::BeginPlay(void) auto Box = GetComponent("BoxCollision"); if (Box) { - Box->SetHiddenInGame(false); + Box->SetHiddenInGame(true); Box->SetBoxExtent(FVector3f(0.6f, 0.3f, 0.3f)); FTransform transform = Box->GetLocalTransform(); transform.SetPosition(FVector3(0.f, 0.f, 0.2f)); @@ -216,6 +232,18 @@ void BP_Player::Fire(void) } } +/////////////////////////////////////////////////////////////////////////////// +void BP_Player::Beam(void) +{ + if (IsLocallyControlled() && m_lastFiredTime >= 1.0f) + { + // Call the server RPC to handle beaming + this->ServerBeam(); + // Reset last fired time + m_lastFiredTime = 0.0f; + } +} + /////////////////////////////////////////////////////////////////////////////// void BP_Player::RPC_ServerFire(void) { @@ -237,6 +265,27 @@ void BP_Player::RPC_ServerFire(void) } } +/////////////////////////////////////////////////////////////////////////////// +void BP_Player::RPC_ServerBeam(void) +{ + if (IsAuthority() && m_lastFiredTime >= 1.0f) + { + // Reset last fired time + m_lastFiredTime = 0.0f; + + // Get player transform + FTransform transform = GetTransform(); + transform.SetRotation(FRotator(0.f, 0.f, 0.f)); + transform.SetScale(FVector3f::One); + + // Call multicast RPC to notify all clients + this->MulticastBeam(transform); + + // Spawn a beam + World::SpawnActor("BP_Beam", transform); + } +} + /////////////////////////////////////////////////////////////////////////////// void BP_Player::RPC_MulticastFire(FTransform transform) { @@ -248,6 +297,17 @@ void BP_Player::RPC_MulticastFire(FTransform transform) m_lastFiredTime = 0.0f; } +/////////////////////////////////////////////////////////////////////////////// +void BP_Player::RPC_MulticastBeam(FTransform transform) +{ + // Play beaming effects on all clients, + if (IsAuthority()) { return; } + + World::SpawnActor("BP_Beam", transform); + // Reset last fired time + m_lastFiredTime = 0.0f; +} + /////////////////////////////////////////////////////////////////////////////// void BP_Player::MoveHorizontal(Float32 value) { diff --git a/Games/RType/Source/Core/Player/BP_Player.hpp b/Games/RType/Source/Core/Player/BP_Player.hpp index 827b00c3..237651b1 100644 --- a/Games/RType/Source/Core/Player/BP_Player.hpp +++ b/Games/RType/Source/Core/Player/BP_Player.hpp @@ -34,6 +34,9 @@ class BP_Player : public APawn UFunction<> ServerFire; // MulticastFire; // ServerBeam; // MulticastBeam; //IsLocallyControlled()) + { + // Send RPC to server + player->Beam(); + } + } + ); + // Movement axes - handle in Tick for smooth prediction // (See below) } diff --git a/Games/RType/Source/Core/Weapons/BP_Beam.cpp b/Games/RType/Source/Core/Weapons/BP_Beam.cpp new file mode 100644 index 00000000..5fd0b4ca --- /dev/null +++ b/Games/RType/Source/Core/Weapons/BP_Beam.cpp @@ -0,0 +1,123 @@ +/////////////////////////////////////////////////////////////////////////////// +// Dependencies +/////////////////////////////////////////////////////////////////////////////// +#include +#include +#include +#include + +/////////////////////////////////////////////////////////////////////////////// +// Namespace tkd +/////////////////////////////////////////////////////////////////////////////// +namespace tkd +{ + +/////////////////////////////////////////////////////////////////////////////// +BP_Beam::BP_Beam(void) + : AActor("BP_Beam") +{ + // Remove transform replication for projectiles + SetTransformReplicated(false); + + // Add flipbook component + AddComponent("BC_BeamSprite"); + AddComponent("CC_BeamCollision"); +} + +/////////////////////////////////////////////////////////////////////////////// +void BP_Beam::BeginPlay(void) +{ + // Call parent BeginPlay first + Super::BeginPlay(); + + FTransform t = GetTransform(); + t.SetPosition(t.GetPosition() + FVector3(1.f, -0.3f, 0.f)); + SetTransform(t); + + // Set the flipbook for the projectile's billboard component + auto Billboard = GetComponent("BC_BeamSprite"); + if (Billboard) + { + Billboard->SetDisplayMode(UBillboardComponent::EDisplayMode::FlipBook); + Billboard->SetFlipBook(&m_chargeflipBook); + } + + // Setup collision for the projectile + auto Collision = GetComponent("CC_BeamCollision"); + if (Collision) + { + Collision->SetHiddenInGame(true); + Collision->SetBoxExtent(FVector3(0.20f, 0.20f, 0.40f)); + FTransform transform = Collision->GetLocalTransform(); + transform.SetPosition(FVector3(0.f, 0.f, 0.1f)); + Collision->SetLocalTransform(transform); + + auto* cs = Collision->GetCollisionSystem(); + if (cs) + { + cs->BindOnOverlapBegin( + Collision, + [this](const FCollisionInfo& info) + { + // Safety checks - validate all pointers before use + if (!info.otherActor) { return; } + if (!info.otherComponent) { return; } + + // Check if either actor is already marked for deletion + if (info.otherActor->IsMarkedForDeletion()) { return; } + if (this->IsMarkedForDeletion()) { return; } + + // Don't collide with players + if (info.otherActor->Is()) { return; } + + // Only destroy monsters + if (info.otherActor->Is()) + { + // Mark both for deletion + info.otherActor->MarkForDeletion(); + } + if (info.otherActor->Is()) + { + auto boss = info.otherActor->As(); + boss->TakeDamage(5); + this->MarkForDeletion(); + } + } + ); + } + } +} + +/////////////////////////////////////////////////////////////////////////////// +void BP_Beam::Tick(Float32 deltaTime) +{ + // Early exit if marked for deletion + if (IsMarkedForDeletion()) { return; } + + // Call Super Tick + Super::Tick(deltaTime); + + // Move the projectile forward + auto billboard = GetComponent("BC_BeamSprite"); + if (billboard) + { + auto fb = billboard->GetFlipBook(); + if (fb->HasFinished() || fb->GetName() == "FB_Beam") + { + if (fb->GetName() != "FB_Beam") + { + billboard->SetFlipBook(&m_beamFlipBook); + } + Translate(FVector3(8.0f * deltaTime, 0.0f, 0.0f)); + } + else { Translate(FVector3(0.0f * deltaTime, 0.0f, 0.0f)); } + } + + // If the projectile goes out of bounds, destroy it + if (GetTransform().GetPosition().x > 200.0f) { MarkForDeletion(); } +} + +/////////////////////////////////////////////////////////////////////////////// +IMPLEMENT_CLASS_WITH_SUPER(BP_Beam, AActor) + +} // namespace tkd diff --git a/Games/RType/Source/Core/Weapons/BP_Beam.hpp b/Games/RType/Source/Core/Weapons/BP_Beam.hpp new file mode 100644 index 00000000..5d526d28 --- /dev/null +++ b/Games/RType/Source/Core/Weapons/BP_Beam.hpp @@ -0,0 +1,67 @@ +/////////////////////////////////////////////////////////////////////////////// +// Header guard +/////////////////////////////////////////////////////////////////////////////// +#pragma once + +/////////////////////////////////////////////////////////////////////////////// +// Dependencies +/////////////////////////////////////////////////////////////////////////////// +#include +#include +#include + +/////////////////////////////////////////////////////////////////////////////// +// Namespace tkd +/////////////////////////////////////////////////////////////////////////////// +namespace tkd +{ + +/////////////////////////////////////////////////////////////////////////////// +/// \brief +/// +/////////////////////////////////////////////////////////////////////////////// +class BP_Beam : public AActor +{ +private: + /////////////////////////////////////////////////////////////////////////// + // Class Member + /////////////////////////////////////////////////////////////////////////// + FB_BeamCharge m_chargeflipBook; //("BC_ProjectileSprite"); if (Billboard) @@ -43,8 +47,8 @@ void BP_Projectile::BeginPlay(void) GetComponent("CC_ProjectileCollision"); if (Collision) { - Collision->SetHiddenInGame(false); - Collision->SetBoxExtent(FVector3(0.40f, 0.40f, 0.40f)); + Collision->SetHiddenInGame(true); + Collision->SetBoxExtent(FVector3(0.20f, 0.20f, 0.40f)); FTransform transform = Collision->GetLocalTransform(); transform.SetPosition(FVector3(0.f, 0.f, 0.1f)); Collision->SetLocalTransform(transform); @@ -96,7 +100,16 @@ void BP_Projectile::Tick(Float32 deltaTime) Super::Tick(deltaTime); // Move the projectile forward - Translate(FVector3(8.0f * deltaTime, 0.0f, 0.0f)); + auto billboard = GetComponent("BC_ProjectileSprite"); + if (billboard) + { + auto fb = billboard->GetFlipBook(); + if (fb->HasFinished()) + { + Translate(FVector3(8.0f * deltaTime, 0.0f, 0.0f)); + } + else { Translate(FVector3(0.0f * deltaTime, 0.0f, 0.0f)); } + } // If the projectile goes out of bounds, destroy it if (GetTransform().GetPosition().x > 200.0f) { MarkForDeletion(); } diff --git a/Games/RType/Source/Core/Weapons/FlipBooks/FB_Beam.cpp b/Games/RType/Source/Core/Weapons/FlipBooks/FB_Beam.cpp new file mode 100644 index 00000000..28b19a16 --- /dev/null +++ b/Games/RType/Source/Core/Weapons/FlipBooks/FB_Beam.cpp @@ -0,0 +1,26 @@ +/////////////////////////////////////////////////////////////////////////////// +// Dependencies +/////////////////////////////////////////////////////////////////////////////// +#include + +/////////////////////////////////////////////////////////////////////////////// +// Namespace tkd +/////////////////////////////////////////////////////////////////////////////// +namespace tkd +{ + +/////////////////////////////////////////////////////////////////////////////// +FB_Beam::FB_Beam(void) + : UFlipBook("FB_Beam", ESourceMode::FromSprite, EPlayMode::Loop) +{ + SetSpriteSheetPath("Assets/Images/T_Projectiles.png"); + AddFrame(FRectangle(199, 119, 34, 17)); + AddFrame(FRectangle(233, 119, 34, 17)); + SetDuration(0.2f); + SetPlaybackSpeed(1.f); +} + +/////////////////////////////////////////////////////////////////////////////// +IMPLEMENT_CLASS_WITH_SUPER(FB_Beam, UFlipBook) + +} // namespace tkd diff --git a/Games/RType/Source/Core/Weapons/FlipBooks/FB_Beam.hpp b/Games/RType/Source/Core/Weapons/FlipBooks/FB_Beam.hpp new file mode 100644 index 00000000..47b55952 --- /dev/null +++ b/Games/RType/Source/Core/Weapons/FlipBooks/FB_Beam.hpp @@ -0,0 +1,43 @@ +/////////////////////////////////////////////////////////////////////////////// +// Header guard +/////////////////////////////////////////////////////////////////////////////// +#pragma once + +/////////////////////////////////////////////////////////////////////////////// +// Dependencies +/////////////////////////////////////////////////////////////////////////////// +#include + +/////////////////////////////////////////////////////////////////////////////// +// Namespace tkd +/////////////////////////////////////////////////////////////////////////////// +namespace tkd +{ + +/////////////////////////////////////////////////////////////////////////////// +/// \brief Animation for the 'Beam' action +/// +/////////////////////////////////////////////////////////////////////////////// +class FB_Beam : public UFlipBook +{ +public: + /////////////////////////////////////////////////////////////////////////// + /// \brief Default constructor + /// + /////////////////////////////////////////////////////////////////////////// + FB_Beam(void); + + /////////////////////////////////////////////////////////////////////////// + /// \brief Default destructor + /// + /////////////////////////////////////////////////////////////////////////// + virtual ~FB_Beam() = default; + +public: + /////////////////////////////////////////////////////////////////////////// + // Class Declarations + /////////////////////////////////////////////////////////////////////////// + DECLARE_CLASS_WITH_SUPER(FB_Beam, UFlipBook) +}; + +} // namespace tkd diff --git a/Games/RType/Source/Core/Weapons/FlipBooks/FB_BeamCharge.cpp b/Games/RType/Source/Core/Weapons/FlipBooks/FB_BeamCharge.cpp new file mode 100644 index 00000000..bce02af4 --- /dev/null +++ b/Games/RType/Source/Core/Weapons/FlipBooks/FB_BeamCharge.cpp @@ -0,0 +1,32 @@ +/////////////////////////////////////////////////////////////////////////////// +// Dependencies +/////////////////////////////////////////////////////////////////////////////// +#include + +/////////////////////////////////////////////////////////////////////////////// +// Namespace tkd +/////////////////////////////////////////////////////////////////////////////// +namespace tkd +{ + +/////////////////////////////////////////////////////////////////////////////// +FB_BeamCharge::FB_BeamCharge(void) + : UFlipBook("FB_BeamCharge", ESourceMode::FromSprite, EPlayMode::Once) +{ + SetSpriteSheetPath("Assets/Images/T_Projectiles.png"); + AddFrame(FRectangle(0, 51, 33, 33)); + AddFrame(FRectangle(33, 51, 33, 33)); + AddFrame(FRectangle(66, 51, 33, 33)); + AddFrame(FRectangle(99, 51, 33, 33)); + AddFrame(FRectangle(132, 51, 33, 33)); + AddFrame(FRectangle(165, 51, 33, 33)); + AddFrame(FRectangle(198, 51, 33, 33)); + AddFrame(FRectangle(231, 51, 33, 33)); + SetDuration(1.f); + SetPlaybackSpeed(1.f); +} + +/////////////////////////////////////////////////////////////////////////////// +IMPLEMENT_CLASS_WITH_SUPER(FB_BeamCharge, UFlipBook) + +} // namespace tkd diff --git a/Games/RType/Source/Core/Weapons/FlipBooks/FB_BeamCharge.hpp b/Games/RType/Source/Core/Weapons/FlipBooks/FB_BeamCharge.hpp new file mode 100644 index 00000000..8ef0bd9a --- /dev/null +++ b/Games/RType/Source/Core/Weapons/FlipBooks/FB_BeamCharge.hpp @@ -0,0 +1,43 @@ +/////////////////////////////////////////////////////////////////////////////// +// Header guard +/////////////////////////////////////////////////////////////////////////////// +#pragma once + +/////////////////////////////////////////////////////////////////////////////// +// Dependencies +/////////////////////////////////////////////////////////////////////////////// +#include + +/////////////////////////////////////////////////////////////////////////////// +// Namespace tkd +/////////////////////////////////////////////////////////////////////////////// +namespace tkd +{ + +/////////////////////////////////////////////////////////////////////////////// +/// \brief Animation for the 'Beam' action +/// +/////////////////////////////////////////////////////////////////////////////// +class FB_BeamCharge : public UFlipBook +{ +public: + /////////////////////////////////////////////////////////////////////////// + /// \brief Default constructor + /// + /////////////////////////////////////////////////////////////////////////// + FB_BeamCharge(void); + + /////////////////////////////////////////////////////////////////////////// + /// \brief Default destructor + /// + /////////////////////////////////////////////////////////////////////////// + virtual ~FB_BeamCharge() = default; + +public: + /////////////////////////////////////////////////////////////////////////// + // Class Declarations + /////////////////////////////////////////////////////////////////////////// + DECLARE_CLASS_WITH_SUPER(FB_BeamCharge, UFlipBook) +}; + +} // namespace tkd diff --git a/Games/RType/Source/Core/Weapons/FlipBooks/FB_Projectile.cpp b/Games/RType/Source/Core/Weapons/FlipBooks/FB_Projectile.cpp index d7f97d20..03d01ba7 100644 --- a/Games/RType/Source/Core/Weapons/FlipBooks/FB_Projectile.cpp +++ b/Games/RType/Source/Core/Weapons/FlipBooks/FB_Projectile.cpp @@ -11,14 +11,13 @@ namespace tkd /////////////////////////////////////////////////////////////////////////////// FB_Projectile::FB_Projectile(void) - : UFlipBook("FB_Projectile", ESourceMode::FromSprite, EPlayMode::Loop) + : UFlipBook("FB_Projectile", ESourceMode::FromSprite, EPlayMode::Once) { SetSpriteSheetPath("Assets/Images/T_Projectiles.png"); - AddFrame(FRectangle(233, 17, 34, 34)); - AddFrame(FRectangle(199, 17, 34, 34)); - AddFrame(FRectangle(165, 17, 34, 34)); - AddFrame(FRectangle(131, 17, 34, 34)); - SetDuration(0.6f); + AddFrame(FRectangle(212, 85, 17, 17)); + AddFrame(FRectangle(229, 85, 17, 17)); + AddFrame(FRectangle(246, 85, 17, 17)); + SetDuration(0.2f); SetPlaybackSpeed(1.f); } diff --git a/Games/RType/Source/Levels/L_RType_Level1.cpp b/Games/RType/Source/Levels/L_RType_Level1.cpp index 8f30eab6..ed869634 100644 --- a/Games/RType/Source/Levels/L_RType_Level1.cpp +++ b/Games/RType/Source/Levels/L_RType_Level1.cpp @@ -15,12 +15,25 @@ L_RType_Level1::L_RType_Level1() { SetLevelName("L_RType_Level1"); SetGameMode("RTypeGameMode"); - AddActorEntry("BP_Player", "Player1", FTransform::Identity); AddActorEntry("BP_Background", "Background1", FTransform::Identity); - AddActorEntry("BP_Monster", "Monster1", FTransform::Identity); AddActorEntry( "BP_MonsterSpawner", "MonsterSpawner1", FTransform::Identity ); + FTransform spawnerTransform1; + spawnerTransform1.SetPosition(FVector3(2.6f, -3.4f, 0.0f)); + AddActorEntry("BP_MonsterSpawner", "MonsterSpawner2", spawnerTransform1); + FTransform spawnerTransform2; + spawnerTransform2.SetPosition(FVector3(1.1f, 4.4f, 0.0f)); + AddActorEntry("BP_MonsterSpawner", "MonsterSpawner3", spawnerTransform2); + FTransform spawnerTransform3; + spawnerTransform3.SetPosition(FVector3(5.7f, -0.1f, 0.0f)); + AddActorEntry("BP_MonsterSpawner", "MonsterSpawner4", spawnerTransform3); + FTransform spawnerTransform4; + spawnerTransform4.SetPosition(FVector3(-3.5f, 0.8f, 0.0f)); + AddActorEntry("BP_MonsterSpawner", "MonsterSpawner5", spawnerTransform4); + FTransform spawnerTransform5; + spawnerTransform5.SetPosition(FVector3(-6.7f, -1.1f, 0.0f)); + AddActorEntry("BP_MonsterSpawner", "MonsterSpawner5", spawnerTransform5); } /////////////////////////////////////////////////////////////////////////////// diff --git a/Games/RType/Source/Levels/L_RType_Level2.cpp b/Games/RType/Source/Levels/L_RType_Level2.cpp index 64e5d826..8ce2b3d5 100644 --- a/Games/RType/Source/Levels/L_RType_Level2.cpp +++ b/Games/RType/Source/Levels/L_RType_Level2.cpp @@ -15,7 +15,6 @@ L_RType_Level2::L_RType_Level2() { SetLevelName("L_RType_Level2"); SetGameMode("RTypeGameMode"); - AddActorEntry("BP_Player", "Player1", FTransform::Identity); AddActorEntry("BP_Background", "Background1", FTransform::Identity); AddActorEntry("BP_Boss", "Boss1", FTransform::Identity); } diff --git a/Games/RType/Source/Settings.hpp b/Games/RType/Source/Settings.hpp index 64682f92..1d6f9123 100644 --- a/Games/RType/Source/Settings.hpp +++ b/Games/RType/Source/Settings.hpp @@ -70,7 +70,10 @@ static const FEngineSettings RTYPE_ENGINE_SETTINGS = { // tkd::EInput::Mouse_Left, /* Disable for UI */ tkd::EInput::GamePadAxis_RightTrigger, tkd::EInput::Keyboard_Space - } } + } }, + { "Beam", { + tkd::EInput::Keyboard_LControl, + } }, }, .inputAxes = { { "HorizontalMoves", {