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; } }
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); }
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; } }
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)); }