void CFrogBoid::OnPickup( bool bPickup,float fSpeed ) { if (bPickup) { m_physicsControlled = true; PlayAnimationId( FROG_PICKUP_ANIM,true ); //PlaySound(FROG_SOUND_PICKUP); } else { m_bThrown = true; //PlaySound(FROG_SOUND_THROW); if (fSpeed > 5.0f && !m_invincible) { Kill( m_pos,Vec3(0,0,0) ); } else { // Wait until fall to the ground and go resting. PlayAnimationId( FROG_THROW_ANIM,true ); } if (m_pPhysics) { // Enabling reporting of physics collisions. pe_params_flags pf; pf.flagsOR = pef_log_collisions; m_pPhysics->SetParams(&pf); } } }
void CBoidBird::UpdateOnGroundAction(float dt, SBoidContext& bc) { if(m_actionTime > m_maxActionTime) { switch(m_onGroundStatus) { case Bird::OGS_IDLE: // walk again if the designer has provided us with a walk speed > 0 if(bc.walkSpeed > 0) { m_onGroundStatus = Bird::OGS_WALKING; PlayAnimationId(Bird::ANIM_WALK,true); m_actionTime = 0; m_maxActionTime = Random(bc.fOnGroundWalkDurationMin, bc.fOnGroundWalkDurationMax); } else { // otherwise just keep idling PlayAnimationId(Bird::ANIM_IDLE,true); m_actionTime = 0; m_maxActionTime = Random(bc.fOnGroundIdleDurationMin, bc.fOnGroundIdleDurationMax); } break; case Bird::OGS_SLOWINGDOWN: // came to a rest? => start idling if(m_speed < 0.001f) { m_onGroundStatus = Bird::OGS_IDLE; PlayAnimationId(Bird::ANIM_IDLE,true); m_actionTime = 0; m_maxActionTime = Random(bc.fOnGroundIdleDurationMin, bc.fOnGroundIdleDurationMax); } else { // still slowing down m_elapsedSlowdownTime += dt; } break; case Bird::OGS_WALKING: // start slowing down until we come to a rest m_onGroundStatus = Bird::OGS_SLOWINGDOWN; m_elapsedSlowdownTime = 0.0f; break; default: CRY_ASSERT_MESSAGE(0, "CBoidBird::UpdateOnGroundAction: omitted EOnGroundStatus"); } } }
void CChickenBoid::OnPickup(bool bPickup,float fSpeed) { if(bPickup) { m_physicsControlled = true; if(!m_dead) { PlayAnimationId(CHICKEN_PICKUP_ANIM,true); PlaySound(CHICKEN_SOUND_PICKUP); } } else { m_landing = false; m_bThrown = true; m_physicsControlled = false; if(!m_dead) { if(fSpeed > 5.0f) { Kill(m_pos,Vec3(0,0,0)); } else { PlayAnimationId(CHICKEN_WALK_ANIM,true); //m_physicsControlled = true; } PlaySound(CHICKEN_SOUND_THROW); // Wait until fall to the ground and go resting. //PlayAnimationId( CHICKEN_THROW_ANIM,true ); } if(m_pPhysics) { // Enabling reporting of physics collisions. pe_params_flags pf; pf.flagsOR = pef_log_collisions; m_pPhysics->SetParams(&pf); pe_action_awake aa; aa.bAwake = 1; m_pPhysics->Action(&aa); } } }
void CBoidBird::TakeOff( SBoidContext &bc ) { // Take-off. if(m_status != Bird::LANDING && m_status != Bird::ON_GROUND) return; SetStatus(Bird::TAKEOFF); static_cast<CBirdsFlock*>(m_flock)->LeaveLandingPoint(m_landingPoint); m_landingPoint.zero(); m_actionTime = 0; // m_maxActionTime = MIN_FLIGHT_TIME + (Boid::Frand()+1)/2*(MAX_FLIGHT_TIME-MIN_FLIGHT_TIME); m_maxActionTime = bc.flightTime *(1.2f +Boid::Frand()* 0.2f);// /2*(MAX_FLIGHT_TIME-MIN_FLIGHT_TIME); m_desiredHeigh = bc.MinHeight + (Boid::Frand()+1)/2*(bc.MaxHeight - bc.MinHeight)+bc.flockPos.z; m_takeOffStartTime = gEnv->pTimer->GetFrameStartTime(); if (m_object) { const char* takeoffName = bc.GetAnimationName(Bird::ANIM_TAKEOFF); if(m_TakeOffAnimLength ==0 && takeoffName != NULL && strlen(takeoffName) ) { int id = m_object->GetIAnimationSet()->GetAnimIDByName(takeoffName); m_TakeOffAnimLength = m_object->GetIAnimationSet()->GetDuration_sec(id); if(m_TakeOffAnimLength ==0) m_TakeOffAnimLength = 0.5f; } m_playingTakeOffAnim = PlayAnimation( takeoffName ,false ); if(!m_playingTakeOffAnim) PlayAnimationId(Bird::ANIM_FLY,true); } }
void CTurtleBoid::Think(float dt,SBoidContext &bc) { bc.fMaxTurnRatio = 0.05f; if(m_bScared) { m_landing = false; m_actionTime = 0; dt = 0; } bool bWasScared = m_bScared; CChickenBoid::Think(dt,bc); if(m_bThrown) { m_pos.z = bc.engine->GetTerrainElevation(m_pos.x,m_pos.y) + bc.fBoidRadius*0.5f; } if(m_bScared && !m_bThrown) { // When scared will not move m_accel.Set(0,0,0); // If first frame scared play scared animation. if(!bWasScared) PlayAnimationId(CHICKEN_IDLE_ANIM+1,false,1.0f); m_landing = true; m_actionTime = 0; } else if(bWasScared) { // Not scared anymore, resume idle anim. m_maxNonIdleTime = cry_frand()*MAX_WALK_TIME; PlayAnimationId(CHICKEN_WALK_ANIM,true); m_landing = false; m_actionTime = 0; } }
void CBoidBird::Landed(SBoidContext& bc) { SetStatus(Bird::ON_GROUND); static_cast<CBirdsFlock*>(m_flock)->NotifyBirdLanded(); m_actionTime = 1000; m_accel.zero(); m_heading.z = 0; m_heading.NormalizeSafe(Vec3Constants<float>::fVec3_OneY); m_speed = 0; m_onGroundStatus = Bird::OGS_IDLE; PlayAnimationId( Bird::ANIM_IDLE,true ); }
void CFrogBoid::Think( float dt,SBoidContext &bc ) { Vec3 flockHeading(0,0,0); m_accel(0,0,0); bool bScaredJump = false; ////////////////////////////////////////////////////////////////////////// // Scare points also scare chicken off. ////////////////////////////////////////////////////////////////////////// if (bc.scareRatio > 0) { float sqrScareDist = m_pos.GetSquaredDistance(bc.scarePoint); if (sqrScareDist < bc.scareRadius*bc.scareRadius) { bScaredJump = true; } } ////////////////////////////////////////////////////////////////////////// m_fTimeToNextJump -= dt; if (m_onGround) { float fScareDist = MAX_FROG_SCARE_DISTANCE; float sqrPlayerDist = m_pos.GetSquaredDistance(bc.playerPos); if (m_fTimeToNextJump <= 0 || sqrPlayerDist < fScareDist*fScareDist || bScaredJump) { PlaySound(FROG_SOUND_JUMP); PlayAnimationId( FROG_JUMP_ANIM,false,0 ); m_fTimeToNextJump = 2.0f + cry_frand()*5.0f; // about every 5-6 second. //m_fTimeToNextJump = 0; // Scared by player or random jump. m_onGround = false; m_heading = m_pos - bc.playerPos; if (bScaredJump) { // Jump from scare point. m_heading = Vec3(m_pos - bc.scarePoint).GetNormalized(); } else if (sqrPlayerDist < fScareDist*fScareDist) { // Jump from player. m_heading = Vec3(m_pos - bc.playerPos).GetNormalized(); } else { if (m_heading != Vec3(0,0,0)) { m_heading = m_heading.GetNormalized(); } else m_heading = Vec3(Boid::Frand(),Boid::Frand(),Boid::Frand()).GetNormalized(); if (m_pos.GetSquaredDistance(bc.flockPos) > bc.fSpawnRadius) { // If we are too far from spawn radius, jump back. Vec3 jumpToOrigin = Vec3( bc.flockPos.x+Boid::Frand()*bc.fSpawnRadius,bc.flockPos.y+Boid::Frand()*bc.fSpawnRadius,bc.flockPos.z+Boid::Frand()*bc.fSpawnRadius ); m_heading = Vec3(jumpToOrigin-m_pos).GetNormalized(); } } m_heading += Vec3(Boid::Frand()*0.4f,Boid::Frand()*0.4f,0 ); m_heading.Normalize(); m_heading.z = 0.5f + (Boid::Frand()+1.0f)*0.3f; m_heading.Normalize(); if (bc.avoidObstacles) { int retries = 4; bool bCollision; do { bCollision = false; // Avoid obstacles & terrain. IPhysicalWorld *physWorld = bc.physics; Vec3 vPos = m_pos + Vec3(0,0,bc.fBoidRadius*0.5f); Vec3 vDir = m_heading*(bc.fBoidRadius*5) + Vec3(0,0,bc.fBoidRadius*1.0f); 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) { bCollision = true; m_heading = Vec3(Boid::Frand(),Boid::Frand(),0 ); // Pick some random jump vector. m_heading.Normalize(); m_heading.z = 0.5f + (Boid::Frand()+1.0f)*0.3f; m_heading.Normalize(); } } while (!bCollision && retries-- > 0); } m_speed = bc.MinSpeed + cry_frand()*(bc.MaxSpeed-bc.MinSpeed); } } bc.terrainZ = bc.engine->GetTerrainElevation(m_pos.x,m_pos.y) + bc.fBoidRadius*0.5f; float range = bc.MaxAttractDistance; Vec3 origin = bc.flockPos; if (bc.followPlayer) { origin = bc.playerPos; } // Keep in range. if (bc.followPlayer) { bool bChanged = false; if (m_pos.x < origin.x - range) { m_pos.x = origin.x + range; bChanged = true; } if (m_pos.y < origin.y - range) { m_pos.y = origin.y + range; bChanged = true; } if (m_pos.x > origin.x + range) { m_pos.x = origin.x - range; bChanged = true; } if (m_pos.y > origin.y + range) { m_pos.y = origin.y - range; bChanged = true; } if (bChanged) m_pos.z = bc.terrainZ = bc.engine->GetTerrainElevation(m_pos.x,m_pos.y) + bc.fBoidRadius*0.5f; } else { } if (!m_onGround) { m_accel.Set( 0,0,-10 ); } if (m_pos.z < bc.terrainZ+0.001f) { // Land. m_pos.z = bc.terrainZ+0.001f; if (!m_onGround) { m_heading.z = 0; m_onGround = true; m_speed = 0; PlayAnimationId( FROG_IDLE_ANIM,true ); } } // Do random idle sounds. if ((cry_rand()&0xFF) == 0) PlaySound(FROG_SOUND_IDLE); }
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; } ////////////////////////////////////////////////////////////////////////// }
void CBoidBird::Update( float dt,SBoidContext &bc ) { if (m_physicsControlled) { UpdatePhysics(dt,bc); return; } if (m_dead) return; if (m_heading.IsZero()) m_heading = Vec3(1,0,0); m_lastThinkTime += dt; { if (bc.followPlayer && !m_spawnFromPt) { if (m_pos.GetSquaredDistance(bc.playerPos) > MAX_BIRDS_DISTANCE*MAX_BIRDS_DISTANCE) { float z = bc.MinHeight + (Boid::Frand()+1)/2.0f*(bc.MaxHeight - bc.MinHeight); m_pos = bc.playerPos + Vec3(Boid::Frand()*MAX_BIRDS_DISTANCE,Boid::Frand()*MAX_BIRDS_DISTANCE,z ); m_speed = bc.MinSpeed + ((Boid::Frand()+1)/2.0f) / (bc.MaxSpeed - bc.MinSpeed); m_heading = Vec3(Boid::Frand(),Boid::Frand(),0).GetNormalized(); } } if(m_status == Bird::TAKEOFF) { float timePassed = (gEnv->pTimer->GetFrameStartTime() - m_takeOffStartTime).GetSeconds(); if(m_playingTakeOffAnim && timePassed >= m_TakeOffAnimLength) { m_playingTakeOffAnim = false; PlayAnimationId(Bird::ANIM_FLY,true); } else if( timePassed > TAKEOFF_TIME) { SetStatus(Bird::FLYING); } } if(m_status == Bird::LANDING) { Vec3 vDist(m_landingPoint - m_pos); float dist2 = vDist.GetLengthSquared2D(); float dist = sqrt_tpl(dist2 + vDist.z*vDist.z); if(dist > 0.02f && m_pos.z > m_landingPoint.z) { //if(vDist.z < 3 && m_heading) vDist /= dist; float fInterpSpeed = 2+fabs(m_heading.Dot(vDist))*3.f; Interpolate(m_heading,vDist, fInterpSpeed, dt); m_heading.NormalizeSafe(); if(m_heading.z < vDist.z) { Interpolate(m_heading.z,vDist.z,3.0f,dt); m_heading.NormalizeSafe(); } bool wasLandDeceleratingAlready = m_landDecelerating; m_accel.zero(); m_landDecelerating = dist < bc.landDecelerationHeight; if(m_landDecelerating) { float newspeed= m_startLandSpeed* dist/3.f; if(m_speed > newspeed) m_speed = newspeed; if(m_speed < 0.2f) m_speed = 0.2f; if(!wasLandDeceleratingAlready) PlayAnimationId(Bird::ANIM_LANDING_DECELERATING, true); } else m_startLandSpeed = m_speed; } else Landed(bc); CalcMovementBird( dt,bc,true ); UpdatePitch(dt,bc); return; } if (m_status != Bird::ON_GROUND) { Think(dt,bc); // Calc movement with current velocity. CalcMovementBird( dt,bc,true ); } else { if(bc.walkSpeed > 0 && m_onGroundStatus == Bird::OGS_WALKING) ThinkWalk(dt,bc); CalcMovementBird( dt,bc,true ); } m_accel.Set(0,0,0); UpdatePitch(dt,bc); // Check if landing/on ground after think(). if ( m_status == Bird::LANDING ||(m_dying && m_status != Bird::ON_GROUND)) { float LandEpsilon = 0.5f; // Check if landed on water. if (m_pos.z-bc.waterLevel < LandEpsilon+0.1f && !m_dying) { //! From water immidiatly take off. //! Gives fishing effect. TakeOff(bc); } } m_actionTime += dt; if (m_status == Bird::ON_GROUND ) UpdateOnGroundAction(dt, bc); else { if(!bc.noLanding && m_actionTime > m_maxActionTime && !static_cast<CBirdsFlock*>(m_flock)->IsPlayerNearOrigin()) Land(); } } }