📄 g_phys.cpp
字号:
)
)
{
// entity is trapped in another solid
ent->velocity = vec_zero;
return 3;
}
if ( trace.fraction > 0 )
{
// actually covered some distance
ent->setOrigin( trace.endpos );
original_velocity = ent->velocity;
numplanes = 0;
}
if ( trace.fraction == 1 )
{
// moved the entire distance
break;
}
hit = trace.ent->entity;
if ( trace.plane.normal[ 2 ] > 0.7 )
{
// floor
blocked |= 1;
if ( hit->getSolidType() == SOLID_BSP )
{
ent->groundentity = hit->edict;
ent->groundentity_linkcount = hit->edict->linkcount;
ent->groundplane = trace.plane;
ent->groundsurface = trace.surface;
ent->groundcontents = trace.contents;
}
}
if ( !trace.plane.normal[ 2 ] )
{
// step
blocked |= 2;
}
//
// run the impact function
//
G_Impact( ent, &trace );
if ( !edict->inuse )
{
break; // removed by the impact function
}
time_left -= time_left * trace.fraction;
// cliped to another plane
if ( numplanes >= MAX_CLIP_PLANES )
{
// this shouldn't really happen
ent->velocity = vec_zero;
return 3;
}
VectorCopy( trace.plane.normal, planes[ numplanes ] );
numplanes++;
//
// modify original_velocity so it parallels all of the clip planes
//
for( i = 0; i < numplanes; i++ )
{
G_ClipVelocity( original_velocity, Vector( planes[ i ] ), new_velocity, 1.01, ent->gravaxis );
for( j = 0; j < numplanes; j++ )
{
if ( j != i )
{
if ( ( new_velocity * planes[ j ] ) < 0 )
{
// not ok
break;
}
}
}
if ( j == numplanes )
{
break;
}
}
if ( i != numplanes )
{
// go along this plane
ent->velocity = new_velocity;
}
else
{
// go along the crease
if ( numplanes != 2 )
{
ent->velocity = vec_zero;
return 7;
}
CrossProduct( planes[ 0 ], planes[ 1 ], dir.vec3() );
d = dir * ent->velocity;
ent->velocity = dir * d;
}
//
// if original velocity is against the original velocity, stop dead
// to avoid tiny occilations in sloping corners
//
if ( ( ent->velocity * primal_velocity ) <= 0 )
{
ent->velocity = vec_zero;
return blocked;
}
}
return blocked;
}
/*
============
G_AddGravity
============
*/
void G_AddGravity
(
Entity *ent
)
{
float grav;
if ( ent->waterlevel > 2 )
{
grav = ent->gravity * 60 * FRAMETIME * gravity_axis[ ent->gravaxis ].sign;
}
else
{
grav = ent->gravity * sv_gravity->value * FRAMETIME * gravity_axis[ ent->gravaxis ].sign;
}
ent->velocity[ gravity_axis[ ent->gravaxis ].z ] -= grav;
}
/*
===============================================================================
PUSHMOVE
===============================================================================
*/
/*
============
G_PushEntity
Does not change the entities velocity at all
============
*/
trace_t G_PushEntity
(
Entity *ent,
Vector push
)
{
trace_t trace;
Vector start;
Vector end;
int mask;
edict_t *edict;
start = ent->worldorigin;
end = start + push;
retry:
if ( ent->edict->clipmask )
{
mask = ent->edict->clipmask;
}
else
{
mask = MASK_SOLID;
}
if ( !sv_fatrockets->value && ( ent->flags & FL_FATPROJECTILE ) )
{
trace = G_FullTrace( start, ent->mins, ent->maxs, end, ent->maxs.y, ent, mask, "G_PushEntity" );
}
else
{
trace = G_Trace( start, ent->mins, ent->maxs, end, ent, mask, "G_PushEntity" );
}
edict = ent->edict;
ent->setOrigin( trace.endpos );
if ( trace.fraction != 1.0 )
{
G_Impact( ent, &trace );
// if the pushed entity went away and the pusher is still there
if ( !trace.ent->inuse && edict->inuse )
{
// move the pusher back and try again
ent->setOrigin( start );
goto retry;
}
}
if ( edict && ( edict != ent->edict ) )
{
G_TouchTriggers( ent );
}
return trace;
}
/*
============
G_SlideEntity
============
*/
trace_t G_SlideEntity
(
Entity *ent,
Vector push
)
{
trace_t trace;
Vector start;
Vector end;
int mask;
edict_t *edict;
start = ent->worldorigin;
end = start + push;
if ( ent->edict->clipmask )
{
mask = ent->edict->clipmask;
}
else
{
mask = MASK_SOLID;
}
trace = G_Trace( start, ent->mins, ent->maxs, end, ent, mask, "G_SlideEntity" );
edict = ent->edict;
ent->setOrigin( trace.endpos );
return trace;
}
/*
================
G_SnapPosition
================
*/
/*
qboolean G_SnapPosition
(
Entity *ent
)
{
int x, y, z;
Vector offset( 0, -1, 1 );
Vector base;
base = ent->worldorigin;
for ( z = 0; z < 3; z++ )
{
ent->worldorigin.z = base.z + offset[ z ];
for ( y = 0; y < 3; y++ )
{
ent->worldorigin.y = base.y + offset[ y ];
for ( x = 0; x < 3; x++ )
{
ent->worldorigin.x = base.x + offset[ x ];
if ( G_TestEntityPosition( ent ) )
{
ent->origin.x += offset[ x ];
ent->origin.y += offset[ y ];
ent->origin.z += offset[ z ];
ent->setOrigin( ent->origin );
return true;
}
}
}
}
// can't find a good position, so put him back.
ent->worldorigin = base;
return false;
}
*/
/*
============
G_Push
Objects need to be moved back on a failed push,
otherwise riders would continue to slide.
============
*/
qboolean G_Push
(
Entity *pusher,
Vector pushermove,
Vector pusheramove
)
{
Entity *check, *block;
edict_t *edict, *next;
Vector move, amove;
Vector mins, maxs;
Vector save;
pushed_t *p;
Vector org, org2, move2;
float mat[ 3 ][ 3 ];
pushed_t *pusher_p;
// save the pusher's original position
pusher_p = pushed_p;
pushed_p->ent = pusher;
pushed_p->origin = pusher->origin;
pushed_p->worldorigin = pusher->worldorigin;
pushed_p->angles = pusher->angles;
pushed_p->worldangles = pusher->worldangles;
if ( pusher->client )
{
pushed_p->deltayaw = pusher->client->ps.pmove.delta_angles[ YAW ];
}
pushed_p++;
if ( pushed_p >= &pushed[ MAX_EDICTS ] )
{
gi.error( ERR_FATAL, "Pushed too many entities." );
}
// move the pusher to it's final position
pusher->setAngles( pusher->angles + pusheramove );
pusher->setOrigin( pusher->origin + pushermove );
if ( pusher->edict->solid == SOLID_NOT )
{
// Doesn't push anything
return true;
}
// change the move to worldspace
move = pusher->worldorigin - pusher_p->worldorigin;
amove = pusher->worldangles - pusher_p->worldangles;
// we need this for pushing things later
AnglesToMat( amove.vec3(), mat );
// find the bounding box
mins = pusher->absmin;
maxs = pusher->absmax;
// see if any solid entities are inside the final position
for( edict = g_edicts->next; edict != &active_edicts; edict = next )
{
assert( edict );
assert( edict->inuse );
assert( edict->entity );
next = edict->next;
check = edict->entity;
if ( check->movetype == MOVETYPE_PUSH ||
check->movetype == MOVETYPE_STOP ||
check->movetype == MOVETYPE_NONE ||
check->movetype == MOVETYPE_NOCLIP )
{
continue;
}
// if the entity is standing on the pusher, it will definitely be moved
if ( check->groundentity != pusher->edict )
{
// Only move triggers and non-solid objects if they're sitting on a moving object
if ( check->edict->solid == SOLID_TRIGGER || check->edict->solid == SOLID_NOT )
{
continue;
}
// see if the ent needs to be tested
if ( check->absmin[ 0 ] >= maxs[ 0 ] ||
check->absmin[ 1 ] >= maxs[ 1 ] ||
check->absmin[ 2 ] >= maxs[ 2 ] ||
check->absmax[ 0 ] <= mins[ 0 ] ||
check->absmax[ 1 ] <= mins[ 1 ] ||
check->absmax[ 2 ] <= mins[ 2 ] )
{
continue;
}
// see if the ent's bbox is inside the pusher's final position
if ( !G_TestEntityPosition( check ) )
{
continue;
}
}
if ( ( pusher->movetype == MOVETYPE_PUSH ) || ( check->groundentity == pusher->edict ) )
{
// move this entity
pushed_p->ent = check;
pushed_p->origin = check->origin;
pushed_p->worldorigin = check->worldorigin;
pushed_p->angles = check->angles;
pushed_p->worldangles = check->worldangles;
pushed_p++;
if ( pushed_p >= &pushed[ MAX_EDICTS ] )
{
gi.error( ERR_FATAL, "Pushed too many entities." );
}
// save off the origin
save = check->origin;
// try moving the contacted entity
move2 = move;
#if 0
// The way id had this was wrong (delta_angles are shorts, not floats)
// This is probably what it should be, but it's not interpolated by the client, so it jitters.
if ( check->client )
{
// FIXME: doesn't rotate monsters?
//check->client->ps.pmove.delta_angles[ YAW ] += amove[ YAW ];
check->client->ps.pmove.delta_angles[ YAW ] =
ANGLE2SHORT(
SHORT2ANGLE( check->client->ps.pmove.delta_angles[ YAW ] ) + amove[ YAW ] );
}
#endif
// figure movement due to the pusher's amove
org = check->worldorigin - pusher->worldorigin;
MatrixTransformVector( org.vec3(), mat, org2.vec3() );
move2 += org2 - org;
//FIXME
// We should probably do a flymove here so that we slide against other objects
check->setOrigin( check->origin + check->getParentVector( move2 ) );
// may have pushed them off an edge
if ( check->groundentity != pusher->edict )
{
check->groundentity = NULL;
}
block = G_TestEntityPosition( check );
if ( !block )
{
// pushed ok
check->link();
// impact?
continue;
}
// try to snap it to a good position
/*
if ( G_SnapPosition( check ) )
{
// snapped ok. we don't have to link since G_SnapPosition does it for us.
continue;
}
*/
// if it is ok to leave in the old position, do it
// this is only relevent for riding entities, not pushed
// FIXME: this doesn't acount for rotation
check->setOrigin( save );
block = G_TestEntityPosition( check );
if ( !block )
{
pushed_p--;
continue;
}
}
// save off the obstacle so we can call the block function
obstacle = check;
// move back any entities we already moved
// go backwards, so if the same entity was pushed
// twice, it goes back to the original position
for( p = pushed_p - 1; p >= pushed; p-- )
{
p->ent->angles = p->angles;
p->ent->origin = p->origin;
if ( p->ent->client )
{
p->ent->client->ps.pmove.delta_angles[ YAW ] = p->deltayaw;
}
}
// Only "really" move it in order so that the bound coordinate system is correct
for( p = pushed; p < pushed_p; p++ )
{
p->ent->setAngles( p->ent->angles );
p->ent->setOrigin( p->ent->origin );
}
return false;
}
//FIXME: is there a better way to handle this?
// see if anything we moved has touched a trigger
for( p = pushed_p - 1; p >= pushed; p-- )
{
G_TouchTriggers( p->ent );
}
return true;
}
/*
================
G_PushMove
================
*/
qboolean G_PushMove
(
Entity *ent,
Vector move,
Vector amove
)
{
Entity *part;
Vector m, a;
Event *ev;
m = move;
a = amove;
pushed_p = pushed;
for( part = ent; part; part = part->teamchain )
{
if ( !G_Push( part, m, a ) )
{
// move was blocked
// call the pusher's "blocked" function
// otherwise, just stay in place until the obstacle is gone
ev = new Event( EV_Blocked );
ev->AddEntity( obstacle );
part->ProcessEvent( ev );
return false;
}
m = vec_zero;
a = vec_zero;
}
return true;
}
/*
================
G_Physics_Pusher
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -