Skip to content
2 changes: 1 addition & 1 deletion Games/RType/Source/Core/Boss/BP_Boss.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ void BP_Boss::BeginPlay(void)
auto Box = GetComponent<UBoxCollisionComponent>("BoxCollision");
if (Box)
{
Box->SetHiddenInGame(false);
Box->SetHiddenInGame(true);
Box->SetBoxExtent(FVector3f(1.5f, 2.5f, 1.5f));
}
}
Expand Down
2 changes: 1 addition & 1 deletion Games/RType/Source/Core/Monsters/BP_Monster.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
62 changes: 61 additions & 1 deletion Games/RType/Source/Core/Player/BP_Player.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -62,7 +78,7 @@ void BP_Player::BeginPlay(void)
auto Box = GetComponent<UBoxCollisionComponent>("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));
Expand Down Expand Up @@ -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)
{
Expand All @@ -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)
{
Expand All @@ -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)
{
Expand Down
23 changes: 23 additions & 0 deletions Games/RType/Source/Core/Player/BP_Player.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ class BP_Player : public APawn
UFunction<> ServerFire; //<! Server RPC to handle firing
UFunction<FTransform> MulticastFire; //<! Multicast RPC to handle firing

UFunction<> ServerBeam; //<! Server RPC to handle beaming
UFunction<FTransform> MulticastBeam; //<! Multicast RPC to handle beaming

protected:
///////////////////////////////////////////////////////////////////////////
// Class Member
Expand Down Expand Up @@ -82,6 +85,12 @@ class BP_Player : public APawn
///////////////////////////////////////////////////////////////////////////
void Fire(void);

///////////////////////////////////////////////////////////////////////////
/// \brief Activate beam ability
///
///////////////////////////////////////////////////////////////////////////
void Beam(void);

///////////////////////////////////////////////////////////////////////////
/// \brief Move the player horizontally
///
Expand Down Expand Up @@ -136,6 +145,20 @@ class BP_Player : public APawn
///////////////////////////////////////////////////////////////////////////
void RPC_MulticastFire(FTransform transform);

///////////////////////////////////////////////////////////////////////////
/// \brief Server RPC to handle firing
///
///////////////////////////////////////////////////////////////////////////
void RPC_ServerBeam(void);

///////////////////////////////////////////////////////////////////////////
/// \brief Multicast RPC to handle firing
///
/// \param transform The transform to use for spawning the projectile
///
///////////////////////////////////////////////////////////////////////////
void RPC_MulticastBeam(FTransform transform);

public:
///////////////////////////////////////////////////////////////////////////
// Class metadata
Expand Down
12 changes: 12 additions & 0 deletions Games/RType/Source/Core/Player/BP_PlayerController.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,18 @@ void BP_PlayerController::SetupInputBindings(void)
}
);

BindActionPressed(
"Beam",
[player](EInput input)
{
if (player->IsLocallyControlled())
{
// Send RPC to server
player->Beam();
}
}
);

// Movement axes - handle in Tick for smooth prediction
// (See below)
}
Expand Down
123 changes: 123 additions & 0 deletions Games/RType/Source/Core/Weapons/BP_Beam.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
///////////////////////////////////////////////////////////////////////////////
// Dependencies
///////////////////////////////////////////////////////////////////////////////
#include <Core/Weapons/BP_Beam.hpp>
#include <Core/Boss/BP_Boss.hpp>
#include <Core/Monsters/BP_Monster.hpp>
#include <Core/Player/BP_Player.hpp>

///////////////////////////////////////////////////////////////////////////////
// Namespace tkd
///////////////////////////////////////////////////////////////////////////////
namespace tkd
{

///////////////////////////////////////////////////////////////////////////////
BP_Beam::BP_Beam(void)
: AActor("BP_Beam")
{
// Remove transform replication for projectiles
SetTransformReplicated(false);

// Add flipbook component
AddComponent<UBillboardComponent>("BC_BeamSprite");
AddComponent<UBoxCollisionComponent>("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<UBillboardComponent>("BC_BeamSprite");
if (Billboard)
{
Billboard->SetDisplayMode(UBillboardComponent::EDisplayMode::FlipBook);
Billboard->SetFlipBook(&m_chargeflipBook);
}

// Setup collision for the projectile
auto Collision = GetComponent<UBoxCollisionComponent>("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<BP_Player>()) { return; }

// Only destroy monsters
if (info.otherActor->Is<BP_Monster>())
{
// Mark both for deletion
info.otherActor->MarkForDeletion();
}
if (info.otherActor->Is<BP_Boss>())
{
auto boss = info.otherActor->As<BP_Boss>();
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<UBillboardComponent>("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
67 changes: 67 additions & 0 deletions Games/RType/Source/Core/Weapons/BP_Beam.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
///////////////////////////////////////////////////////////////////////////////
// Header guard
///////////////////////////////////////////////////////////////////////////////
#pragma once

///////////////////////////////////////////////////////////////////////////////
// Dependencies
///////////////////////////////////////////////////////////////////////////////
#include <Core/Weapons/FlipBooks/FB_Beam.hpp>
#include <Core/Weapons/FlipBooks/FB_BeamCharge.hpp>
#include <Engine.hpp>

///////////////////////////////////////////////////////////////////////////////
// Namespace tkd
///////////////////////////////////////////////////////////////////////////////
namespace tkd
{

///////////////////////////////////////////////////////////////////////////////
/// \brief
///
///////////////////////////////////////////////////////////////////////////////
class BP_Beam : public AActor
{
private:
///////////////////////////////////////////////////////////////////////////
// Class Member
///////////////////////////////////////////////////////////////////////////
FB_BeamCharge m_chargeflipBook; //<! The projectile's flipbook
FB_Beam m_beamFlipBook; //<! The beam's flipbook

public:
///////////////////////////////////////////////////////////////////////////
/// \brief Default constructor
///
///////////////////////////////////////////////////////////////////////////
BP_Beam(void);

public:
///////////////////////////////////////////////////////////////////////////
/// \brief Called when the object is first created
///
///////////////////////////////////////////////////////////////////////////
virtual void BeginPlay(void) override;

///////////////////////////////////////////////////////////////////////////
/// \brief Ticks the object
///
/// \param deltaTime The time elapsed since the last tick
///
///////////////////////////////////////////////////////////////////////////
virtual void Tick(Float32 deltaTime) override;

///////////////////////////////////////////////////////////////////////////
/// \brief Called when the object is being destroyed
///
///////////////////////////////////////////////////////////////////////////
// virtual void EndPlay(void) override;

public:
///////////////////////////////////////////////////////////////////////////
// Class metadata
///////////////////////////////////////////////////////////////////////////
DECLARE_CLASS_WITH_SUPER(BP_Beam, AActor)
};

} // namespace tkd
Loading