void FixedUpdate() { //Algorithm based on //http://www.cs.toronto.edu/~dt/siggraph97-course/cwr87/ //http://www.red3d.com/cwr/boids/ //Bird is affected by 3 base forses: // cohesion // separation + collisionAvoidance // alignmentForce var sepForce = new BoidTools.SeparationForce(sts); var collAvoid = new BoidTools.CollisionAvoidanceForce( sts, sepForce.Calc(sts.OptDistance) ); //Geometric center of visible birds var centeroid = Vector3.zero; var collisionAvoidance = Vector3.zero; var avgSpeed = Vector3.zero; var neighbourCount = 0; //Store it as an optimization var direction = transform.rotation * Vector3.forward; var curPos = transform.position; foreach( var vis in Physics.OverlapSphere(curPos, sts.ViewRadius) ) { var visPos = vis.transform.position; Boid boid; ITrigger trigger; if( (boid = vis.GetComponent<Boid>()) != null ) //Birds processing { Vector3 separationForce; if( !sepForce.Calc(curPos, visPos, out separationForce) ) continue; collisionAvoidance += separationForce; ++neighbourCount; centeroid += visPos; avgSpeed += boid.velocity; } else if( (trigger = vis.GetInterface<ITrigger>()) != null ) { if( GetComponent<Collider>().bounds.Intersects(vis.bounds) ) trigger.OnTouch(this); } else //Obstacles processing { BoidTools.CollisionAvoidanceForce.Force force; if( collAvoid.Calc(curPos, direction, vis, out force) ) { collisionAvoidance += force.dir; if( dbgSts.enableDrawing && dbgSts.obstaclesAvoidanceDraw ) Drawer.DrawRay( force.pos, force.dir, dbgSts.obstaclesAvoidanceColor ); } } } if( neighbourCount > 0 ) { //Cohesion force. It makes united formula with BoidTools.SeparationForce centeroid = centeroid / neighbourCount - curPos; //Spherical shape of flock looks unnatural, so let's scale it along y axis centeroid.y *= sts.VerticalPriority; //Difference between current bird speed and average speed of visible birds avgSpeed = avgSpeed / neighbourCount - velocity; } var positionForce = (1.0f - sts.AligmentForcePart) * sts.SpeedMultipliyer * (centeroid + collisionAvoidance); var alignmentForce = sts.AligmentForcePart * avgSpeed / Time.deltaTime; var attractionForce = CalculateAttractionForce( sts, curPos, velocity ); var totalForce = sts.TotalForceMultipliyer * ( positionForce + alignmentForce + attractionForce ); var newVelocity = (1 - sts.Inertness) * (totalForce * Time.deltaTime) + sts.Inertness * velocity; velocity = CalcNewVelocity( sts.MinSpeed, velocity, newVelocity, direction ); var rotation = CalcRotation( sts.InclineFactor, velocity, totalForce ); if( MathTools.IsValid(rotation) ) gameObject.transform.rotation = rotation; ///////////////////////////////////////////////////////////// // Debug drawing ///////////////////////////////////////////////////////////// if( dbgSts.enableDrawing ) { if( dbgSts.velocityDraw ) Drawer.DrawRay( curPos, velocity, dbgSts.velocityColor ); if( dbgSts.positionForceDraw ) Drawer.DrawRay( curPos, positionForce, dbgSts.positionForceColor ); if( dbgSts.alignmentForceDraw ) Drawer.DrawRay( curPos, alignmentForce, dbgSts.alignmentForceColor ); if( dbgSts.cohesionForceDraw ) Drawer.DrawRay( curPos, centeroid, dbgSts.cohesionForceColor ); if( dbgSts.collisionsAvoidanceForceDraw ) Drawer.DrawRay( curPos, collisionAvoidance, dbgSts.collisionsAvoidanceForceColor ); if( dbgSts.attractionForceDraw ) Drawer.DrawRay( curPos, attractionForce, dbgSts.attractionForceColor ); if( dbgSts.totalForceDraw ) Drawer.DrawRay( curPos, totalForce, dbgSts.totalForceColor ); } }
void FixedUpdate() { //Algorithm based on //http://www.cs.toronto.edu/~dt/siggraph97-course/cwr87/ //http://www.red3d.com/cwr/boids/ //Bird is affected by 3 base forses: // cohesion // separation + collisionAvoidance // alignmentForce var sepForce = new BoidTools.SeparationForce(sts); var collAvoid = new BoidTools.CollisionAvoidanceForce(sts, sepForce.Calc(sts.OptDistance)); //Geometric center of visible birds var centeroid = Vector3.zero; var collisionAvoidance = Vector3.zero; var avgSpeed = Vector3.zero; var neighbourCount = 0; //Store it as an optimization var direction = transform.rotation * Vector3.forward; var curPos = transform.position; foreach (var vis in Physics.OverlapSphere(curPos, sts.ViewRadius)) { var visPos = vis.transform.position; Boid boid; ITrigger trigger; if ((boid = vis.GetComponent <Boid>()) != null) //Birds processing { Vector3 separationForce; if (!sepForce.Calc(curPos, visPos, out separationForce)) { continue; } collisionAvoidance += separationForce; ++neighbourCount; centeroid += visPos; avgSpeed += boid.velocity; } else if ((trigger = vis.GetInterface <ITrigger>()) != null) { if (collider.bounds.Intersects(vis.bounds)) { trigger.OnTouch(this); } } else //Obstacles processing { BoidTools.CollisionAvoidanceForce.Force force; if (collAvoid.Calc(curPos, direction, vis, out force)) { collisionAvoidance += force.dir; if (dbgSts.enableDrawing && dbgSts.obstaclesAvoidanceDraw) { Drawer.DrawRay(force.pos, force.dir, dbgSts.obstaclesAvoidanceColor); } } } } if (neighbourCount > 0) { //Cohesion force. It makes united formula with BoidTools.SeparationForce centeroid = centeroid / neighbourCount - curPos; //Spherical shape of flock looks unnatural, so let's scale it along y axis centeroid.y *= sts.VerticalPriority; //Difference between current bird speed and average speed of visible birds avgSpeed = avgSpeed / neighbourCount - velocity; } var positionForce = (1.0f - sts.AligmentForcePart) * sts.SpeedMultipliyer * (centeroid + collisionAvoidance); var alignmentForce = sts.AligmentForcePart * avgSpeed / Time.deltaTime; var attractionForce = CalculateAttractionForce(sts, curPos, velocity); var totalForce = sts.TotalForceMultipliyer * (positionForce + alignmentForce + attractionForce); var newVelocity = (1 - sts.Inertness) * (totalForce * Time.deltaTime) + sts.Inertness * velocity; velocity = CalcNewVelocity(sts.MinSpeed, velocity, newVelocity, direction); var rotation = CalcRotation(sts.InclineFactor, velocity, totalForce); if (MathTools.IsValid(rotation)) { gameObject.transform.rotation = rotation; } ///////////////////////////////////////////////////////////// // Debug drawing ///////////////////////////////////////////////////////////// if (dbgSts.enableDrawing) { if (dbgSts.velocityDraw) { Drawer.DrawRay(curPos, velocity, dbgSts.velocityColor); } if (dbgSts.positionForceDraw) { Drawer.DrawRay(curPos, positionForce, dbgSts.positionForceColor); } if (dbgSts.alignmentForceDraw) { Drawer.DrawRay(curPos, alignmentForce, dbgSts.alignmentForceColor); } if (dbgSts.cohesionForceDraw) { Drawer.DrawRay(curPos, centeroid, dbgSts.cohesionForceColor); } if (dbgSts.collisionsAvoidanceForceDraw) { Drawer.DrawRay(curPos, collisionAvoidance, dbgSts.collisionsAvoidanceForceColor); } if (dbgSts.attractionForceDraw) { Drawer.DrawRay(curPos, attractionForce, dbgSts.attractionForceColor); } if (dbgSts.totalForceDraw) { Drawer.DrawRay(curPos, totalForce, dbgSts.totalForceColor); } } }