void SpawnRandomEntity()
    {
        // we randomly get an entity from the array, and instantiate it in the scene.
        GameObject spawnedObject = Instantiate(GetGameObjectBasedOnProbability()) as GameObject;
        // compute a angle offset. this will ensure that the arc's center is always facing the player's initial orientation.
        float angleOffset = (180 - this.spawnAngle) / 2f;

        // The lower angle shall be at the offset + 0. defines the left side of the arc.
        lowerAngle = angleOffset;
        // The higher angle shall be at the offset + angle. defines the right side of the arc.
        higherAngle = this.spawnAngle + angleOffset;
        // chooses a random angle between the lower and the higher, i.e. a random point in the arc.
        float angle = Random.Range(lowerAngle, higherAngle);
        // does math magic to translate the angle to a point of a radius 1 circunference.
        Vector3 randomCircle = new Vector3(Mathf.Cos(angle * Mathf.Deg2Rad), 0, Mathf.Sin(angle * Mathf.Deg2Rad));
        // multiplies the coordinate of the radius 1 circunference by the radius to obtain the coordinate in the actual circunference.
        Vector3 worldPos = transform.TransformPoint(randomCircle * radius);

        // set the gameobject (entity) position and look at the player.
        spawnedObject.transform.position = worldPos;
        spawnedObject.transform.LookAt(player.transform);
        if (ShouldAttachMoveComponent())
        {
            AttachMoveComponent(spawnedObject, angle);
        }
        // we get the Target Script. we know all entities are targets and so, contain this script.
        TargetScript ts = spawnedObject.GetComponent <TargetScript>();

        if (ts != null)
        {
            if (ts.GetType() == typeof(ScoreTarget))
            {
                ((ScoreTarget)ts).scoreManager = this.scoreManager;
            }
            if (ts.GetType() == typeof(BonusTarget))
            {
                ((BonusTarget)ts).bonusManager = this.bonusManager;
            }

            ts.timeToHide = timeUntilTargetDisappears;
            ts.player     = this.player.transform;

            ts.desiredHeightOffset = GetRandomHeight();
            // float halfAngle = (lowerAngle + higherAngle) / 2f;
            // //first sector. lerp from A0 (lower angle) to A1 (higher angle) (A0 -> min height, A1 -> max height);
            // if (angle < halfAngle)
            // {
            //     ts.desiredHeightOffset = Mathf.Lerp(minHeight, maxHeight, Mathf.InverseLerp(lowerAngle, halfAngle, angle)); // the height will depend on the angle.
            // }
            // else
            // {
            //     // second sector. lerp from A1 (higher angle) to A0 (lower angle).
            //     ts.desiredHeightOffset = Mathf.Lerp(maxHeight, minHeight, Mathf.InverseLerp(halfAngle, higherAngle, angle)); // the height will depend on the angle.
            // }
        }
    }
        public IEnumerator Should_ThrowArgumentException_When_GameObjectArrayRemainsEmpty()
        {
            TargetScript = DummyGameObject.AddComponent <ToggleGameObjects>();
            FieldInfo    = TargetScript.GetType().BaseType.GetField("_objects", BindingFlags.NonPublic | BindingFlags.Instance);

            FieldInfo.SetValue(TargetScript, new GameObject[] {});

            TestSettings.ExpectException("ArgumentException:");
            yield return(null);
        }
        public IEnumerator Should_ThrowNullReferenceException_When_AtLeastOneGameObjectArrayElementIsNull()
        {
            TargetScript = DummyGameObject.AddComponent <ToggleGameObjects>();
            FieldInfo    = TargetScript.GetType().BaseType.GetField("_objects", BindingFlags.NonPublic | BindingFlags.Instance);

            var gameobjects = new GameObject[] { null };

            FieldInfo.SetValue(TargetScript, gameobjects);

            TestSettings.ExpectException("NullReferenceException:");
            yield return(null);
        }
        public IEnumerator Should_ContainOnlyActiveGameObjects_When_ScriptFullyInitialized()
        {
            TargetScript = DummyGameObject.AddComponent <ToggleGameObjects>();
            FieldInfo    = TargetScript.GetType().BaseType.GetField("_objects", BindingFlags.NonPublic | BindingFlags.Instance);

            var gameobjects = new[] { new GameObject(TypeName), new GameObject(TypeName) };

            FieldInfo.SetValue(TargetScript, gameobjects);

            var actual = gameobjects[0].activeSelf && gameobjects[1].activeSelf;

            Assert.IsTrue(actual);
            yield return(null);
        }
        public IEnumerator Should_DisableAllGameObjects_When_ToggleMethodWasCalled()
        {
            TargetScript = DummyGameObject.AddComponent <ToggleGameObjects>();
            FieldInfo    = TargetScript.GetType().BaseType.GetField("_objects", BindingFlags.NonPublic | BindingFlags.Instance);

            var gameobjects = new[] { new GameObject(TypeName), new GameObject(TypeName) };

            FieldInfo.SetValue(TargetScript, gameobjects);
            TargetScript.Toggle();

            var actual = gameobjects[0].activeSelf || gameobjects[1].activeSelf;

            Assert.IsFalse(actual);
            yield return(null);
        }
        public IEnumerator Should_ContainOnlyActiveComponents_When_ScriptFullyInitialized()
        {
            TargetScript = DummyGameObject.AddComponent <ToggleComponents>();
            FieldInfo    = TargetScript.GetType().BaseType.GetField("_objects", BindingFlags.NonPublic | BindingFlags.Instance);

            var monoBehaviour1 = new GameObject(TypeName).AddComponent <DefaultBehaviour>();
            var monoBehaviour2 = new GameObject(TypeName).AddComponent <DefaultBehaviour>();
            var components     = new[] { monoBehaviour1, monoBehaviour2 };

            FieldInfo.SetValue(TargetScript, components);

            var propertyInfo         = typeof(MonoBehaviour).GetProperty("enabled");
            var monobehaviour1Status = (bool)propertyInfo.GetValue(monoBehaviour1, null);;
            var monobehaviour2Status = (bool)propertyInfo.GetValue(monoBehaviour2, null);;

            var actual = monobehaviour1Status && monobehaviour2Status;

            Assert.IsTrue(actual);
            yield return(null);
        }