using UnityEngine;
using System.Collections.Generic;
using System;
using System.Collections;
public enum AntState
{
LOOKING_FOR_FOOD,
RETURNING_FOOD_TO_NEST,
/* To be Implmented
ATTACKING_ENEMY,
WARNING_ALLIES
*/
};
public class Ant : MonoBehaviour
{
//an ants actions depend on his current state
public AntState state { get; private set; }
public Vector3 position { get { return transform.position; } set { transform.position = value; } }
//a reference to the last pheromone. Used to set the direction of the next pheromone
public Pheromone last_placed_pheromone { get; set; }
//the final velocity of an ant is based on a random direction and influences from pheromones.
private Vector3 _velocity_random, _velocity_pheromone, _velocity_opposing;
//this is the actual velocity that the ant will use to move
public Vector3 velocity_final;
public NodeManager node_manager { private get; set; }
public Vector3 nest_position { private get; set; }
//random interval, so not all ants are updated at the same time.
private float _speed_random;
//the final speed the ant will use to move
private float _speed_final;
private bool _can_walk = true;
///
///the start function is a coroutine and functions as the update function.
///
IEnumerator Start( )
{
state = AntState.LOOKING_FOR_FOOD;
//all ants start at the nest.
position = nest_position.clone( );
//give a random element to the update time, so update times are spread
_speed_random = UnityEngine.Random.value * 2;
//set timers that will fire every so many seconds
float t_a = 7 / _speed_final, t_b = 51;
while ( true )
{
t_a += Time.deltaTime;
//the timer fires at different intervals, depending on the ant speed.
//this way, the rate of pheromone drops is equal, regardless of speed
if ( t_a >= 7 / _speed_final )
{
_speed_final = _speed_random + node_manager.gui_editor.get_ant_speed( );
node_manager.drop_pheromone( this );
//reset the pheromone drop timer
t_a = 0;
t_b++;
}
//if we are getting or delivering food we dont do anything this update
if ( !_can_walk )
{
//first, we are no longer unable to walk
_can_walk = true;
//wait for 2 seconds before going back to work.
yield return new WaitForSeconds( 2 );
}
//after 7 pheromones were dropped, move the ant in another direction.
if ( t_b >= node_manager.gui_editor.get_change_direction_rate( ) )
{
set_random_direction( );
//get a direction that is influenced by the pheromones in the vicinity
set_influence_from_pheromones( );
//Finally, set the velocity of the ant and make it move
StartCoroutine( calculate_velocity( ) );
//reset the counter so that the
t_b = 0;
}
//if we are at the edge of the grid (we have a collision with the 'walls' of the grid
if ( is_at_border( ) )
{
//reset the counter, so the ant doesnt change direction.
t_b = 0;
}
yield return null;
}
}
///
/// makes sure the ant doesn't walk out of the grid
///
bool is_at_border( )
{
foreach ( Plain p in node_manager.borders )
{
Vector3 ray;
if ( p.will_collide( this, NodeManager.node_size, out ray ) )
{
//make the ant walk in the opposite direction.
p.reflect_velocity( ref velocity_final, ray );
//make the ant move to the new location
StartCoroutine( move_to_new_location( position + velocity_final, 4 ) );
return true;
}
}
return false;
}
///
/// calculates the final velocity and then makes the ant move in that direction.
///
private IEnumerator calculate_velocity( )
{
update_velocity_smoothly( );
//then, we are moving towards that velocity over a period of 4 seconds
yield return StartCoroutine( move_to_new_location( position + velocity_final, 4 ) );
}
void OnTriggerEnter( Collider other )
{
switch( other.gameObject.tag )
{
//if we collided with the nest
case "nest":
// and we were looking for it
if ( state == AntState.RETURNING_FOOD_TO_NEST )
{
state = AntState.LOOKING_FOR_FOOD;
//we cannot walk for a short period of time (we are returning food)
_can_walk = false;
}
break;
//if we collided with food
case "food":
//and we are looking for food
if ( state == AntState.LOOKING_FOR_FOOD )
{
//since food can disappear after we ate it all, return if it is null
if ( other.gameObject == null ) return;
//otherwise, get the food component and tell it we are eating it
( other.gameObject.GetComponent( typeof( Food ) ) as Food ).on_ant_took_food( );
state = AntState.RETURNING_FOOD_TO_NEST;
_can_walk = false;
}
break;
}
}
void update_velocity_smoothly( )
{
//add the three components to summon to_velocity, master of direction! Vector3 to_velocity = ( _velocity_random + _velocity_pheromone + _velocity_opposing ).normalized * _speed_final; //get a mor