Unity/Futile Pong Example (Part 7) – Scoring conditions and the user interface

By the end of this tutorial, you should have something that looks like this. You can download the Assets folder for this tutorial here.

The last tutorial gave some life to our game by adding collision detection. Unfortunately, we still don’t have any code for checking when one player has managed to get the ball by another player. We’ll cover that in this tutorial, along with finding a suitable way to display scores.

We’ll display scores using the FLabel class provided by Futile. To utilize it, we first need a bitmap font to work with. Then, we need to add it to our texture atlas in TexturePacker. Since I’m currently on my Windows machine, I used BMFont, which is a freeware application. If I was on a Mac, I would use Glyph Designer, which requires a license, but is arguably the best font atlas tool you will come across. I will not be going into detail on using these apps, as plenty of information already exists on them. As with all of my tutorials, I provide a zip file containing all of the assets I use, so you can just grab the new PongDemo.png, PongDemo.txt, and arial.txt file from there if you don’t want to fool around with creating a bitmap font.

Both of these programs create a PNG image, as well as a .fnt file. The .fnt file is similar to PongDemo.txt, in that it provides metadata about how to read and splice the texture. Since Unity will only load text files that end in a .txt extension, I changed the name of arial.fnt to arial.txt. That file will be put in Assets/Resources/Atlases. I then need to add the arial.png file to TexturePacker and then publish the output.

In PongDemo.cs, just beneath our LoadAtlas call, add the following line.

Futile.atlasManager.LoadFont("arial", "arial", "Atlases/arial", 0, 0);

The first parameter is the name we are giving the font, the second is the name of the PNG file referenced in PongDemo.txt, the third is the location of the arial.txt file without the extension, and the last two are x and y offsets.

To create and configure the labels, open PDGame.cs and add the following variable declarations to the PDGame class.

	public FLabel lblScore1;
	public FLabel lblScore2;

Next, in the PDGame() constructor, add the following code after the AddChild calls.

		// Create player1's score label
		lblScore1 = new FLabel("arial", player1.name + ": " + player1.score);
		lblScore1.anchorX = 0; // Anchor the label at the left edge
		lblScore1.anchorY = 0; // Anchor the label at the bottom edge
		lblScore1.x = -Futile.screen.halfWidth; // Move the label to the far left hand side of the screen
		lblScore1.y = -Futile.screen.halfHeight; // Move the label to the bottom of the screen
		
		// Create player2's score label
		lblScore2 = new FLabel("arial", player2.name + ": " + player2.score);
		lblScore2.anchorX = 1.0f; // Anchor the label at the right edge
		lblScore2.anchorY = 0; // Anchor the label at the bottom edge
		lblScore2.x = Futile.screen.halfWidth; // Move the label to the far right hand side of the screen
		lblScore2.y = -Futile.screen.halfHeight; // Move the label to the bottom of the screen
		
		// Add the labels to the stage
		Futile.stage.AddChild(lblScore1);
		Futile.stage.AddChild(lblScore2);

Execute the code, and you will see the labels we added, positioned at the bottom left and bottom right hand corners of the screen.

Next, let’s create the scoring conditions so that we can update the labels when a player scores. After the last line of the Update function for the PDGame class, add the following.

		// Scoring conditions
		PDPaddle scoringPlayer = null; // No one scored yet, but we need to create a reference
		
		if (newBallX - ball.width/2 < -Futile.screen.halfWidth) { // If the right side of the ball leaves the left side of the screen, player2 scored
			scoringPlayer = player2;
		} else if (newBallX + ball.width/2 > Futile.screen.halfWidth) { // If the left side of the ball leaves the right side of the screen, player1 scored
			scoringPlayer = player1;
		}
		
		// Reset the board if someone scores, and handle win/scoring conditions
		if (scoringPlayer != null) {
			ResetBall();
			ResetPaddles();
			scoringPlayer.score++; // Increment the scoring player's score
			lblScore1.text = player1.name + ": " + player1.score; // Update our labels, regardless of who scored
			lblScore2.text = player2.name + ": " + player2.score;
		}

The code speaks for itself for the most part. If the ball leaves the left side of the screen, player2 must have scored, and the inverse is true for player1. Reset the ball, paddles, increment the scoring player’s score, and then update the score labels.

With scoring working properly, let’s add some logic to pick a winner.

Add the following variable declarations to your PDGame class.

	public bool paused = false; // Is the game state paused?
	public int maxScore = 5; // Points needed to win the game

We then want to wrap all of the code inside of the Update function with a conditional statement.

	public void Update(float dt) {
		if (!paused) { ...

Finally, in the code used to catch a scoring conditioned, replace the whole block with the following code.

			// Reset the board if someone scores, and handle win/scoring conditions
			if (scoringPlayer != null) {
				ResetBall();
				ResetPaddles();
				scoringPlayer.score++; // Increment the scoring player's score
				lblScore1.text = player1.name + ": " + player1.score; // Update our labels, regardless of who scored
				lblScore2.text = player2.name + ": " + player2.score;
				
				// If the scoring player won
				if (scoringPlayer.score >= maxScore) {
					paused = true; // Pause our update loop
					Futile.stage.RemoveAllChildren(); // Remove all sprites from the screen
					FLabel lblWinner = new FLabel("arial", scoringPlayer.name + " WINS!"); // Create a label declaring the winner
					Futile.stage.AddChild(lblWinner); // Display the label
				}
			}

When you execute the code, the first player to get to 5 will now win, and the game state will pause and announce the winner.

There really isn’t much more to Pong, but since the purpose of this tutorial series is to introduce readers to Futile, I would like to explore a few more of its features before tinkering with the gameplay anymore. In the next tutorial, I will cover the FContainer class, which will allow us to easily create and manage various game screens, we’re going to start adding a bit of polish to our game. We will be adding a power-up to the game, while simultaneously introducing animated sprites.

Take me to the next tutorial!

By the end of the tutorial you just read, you should have something that looks like this. You can download the Assets folder for this tutorial here.

About these ads

10 thoughts on “Unity/Futile Pong Example (Part 7) – Scoring conditions and the user interface

  1. Pingback: Unity/Futile Tutorial Part 6 – Adding collision detection to our Pong game | Game Development

  2. It’s great that you are doing this tutorial series, and that you are putting the posts out so quickly. Thanks a lot!

    I know that this series is supposed to be about pong, but do you think you could also do a post on sprite animation? In the context of pong, you could just have an atlas for the ball that causes it a sort of glowing blink animation when it collides with a paddle.

    • I will absolutely be adding a post on sprite animation. There are plenty of places I can fit them in. After I do my next post on containers, that may be the most logical place to go. I very well might apply a sprite animation exactly as you described.

      The goal here wasn’t to focus on Pong as much as it was to introduce the Futile, and show how it can be used in a retro remake. If I could redo the entire series, I probably would have structured it differently so that every tutorial introduced a new Futile class or application.

      • After some thought, I will be skipping over FContainers so that I can introduce animated sprites. FContainers are a great way to create views/screens for a game, but introducing them now would be a bit confusing.

  3. Doesn’t seem that I can comment on your last reply, but that sounds great. I’m really enjoying all this because I’ve wondered for a long time which language and framework (or engine) I would like to create a game for. After considering C#/XNA/Monogame, ANSI C/SDL/OpenGL, Unity, even JRuby/lwjgl or WebGL and Canvas (but these only for prototyping or game tools), etc., I think I’ve finally settled on Unity/Futile. I’ve wanted something that could be approached from a programmers perspective, and Futile is perfect. Gets rid of my arguments against myself using Unity (which were few).

  4. Pingback: Unity/Futile Pong Example (Part 8) – Adding powerups and introducing animated sprites | Game Development

  5. I just started working on this today and have gotten to this tutorial. I downloaded the development version of Futile, and I am trying to load the font but I do not have the 5 variable LoadFont method, and when I take out the x and y offsets I get a NullReference and just get black. Any ideas how to fix, without just getting an older futile?

    PS; loving the tutorials, thanks a lot for writing them!

    • I have to believe that you aren’t using the development branch… here is the FAtlasManager.cs file from development:

      https://github.com/MattRix/Futile/blob/development/BananaDemoProject/Assets/Plugins/Futile/Core/FAtlasManager.cs

      Specifically, here are the two LoadFont methods. One takes 5 params, the other 6.

      public void LoadFont (string name, string elementName, string configPath, float offsetX, float offsetY)
      {
      LoadFont (name,elementName,configPath, offsetX, offsetY, new FTextParams());
      }

      public void LoadFont (string name, string elementName, string configPath, float offsetX, float offsetY, FTextParams textParams)
      {
      FAtlasElement element = GetElementWithName(elementName);
      FFont font = new FFont(name,element,configPath, offsetX, offsetY, textParams);

      _fonts.Add(font);
      _fontsByName.Add (name, font);
      }

      The only branch (of the three) that does not have a 5 parameter LoadFont method is the master branch, which is wildly out of date.

      Let me know if you are still having trouble.

  6. Pingback: Planning Pong | skylergame101

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s