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

📄 hl1_npc_aflock.cpp

📁 hl2 source code. Do not use it illegal.
💻 CPP
📖 第 1 页 / 共 2 页
字号:
		SetThink( &CNPC_FlockingFlyer::FlockFollowerThink );
	}

	SetActivity ( ACT_FLY );
	ResetSequenceInfo( );
	BoidAdvanceFrame( );

	m_flSpeed = AFLOCK_FLY_SPEED;// no delay!
}

//=========================================================
//=========================================================
void CNPC_FlockingFlyer::BoidAdvanceFrame ( void )
{
	float flapspeed = ( m_flSpeed - m_flTempVar ) / AFLOCK_ACCELERATE;
	m_flTempVar = m_flTempVar * .8 + m_flSpeed * .2;

	if (flapspeed < 0) flapspeed = -flapspeed;
	if (flapspeed < 0.25) flapspeed = 0.25;
	if (flapspeed > 1.9) flapspeed = 1.9;

	m_flPlaybackRate = flapspeed;

	QAngle angVel = GetLocalAngularVelocity();

	// lean
	angVel.x = - GetAbsAngles().x + flapspeed * 5;

	// bank
	angVel.z = - GetAbsAngles().z + angVel.y;

	SetLocalAngularVelocity( angVel );

	// pev->framerate		= flapspeed;
	StudioFrameAdvance();
}

//=========================================================
// Leader boids use this think every tenth
//=========================================================
void CNPC_FlockingFlyer::FlockLeaderThink( void )
{
	trace_t			tr;
	Vector			vecDist;// used for general measurements
	Vector			vecDir;// used for general measurements
	float			flLeftSide;
	float			flRightSide;
	Vector			vForward, vRight, vUp;
	

	SetNextThink( gpGlobals->curtime + 0.1f );
	
	AngleVectors ( GetAbsAngles(), &vForward, &vRight, &vUp );

	// is the way ahead clear?
	if ( !FPathBlocked () )
	{
		// if the boid is turning, stop the trend.
		if ( m_fTurning )
		{
			m_fTurning = FALSE;

			QAngle angVel = GetLocalAngularVelocity();
			angVel.y = 0;
			SetLocalAngularVelocity( angVel );
		}

		m_fPathBlocked = FALSE;

		if ( m_flSpeed <= AFLOCK_FLY_SPEED )
			 m_flSpeed += 5;

		SetAbsVelocity( vForward * m_flSpeed );

		BoidAdvanceFrame( );

		return;
	}
	
	// IF we get this far in the function, the leader's path is blocked!
	m_fPathBlocked = TRUE;

	if ( !m_fTurning)// something in the way and boid is not already turning to avoid
	{
		// measure clearance on left and right to pick the best dir to turn
		UTIL_TraceLine(GetAbsOrigin(), GetAbsOrigin() + vRight * AFLOCK_CHECK_DIST, MASK_SOLID_BRUSHONLY, this, COLLISION_GROUP_NONE, &tr);
		vecDist = (tr.endpos - GetAbsOrigin());
		flRightSide = vecDist.Length();

		UTIL_TraceLine(GetAbsOrigin(), GetAbsOrigin() - vRight * AFLOCK_CHECK_DIST, MASK_SOLID_BRUSHONLY, this, COLLISION_GROUP_NONE, &tr);
		vecDist = (tr.endpos - GetAbsOrigin());
		flLeftSide = vecDist.Length();

		// turn right if more clearance on right side
		if ( flRightSide > flLeftSide )
		{
			QAngle angVel = GetLocalAngularVelocity();
			angVel.y = -AFLOCK_TURN_RATE;
			SetLocalAngularVelocity( angVel );

			m_fTurning = TRUE;
		}
		// default to left turn :)
		else if ( flLeftSide > flRightSide )
		{
			QAngle angVel = GetLocalAngularVelocity();
			angVel.y = AFLOCK_TURN_RATE;
			SetLocalAngularVelocity( angVel );

			m_fTurning = TRUE;
		}
		else
		{
			// equidistant. Pick randomly between left and right.
			m_fTurning = TRUE;

			QAngle angVel = GetLocalAngularVelocity();

			if ( random->RandomInt( 0, 1 ) == 0 )
			{
				angVel.y = AFLOCK_TURN_RATE;
			}
			else
			{
				angVel.y = -AFLOCK_TURN_RATE;
			}

			SetLocalAngularVelocity( angVel );
		}
	}

	SpreadFlock( );

	SetAbsVelocity( vForward * m_flSpeed );
	
	// check and make sure we aren't about to plow into the ground, don't let it happen
	UTIL_TraceLine(GetAbsOrigin(), GetAbsOrigin() - vUp * 16, MASK_SOLID_BRUSHONLY, this, COLLISION_GROUP_NONE, &tr);
	if (tr.fraction != 1.0 && GetAbsVelocity().z < 0 )
	{
		Vector vecVel = GetAbsVelocity();
		vecVel.z = 0;
		SetAbsVelocity( vecVel );
	}

	// maybe it did, though.
	if ( GetFlags() & FL_ONGROUND )
	{
		UTIL_SetOrigin( this, GetAbsOrigin() + Vector ( 0 , 0 , 1 ) );
		Vector vecVel = GetAbsVelocity();
		vecVel.z = 0;
		SetAbsVelocity( vecVel );
	}

	if ( m_flFlockNextSoundTime < gpGlobals->curtime )
	{
//		MakeSound();
		m_flFlockNextSoundTime = gpGlobals->curtime + random->RandomFloat( 1, 3 );
	}

	BoidAdvanceFrame( );
	
	return;
}

//=========================================================
// FBoidPathBlocked - returns TRUE if there is an obstacle ahead
//=========================================================
bool CNPC_FlockingFlyer::FPathBlocked( void )
{
	trace_t			tr;
	Vector			vecDist;// used for general measurements
	Vector			vecDir;// used for general measurements
	bool			fBlocked;
	Vector			vForward, vRight, vUp;

	if ( m_flFakeBlockedTime > gpGlobals->curtime )
	{
		m_flLastBlockedTime = gpGlobals->curtime;
		return TRUE;
	}

	// use VELOCITY, not angles, not all boids point the direction they are flying
	//vecDir = UTIL_VecToAngles( pevBoid->velocity );
	AngleVectors ( GetAbsAngles(), &vForward, &vRight, &vUp );

	fBlocked = FALSE;// assume the way ahead is clear

	// check for obstacle ahead
	UTIL_TraceLine(GetAbsOrigin(), GetAbsOrigin() + vForward * AFLOCK_CHECK_DIST, MASK_SOLID_BRUSHONLY, this, COLLISION_GROUP_NONE, &tr);
	
	if (tr.fraction != 1.0)
	{
		m_flLastBlockedTime = gpGlobals->curtime;
		fBlocked = TRUE;
	}

	// extra wide checks
	UTIL_TraceLine(GetAbsOrigin() + vRight * 12, GetAbsOrigin() + vRight * 12 + vForward * AFLOCK_CHECK_DIST, MASK_SOLID_BRUSHONLY, this, COLLISION_GROUP_NONE, &tr);
	
	if (tr.fraction != 1.0)
	{
		m_flLastBlockedTime = gpGlobals->curtime;
		fBlocked = TRUE;
	}

	UTIL_TraceLine(GetAbsOrigin() - vRight * 12, GetAbsOrigin() - vRight * 12 + vForward * AFLOCK_CHECK_DIST, MASK_SOLID_BRUSHONLY, this, COLLISION_GROUP_NONE, &tr);
	
	if (tr.fraction != 1.0)
	{
		m_flLastBlockedTime = gpGlobals->curtime;
		fBlocked = TRUE;
	}

	if ( !fBlocked && gpGlobals->curtime - m_flLastBlockedTime > 6 )
	{
		// not blocked, and it's been a few seconds since we've actually been blocked.
		m_flFakeBlockedTime = gpGlobals->curtime + random->RandomInt(1, 3); 
	}

	return	fBlocked;
}

//=========================================================
// Searches for boids that are too close and pushes them away
//=========================================================
void CNPC_FlockingFlyer::SpreadFlock( )
{
	Vector		vecDir;
	float		flSpeed;// holds vector magnitude while we fiddle with the direction
	
	CNPC_FlockingFlyer *pList = m_pSquadLeader;
	while ( pList )
	{
		if ( pList != this && ( GetAbsOrigin() - pList->GetAbsOrigin() ).Length() <= AFLOCK_TOO_CLOSE )
		{
			// push the other away
			vecDir = ( pList->GetAbsOrigin() - GetAbsOrigin() );
			VectorNormalize( vecDir );

			// store the magnitude of the other boid's velocity, and normalize it so we
			// can average in a course that points away from the leader.
			flSpeed = pList->GetAbsVelocity().Length();

			Vector vecVel = pList->GetAbsVelocity();
			VectorNormalize( vecVel );
			pList->SetAbsVelocity( ( vecVel + vecDir ) * 0.5 * flSpeed );
		}

		pList = pList->m_pSquadNext;
	}
}

//=========================================================
// Alters the caller's course if he's too close to others 
//
// This function should **ONLY** be called when Caller's velocity is normalized!!
//=========================================================
void CNPC_FlockingFlyer::SpreadFlock2 ( )
{
	Vector		vecDir;
	
	CNPC_FlockingFlyer *pList = m_pSquadLeader;

	while ( pList )
	{
		if ( pList != this && ( GetAbsOrigin() - pList->GetAbsOrigin() ).Length() <= AFLOCK_TOO_CLOSE )
		{
			vecDir = ( GetAbsOrigin() - pList->GetAbsOrigin() );
			VectorNormalize( vecDir );

			SetAbsVelocity( ( GetAbsVelocity() + vecDir ) );
		}

		pList = pList->m_pSquadNext;
	}
}

//=========================================================
//=========================================================
void CNPC_FlockingFlyer::MakeSound( void )
{
	if ( m_flAlertTime > gpGlobals->curtime )
	{
		CPASAttenuationFilter filter1( this );

		// make agitated sounds
		switch ( random->RandomInt( 0, 1 ) )
		{
		case 0:	enginesound->EmitSound( filter1, entindex(), CHAN_WEAPON, "boid/boid_alert1.wav", 1, ATTN_NORM );	break;
		case 1:	enginesound->EmitSound( filter1, entindex(), CHAN_WEAPON, "boid/boid_alert2.wav", 1, ATTN_NORM );	break;
		}

		return;
	}

	// make normal sound
	CPASAttenuationFilter filter2( this );

	switch ( random->RandomInt( 0, 1 ) )
	{
	case 0:	enginesound->EmitSound( filter2, entindex(), CHAN_WEAPON, "boid/boid_idle1.wav", 1, ATTN_NORM );	break;
	case 1:	enginesound->EmitSound( filter2, entindex(), CHAN_WEAPON, "boid/boid_idle2.wav", 1, ATTN_NORM );	break;
	}
}

//=========================================================
// follower boids execute this code when flocking
//=========================================================
void CNPC_FlockingFlyer::FlockFollowerThink( void )	
{
	Vector			vecDist;
	Vector			vecDir;
	Vector			vecDirToLeader;
	float			flDistToLeader;

	SetNextThink( gpGlobals->curtime + 0.1f );

	if ( IsLeader() || !InSquad() )
	{
		// the leader has been killed and this flyer suddenly finds himself the leader. 
		SetThink ( FlockLeaderThink );
		return;
	}

	vecDirToLeader = ( m_pSquadLeader->GetAbsOrigin() - GetAbsOrigin() );
	flDistToLeader = vecDirToLeader.Length();
	
	// match heading with leader
	SetAbsAngles( m_pSquadLeader->GetAbsAngles() );

	//
	// We can see the leader, so try to catch up to it
	//
	if ( FInViewCone ( m_pSquadLeader ) )
	{
		// if we're too far away, speed up
		if ( flDistToLeader > AFLOCK_TOO_FAR )
		{
			m_flGoalSpeed = m_pSquadLeader->GetAbsVelocity().Length() * 1.5;
		}

		// if we're too close, slow down
		else if ( flDistToLeader < AFLOCK_TOO_CLOSE )
		{
			m_flGoalSpeed = m_pSquadLeader->GetAbsVelocity().Length() * 0.5;
		}
	}
	else
	{
		// wait up! the leader isn't out in front, so we slow down to let him pass
		m_flGoalSpeed = m_pSquadLeader->GetAbsVelocity().Length() * 0.5;
	}

	SpreadFlock2();

	Vector vecVel = GetAbsVelocity();
	m_flSpeed = vecVel.Length();
	VectorNormalize( vecVel );

	// if we are too far from leader, average a vector towards it into our current velocity
	if ( flDistToLeader > AFLOCK_TOO_FAR )
	{
		VectorNormalize( vecDirToLeader );
		vecVel = (vecVel + vecDirToLeader) * 0.5; 	
	}

	// clamp speeds and handle acceleration
	if ( m_flGoalSpeed > AFLOCK_FLY_SPEED * 2 )
	{
		m_flGoalSpeed  = AFLOCK_FLY_SPEED * 2;
	}

	if ( m_flSpeed < m_flGoalSpeed )
	{
		m_flSpeed += AFLOCK_ACCELERATE;
	}
	else if ( m_flSpeed > m_flGoalSpeed )
	{
		m_flSpeed -= AFLOCK_ACCELERATE;
	}

	SetAbsVelocity( vecVel * m_flSpeed );

	BoidAdvanceFrame( );
}

//=========================================================
//=========================================================
void CNPC_FlockingFlyer::Event_Killed( const CTakeDamageInfo &info )
{
	CNPC_FlockingFlyer *pSquad;
	
	pSquad = (CNPC_FlockingFlyer *)m_pSquadLeader;

	while ( pSquad )
	{
		pSquad->m_flAlertTime = gpGlobals->curtime + 15;
		pSquad = (CNPC_FlockingFlyer *)pSquad->m_pSquadNext;
	}

	if ( m_pSquadLeader )
	{
		m_pSquadLeader->SquadRemove( this );
	}

	m_lifeState = LIFE_DEAD;

	m_flPlaybackRate = 0;
	m_fEffects = EF_NOINTERP;

	UTIL_SetSize( this, Vector(0,0,0), Vector(0,0,0) );
	SetMoveType( MOVETYPE_FLYGRAVITY );

	SetThink ( FallHack );
	SetNextThink( gpGlobals->curtime + 0.1f );
}

void CNPC_FlockingFlyer::FallHack( void )
{
	if ( GetFlags() & FL_ONGROUND )
	{
		CBaseEntity *groundentity = GetContainingEntity( GetGroundEntity()->edict() );

		if ( !FClassnameIs ( groundentity, "worldspawn" ) )
		{
			RemoveFlag( FL_ONGROUND );
			SetNextThink( gpGlobals->curtime + 0.1f );
		}
		else
		{
			SetAbsVelocity( Vector( 0, 0, 0 ) );
			SetThink( NULL );
		}
	}
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -