Show name bubble on local player in 3rd person camera

This commit is contained in:
Christian Semmler 2026-03-08 09:53:24 -07:00
parent dd56e6c686
commit 1fe1b732e0
No known key found for this signature in database
GPG Key ID: 086DAA1360BEEE5C
3 changed files with 80 additions and 1 deletions

View File

@ -21,6 +21,8 @@ class LegoAnim;
namespace Multiplayer namespace Multiplayer
{ {
class NameBubbleRenderer;
class ThirdPersonCamera { class ThirdPersonCamera {
public: public:
ThirdPersonCamera(); ThirdPersonCamera();
@ -52,6 +54,8 @@ class ThirdPersonCamera {
void StopClickAnimation(); void StopClickAnimation();
bool IsInVehicle() const { return m_currentVehicleType != VEHICLE_NONE; } bool IsInVehicle() const { return m_currentVehicleType != VEHICLE_NONE; }
void SetNameBubbleVisible(bool p_visible);
void OnWorldEnabled(LegoWorld* p_world); void OnWorldEnabled(LegoWorld* p_world);
void OnWorldDisabled(LegoWorld* p_world); void OnWorldDisabled(LegoWorld* p_world);
@ -76,6 +80,9 @@ class ThirdPersonCamera {
void ApplyIdleFrame0(); void ApplyIdleFrame0();
void ReinitForCharacter(); void ReinitForCharacter();
void CreateNameBubble();
void DestroyNameBubble();
bool EnsureDisplayROI(); bool EnsureDisplayROI();
void CreateDisplayClone(); void CreateDisplayClone();
void DestroyDisplayClone(); void DestroyDisplayClone();
@ -121,6 +128,9 @@ class ThirdPersonCamera {
std::map<std::string, AnimCache> m_animCacheMap; std::map<std::string, AnimCache> m_animCacheMap;
NameBubbleRenderer* m_nameBubble;
bool m_showNameBubble;
// Orbit camera state // Orbit camera state
float m_orbitYaw; float m_orbitYaw;
float m_orbitPitch; float m_orbitPitch;

View File

@ -263,6 +263,7 @@ void NetworkManager::ProcessPendingRequests()
for (auto& [peerId, player] : m_remotePlayers) { for (auto& [peerId, player] : m_remotePlayers) {
player->SetNameBubbleVisible(m_showNameBubbles); player->SetNameBubbleVisible(m_showNameBubbles);
} }
m_thirdPersonCamera.SetNameBubbleVisible(m_showNameBubbles);
} }
} }

View File

@ -4,6 +4,7 @@
#include "anim/legoanim.h" #include "anim/legoanim.h"
#include "extensions/multiplayer/charactercloner.h" #include "extensions/multiplayer/charactercloner.h"
#include "extensions/multiplayer/charactercustomizer.h" #include "extensions/multiplayer/charactercustomizer.h"
#include "extensions/multiplayer/namebubblerenderer.h"
#include "islepathactor.h" #include "islepathactor.h"
#include "legogamestate.h" #include "legogamestate.h"
#include "legoanimpresenter.h" #include "legoanimpresenter.h"
@ -42,7 +43,8 @@ ThirdPersonCamera::ThirdPersonCamera()
m_walkAnimCache(nullptr), m_idleAnimCache(nullptr), m_animTime(0.0f), m_idleTime(0.0f), m_idleAnimTime(0.0f), m_walkAnimCache(nullptr), m_idleAnimCache(nullptr), m_animTime(0.0f), m_idleTime(0.0f), m_idleAnimTime(0.0f),
m_wasMoving(false), m_emoteAnimCache(nullptr), m_emoteTime(0.0f), m_emoteDuration(0.0f), m_emoteActive(false), m_wasMoving(false), m_emoteAnimCache(nullptr), m_emoteTime(0.0f), m_emoteDuration(0.0f), m_emoteActive(false),
m_clickAnimObjectId(0), m_currentVehicleType(VEHICLE_NONE), m_rideAnim(nullptr), m_rideRoiMap(nullptr), m_clickAnimObjectId(0), m_currentVehicleType(VEHICLE_NONE), m_rideAnim(nullptr), m_rideRoiMap(nullptr),
m_rideRoiMapSize(0), m_rideVehicleROI(nullptr), m_orbitYaw(DEFAULT_ORBIT_YAW), m_rideRoiMapSize(0), m_rideVehicleROI(nullptr), m_nameBubble(nullptr), m_showNameBubble(true),
m_orbitYaw(DEFAULT_ORBIT_YAW),
m_orbitPitch(DEFAULT_ORBIT_PITCH), m_orbitDistance(DEFAULT_ORBIT_DISTANCE), m_touch{} m_orbitPitch(DEFAULT_ORBIT_PITCH), m_orbitDistance(DEFAULT_ORBIT_DISTANCE), m_touch{}
{ {
SDL_memset(m_displayUniqueName, 0, sizeof(m_displayUniqueName)); SDL_memset(m_displayUniqueName, 0, sizeof(m_displayUniqueName));
@ -94,6 +96,7 @@ void ThirdPersonCamera::Disable()
} }
m_active = false; m_active = false;
DestroyNameBubble();
DestroyDisplayClone(); DestroyDisplayClone();
ClearRideAnimation(); ClearRideAnimation();
m_animCacheMap.clear(); m_animCacheMap.clear();
@ -133,6 +136,7 @@ void ThirdPersonCamera::OnActorEnter(IslePathActor* p_actor)
m_playerROI->SetVisibility(FALSE); m_playerROI->SetVisibility(FALSE);
VideoManager()->Get3DManager()->Remove(*m_playerROI); VideoManager()->Get3DManager()->Remove(*m_playerROI);
} }
DestroyNameBubble();
m_active = false; m_active = false;
return; return;
} }
@ -151,6 +155,7 @@ void ThirdPersonCamera::OnActorEnter(IslePathActor* p_actor)
m_active = true; m_active = true;
SetupCamera(userActor); SetupCamera(userActor);
BuildRideAnimation(m_currentVehicleType); BuildRideAnimation(m_currentVehicleType);
CreateNameBubble();
return; return;
} }
@ -187,6 +192,7 @@ void ThirdPersonCamera::OnActorEnter(IslePathActor* p_actor)
ApplyIdleFrame0(); ApplyIdleFrame0();
SetupCamera(userActor); SetupCamera(userActor);
CreateNameBubble();
} }
void ThirdPersonCamera::OnActorExit(IslePathActor* p_actor) void ThirdPersonCamera::OnActorExit(IslePathActor* p_actor)
@ -216,6 +222,7 @@ void ThirdPersonCamera::OnActorExit(IslePathActor* p_actor)
} }
else if (m_active && static_cast<LegoPathActor*>(p_actor) == UserActor()) { else if (m_active && static_cast<LegoPathActor*>(p_actor) == UserActor()) {
// Exiting on foot: full teardown. // Exiting on foot: full teardown.
DestroyNameBubble();
if (m_playerROI) { if (m_playerROI) {
m_playerROI->SetVisibility(FALSE); m_playerROI->SetVisibility(FALSE);
VideoManager()->Get3DManager()->Remove(*m_playerROI); VideoManager()->Get3DManager()->Remove(*m_playerROI);
@ -260,6 +267,10 @@ void ThirdPersonCamera::Tick(float p_deltaTime)
// Update orbit camera position each frame so it tracks the player // Update orbit camera position each frame so it tracks the player
ApplyOrbitCamera(); ApplyOrbitCamera();
if (m_nameBubble) {
m_nameBubble->Update(m_playerROI);
}
// Small vehicle with ride animation (like RemotePlayer) // Small vehicle with ride animation (like RemotePlayer)
if (m_currentVehicleType != VEHICLE_NONE) { if (m_currentVehicleType != VEHICLE_NONE) {
StopClickAnimation(); StopClickAnimation();
@ -524,6 +535,7 @@ void ThirdPersonCamera::OnWorldDisabled(LegoWorld* p_world)
m_active = false; m_active = false;
m_roiUnflipped = false; m_roiUnflipped = false;
m_playerROI = nullptr; m_playerROI = nullptr;
DestroyNameBubble();
DestroyDisplayClone(); DestroyDisplayClone();
ClearRideAnimation(); ClearRideAnimation();
m_animCacheMap.clear(); m_animCacheMap.clear();
@ -650,6 +662,58 @@ void ThirdPersonCamera::DestroyDisplayClone()
} }
} }
void ThirdPersonCamera::CreateNameBubble()
{
if (m_nameBubble) {
return;
}
char name[8] = {};
LegoGameState* gs = GameState();
if (gs && gs->m_playerCount > 0) {
const LegoGameState::Username& username = gs->m_players[0];
for (int i = 0; i < 7; i++) {
MxS16 letter = username.m_letters[i];
if (letter < 0) {
break;
}
if (letter <= 25) {
name[i] = (char) ('A' + letter);
}
else {
name[i] = '?';
}
}
}
if (name[0] == '\0') {
return;
}
m_nameBubble = new NameBubbleRenderer();
m_nameBubble->Create(name);
if (!m_showNameBubble) {
m_nameBubble->SetVisible(false);
}
}
void ThirdPersonCamera::DestroyNameBubble()
{
if (m_nameBubble) {
delete m_nameBubble;
m_nameBubble = nullptr;
}
}
void ThirdPersonCamera::SetNameBubbleVisible(bool p_visible)
{
m_showNameBubble = p_visible;
if (m_nameBubble) {
m_nameBubble->SetVisible(p_visible);
}
}
void ThirdPersonCamera::ClearRideAnimation() void ThirdPersonCamera::ClearRideAnimation()
{ {
if (m_rideRoiMap) { if (m_rideRoiMap) {
@ -847,6 +911,8 @@ void ThirdPersonCamera::HandleSDLEvent(SDL_Event* p_event)
void ThirdPersonCamera::ReinitForCharacter() void ThirdPersonCamera::ReinitForCharacter()
{ {
DestroyNameBubble();
LegoPathActor* userActor = UserActor(); LegoPathActor* userActor = UserActor();
if (!userActor) { if (!userActor) {
m_active = false; m_active = false;
@ -898,6 +964,7 @@ void ThirdPersonCamera::ReinitForCharacter()
m_active = true; m_active = true;
SetupCamera(userActor); SetupCamera(userActor);
BuildRideAnimation(vehicleType); BuildRideAnimation(vehicleType);
CreateNameBubble();
return; return;
} }
@ -940,4 +1007,5 @@ void ThirdPersonCamera::ReinitForCharacter()
ApplyIdleFrame0(); ApplyIdleFrame0();
SetupCamera(userActor); SetupCamera(userActor);
CreateNameBubble();
} }