mirror of
https://github.com/KartKrewDev/RingRacers.git
synced 2025-12-20 06:53:00 +00:00
Add round end camera system
- Spins and zooms around a center point - Freezes the level while spinning - Pans over to follow and object after spinning ends - Timing and speed completely customizable
This commit is contained in:
parent
446f5d23f3
commit
7d6239e06c
8 changed files with 310 additions and 4 deletions
|
|
@ -157,6 +157,7 @@ add_executable(SRB2SDL2 MACOSX_BUNDLE WIN32
|
|||
k_dialogue.cpp
|
||||
k_tally.cpp
|
||||
k_bans.cpp
|
||||
k_endcam.cpp
|
||||
music.cpp
|
||||
music_manager.cpp
|
||||
)
|
||||
|
|
|
|||
197
src/k_endcam.cpp
Normal file
197
src/k_endcam.cpp
Normal file
|
|
@ -0,0 +1,197 @@
|
|||
// DR. ROBOTNIK'S RING RACERS
|
||||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) 2024 by James Robert Roman
|
||||
//
|
||||
// This program is free software distributed under the
|
||||
// terms of the GNU General Public License, version 2.
|
||||
// See the 'LICENSE' file for more details.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "archive_wrapper.hpp"
|
||||
|
||||
#include "byteptr.h"
|
||||
#include "doomdef.h"
|
||||
#include "doomtype.h"
|
||||
#include "g_game.h"
|
||||
#include "k_endcam.h"
|
||||
#include "m_easing.h"
|
||||
#include "p_local.h"
|
||||
#include "p_mobj.h"
|
||||
#include "p_saveg.h"
|
||||
#include "p_tick.h"
|
||||
#include "r_fps.h"
|
||||
#include "r_main.h"
|
||||
|
||||
endcam_t g_endcam;
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
fixed_t interval(tic_t t, tic_t d)
|
||||
{
|
||||
return (std::min(t, d) * FRACUNIT) / std::max(d, 1u);
|
||||
}
|
||||
|
||||
fixed_t interval(tic_t t, tic_t s, tic_t d)
|
||||
{
|
||||
return interval(std::max(t, s) - s, d);
|
||||
}
|
||||
|
||||
INT32 lerp(fixed_t f, INT32 a, INT32 b)
|
||||
{
|
||||
return a + FixedMul(f, b - a);
|
||||
}
|
||||
|
||||
struct Camera : camera_t
|
||||
{
|
||||
void pos(const vector3_t& p)
|
||||
{
|
||||
x = p.x;
|
||||
y = p.y;
|
||||
z = p.z;
|
||||
subsector = R_PointInSubsector(x, y);
|
||||
}
|
||||
};
|
||||
|
||||
struct EndCam : endcam_t
|
||||
{
|
||||
tic_t Time() const { return leveltime - begin; }
|
||||
bool Freezing() const { return Time() <= swirlDuration; }
|
||||
|
||||
void GC()
|
||||
{
|
||||
if (P_MobjWasRemoved(panMobj))
|
||||
{
|
||||
P_SetTarget(&panMobj, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
void Start()
|
||||
{
|
||||
active = true;
|
||||
begin = leveltime;
|
||||
|
||||
// Reset all viewpoints
|
||||
for (int i = 0; i < MAXSPLITSCREENPLAYERS; ++i)
|
||||
{
|
||||
Move(static_cast<Camera&>(camera[i]));
|
||||
}
|
||||
|
||||
R_ResetViewInterpolation(0);
|
||||
}
|
||||
|
||||
void Move(Camera& cam)
|
||||
{
|
||||
tic_t t = Time();
|
||||
fixed_t pan = Easing_OutQuint(interval(t, swirlDuration, panDuration), FRACUNIT, 0);
|
||||
|
||||
auto aim = [&](vector3_t& p, vector3_t& q)
|
||||
{
|
||||
cam.aiming = lerp(pan, cam.aiming, R_PointToAngle2(0, p.z, FixedHypot(q.x - p.x, q.y - p.y), q.z));
|
||||
cam.pos(p);
|
||||
};
|
||||
|
||||
if (t <= swirlDuration)
|
||||
{
|
||||
fixed_t swirl = interval(t, swirlDuration);
|
||||
|
||||
angle_t ang = FixedAngle(swirl < FRACUNIT/2 ?
|
||||
Easing_InOutQuint(swirl, startAngle, endAngle) :
|
||||
Easing_InOutQuad(swirl, startAngle, endAngle));
|
||||
|
||||
fixed_t hDist = Easing_OutQuad(swirl, startRadius.x, endRadius.x);
|
||||
|
||||
vector3_t p = {
|
||||
origin.x - FixedMul(FCOS(ang), hDist),
|
||||
origin.y - FixedMul(FSIN(ang), hDist),
|
||||
origin.z + Easing_OutQuad(swirl, startRadius.y, endRadius.y)
|
||||
};
|
||||
|
||||
aim(p, origin);
|
||||
cam.angle = ang;
|
||||
}
|
||||
else if (!P_MobjWasRemoved(panMobj))
|
||||
{
|
||||
vector3_t q = {panMobj->x, panMobj->y, P_GetMobjHead(panMobj)};
|
||||
vector3_t p = {cam.x, cam.y, cam.z};
|
||||
Follow(FixedMul(pan, panSpeed), p, q); // modifies p
|
||||
|
||||
aim(p, q);
|
||||
cam.angle = lerp(
|
||||
Easing_Linear(pan, FRACUNIT/4, FRACUNIT),
|
||||
cam.angle,
|
||||
R_PointToAngle2(p.x, p.y, q.x, q.y)
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void Archive(T&& ar)
|
||||
{
|
||||
static_assert(srb2::is_archive_wrapper_v<T>);
|
||||
#define X(T, var) SRB2_ARCHIVE_WRAPPER_CALL(ar, T, var)
|
||||
X(vector3_t, origin);
|
||||
X(vector2_t, startRadius);
|
||||
X(vector2_t, endRadius);
|
||||
X(tic_t, swirlDuration);
|
||||
X(fixed_t, startAngle);
|
||||
X(fixed_t, endAngle);
|
||||
// panMobj is handled in p_saveg.c
|
||||
X(tic_t, panDuration);
|
||||
X(fixed_t, panSpeed);
|
||||
X(bool, active);
|
||||
X(tic_t, begin);
|
||||
#undef X
|
||||
}
|
||||
|
||||
private:
|
||||
void Follow(fixed_t f, vector3_t& p, vector3_t q) const
|
||||
{
|
||||
FV3_Sub(&q, &p);
|
||||
q.x = FixedMul(q.x, f);
|
||||
q.y = FixedMul(q.y, f);
|
||||
q.z = FixedMul(q.z, f);
|
||||
|
||||
FV3_Add(&p, &q);
|
||||
}
|
||||
};
|
||||
|
||||
EndCam& endcam_cast()
|
||||
{
|
||||
return static_cast<EndCam&>(g_endcam);
|
||||
}
|
||||
|
||||
}; // namespace
|
||||
|
||||
void K_CommitEndCamera(void)
|
||||
{
|
||||
endcam_cast().Start();
|
||||
}
|
||||
|
||||
void K_MoveEndCamera(camera_t *thiscam)
|
||||
{
|
||||
endcam_cast().Move(static_cast<Camera&>(*thiscam));
|
||||
}
|
||||
|
||||
void K_EndCameraGC(void)
|
||||
{
|
||||
endcam_cast().GC();
|
||||
}
|
||||
|
||||
boolean K_EndCameraIsFreezing(void)
|
||||
{
|
||||
return endcam_cast().Freezing();
|
||||
}
|
||||
|
||||
void K_SaveEndCamera(savebuffer_t *save)
|
||||
{
|
||||
endcam_cast().Archive(srb2::ArchiveWrapper(save));
|
||||
}
|
||||
|
||||
void K_LoadEndCamera(savebuffer_t *save)
|
||||
{
|
||||
endcam_cast().Archive(srb2::UnArchiveWrapper(save));
|
||||
}
|
||||
74
src/k_endcam.h
Normal file
74
src/k_endcam.h
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
// DR. ROBOTNIK'S RING RACERS
|
||||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) 2024 by James Robert Roman
|
||||
//
|
||||
// This program is free software distributed under the
|
||||
// terms of the GNU General Public License, version 2.
|
||||
// See the 'LICENSE' file for more details.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef k_endcam_h
|
||||
#define k_endcam_h
|
||||
|
||||
#include "typedef.h"
|
||||
|
||||
#include "doomtype.h"
|
||||
#include "m_fixed.h"
|
||||
#include "tables.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct endcam_t
|
||||
{
|
||||
//
|
||||
// Configurable properties
|
||||
//
|
||||
|
||||
vector3_t origin; // center point
|
||||
vector2_t startRadius; // X = horizontal, Y = vertical
|
||||
vector2_t endRadius;
|
||||
|
||||
tic_t swirlDuration;
|
||||
fixed_t startAngle; // 180*FRACUNIT, NOT ANGLE_180
|
||||
fixed_t endAngle;
|
||||
|
||||
// 1) Camera pans vertically to keep this object centered
|
||||
// 2) After swirling ends, pan horizontally too
|
||||
mobj_t *panMobj;
|
||||
tic_t panDuration; // dropoff after swirling ends
|
||||
fixed_t panSpeed; // 0-FRACUNIT
|
||||
|
||||
/// ...
|
||||
|
||||
// You should not set these yourself.
|
||||
// Use K_CommitEndCamera.
|
||||
boolean active;
|
||||
tic_t begin; // leveltime
|
||||
};
|
||||
|
||||
extern endcam_t g_endcam;
|
||||
|
||||
// Sets endcam_t.active and endcam_t.begin.
|
||||
//
|
||||
// VERY IMPORTANT:
|
||||
//
|
||||
// Set the OTHER fields in endcam_t BEFORE calling this
|
||||
// function, so the camera can cut away cleanly.
|
||||
void K_CommitEndCamera(void);
|
||||
|
||||
/// ...
|
||||
|
||||
// Low-level functions
|
||||
void K_MoveEndCamera(camera_t *thiscam);
|
||||
void K_EndCameraGC(void);
|
||||
boolean K_EndCameraIsFreezing(void);
|
||||
void K_SaveEndCamera(savebuffer_t *save);
|
||||
void K_LoadEndCamera(savebuffer_t *save);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif/*k_endcam_h*/
|
||||
|
|
@ -47,6 +47,7 @@
|
|||
#include "g_party.h"
|
||||
#include "k_vote.h"
|
||||
#include "k_zvote.h"
|
||||
#include "k_endcam.h"
|
||||
|
||||
#include <tracy/tracy/TracyC.h>
|
||||
|
||||
|
|
@ -5745,6 +5746,12 @@ static void P_RelinkPointers(void)
|
|||
|
||||
P_LoadMobjPointers(RelinkMobjVoid);
|
||||
|
||||
if (g_endcam.panMobj)
|
||||
{
|
||||
if (!RelinkMobj(&g_endcam.panMobj))
|
||||
CONS_Debug(DBG_GAMELOGIC, "g_endcam.panMobj not found\n");
|
||||
}
|
||||
|
||||
// use info field (value = oldposition) to relink mobjs
|
||||
for (currentthinker = thlist[THINK_MOBJ].next; currentthinker != &thlist[THINK_MOBJ];
|
||||
currentthinker = currentthinker->next)
|
||||
|
|
@ -6868,6 +6875,9 @@ void P_SaveNetGame(savebuffer_t *save, boolean resending)
|
|||
}
|
||||
}
|
||||
|
||||
K_SaveEndCamera(save);
|
||||
WriteMobjPointer(g_endcam.panMobj);
|
||||
|
||||
P_NetArchivePlayers(save);
|
||||
P_NetArchiveParties(save);
|
||||
P_NetArchiveRoundQueue(save);
|
||||
|
|
@ -6933,6 +6943,9 @@ boolean P_LoadNetGame(savebuffer_t *save, boolean reloading)
|
|||
if (!P_NetUnArchiveMisc(save, reloading))
|
||||
return false;
|
||||
|
||||
K_LoadEndCamera(save);
|
||||
ReadMobjPointer(&g_endcam.panMobj);
|
||||
|
||||
P_NetUnArchivePlayers(save);
|
||||
P_NetUnArchiveParties(save);
|
||||
P_NetUnArchiveRoundQueue(save);
|
||||
|
|
|
|||
|
|
@ -115,6 +115,7 @@
|
|||
#include "music.h"
|
||||
#include "k_dialogue.h"
|
||||
#include "k_hud.h" // K_ClearPersistentMessages
|
||||
#include "k_endcam.h"
|
||||
|
||||
// Replay names have time
|
||||
#if !defined (UNDER_CE)
|
||||
|
|
@ -7696,6 +7697,8 @@ static void P_InitLevelSettings(void)
|
|||
|
||||
K_ResetSpecialStage();
|
||||
K_ResetBossInfo();
|
||||
|
||||
memset(&g_endcam, 0, sizeof g_endcam);
|
||||
}
|
||||
|
||||
#if 0
|
||||
|
|
|
|||
|
|
@ -48,6 +48,7 @@
|
|||
#include "k_dialogue.h"
|
||||
#include "m_easing.h"
|
||||
#include "k_hud.h" // messagetimer
|
||||
#include "k_endcam.h"
|
||||
|
||||
#include "lua_profile.h"
|
||||
|
||||
|
|
@ -65,12 +66,12 @@ static boolean g_freezeLevel;
|
|||
|
||||
boolean P_LevelIsFrozen(void)
|
||||
{
|
||||
return (g_freezeLevel || g_freezeCheat);
|
||||
return (g_freezeLevel || g_freezeCheat || K_EndCameraIsFreezing());
|
||||
}
|
||||
|
||||
boolean P_FreezeCheat(void)
|
||||
{
|
||||
return (g_freezeLevel || g_freezeCheat);
|
||||
return (g_freezeLevel || g_freezeCheat || K_EndCameraIsFreezing());
|
||||
}
|
||||
|
||||
void P_SetFreezeCheat(boolean value)
|
||||
|
|
@ -101,7 +102,7 @@ boolean P_MobjIsFrozen(mobj_t *mobj)
|
|||
}
|
||||
}
|
||||
|
||||
if (g_freezeLevel == true)
|
||||
if (g_freezeLevel == true || K_EndCameraIsFreezing())
|
||||
{
|
||||
// level totally frozen
|
||||
return true;
|
||||
|
|
@ -767,6 +768,8 @@ void P_RunChaseCameras(void)
|
|||
P_MoveChaseCamera(&players[displayplayers[i]], &camera[i], false);
|
||||
}
|
||||
}
|
||||
|
||||
K_EndCameraGC();
|
||||
}
|
||||
|
||||
static fixed_t P_GetDarkness(tic_t start, tic_t end)
|
||||
|
|
|
|||
14
src/p_user.c
14
src/p_user.c
|
|
@ -67,6 +67,7 @@
|
|||
#include "music.h"
|
||||
#include "k_tally.h"
|
||||
#include "k_objects.h"
|
||||
#include "k_endcam.h"
|
||||
|
||||
#ifdef HWRENDER
|
||||
#include "hardware/hw_light.h"
|
||||
|
|
@ -3062,6 +3063,11 @@ void P_ToggleDemoCamera(UINT8 viewnum)
|
|||
|
||||
void P_ResetCamera(player_t *player, camera_t *thiscam)
|
||||
{
|
||||
if (g_endcam.active)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
tic_t tries = 0;
|
||||
fixed_t x, y, z;
|
||||
|
||||
|
|
@ -3155,7 +3161,7 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall
|
|||
num = 0;
|
||||
}
|
||||
|
||||
if (thiscam->freecam || player->spectator)
|
||||
if ((thiscam->freecam || player->spectator) && !g_endcam.active)
|
||||
{
|
||||
P_DemoCameraMovement(thiscam, num);
|
||||
return true;
|
||||
|
|
@ -3164,6 +3170,12 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall
|
|||
if (paused || P_AutoPause())
|
||||
return true;
|
||||
|
||||
if (g_endcam.active)
|
||||
{
|
||||
K_MoveEndCamera(thiscam);
|
||||
return true;
|
||||
}
|
||||
|
||||
playerScale = FixedDiv(player->mo->scale, mapobjectscale);
|
||||
scaleDiff = playerScale - FRACUNIT;
|
||||
|
||||
|
|
|
|||
|
|
@ -190,6 +190,9 @@ TYPEDEF (botcontroller_t);
|
|||
// k_brightmap.h
|
||||
TYPEDEF (brightmapStorage_t);
|
||||
|
||||
// k_endcam.h
|
||||
TYPEDEF (endcam_t);
|
||||
|
||||
// k_follower.h
|
||||
TYPEDEF (follower_t);
|
||||
TYPEDEF (followercategory_t);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue