public static DOutput rotate_right(ResourceFightDNCreature p_cre)
 {
     return((float p_input) =>
     {
         p_cre.m_actions.add("ROTATE", p_input, () => { p_cre.transform.Rotate(0, 0, 2); });
     });
 }
 public static DInput zero_input(ResourceFightDNCreature p_cre)
 {
     return(() =>
     {
         return 0;
     });
 }
 public static DInput canShoot(ResourceFightDNCreature p_cre)
 {
     return(() =>
     {
         return p_cre.m_cooldowns.isCooldownOver("SHOOT") ? 1f : 0f;
     });
 }
 public static DOutput dont_gather_resource(ResourceFightDNCreature p_cre)
 {
     return((float p_input) =>
     {
         p_cre.m_actions.add("GATHER", p_input, () => { return; });
     });
 }
 public static DOutput dont_shoot(ResourceFightDNCreature p_cre)
 {
     return((float p_input) =>
     {
         p_cre.m_actions.add("SHOOT", p_input, () => { return; });
     });
 }
 public static DOutput stop_rotation(ResourceFightDNCreature p_cre)
 {
     return((float p_input) =>
     {
         p_cre.m_actions.add("ROTATE", p_input, () => { p_cre.m_rb.angularVelocity *= 0.85f; });
     });
 }
 public static DOutput move_backwards(ResourceFightDNCreature p_cre)
 {
     return((float p_input) =>
     {
         p_cre.m_actions.add("MOVE", p_input, () => { p_cre.move(-p_cre.m_forward * 5f); });
     });
 }
    public static DInput isHurt(ResourceFightDNCreature p_cre)
    {
        DActivationFunction activate = ActivationFactory.generateSigmoid(1, 1, false, true, true);

        return(() =>
        {
            return activate(p_cre.m_health.Value / p_cre.m_health.Max);
        });
    }
    //Shooting

    public static DInput creatureInShotline(ResourceFightDNCreature p_cre)
    {
        return(() =>
        {
            RaycastHit2D hit = Physics2D.Raycast(p_cre.transform.position + Vector3Calc.fromVec2(p_cre.m_forward * 0.13f), p_cre.m_forward, 10f, 1 << 10);
            //Debug.DrawLine(p_cre.transform.position + Vector3Calc.fromVec2(p_cre.m_forward*0.13f) ,p_cre.transform.position+ Vector3Calc.fromVec2(p_cre.m_forward)*3, Color.red, 10f);
            return hit ? 1f : 0f;
        });
    }
 public static DOutput shoot(ResourceFightDNCreature p_cre)
 {
     return((float p_input) =>
     {
         if (p_cre.m_cooldowns.isCooldownOver("SHOOT"))
         {
             p_cre.m_actions.add("SHOOT", p_input, () => { p_cre.shoot(); });
         }
     });
 }
    //Resource
    public static DInput isHungry(ResourceFightDNCreature p_cre)
    {
        DActivationFunction activate = ActivationFactory.generateSigmoid(1, 1, false, true, true);

        return(() =>
        {
            //Debug.Log(p_cre.m_energy.Value + " : " + activate(p_cre.m_energy.Value/p_cre.m_energy.Max));
            return activate(p_cre.m_energy.Value / p_cre.m_energy.Max);
        });
    }
    public static DInput bulletsUpAhead(ResourceFightDNCreature p_cre)
    {
        DActivationFunction activate = ActivationFactory.generateSigmoid(5, 1, false, true, false);

        return(() =>
        {
            GameObject[] bullets = p_cre.sense("BULLET");
            // Debug.Log(bullets.Length + " : " + activate(bullets.Length));
            return activate(bullets.Length);
        });
    }
    //Spawning: Controls location, initialization, etc.
    void spawnCreature()
    {
        GameObject obj = Instantiate(
            m_creature_prefab,
            new Vector3(

                /*RandomCalc.Rand(new Range<float>(-10f, 10)),
                *  RandomCalc.Rand(new Range<float>(-10f, 10)),*/0, 0,
                0
                ),
            Quaternion.Euler(0, 0, Random.Range(0, 360))
            );

        ResourceFightDNCreature cre = obj.GetComponent <ResourceFightDNCreature>();

        cre.Initialize(m_evolution.birth(), this);
    }
    public static DOutput aim_at_nearest_creature(ResourceFightDNCreature p_cre)
    {
        return((float p_input) =>
        {
            GameObject creature = p_cre.senseClosest("CREATURE");

            if (creature)
            {
                float angle = Vector2Calc.getAngle(p_cre.m_forward, creature.transform.position - p_cre.transform.position);
                p_cre.m_actions.add("ROTATE", p_input, () => { p_cre.transform.Rotate(0, 0, -2 * Mathf.Sign(angle)); });
            }
            else
            {
                return;
            }
        });
    }
    public static DOutput search_resource(ResourceFightDNCreature p_cre)
    {
        return((float p_input) =>
        {
            GameObject resource = p_cre.senseClosest("RESOURCE");

            if (resource)
            {
                float angle = Vector2Calc.getAngle(p_cre.m_forward, resource.transform.position - p_cre.transform.position);
                p_cre.m_actions.add("ROTATE", p_input, () => { p_cre.transform.Rotate(0, 0, -2 * Mathf.Sign(angle)); });

                if (angle < 10f)
                {
                    p_cre.m_actions.add("MOVE", p_input, () => { p_cre.move(p_cre.m_forward); });
                }
            }
            else
            {
                p_cre.m_actions.add("ROTATE", p_input, () => { p_cre.transform.Rotate(0, 0, 1); });
            }
        });
    }
    //Dodging
    public static DInput bulletCollisionImminent(ResourceFightDNCreature p_cre)
    {
        DActivationFunction prox_activate  = ActivationFactory.generateSigmoid(1.5f, 2, false, true, true);
        DActivationFunction angle_activate = ActivationFactory.generateSigmoid(10f, 2, false, true, true);
        DActivationFunction full_activate  = ActivationFactory.generateSigmoid(1, 1, false, true, false);


        return(() =>
        {
            GameObject[] bullets = p_cre.sense("BULLET");

            List <GameObject> bullets_close_and_coming_towards = new List <GameObject>();

            foreach (GameObject bul in bullets)
            {
                if (Vector2Calc.proximity(bul.transform.position, p_cre.transform.position) < 2 && Vector2Calc.checkAngle(p_cre.transform.position - bul.transform.position, bul.GetComponent <Rigidbody2D>().velocity, 10))
                {
                    bullets_close_and_coming_towards.Add(bul);
                }
            }

            float activation = 0;

            foreach (GameObject bul in bullets_close_and_coming_towards)
            {
                float bul_prox = prox_activate(Vector2Calc.proximity(bul.transform.position, p_cre.transform.position) - 0.5f);
                float bul_angle = angle_activate(Mathf.Abs(Vector2Calc.getAngle(p_cre.transform.position - bul.transform.position, bul.GetComponent <Rigidbody2D>().velocity)));

                float bul_active = full_activate(bul_prox * bul_angle);
                if (bul_active > activation)
                {
                    activation = bul_active;
                }
            }
            //if(activation >0 ) Debug.Log(activation);

            return activation;
        });
    }
    public static DInput isStronger(ResourceFightDNCreature p_cre)
    {
        DActivationFunction activate = ActivationFactory.generateSigmoid(1f, 1, false, true, false);

        return(() =>
        {
            GameObject closest = p_cre.senseClosest("CREATURE");

            if (closest == null)
            {
                return 0;
            }

            ResourceFightDNCreature enemy = closest.GetComponent <ResourceFightDNCreature>();

            float strength_check = (p_cre.m_health.Value + (p_cre.m_damage * 5)) / (enemy.m_health.Value + (enemy.m_damage * 5));

            //Debug.Log( "[" + strength_check +"] " +  activate( strength_check-0.5f ) );

            return activate(strength_check - 0.5f); //Your mesure of toughness/ enemy mesure of toughness set up so double enemy gives 0 and half enemy 1
        });
    }
    void Start()
    {
        //Instantiate controller
        m_evolution = new DNABasedEvolutionManager <MindBodyDNDNA <ResourceFightDNCreature> >(
            new MindBodySpeciesDN <ResourceFightDNCreature>(0,
                                                            new TraitGenesSpecies(0, new HashSet <string> {
            "SPEED", "HEALTH", "DAMAGE", "ENERGY", "ATTACKSPEED"
        }, 1, new Range <float>(2f, 2f), 0, new Range <float>(0f, 0f)),
                                                            new DecisionNetSpecies <ResourceFightDNCreature>(0, ResourceFightDNCreature.getInputFactorys(), ResourceFightDNCreature.getOutputFactorys(), new Range <float>(0.8f, 1.2f))
                                                            ), 0.1f, 20, (float p_fitness) => { return(p_fitness * 0.95f); }, 1f
            );

        //Fill with 20 random
        for (int i = 0; i < 10; i++)
        {
            m_evolution.addRandom();
        }

        //Instantaite Interval and Listeners
        m_interval = new IntervalEventManager();

        for (int i = 0; i < 5; i++)
        {
            spawnResource();
        }

        for (int i = 0; i < 50; i++)
        {
            spawnCreature();
        }

        // spawnCreature();
        // spawnCreature();


        m_interval.addListener(5f, () => {
            for (int i = 0; i < 5; i++)
            {
                spawnCreature();
            }
        });

        m_interval.addListener(10f, () => {
            for (int i = 0; i < 1; i++)
            {
                spawnResource();
            }
        });

        m_interval.addListener(30f, () => {
            GameObject[] obs = ObjectLogger.getByType("CREATURE");

            foreach (GameObject ob in obs)
            {
                ob.GetComponent <ResourceFightDNCreature>().logFitness();
            }
        });
    }