public IEnumerator ActualTimeToContactAndInitialRadiusOfBallIsRandom()
            {
                LogAssert.ignoreFailingMessages = true;

                ISet <float> actualTimesToContact = new HashSet <float>();
                ISet <float> ballInitialRadiuses  = new HashSet <float>();

                foreach (var i in Enumerable.Range(1, SaveOneBall.NUMBER_OF_ROUNDS))
                {
                    // Wait for soccer players to load, kick balls, and then balls to be spawned
                    yield return(new WaitUntil(() => Object.FindObjectOfType <SoccerPlayer>() != null));

                    SoccerPlayer soccerPlayer = Object.FindObjectOfType <SoccerPlayer>();
                    yield return(new WaitUntil(() => soccerPlayer.PlayerHasKickedBall()));

                    yield return(new WaitUntil(() => Object.FindObjectOfType <BallProjectile>() != null));

                    foreach (BallProjectile ball in Object.FindObjectsOfType <BallProjectile>())
                    {
                        actualTimesToContact.Add(ball.ActualTimeToContact);
                        ballInitialRadiuses.Add(ball.BallInitialRadius);
                    }

                    Press(keyboard.aKey);
                }

                int numberOfUniqueActualTimesToContact = actualTimesToContact.Count;
                int numberOfUniqueBallInitialRadiuses  = ballInitialRadiuses.Count;

                Assert.AreNotEqual(1, numberOfUniqueActualTimesToContact);
                Assert.AreNotEqual(1, numberOfUniqueBallInitialRadiuses);
            }
            public IEnumerator WHEN_BallKickedAndRightBallKeyPressed_THEN_GloveMovesHorizontallyRightToTargetRing()
            {
                GameObject rightTargetRing = GameObject.Find("Canvas").transform.Find("RightTargetRing").gameObject;

                foreach (var _ in Enumerable.Range(1, SaveOneBall.NUMBER_OF_ROUNDS))
                {
                    // Wait for soccer player to load, kick ball, and then ball to be spawned
                    yield return(new WaitUntil(() => Object.FindObjectOfType <SoccerPlayer>() != null));

                    SoccerPlayer soccerPlayer = Object.FindObjectOfType <SoccerPlayer>();
                    yield return(new WaitUntil(() => soccerPlayer.PlayerHasKickedBall()));

                    yield return(new WaitUntil(() => Object.FindObjectOfType <BallProjectile>() != null));

                    GameObject glove = GameObject.Find("Glove");

                    Assert.False(glove.transform.position.Equals(rightTargetRing.transform.position.x));

                    Press(keyboard[SaveOneBall.RIGHT_BALL_KEY]);

                    yield return(new WaitForSeconds(
                                     CatchTheBall.SECONDS_FOR_GLOVES_TO_MOVE +
                                     0.5F * CatchTheBall.SECONDS_FOR_GLOVES_TO_REMAIN_IDLE
                                     ));

                    Assert.AreEqual(rightTargetRing.transform.position.x, glove.transform.position.x, 0.1F);
                }
            }
            public IEnumerator WHEN_BallsKicked_THEN_BallPositionsDoNotChange()
            {
                // Wait for soccer player to load, kick ball, and then ball to be spawned
                yield return(new WaitUntil(() => Object.FindObjectOfType <SoccerPlayer>() != null));

                SoccerPlayer soccerPlayer = Object.FindObjectOfType <SoccerPlayer>();

                yield return(new WaitUntil(() => soccerPlayer.PlayerHasKickedBall()));

                yield return(new WaitUntil(() => Object.FindObjectOfType <BallProjectile>() != null));

                BallProjectile[] balls = Object.FindObjectsOfType <BallProjectile>();
                BallProjectile   ball1 = balls[0];
                BallProjectile   ball2 = balls[1];

                float endingTime  = Time.time + Math.Max(ball1.ActualTimeToContact, ball2.ActualTimeToContact);
                float currentTime = Time.time;

                Vector3 ball1StartingPosition = ball1.transform.position;
                Vector3 ball2StartingPosition = ball2.transform.position;

                // For every frame before the last ball arrives, their positions should be
                // unchanged.
                while (endingTime - currentTime > 0)
                {
                    Assert.AreEqual(ball1StartingPosition, ball1.transform.position);
                    Assert.AreEqual(ball2StartingPosition, ball2.transform.position);
                    yield return(new WaitForSeconds(0.05f));

                    currentTime = Time.time;
                }
            }
Example #4
0
            public IEnumerator ActualTimeToContactAndInitialRadiusOfBallIsRandom()
            {
                ISet <float> actualTimesToContact = new HashSet <float>();
                ISet <float> ballInitialRadiuses  = new HashSet <float>();

                foreach (var i in Enumerable.Range(1, JudgeTheBall.NUMBER_OF_ROUNDS))
                {
                    // Wait for soccer players to load, kick balls, and then balls to be spawned
                    yield return(new WaitUntil(() => Object.FindObjectOfType <SoccerPlayer>() != null));

                    SoccerPlayer soccerPlayer = Object.FindObjectOfType <SoccerPlayer>();
                    yield return(new WaitUntil(() => soccerPlayer.PlayerHasKickedBall()));

                    yield return(new WaitUntil(() => Object.FindObjectOfType <BallProjectile>() != null));

                    foreach (BallProjectile ball in Object.FindObjectsOfType <BallProjectile>())
                    {
                        actualTimesToContact.Add(ball.ActualTimeToContact);
                        ballInitialRadiuses.Add(ball.BallInitialRadius);
                    }

                    yield return(new WaitUntil(() => Object.FindObjectOfType <Button>() != null));

                    Button submitButton = Object.FindObjectOfType <Button>();
                    submitButton.onClick.Invoke();
                }

                int numberOfUniqueActualTimesToContact = actualTimesToContact.Count;
                int numberOfUniqueBallInitialRadiuses  = ballInitialRadiuses.Count;

                Assert.AreNotEqual(1, numberOfUniqueActualTimesToContact);
                Assert.AreNotEqual(1, numberOfUniqueBallInitialRadiuses);
            }
Example #5
0
            public IEnumerator WHEN_BallKicked_THEN_BallPositionDoesNotChange()
            {
                // Wait for soccer player to load, kick ball, and then ball to be spawned
                yield return(new WaitUntil(() => Object.FindObjectOfType <SoccerPlayer>() != null));

                SoccerPlayer soccerPlayer = Object.FindObjectOfType <SoccerPlayer>();

                yield return(new WaitUntil(() => soccerPlayer.PlayerHasKickedBall()));

                yield return(new WaitUntil(() => Object.FindObjectOfType <BallProjectile>() != null));

                BallProjectile ball             = Object.FindObjectOfType <BallProjectile>();
                Vector3        startingPosition = ball.transform.position;

                float endingTime  = Time.time + ball.ActualTimeToContact;
                float currentTime = Time.time;

                // For every frame before the ball arrives, its position should be
                // unchanged.
                while (endingTime - currentTime > 0)
                {
                    Assert.AreEqual(startingPosition, ball.transform.position);
                    yield return(new WaitForSeconds(0.05f));

                    currentTime = Time.time;
                }
            }
Example #6
0
            public IEnumerator BallMovesAtConstantVelocity()
            {
                // Wait for soccer player to load, kick ball, and then ball to be spawned
                yield return(new WaitUntil(() => Object.FindObjectOfType <SoccerPlayer>() != null));

                SoccerPlayer soccerPlayer = Object.FindObjectOfType <SoccerPlayer>();

                yield return(new WaitUntil(() => soccerPlayer.PlayerHasKickedBall()));

                yield return(new WaitUntil(() => Object.FindObjectOfType <BallProjectile>() != null));

                BallProjectile ball             = Object.FindObjectOfType <BallProjectile>();
                Vector3        startingPosition = ball.transform.position;

                float endingTime  = Time.time + ball.ActualTimeToContact;
                float currentTime = Time.time;

                // For every frame before the ball arrives, its position should be
                // unchanged.
                List <double> ballScales = new List <double>();

                while (endingTime - currentTime > 0)
                {
                    ballScales.Add(ball.transform.localScale.x);
                    yield return(new WaitForSeconds(0.05f));

                    currentTime = Time.time;
                }

                // Utility method for calculating standard deviation
                // Credit: https://stackoverflow.com/a/6252351
                double StandardDeviation(IEnumerable <double> values)
                {
                    double avg = values.Average();

                    return(Math.Sqrt(values.Average(v => Math.Pow(v - avg, 2))));
                }

                // Find the absolute difference between two any
                // ball scales.
                IEnumerable <double> ballScaleDifferences = Enumerable.Zip(ballScales,
                                                                           ballScales.Skip(1),
                                                                           (x1, x2) => Math.Abs(x2 - x1));

                // If the data is linear, then
                // (ballScale(i+1) - ballScale(i)) = (ballScale(j+1) - ballScale(j))
                // for any frame i and j. Thus, we can take the standard deviation
                // of the ball scale differences. If it is close to 0, then
                // the ball scale differences are all almost the same, thus indicating
                // a linear relationship.
                double standardDeviation = StandardDeviation(ballScaleDifferences);

                // Check if the standard deviation is equal to 0 with a possible error
                // of ± 0.1.
                Assert.AreEqual(0, standardDeviation, 0.1);
            }
        public override IEnumerator StartRound()
        {
            BallRound ballRound = GenerateDataForRound(ballStorage.TargetRadius);

            Vector3 leftBallPosition  = LeftTargetRing.transform.position;
            Vector3 rightBallPosition = RightTargetRing.transform.position;

            SoccerPlayer leftSoccerPlayer  = InstantiateSoccerPlayer(leftBallPosition, ballRound.InitialLeftBallRadius);
            SoccerPlayer rightSoccerPlayer = InstantiateSoccerPlayer(rightBallPosition, ballRound.InitialRightBallRadius);

            yield return(new WaitUntil(() => leftSoccerPlayer.PlayerHasKickedBall() &&
                                       rightSoccerPlayer.PlayerHasKickedBall()
                                       ));

            BallProjectile leftBallProjectile = InstantiateBallProjectile(leftBallPosition,
                                                                          ballStorage.TargetRadius,
                                                                          ballRound.InitialLeftBallRadius,
                                                                          ballRound.LeftActualTimeToContact,
                                                                          // Ball doesn't disappear in Save One Ball
                                                                          ballTimeBeforeDisappearance: null
                                                                          );

            BallProjectile rightBallProjectile = InstantiateBallProjectile(rightBallPosition,
                                                                           ballStorage.TargetRadius,
                                                                           ballRound.InitialRightBallRadius,
                                                                           ballRound.RightActualTimeToContact,
                                                                           // Ball doesn't disappear in Save One Ball
                                                                           ballTimeBeforeDisappearance: null
                                                                           );

            // Record the time at which the "kick" takes place
            float beginTime = Time.time;

            // Make round end when the user hits any
            // key, or when they have waited too long (2 times the actual
            // time to contact)
            yield return(StartCoroutine(
                             WaitForInputOrTimeExpires(
                                 beginTime: beginTime,
                                 maxTimeToWait: 2 * Math.Min(ballRound.LeftActualTimeToContact, ballRound.RightActualTimeToContact),
                                 inputReceived: () => Keyboard.current[LEFT_BALL_KEY].isPressed || Keyboard.current[RIGHT_BALL_KEY].isPressed,
                                 ballProjectiles: new List <BallProjectile> {
                leftBallProjectile, rightBallProjectile
            },
                                 ballRound: ballRound
                                 )
                             ));
        }
        public override IEnumerator StartRound()
        {
            BallRound ballRound = GenerateDataForRound(ballStorage.TargetRadius);

            // The ball is at the centre of the screen in this round
            Vector3 ballPosition = new Vector3(0, 0, 0);

            SoccerPlayer soccerPlayer = InstantiateSoccerPlayer(ballPosition, ballRound.InitialBallRadius);

            yield return(new WaitUntil(() => soccerPlayer.PlayerHasKickedBall()));

            BallProjectile ballProjectile = InstantiateBallProjectile(ballPosition,
                                                                      ballStorage.TargetRadius,
                                                                      ballRound.InitialBallRadius,
                                                                      ballRound.ActualTimeToContact,
                                                                      // Balls don't disappear in Catch The Ball
                                                                      ballTimeBeforeDisappearance: null);

            // Record the time at which the "kick" takes place
            float beginTime = Time.time;

            // Make round end when the user hits any
            // key, or when they have waited too long (2 times the actual
            // time to contact)
            yield return(StartCoroutine(
                             WaitForInputOrTimeExpires(
                                 beginTime: beginTime,
                                 maxTimeToWait: 2 * ballRound.ActualTimeToContact,
                                 inputReceived: () => Keyboard.current.anyKey.isPressed,
                                 ballProjectiles: new List <BallProjectile> {
                ballProjectile
            },
                                 ballRound: ballRound
                                 )
                             ));
        }
        public override IEnumerator StartRound()
        {
            BallRound ballRound = GenerateDataForRound(ballStorage.TargetRadius);

            Vector3 fastBallPosition   = LeftTargetRing.transform.position;
            Vector3 playerBallPosition = MiddleTargetRing.transform.position;
            Vector3 slowBallPosition   = RightTargetRing.transform.position;

            SoccerPlayer fastBallPlayer   = InstantiateSoccerPlayer(fastBallPosition, ballRound.InitialFastBallRadius);
            SoccerPlayer playerBallPlayer = InstantiateSoccerPlayer(playerBallPosition, ballRound.InitialPlayerBallRadius);
            SoccerPlayer slowBallPlayer   = InstantiateSoccerPlayer(slowBallPosition, ballRound.InitialSlowBallRadius);

            yield return(new WaitUntil(() => fastBallPlayer.PlayerHasKickedBall() &&
                                       playerBallPlayer.PlayerHasKickedBall() && slowBallPlayer.PlayerHasKickedBall()
                                       ));

            BallProjectile fastBallProjectile = InstantiateBallProjectile(fastBallPosition,
                                                                          ballStorage.TargetRadius,
                                                                          ballRound.InitialFastBallRadius,
                                                                          ballRound.FastBallActualTimeToContact,
                                                                          ballRound.TimeBeforeDisappearence
                                                                          );

            BallProjectile playerBallProjectile = InstantiateBallProjectile(playerBallPosition,
                                                                            ballStorage.TargetRadius,
                                                                            ballRound.InitialPlayerBallRadius,
                                                                            ballRound.PlayerBallActualTimeToContact,
                                                                            ballRound.TimeBeforeDisappearence
                                                                            );

            BallProjectile slowBallProjectile = InstantiateBallProjectile(slowBallPosition,
                                                                          ballStorage.TargetRadius,
                                                                          ballRound.InitialSlowBallRadius,
                                                                          ballRound.SlowBallActualTimeToContact,
                                                                          ballRound.TimeBeforeDisappearence
                                                                          );

            // After the balls have disappeared,
            yield return(new WaitForSeconds(ballRound.TimeBeforeDisappearence));

            // Show the slider and submit button
            Slider.gameObject.SetActive(true);
            SubmitButton.gameObject.SetActive(true);

            // Make the lower value of the slider equal to arrival
            // time of the faster ball; make the upper value of the slider
            // equal to the arrival time of the slower ball
            Slider.minValue = ballRound.FastBallActualTimeToContact;
            Slider.maxValue = ballRound.SlowBallActualTimeToContact;

            // Move slider to half-way position
            Slider.value = (Slider.minValue + Slider.maxValue) / 2;

            bool buttonHasBeenClicked = false;
            // When the round is about to end,
            UnityAction whenButtonClicked = () =>
            {
                // Record the player's predicted time to contact
                // by seeing how they judged it compared to the reference
                // first-arriving and last-arriving balls.
                ballRound.PredictedTimeToContact = Slider.value;

                // Save data for this round
                ballStorage.Rounds.Add(ballRound);

                // Hide the slider and submit button
                Slider.gameObject.SetActive(false);
                SubmitButton.gameObject.SetActive(false);

                buttonHasBeenClicked = true;
            };

            // When the submit button is pressed, the round should end
            SubmitButton.onClick.AddListener(whenButtonClicked);

            yield return(new WaitUntil(() => buttonHasBeenClicked));
        }