⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 g_phys.cpp

📁 this keik game source
💻 CPP
📖 第 1 页 / 共 3 页
字号:
            )
         )
			{	
			// 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 + -