Player orbiting physics

This commit is contained in:
James R 2022-11-21 16:19:41 -08:00
parent e5a533544d
commit b3511a9149
6 changed files with 211 additions and 3 deletions

View file

@ -48,6 +48,7 @@ add_executable(SRB2SDL2 MACOSX_BUNDLE WIN32
p_floor.c
p_inter.c
p_lights.c
p_loop.c
p_map.c
p_maputl.c
p_mobj.c

View file

@ -193,6 +193,10 @@ boolean P_AutoPause(void);
void P_ElementalFire(player_t *player, boolean cropcircle);
void P_SpawnSkidDust(player_t *player, fixed_t radius, boolean sound);
void P_HaltPlayerOrbit(player_t *player);
void P_ExitPlayerOrbit(player_t *player);
boolean P_PlayerOrbit(player_t *player);
void P_MovePlayer(player_t *player);
void P_PlayerThink(player_t *player);
void P_PlayerAfterThink(player_t *player);

180
src/p_loop.c Normal file
View file

@ -0,0 +1,180 @@
// SONIC ROBO BLAST 2 KART
//-----------------------------------------------------------------------------
// Copyright (C) 2023 by Kart Krew
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
// See the 'LICENSE' file for more details.
//-----------------------------------------------------------------------------
/// \file p_loop.c
/// \brief Sonic loop physics
#include "doomdef.h"
#include "d_player.h"
#include "k_kart.h"
#include "p_local.h"
#include "p_setup.h"
#include "p_slopes.h"
#include "r_main.h"
static inline angle_t
get_pitch (fixed_t revolution)
{
return FixedAngle((revolution & FRACMASK) * 360);
}
static inline fixed_t
get_shift_curve (const sonicloopvars_t *s)
{
const angle_t th = get_pitch(FixedDiv(
s->revolution - s->min_revolution,
s->max_revolution - s->min_revolution));
// XY shift is transformed on wave scale; less movement
// at start and end of rotation, more halfway.
return FSIN((th / 2) - ANGLE_90);
}
void P_HaltPlayerOrbit(player_t *player)
{
// see P_PlayerOrbit
player->mo->flags &= ~(MF_NOCLIPHEIGHT);
player->loop.radius = 0;
}
void P_ExitPlayerOrbit(player_t *player)
{
sonicloopvars_t *s = &player->loop;
angle_t pitch = get_pitch(s->revolution);
angle_t yaw = s->yaw;
fixed_t co, si;
fixed_t speed;
if (s->radius < 0)
{
pitch += ANGLE_180;
}
co = FCOS(pitch);
si = FSIN(pitch);
speed = FixedMul(co, player->speed);
P_InstaThrust(player->mo, yaw, speed);
player->mo->momz = FixedMul(si, player->speed);
if (speed < 0)
{
yaw += ANGLE_180;
}
// excludes only extremely vertical angles
if (abs(co) * 4 > abs(si))
{
P_SetPlayerAngle(player, yaw);
}
if (s->flip)
{
player->mo->eflags ^= MFE_VERTICALFLIP;
player->mo->flags2 ^= MF2_OBJECTFLIP;
P_SetPitchRoll(player->mo,
pitch + ANGLE_180, s->yaw);
}
// tiregrease gives less friction, extends momentum
player->tiregrease = TICRATE;
P_HaltPlayerOrbit(player);
}
boolean P_PlayerOrbit(player_t *player)
{
sonicloopvars_t *s = &player->loop;
angle_t pitch;
fixed_t xy, z;
fixed_t xs, ys;
fixed_t step, th, left;
fixed_t grav;
if (s->radius == 0)
{
return false;
}
grav = abs(P_GetMobjGravity(player->mo));
// Lose speed on the way up. revolution = 0.5 always
// points straight up.
if (abs(s->revolution & FRACMASK) < FRACUNIT/2)
{
player->speed -= grav;
}
else
{
player->speed += 4 * grav;
}
pitch = get_pitch(s->revolution);
xy = FixedMul(abs(s->radius), FSIN(pitch));
z = FixedMul(abs(s->radius), -(FCOS(pitch)));
th = get_shift_curve(s);
xs = FixedMul(s->shift.x, th);
ys = FixedMul(s->shift.y, th);
xs += FixedMul(xy, FCOS(s->yaw));
ys += FixedMul(xy, FSIN(s->yaw));
P_MoveOrigin(player->mo,
s->origin.x + xs,
s->origin.y + ys,
s->origin.z + z);
// Match rollangle to revolution
P_SetPitchRoll(player->mo,
s->radius < 0 ? (ANGLE_180 + pitch) : pitch,
s->yaw);
// circumfrence = (2r)PI
step = FixedDiv(player->speed,
FixedMul(s->radius, M_TAU_FIXED));
left = (s->max_revolution - s->revolution);
if (abs(left) < abs(step))
{
P_ExitPlayerOrbit(player);
return false;
}
// If player slows down by too much, throw them out of
// the loop in a tumble.
if (player->speed < player->mo->scale)
{
P_HaltPlayerOrbit(player);
K_StumblePlayer(player);
return false;
}
s->revolution += step;
// We need to not clip the ground. It sucks but setting
// this flag is the only way to do that.
player->mo->flags |= (MF_NOCLIPHEIGHT);
return true;
}

View file

@ -2674,6 +2674,22 @@ fixed_t P_GetThingStepUp(mobj_t *thing, fixed_t destX, fixed_t destY)
return maxstep;
}
static boolean P_UsingStepUp(mobj_t *thing)
{
if (thing->flags & MF_NOCLIP)
{
return false;
}
// orbits have no collision
if (thing->player && thing->player->loop.radius)
{
return false;
}
return true;
}
static boolean
increment_move
( mobj_t * thing,
@ -2734,7 +2750,7 @@ increment_move
// copy into the spechitint buffer from spechit
spechitint_copyinto();
if (!(thing->flags & MF_NOCLIP))
if (P_UsingStepUp(thing))
{
// All things are affected by their scale.
fixed_t maxstep = P_GetThingStepUp(thing, tryx, tryy);

View file

@ -3979,7 +3979,8 @@ static void P_CheckFloatbobPlatforms(mobj_t *mobj)
static void P_SquishThink(mobj_t *mobj)
{
if (!(mobj->flags & MF_NOSQUISH) &&
!(mobj->eflags & MFE_SLOPELAUNCHED))
!(mobj->eflags & MFE_SLOPELAUNCHED) &&
!(mobj->player && mobj->player->loop.radius != 0))
{
K_Squish(mobj);
}
@ -4002,7 +4003,8 @@ static void P_PlayerMobjThinker(mobj_t *mobj)
// Zoom tube
if ((mobj->player->carry == CR_ZOOMTUBE && mobj->tracer && !P_MobjWasRemoved(mobj->tracer))
|| mobj->player->respawn.state == RESPAWNST_MOVE)
|| mobj->player->respawn.state == RESPAWNST_MOVE
|| mobj->player->loop.radius != 0)
{
P_HitSpecialLines(mobj, mobj->x, mobj->y, mobj->momx, mobj->momy);
P_UnsetThingPosition(mobj);

View file

@ -4227,6 +4227,11 @@ void P_PlayerThink(player_t *player)
P_DoZoomTube(player);
player->rmomx = player->rmomy = 0;
}
else if (player->loop.radius != 0)
{
P_PlayerOrbit(player);
player->rmomx = player->rmomy = 0;
}
else
{
// Move around.