Esempio n. 1
0
void CBoidFish::Update( float dt,SBoidContext &bc )
{
	if (m_dead)
		return;

	if (m_physicsControlled)
	{
		if (m_pPhysics)
		{
			// If fish is dead, get it position from physics.
			pe_status_pos ppos;
			m_pPhysics->GetStatus(&ppos);
			m_pos = ppos.pos;

			{
				m_dyingTime += Boid::Frand()*0.2f;
				// Apply force on this body.
				pe_action_impulse theAction;
				theAction.impulse = Vec3(sinf(m_dyingTime*0.1f),cosf(m_dyingTime*0.13f),cosf(m_dyingTime*0.171f)*2.8f) * 0.01f;
				theAction.point = m_pos + Vec3(Boid::Frand(),Boid::Frand(),Boid::Frand())*0.1f;
				theAction.iApplyTime = 0;
				theAction.ipart = 0;
				m_pPhysics->Action(&theAction);

				pe_simulation_params sym;
				sym.density = 950.0f + 200.0f*sinf(m_dyingTime);
				if (sym.density < FISH_PHYSICS_DENSITY)
					sym.density = FISH_PHYSICS_DENSITY;
				m_pPhysics->SetParams( &sym );
			}
		}
	}
	if (m_dying)
	{
		// If fish is dying it floats up to the water surface, and die there.
		//UpdateDying(dt,bc);
		m_dyingTime += dt;
		if (m_dyingTime > 60)
		{
			m_dead = true;
			m_dying = false;
			if (m_object)
				m_object->GetISkeletonAnim()->StopAnimationsAllLayers();
		}
		return;
	}


	//////////////////////////////////////////////////////////////////////////
	if (bc.followPlayer)
	{
		if (m_pos.GetSquaredDistance(bc.playerPos) > MAX_FISH_DISTANCE*MAX_FISH_DISTANCE)
		{
			float z = bc.MinHeight + (Boid::Frand()+1)/2.0f*(bc.MaxHeight - bc.MinHeight);
			m_pos = bc.playerPos + Vec3(Boid::Frand()*MAX_FISH_DISTANCE,Boid::Frand()*MAX_FISH_DISTANCE,z );
			m_speed = bc.MinSpeed + ((Boid::Frand()+1)/2.0f) / (bc.MaxSpeed - bc.MinSpeed);
			m_heading = Vec3(Boid::Frand(),Boid::Frand(),0).GetNormalized();
		}
	}

	float height = m_pos.z - bc.terrainZ;

	m_accel.Set(0,0,0);
	m_accel = bc.factorRandomAccel*Vec3(Boid::Frand(),Boid::Frand(),Boid::Frand());
	// Continue accelerating in same dir until target speed reached.
	// Try to maintain average speed of (maxspeed+minspeed)/2
	float targetSpeed = (bc.MaxSpeed + bc.MinSpeed)/2;
	m_accel -= m_heading*(m_speed-targetSpeed)*0.2f;


	
	if (bc.factorAlignment != 0)
	{
		Vec3 alignmentAccel;
		Vec3 cohesionAccel;
		Vec3 separationAccel;
		CalcFlockBehavior(bc,alignmentAccel,cohesionAccel,separationAccel);

		m_accel += alignmentAccel*bc.factorAlignment;
		m_accel += cohesionAccel*bc.factorCohesion;
		m_accel += separationAccel;
	}

	// Avoid water.
	if (m_pos.z > bc.waterLevel-1)
	{
		float h = bc.waterLevel - m_pos.z;
		float v = (1.0f - h);
		float vv = v*v;
		m_accel.z += (-vv)*bc.factorAvoidLand;

		//gEnv->pRenderer->GetIRenderAuxGeom()->DrawLine( m_pos,ColorB(0,0,255,255),m_pos+m_accel,ColorB(0,0,255,255) );
	}
	// Avoid land.
	if (height < bc.MinHeight)
	{
		float v = (1.0f - height/(bc.MinHeight+0.01f));
		float vv = v*v;
		m_accel.z += vv*bc.factorAvoidLand;
		
		// Slow down fast.
		m_accel -= m_heading*(m_speed-0.1f)*vv*bc.factorAvoidLand;
		// Go to origin.
		m_accel += (bc.flockPos - m_pos) * vv * bc.factorAvoidLand;

		//gEnv->pRenderer->GetIRenderAuxGeom()->DrawLine( m_pos,ColorB(255,0,0,255),Vec3(m_pos.x,m_pos.y,bc.terrainZ),ColorB(255,0,0,255) );
	}

	if (fabs(m_heading.z) > 0.5f)
	{
		// Always try to accelerate in direction opposite to the current in Z axis.
		m_accel.z += -m_heading.z * 0.8f;
	}

	// Attract to the origin point.
	if (bc.followPlayer)
	{
		m_accel += (bc.playerPos - m_pos) * bc.factorAttractToOrigin;
	}
	else
	{
		m_accel += (bc.randomFlockCenter - m_pos) * bc.factorAttractToOrigin;
	}

	bool bAvoidObstacles = bc.avoidObstacles;
	//////////////////////////////////////////////////////////////////////////
	// High Terrain avoidance.
	//////////////////////////////////////////////////////////////////////////
	Vec3 fwd_pos = m_pos + m_heading*1.0f; // Look ahead 1 meter.
	float fwd_z = bc.engine->GetTerrainElevation(fwd_pos.x,fwd_pos.y);
	if (fwd_z >= m_pos.z-bc.fBoidRadius)
	{
		// If terrain in front of the fish is high, enable obstacle avoidance.
		bAvoidObstacles = true;
	}

	//////////////////////////////////////////////////////////////////////////

	// Avoid collision with Terrain and Static objects.
	float fCollisionAvoidanceWeight = 10.0f;
	float fCollisionDistance = 2.0f;

	if (bAvoidObstacles)
	{
		// Avoid obstacles & terrain.
		IPhysicalWorld *physWorld = bc.physics;

		Vec3 vPos = m_pos;
		Vec3 vDir = m_heading*fCollisionDistance;
		// Add some random variation in probe ray.
		vDir.x += Boid::Frand()*0.8f;
		vDir.y += Boid::Frand()*0.8f;

		int objTypes = ent_all|ent_no_ondemand_activation;
		int flags = rwi_stop_at_pierceable|rwi_ignore_terrain_holes;
		ray_hit hit;

		//gEnv->pRenderer->GetIRenderAuxGeom()->DrawLine( vPos,ColorB(0,0,255,255),vPos+vDir,ColorB(0,0,255,255) );

		int col = physWorld->RayWorldIntersection( vPos,vDir,objTypes,flags,&hit,1 );
		if (col != 0 && hit.dist > 0)
		{
				// Turn from collided surface.
			Vec3 normal = hit.n;
			//normal.z = 0; // Only turn left/right.
			float w = (1.0f - hit.dist/fCollisionDistance);
			Vec3 R = m_heading - (2.0f*m_heading.Dot(normal))*normal;
			Boid::Normalize_fast(R);
			R += normal;
			R.z = R.z*0.2f;
			m_accel += R*(w*w)*bc.factorAvoidLand * fCollisionAvoidanceWeight;

			//gEnv->pRenderer->GetIRenderAuxGeom()->DrawLine( m_pos,ColorB(0,0,255,255),hit.pt,ColorB(0,0,255,255) );

			//gEnv->pRenderer->GetIRenderAuxGeom()->DrawLine( hit.pt,ColorB(255,0,0,255),hit.pt+R*2,ColorB(255,0,0,255) );
			//gEnv->pRenderer->GetIRenderAuxGeom()->DrawLine( m_pos,ColorB(255,0,0,255),m_pos+R*2,ColorB(255,0,0,255) );
		}
	}

	/*
	if (rand()%80 == 1)
	{
		if (m_pos.GetSquaredDistance(bc.playerPos) < 10.0f*10.0f)
		{
			// Spawn bubble.
			SpawnParticleEffect( m_pos,bc,SPAWN_BUBBLE );
		}
	}
	*/

	//////////////////////////////////////////////////////////////////////////
	// Player must scare fishes off.
	//////////////////////////////////////////////////////////////////////////
	float sqrPlayerDist = m_pos.GetSquaredDistance(bc.playerPos);
	if (sqrPlayerDist < SCARE_DISTANCE*SCARE_DISTANCE)
	{
		Vec3 retreatDir = m_pos - bc.playerPos;
		Boid::Normalize_fast(retreatDir);
		float scareFactor = (1.0f - sqrPlayerDist/(SCARE_DISTANCE*SCARE_DISTANCE));
		m_accel.x += retreatDir.x*scareFactor*bc.factorAvoidLand;
		m_accel.y += retreatDir.y*scareFactor*bc.factorAvoidLand;
	}

	//////////////////////////////////////////////////////////////////////////
	// Calc movement.
	CalcMovement( dt,bc,false );
	m_accel.Set(0,0,0);

	// Limits fishes to under water and above terrain.
	if (m_pos.z > bc.waterLevel-0.2f)
	{
		m_pos.z = bc.waterLevel-0.2f;
		if (rand()%40 == 1)
		{
			if (m_pos.GetSquaredDistance(bc.playerPos) < 10.0f*10.0f)
			{
				// Spawn splash.
				SpawnParticleEffect( m_pos,bc,SPAWN_SPLASH );
			}
		}
	}
	else if (m_pos.z < bc.terrainZ+0.2f && bc.terrainZ < bc.waterLevel)
	{
		m_pos.z = bc.terrainZ+0.2f;
	}
}
Esempio n. 2
0
void CBoidBird::ThinkWalk( float dt,SBoidContext &bc )
{

	m_accel = -m_heading*(m_speed-m_walkSpeed)*0.4f;


	if (bc.factorAlignment != 0)
	{
		Vec3 alignmentAccel;
		Vec3 cohesionAccel;
		Vec3 separationAccel;
		CalcFlockBehavior(bc,alignmentAccel,cohesionAccel,separationAccel);

		m_accel += alignmentAccel*bc.factorAlignmentGround;
		m_accel += cohesionAccel*bc.factorCohesionGround;
		m_accel += separationAccel*bc.factorSeparationGround;
	}


	// Attract to origin point.
	if (bc.followPlayer)
	{
		m_accel += (bc.playerPos - m_pos) * bc.factorAttractToOriginGround;
	}
	else
	{
		if ((cry_rand()&31) == 1)
		{
			m_birdOriginPos = Vec3(	bc.flockPos.x+Boid::Frand()*bc.fSpawnRadius,bc.flockPos.y+Boid::Frand()*bc.fSpawnRadius,bc.flockPos.z+Boid::Frand()*bc.fSpawnRadius );
			if (m_birdOriginPos.z - bc.terrainZ < bc.MinHeight)
			{
				m_birdOriginPos.z = bc.terrainZ + bc.MinHeight;
			}
		}

		m_accel += (m_birdOriginPos - m_pos) * bc.factorAttractToOriginGround;
	}


	// Avoid collision with Terrain and Static objects.
	float fCollisionAvoidanceWeight = 10.0f;

	// Do walk sounds.
// 	if ((cry_rand()&0xFF) == 0)
// 		PlaySound(CHICKEN_SOUND_CLUCK);


	
	m_accel.z = 0;

	//////////////////////////////////////////////////////////////////////////
	// Avoid water ocean..
	if (m_pos.z < bc.waterLevel && bc.bAvoidWater)
	{
		Vec3 nextpos = m_pos + m_heading;
		float farz = bc.engine->GetTerrainElevation(nextpos.x,nextpos.y) + bc.fBoidRadius*0.5f;
		if (farz > m_pos.z)
			m_accel += m_heading*bc.factorAvoidLand;
		else
			m_accel += -m_heading*bc.factorAvoidLand;
		m_accel.z = 0;
	}
	//////////////////////////////////////////////////////////////////////////
}
Esempio n. 3
0
void CChickenBoid::Think( float dt,SBoidContext &bc )
{
	Vec3 flockHeading(0,0,0);

	m_accel(0,0,0);
//	float height = m_pos.z - bc.terrainZ;

	if (m_bThrown)
	{
		m_accel.Set(0,0,-10.0f);
		//float z = bc.engine->GetTerrainElevation(m_pos.x,m_pos.y) + bc.fBoidRadius*0.5f;
		m_pos.z = bc.engine->GetTerrainElevation(m_pos.x,m_pos.y) + bc.fBoidRadius*0.5f;
		//pe_status_pos ppos;
		//m_pPhysics->GetStatus(&ppos);
		//if (m_pos.z < z)
		{
			m_physicsControlled = false;
			m_bThrown = false;
			m_heading.z = 0;
			if (m_heading.IsZero())
				m_heading = Vec3(1,0,0);
			m_heading.Normalize();
			m_accel.Set(0,0,0);
			m_speed = bc.MinSpeed;
			m_heading.z = 0;
		}
		return;
	}

	// Free will.
	// Continue accelerating in same dir untill target speed reached.
	// Try to maintain average speed of (maxspeed+minspeed)/2
	float targetSpeed = bc.MinSpeed;
	m_accel -= m_heading*(m_speed-targetSpeed)*0.4f;

	// Gaussian weight.
	m_accel.z = 0;

	m_bScared = false;

	if (bc.factorAlignment != 0)
	{
		//CalcCohesion();
		Vec3 alignmentAccel;
		Vec3 cohesionAccel;
		Vec3 separationAccel;
		CalcFlockBehavior(bc,alignmentAccel,cohesionAccel,separationAccel);

		//! Adjust for allignment,
		//m_accel += alignmentAccel.Normalized()*ALIGNMENT_FACTOR;
		m_accel += alignmentAccel*bc.factorAlignment;
		m_accel += cohesionAccel*bc.factorCohesion;
		m_accel += separationAccel;
	}

	/*
	// Avoid land.
	if (height < bc.MinHeight && !m_landing)
	{
		float v = (1.0f - height/bc.MinHeight);
		m_accel += Vec3(0,0,v*v)*bc.factorAvoidLand;
	}
	else if (height > bc.MaxHeight) // Avoid max height.
	{
		float v = (height - bc.MaxHeight)*0.1f;
		m_accel += Vec3(0,0,-v);
	}
	else
	{
		// Always try to accelerate in direction oposite to current in Z axis.
		m_accel.z = -(m_heading.z*m_heading.z*m_heading.z * 100.0f);
	}
	*/

	// Attract to origin point.
	if (bc.followPlayer)
	{
		m_accel += (bc.playerPos - m_pos) * bc.factorAttractToOrigin;
	}
	else
	{
		//m_accel += (m_birdOriginPos - m_pos) * bc.factorAttractToOrigin;
		if ((cry_rand()&31) == 1)
		{
			m_birdOriginPos = Vec3(	bc.flockPos.x+frand()*bc.fSpawnRadius,bc.flockPos.y+frand()*bc.fSpawnRadius,bc.flockPos.z+frand()*bc.fSpawnRadius );
			if (m_birdOriginPos.z - bc.terrainZ < bc.MinHeight)
			{
				m_birdOriginPos.z = bc.terrainZ + bc.MinHeight;
			}
		}

		/*
		if (m_pos.x < bc.flockPos.x-bc.fSpawnRadius || m_pos.x > bc.flockPos.x+bc.fSpawnRadius ||
		m_pos.y < bc.flockPos.y-bc.fSpawnRadius || m_pos.y > bc.flockPos.y+bc.fSpawnRadius ||
		m_pos.z < bc.flockPos.z-bc.fSpawnRadius || m_pos.z > bc.flockPos.z+bc.fSpawnRadius)
		*/
		{
			m_accel += (m_birdOriginPos - m_pos) * bc.factorAttractToOrigin;
		}
	}


	// Avoid collision with Terrain and Static objects.
	float fCollisionAvoidanceWeight = 10.0f;

	// Do walk sounds.
	if ((cry_rand()&0xFF) == 0)
		PlaySound(CHICKEN_SOUND_CLUCK);

	//////////////////////////////////////////////////////////////////////////
	// Player must scare chickens off.
	//////////////////////////////////////////////////////////////////////////
	float fScareDist = 5.0f;
	float sqrPlayerDist = m_pos.GetSquaredDistance(bc.playerPos);
	if (sqrPlayerDist < fScareDist*fScareDist)
	{
		Vec3 retreatDir = (m_pos - bc.playerPos) + Vec3(frand()*2.0f,frand()*2.0f,0);
		retreatDir.NormalizeFast();
		float scareFactor = (1.0f - sqrPlayerDist/(fScareDist*fScareDist));
		m_accel.x += retreatDir.x*scareFactor*bc.factorAvoidLand;
		m_accel.y += retreatDir.y*scareFactor*bc.factorAvoidLand;

		m_bScared = true;
		if (m_landing) m_flightTime = m_maxIdleTime+1.0f; // Stop idle.
		// Do walk sounds.
		if ((cry_rand()&0xFF) == 0)
			PlaySound(CHICKEN_SOUND_SCARED);
	}

	//////////////////////////////////////////////////////////////////////////
	// Scare points also scare chicken off.
	//////////////////////////////////////////////////////////////////////////
	if (bc.scareRatio > 0)
	{
		float sqrScareDist = m_pos.GetSquaredDistance(bc.scarePoint);
		if (sqrScareDist < bc.scareRadius*bc.scareRadius)
		{
			float fScareMultiplier = 10.0f;
			Vec3 retreatDir = m_pos - bc.scarePoint;
			retreatDir.NormalizeFast();
			float scareFactor = (1.0f - sqrScareDist/(bc.scareRadius*bc.scareRadius));
			m_accel.x += retreatDir.x*scareFactor*fScareMultiplier;
			m_accel.y += retreatDir.y*scareFactor*fScareMultiplier;

			if (m_landing) m_flightTime = m_maxIdleTime+1.0f; // Stop idle.

			m_bScared = true;

			// Do walk sounds.
			if ((cry_rand()&0xF) == 0)
				PlaySound(CHICKEN_SOUND_CLUCK);
		}
	}
	//////////////////////////////////////////////////////////////////////////


	if (bc.avoidObstacles)
	{
		// Avoid obstacles & terrain.
		IPhysicalWorld *physWorld = bc.physics;

		Vec3 vDir0 = m_heading*bc.fBoidRadius*0.5f;
		Vec3 vPos = m_pos + Vec3(0,0,bc.fBoidRadius*0.5f) + vDir0;
		Vec3 vDir = m_heading*(bc.fBoidRadius*2) + Vec3(0,0,bc.fBoidRadius*0.5f);
		// Add some random variation in probe ray.
		vDir.x += frand()*0.5f;
		vDir.y += frand()*0.5f;

		int objTypes = ent_all|ent_no_ondemand_activation;
		int flags = rwi_stop_at_pierceable|rwi_ignore_terrain_holes;
		ray_hit hit;
		int col = physWorld->RayWorldIntersection( vPos,vDir,objTypes,flags,&hit,1 );
		if (col != 0 && hit.dist > 0)
		{
			// Turn from collided surface.
			Vec3 normal = hit.n;
			float rayLen = vDir.GetLength();
			float w = (1.0f - hit.dist/rayLen);
			Vec3 R = m_heading - (2.0f*m_heading.Dot(normal))*normal;
			R.NormalizeFast();
			R += normal;
			//m_accel += R*(w*w)*bc.factorAvoidLand * fCollisionAvoidanceWeight;
			Vec3 accel = R*w*bc.factorAvoidLand * fCollisionAvoidanceWeight;
			m_avoidanceAccel = m_avoidanceAccel*bc.fSmoothFactor + accel*(1.0f-bc.fSmoothFactor);
		}
	}

	m_accel += m_avoidanceAccel;
	m_avoidanceAccel = m_avoidanceAccel*bc.fSmoothFactor;

	if (!m_landing)
	{
		m_flightTime += dt;
		if (m_flightTime > m_maxNonIdleTime && (m_pos.z > bc.waterLevel && bc.bAvoidWater))
		{
			// Play idle.
			PlayAnimationId( CHICKEN_IDLE_ANIM + (cry_rand()%CHICKEN_IDLE_ANIM_NUM),true );
			m_maxIdleTime = 2.0f + cry_frand()*MAX_REST_TIME;
			m_landing = true;
			m_flightTime = 0;
			
			m_accel.Set(0,0,0);
			m_speed = 0;
		}
	}
	else
	{
		m_accel = m_heading;
		m_speed = 0.1f;

		m_flightTime += dt;
		if (m_flightTime > m_maxIdleTime)
		{
			m_maxNonIdleTime = cry_frand()*MAX_WALK_TIME;
			PlayAnimationId( CHICKEN_WALK_ANIM,true );
			m_landing = false;
			m_flightTime = 0;
		}
	}

	// Limits birds to above water and land.
	m_pos.z = bc.engine->GetTerrainElevation(m_pos.x,m_pos.y) + bc.fBoidRadius*0.5f;
	m_accel.z = 0;

	//////////////////////////////////////////////////////////////////////////
	// Avoid water ocean..
	if (m_pos.z < bc.waterLevel && bc.bAvoidWater)
	{
		if (m_landing)
			m_flightTime = m_maxIdleTime;
		Vec3 nextpos = m_pos + m_heading;
		float farz = bc.engine->GetTerrainElevation(nextpos.x,nextpos.y) + bc.fBoidRadius*0.5f;
		if (farz > m_pos.z)
			m_accel += m_heading*bc.factorAvoidLand;
		else
			m_accel += -m_heading*bc.factorAvoidLand;
		m_accel.z = 0;
	}
	//////////////////////////////////////////////////////////////////////////
}
Esempio n. 4
0
void CBoidBird::Think( float dt,SBoidContext &bc )
{
	m_accel.zero();
	

	float factorAlignment = bc.factorAlignment;
	float factorCohesion = bc.factorCohesion;
	float factorSeparation = bc.factorSeparation;
	float factorAvoidLand = bc.factorAvoidLand;
	float factorAttractToOrigin = bc.factorAttractToOrigin;
	float factorKeepHeight = bc.factorKeepHeight;

	if(m_status == Bird::LANDING)
	{
		//factorAlignment /= 3.f;
		factorCohesion *=10.f;
		factorSeparation = 0;
		factorAvoidLand = 0;
		factorAttractToOrigin *=10;
		factorKeepHeight = 0;
	}
	
	if (m_spawnFromPt)
	{
		// Set the acceleration of the boid
		float fHalfDesired = m_desiredHeigh * .5f;
		if (m_pos.z < fHalfDesired)
		{
			m_accel.z = 3.f;
		}
		else
		{
			m_accel.z = .5f;
			// Set z-acceleration
			float fRange = 1.f - (m_pos.z-fHalfDesired)/fHalfDesired;	// 1..0 range

			if (m_heading.z > 0.2f)
				m_accel.z = .5f + fRange;	// 2..1

			m_accel.x += m_heading.x * .1f;
			m_accel.y += m_heading.y * .1f;
		}

		if (m_pos.z > m_desiredHeigh)
			SetSpawnFromPt(false);

		// Limits birds to above water and land.
		if (m_pos.z < bc.terrainZ-0.2f)
		{
			m_pos.z = bc.terrainZ-0.2f;
		}
		if (m_pos.z < bc.waterLevel-0.2f)
		{
			m_pos.z = bc.waterLevel-0.2f;
		}
		return;
	}
	
	float height = m_pos.z - bc.flockPos.z;

	// Free will.
	// Continue accelerating in same dir until target speed reached.
	// Try to maintain average speed of (maxspeed+minspeed)/2
	float targetSpeed = (bc.MaxSpeed + bc.MinSpeed)/2;
	m_accel -= m_heading*(m_speed-targetSpeed)*0.5f;

	// Desired height.
	float dh = m_desiredHeigh - m_pos.z;
	float dhexp = -(dh*dh)/(3*3);

	dhexp = clamp_tpl(dhexp,-70.0f,70.0f); // Max values for expf
	// Gaussian weight.
	float fKeepHeight = factorKeepHeight - m_fNoKeepHeight;
	m_fNoKeepHeight = max(0.f, m_fNoKeepHeight - .01f*dt);
	m_accel.z = exp_tpl(dhexp) * fKeepHeight;

	if (factorAlignment != 0)
	{
		//CalcCohesion();
		Vec3 alignmentAccel;
		Vec3 cohesionAccel;
		Vec3 separationAccel;
		CalcFlockBehavior(bc,alignmentAccel,cohesionAccel,separationAccel);

		//! Adjust for allignment,
		//m_accel += alignmentAccel.Normalized()*ALIGNMENT_FACTOR;

		m_accel += alignmentAccel*factorAlignment;
		m_accel += cohesionAccel*factorCohesion;
		m_accel += separationAccel*factorSeparation;
	}

	// Avoid land.
	if (height < bc.MinHeight && m_status != Bird::LANDING)
	{
		float v = (1.0f - height/bc.MinHeight);
		m_accel += Vec3(0,0,v*v)*bc.factorAvoidLand;
	}
	else if (height > bc.MaxHeight)
	{		// Avoid max height.
		float v = (height - bc.MaxHeight)*0.1f;
		m_accel += Vec3(0,0,-v);
	}
	else if(m_status != Bird::TAKEOFF)
	{
		// Always try to accelerate in direction opposite to current in Z axis.
		m_accel.z = -(m_heading.z*m_heading.z*m_heading.z * 100.0f);
	}

		// Attract to origin point.
	float fAttractToOrigin = factorAttractToOrigin - m_fNoCenterAttract;
	m_fNoCenterAttract = max(0.f, m_fNoCenterAttract - .01f*dt);
	if (bc.followPlayer)
	{
		m_accel += (bc.playerPos - m_pos) * fAttractToOrigin;
	}
	else
	{
		if ((rand()&31) == 1)
		{
			m_birdOriginPos = Vec3(	bc.flockPos.x+Boid::Frand()*bc.fSpawnRadius,bc.flockPos.y+Boid::Frand()*bc.fSpawnRadius,bc.flockPos.z+Boid::Frand()*bc.fSpawnRadius );
			if (m_birdOriginPos.z - bc.terrainZ < bc.MinHeight)
			{
				m_birdOriginPos.z = bc.terrainZ + bc.MinHeight;
			}
		}

		m_accel += (m_birdOriginPos - m_pos) * fAttractToOrigin;
	}

	// Attract to bc.attractionPoint
	if (m_pos.GetSquaredDistance2D(bc.attractionPoint) < 5.f)
	{
		SetAttracted(false);

		CBirdsFlock *pFlock = (CBirdsFlock *)m_flock;
		if (!pFlock->GetAttractOutput())
		{	// Activate the AttractTo flownode output
			pFlock->SetAttractOutput(true);

			// Activate the flow node output
			IEntity *pFlockEntity = pFlock->GetEntity();
			if (pFlockEntity)
			{
				IScriptTable *scriptObject = pFlockEntity->GetScriptTable();
				if (scriptObject)
					Script::CallMethod(scriptObject, "OnAttractPointReached");
			}
		}
	}
	if (m_attractedToPt)
	{
		if(m_status == Bird::ON_GROUND)
			TakeOff(bc);
		else
			SetStatus(Bird::FLYING);

		m_accel += (bc.attractionPoint - m_pos) * m_fAttractionFactor;
		if (m_fAttractionFactor < 300.f * factorAttractToOrigin) m_fAttractionFactor += 3.f*dt;
	}

	// Avoid collision with Terrain and Static objects.
	float fCollisionAvoidanceWeight = 1.0f;

	m_alignHorizontally = 0;

	if(m_status == Bird::TAKEOFF)
	{ 
		if(m_accel.z < 0)
			m_accel.z = -m_accel.z;

		m_accel.z *= bc.factorTakeOff;
	}

	if (bc.avoidObstacles)
	{
		// Avoid obstacles & terrain.
		float fCollDistance = m_collisionInfo.CheckDistance() ;

		if(m_collisionInfo.IsColliding())
		{
				float w = (1.0f - m_collisionInfo.Distance()/fCollDistance);
				m_accel += m_collisionInfo.Normal() * w*w * bc.factorAvoidLand * fCollisionAvoidanceWeight;
		}
	}

	// Limits birds to above water and land.
	if (m_pos.z < bc.terrainZ-0.2f)
	{
		m_pos.z = bc.terrainZ-0.2f;
	}
	if (m_pos.z < bc.waterLevel-0.2f)
	{
		m_pos.z = bc.waterLevel-0.2f;
	}
}