📄 g_phys.cpp
字号:
Bmodel objects don't interact with each other, but
push all box objects
================
*/
void G_Physics_Pusher
(
Entity *ent
)
{
Vector move, amove;
Entity *part, *mv;
Event *ev;
// team slaves are only moved by their captains
if ( ent->flags & FL_TEAMSLAVE )
{
return;
}
// Check if anyone on the team is moving
for( part = ent; part; part = part->teamchain )
{
if ( part->velocity != vec_zero || part->avelocity != vec_zero )
{
break;
}
}
// make sure all team slaves can move before commiting
// any moves or calling any think functions
// if the move is blocked, all moved objects will be backed out
pushed_p = pushed;
while( part )
{
move = part->velocity * FRAMETIME;
amove = part->avelocity * FRAMETIME;
if ( !G_Push( part, move, amove ) )
{
// move was blocked
break;
}
part = part->teamchain;
}
if ( part )
{
// the move failed, bump all movedone times
for( mv = ent; mv; mv = mv->teamchain )
{
mv->PostponeEvent( EV_MoveDone, FRAMETIME );
}
// if the pusher has a "blocked" function, call it
// otherwise, just stay in place until the obstacle is gone
ev = new Event( EV_Blocked );
ev->AddEntity( obstacle );
part->ProcessEvent( ev );
}
}
//==================================================================
/*
=============
G_Physics_Noclip
A moving object that doesn't obey physics
=============
*/
void G_Physics_Noclip
(
Entity *ent
)
{
ent->angles += ent->avelocity * FRAMETIME;
ent->origin += ent->velocity * FRAMETIME;
ent->link();
}
/*
==============================================================================
TOSS / BOUNCE
==============================================================================
*/
/*
=============
G_Physics_Toss
Toss, bounce, and fly movement. When onground, do nothing.
=============
*/
void G_Physics_Toss
(
Entity *ent
)
{
trace_t trace;
Vector move;
float backoff;
Entity *slave;
qboolean wasinwater;
qboolean isinwater;
Vector old_origin;
Vector basevel;
edict_t *edict;
qboolean onconveyor;
const gravityaxis_t &grav = gravity_axis[ ent->gravaxis ];
// if not a team captain, so movement will be handled elsewhere
if ( ent->flags & FL_TEAMSLAVE )
{
return;
}
if ( ( ent->velocity[ grav.z ] * grav.sign ) > 0 )
{
ent->groundentity = NULL;
}
// check for the groundentity going away
if ( ent->groundentity && !ent->groundentity->inuse )
{
ent->groundentity = NULL;
}
G_AddCurrents( ent, &basevel );
onconveyor = ( basevel != vec_zero );
// if onground, return without moving
if ( ent->groundentity && !onconveyor && ( ent->movetype != MOVETYPE_VEHICLE ) )
{
if ( ent->avelocity.length() )
{
// move angles
ent->setAngles( ent->angles + ent->avelocity * FRAMETIME );
}
ent->velocity = vec_zero;
return;
}
old_origin = ent->origin;
G_CheckVelocity( ent );
// add gravity
if ( !onconveyor && ent->movetype != MOVETYPE_FLY && ent->movetype != MOVETYPE_FLYMISSILE )
{
G_AddGravity( ent );
}
// move angles
ent->setAngles( ent->angles + ent->avelocity * FRAMETIME );
// move origin
move = ( ent->velocity + basevel ) * FRAMETIME;
edict = ent->edict;
if ( ent->movetype == MOVETYPE_VEHICLE )
{
int mask;
if ( ent->edict->clipmask )
{
mask = ent->edict->clipmask;
}
else
{
mask = MASK_MONSTERSOLID;
}
G_FlyMove( ent, basevel, FRAMETIME, mask );
G_TouchTriggers( ent );
return;
}
else
{
trace = G_PushEntity( ent, move );
}
if ( (trace.fraction == 0) && (ent->movetype == MOVETYPE_SLIDE) )
{
// Check for slide by removing the downward velocity
Vector slide;
slide[ grav.x ] = move[ grav.x ] * 0.7f;
slide[ grav.y ] = move[ grav.y ] * 0.7f;
slide[ grav.z ] = 0;
G_PushEntity( ent, slide );
}
if ( !edict->inuse )
{
return;
}
if ( trace.fraction < 1 )
{
if ( ent->movetype == MOVETYPE_BOUNCE )
{
backoff = 1.5;
}
else
{
backoff = 1;
}
G_ClipVelocity( ent->velocity, Vector( trace.plane.normal ), ent->velocity, backoff, ent->gravaxis );
// stop if on ground
if ( ( trace.plane.normal[ grav.z ] * grav.sign ) > 0.7 )
{
if (( ( ent->velocity[ grav.z ] * grav.sign ) < 60 || ent->movetype != MOVETYPE_BOUNCE ) &&
(ent->movetype != MOVETYPE_SLIDE))
{
ent->groundentity = trace.ent;
ent->groundentity_linkcount = trace.ent->linkcount;
ent->groundplane = trace.plane;
ent->groundsurface = trace.surface;
ent->groundcontents = trace.contents;
ent->velocity = vec_zero;
ent->avelocity = vec_zero;
}
}
}
if ( ( move[ grav.z ] == 0 ) && onconveyor )
{
// Check if we still have a ground
ent->CheckGround();
}
// check for water transition
wasinwater = ( ent->watertype & MASK_WATER );
ent->watertype = gi.pointcontents( ent->worldorigin.vec3() );
isinwater = ent->watertype & MASK_WATER;
if ( isinwater )
{
ent->waterlevel = 1;
}
else
{
ent->waterlevel = 0;
}
if ( ( edict->spawntime < ( level.time - FRAMETIME ) ) && ( ent->mass > 0 ) )
{
if ( !wasinwater && isinwater )
{
#ifdef SIN
ent->RandomPositionedSound( old_origin.vec3(), "impact_watersplash" );
#else
gi.positioned_sound( old_origin.vec3(), g_edicts, CHAN_AUTO,
gi.soundindex( "misc/h2ohit1.wav" ), 1, 1, 0, 1, 0, 0 );
#endif
}
else if ( wasinwater && !isinwater )
{
#ifdef SIN
ent->RandomPositionedSound( old_origin.vec3(), "impact_watersplash" );
#else
gi.positioned_sound( old_origin.vec3(), g_edicts, CHAN_AUTO,
gi.soundindex( "misc/h2ohit1.wav" ), 1, 1, 0, 1, 0, 0 );
#endif
}
}
// move teamslaves
for( slave = ent->teamchain; slave; slave = slave->teamchain )
{
slave->origin = ent->origin;
slave->link();
}
G_TouchTriggers( ent );
}
/*
===============================================================================
STEPPING MOVEMENT
===============================================================================
*/
void G_AddRotationalFriction
(
Entity *ent
)
{
int n;
float adjustment;
ent->angles += FRAMETIME * ent->avelocity;
adjustment = FRAMETIME * sv_stopspeed->value * sv_friction->value;
for( n = 0; n < 3; n++ )
{
if ( ent->avelocity[ n ] > 0)
{
ent->avelocity[ n ] -= adjustment;
if ( ent->avelocity[ n ] < 0 )
{
ent->avelocity[ n ] = 0;
}
}
else
{
ent->avelocity[ n ] += adjustment;
if ( ent->avelocity[ n ] > 0 )
{
ent->avelocity[ n ] = 0;
}
}
}
}
/*
=============
G_CheckWater
=============
*/
void G_CheckWater
(
Entity *ent
)
{
if ( ent->isSubclassOf( Actor ) )
{
( ( Actor * )ent )->CheckWater();
}
else
{
ent->watertype = gi.pointcontents( ent->worldorigin.vec3() );
if ( ent->watertype & MASK_WATER )
{
ent->waterlevel = 1;
}
else
{
ent->waterlevel = 0;
}
}
}
/*
=============
G_Physics_Step
Monsters freefall when they don't have a ground entity, otherwise
all movement is done with discrete steps.
This is also used for objects that have become still on the ground, but
will fall if the floor is pulled out from under them.
FIXME: is this true?
=============
*/
void G_Physics_Step
(
Entity *ent
)
{
qboolean wasonground;
qboolean hitsound = false;
Vector vel;
float speed, newspeed, control;
float friction;
int mask;
Vector basevel;
// airborn monsters should always check for ground
if ( !ent->groundentity )
{
ent->CheckGround();
}
if ( ent->groundentity )
{
wasonground = true;
}
else
{
wasonground = false;
}
G_CheckVelocity( ent );
if ( ent->avelocity != vec_zero )
{
G_AddRotationalFriction( ent );
}
// add gravity except:
// flying monsters
// swimming monsters who are in the water
if ( !wasonground )
{
if ( !( ent->flags & FL_FLY ) )
{
if ( !( ( ent->flags & FL_SWIM ) && ( ent->waterlevel > 2 ) ) )
{
if ( ent->velocity[ gravity_axis[ ent->gravaxis ].z ] < sv_gravity->value * ent->gravity * -0.1 *
gravity_axis[ ent->gravaxis ].sign )
{
hitsound = true;
}
// Testing water gravity. If this doesn't work, just restore the uncommented lines
//if ( ent->waterlevel == 0 )
//{
G_AddGravity( ent );
//}
}
}
}
// friction for flying monsters that have been given vertical velocity
if ( ( ent->flags & FL_FLY ) && ( ent->velocity.z != 0 ) )
{
speed = fabs( ent->velocity.z );
control = speed < sv_stopspeed->value ? sv_stopspeed->value : speed;
friction = sv_friction->value / 3;
newspeed = speed - ( FRAMETIME * control * friction );
if ( newspeed < 0 )
{
newspeed = 0;
}
newspeed /= speed;
ent->velocity.z *= newspeed;
}
// friction for flying monsters that have been given vertical velocity
if ( ( ent->flags & FL_SWIM ) && ( ent->velocity.z != 0 ) )
{
speed = fabs( ent->velocity.z );
control = speed < sv_stopspeed->value ? sv_stopspeed->value : speed;
newspeed = speed - ( FRAMETIME * control * sv_waterfriction->value * ent->waterlevel );
if ( newspeed < 0 )
{
newspeed = 0;
}
newspeed /= speed;
ent->velocity.z *= newspeed;
}
if ( ent->velocity != vec_zero )
{
// apply friction
// let dead monsters who aren't completely onground slide
if ( ( wasonground ) || ( ent->flags & ( FL_SWIM | FL_FLY ) ) )
{
if ( !( ent->health <= 0.0 && !M_CheckBottom( ent ) ) )
{
vel = ent->velocity;
vel.z = 0;
speed = vel.length();
if ( speed )
{
friction = sv_friction->value;
control = speed < sv_stopspeed->value ? sv_stopspeed->value : speed;
newspeed = speed - FRAMETIME * control * friction;
if ( newspeed < 0 )
{
newspeed = 0;
}
newspeed /= speed;
ent->velocity.x *= newspeed;
ent->velocity.y *= newspeed;
}
}
}
}
G_AddCurrents( ent, &basevel );
if ( ( basevel != vec_zero ) || ( ent->velocity != vec_zero ) || ( ent->total_delta != vec_zero ) )
{
if ( ent->edict->svflags & SVF_MONSTER )
{
mask = MASK_MONSTERSOLID;
}
else
{
mask = MASK_SOLID;
}
G_FlyMove( ent, basevel, FRAMETIME, mask );
ent->link();
G_CheckWater( ent );
G_TouchTriggers( ent );
if ( ent->groundentity && !wasonground && hitsound )
{
ent->RandomGlobalSound( "impact_softland", 0.5f, CHAN_BODY, 1 );
}
}
}
//============================================================================
/*
================
G_RunEntity
================
*/
void G_RunEntity
(
Entity *ent
)
{
edict_t *edict;
edict = ent->edict;
if ( ent->animating && !level.intermissiontime )
{
ent->AnimateFrame();
}
if ( edict->inuse && ent->flags & FL_PRETHINK )
{
ent->Prethink();
}
if ( edict->inuse )
{
switch ( ( int )ent->movetype )
{
case MOVETYPE_PUSH:
case MOVETYPE_STOP:
G_Physics_Pusher( ent );
break;
case MOVETYPE_NONE:
case MOVETYPE_WALK:
break;
case MOVETYPE_NOCLIP:
G_Physics_Noclip( ent );
break;
case MOVETYPE_STEP:
case MOVETYPE_HURL:
G_Physics_Step( ent );
break;
case MOVETYPE_TOSS:
case MOVETYPE_BOUNCE:
case MOVETYPE_FLY:
case MOVETYPE_FLYMISSILE:
case MOVETYPE_SLIDE:
case MOVETYPE_VEHICLE:
G_Physics_Toss( ent );
break;
default:
gi.error( "G_Physics: bad movetype %i", ( int )ent->movetype );
}
}
if ( ( edict->inuse ) && ( ent->flags & FL_POSTTHINK ) )
{
ent->Postthink();
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -