C# Tutorial – Create a simple punch out boxing game in visual studio
- Subject: C# Tutorials
- Learning Time: 4 hours
In this tutorial we will be making something very exciting. Classic Mike Tyson Punch Out was one of my most favorite game on my old school Nintendo and I loved playing it. This was a difficult tutorial to get off the ground because most of the algorithm for the game had to be written ground up and made simple so it’s easier for a beginner to pick up and start learning. In this tutorial we will learn how to create a simple punch out game where you the player will be boxing it out with the Tough Rob the opponent. Both characters have their own health bars and can block attacks from their opponents. For this tutorial we are going to use Visual Studio 2017, Windows Form Application using the Visual C# programming language. You can use any version of visual studio to follow this tutorial because we are not going to use any external classes or game engines to make this punch out game.
Lesson Objectives –
- Create a simple punch out game in visual studio using c# programming language
- Using progress bars to show the health of player and opponent
- Using Selection to determine the hit test between player and opponent
- Using LIST to create variety of moves for the opponent which is controlled by the CPU
- Using Picture Boxes and Resources to show dynamic images for the player and the opponent
- Determining the who won the round and who lost the round using integers linked to the progress bars
- Using Key Down and Key Up events to control the player
View Preview
Download the punch out boxing game images here
Game Assets | Description |
This is the background ring image for the game, this will be applied the form as the main background of the game. On the top you have the Tough Rob and YOU written because all the UI will be placed accordingly on it so it looks neat and professional. | |
This is the player image. This is the right punch image | |
This is the player image. This is the left punch image | |
This is the player image. This is the block image | |
This is the player stand image. | |
This is the opponent stand image. | |
This is the opponent right upper cut image. | |
This is the opponent left punch image. | |
This is the opponent block image. |
Start a new project, under the Visual C# choose Windows Form Application, name the project PunchOut and click OK.
When the form has loaded, go to the properties window and change the following for the form
Size: 841, 604
Text: Punch Out Game
In this game properties window click on the background images option, you will see this three dotted button on there, click on the button to open the resource selection window.
This is the resource selection window, Make sure the project resource file is selected as above and click on IMPORT button.
Browser to the project asset files you downloaded from MOOICT, select them all and click on OPEN.
You will be returned back to the resource selection window, now select the background image from the list and click OK. So far we have imported all of the images we need for this game so we will not need to import anything else.
This is what the newly applied background looks like right now. Now we need to start adding windows components to the form. Drag and drop a progress bar from the tool box.
<- This is the progress bar icon in the tool box. After you have dropped a tool box to the form, make the following changes to its properties window.
Name: enemyLife
Location: 12, 44
Size: 300, 25
<– This is what the progress bar looks like now after the changes been applied to it. it should be placed under the Tough Rob’s name.
Now drag and drop another progress bar to the form and make the following changes to its properties window.
Name: playerLife
Location: 521, 44
Size: 300, 25
it should be placed under YOU in the form. With this done we can now move on to start adding out picture boxes.
<– This is the picture box icon in the tool box. Drag and drop the first picture box to the form.
Right click on the picture box and click on choose image. This will allow us to choose an image from the resource selection window.
<– This is the resource selection window. Choose the enemy-stand image from the list and click OK. Now while the picture box is selected, make the following changes to its properties.
Name: enemyBoxer
back Colour: Transparent
Location: 385, 297
Size Mode: Auto Size
Add another picture box to the form. This time we will add the boxer picture box.
Drag and drop an empty picture box to the form and then you can make the following changes to its properties.
Name: boxer
Back Colour: Transparent
Image: go to the resource selection windows and chose the boxer-stand image from the list. You can do this the same way you picked the enemy stand image from the steps before.
Location: 401, 367
Size Mode: Auto Size
This is the view so far into the game. Looking good.
One note here, There is an issue with transparency of the objects because there are few picture boxes overlapping, you cannot get true transparency in the windows form application using picture boxes right now. So we will have to work with it as is instead of trying to get true transparency between the picture boxes.
We need two timer objects for this game. Drag and drop two of them to the form.
For timer 1 make the following changes in its properties window
Name: enemyTimer
Enabled: True
Interval: 1000
This is the timer which will make the enemy through punches and blocks this is why we want the timer to run each 1000 milliseconds / 1 second. This will give us a dynamic move for the opponent.
Now click on timer 2 and make the following changes to it.
Name: enemyMove
Enabled: True
Interval: 20
This timer will be used to move the opponent side to side from the player. We will run this timer each 20 milliseconds so it will have a fast frame rate.
<– While you have the enemyMove timer selected, click on that little lightning bolt icon in the properties window. This will take you to the events manager window.
In this events manager window you will see one option available for the timer which is TICK inside that box type in enemyMoveEvent and press enter. This will take you to the code view, come back to the design view so we can add some more events.
Now click on the enemyTimer, click on the little lightning bolt icon to see the events manager, in the tick option type in enemyPunchEvent and press enter.
Click on the form and add 2 events. Make sure the form is selected and no other component just the form. When you look at the events manager from the form there will be lots of them listed. We need to find two specific events KeyDown and KeyUp event.
For KeyDown type is keyisdown and press enter for KeyUp type in keyisup and press enter.
Coding
This is the code view so far into the this game including the events we have added so far.
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; namespace PunchOut { public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void enemyMoveEvent(object sender, EventArgs e) { } private void enemyPunchEvent(object sender, EventArgs e) { } private void keyisdown(object sender, KeyEventArgs e) { } private void keyisup(object sender, KeyEventArgs e) { } } }
The Variables and set up
Add the highlighted code below to the code view, make sure you match where the codes are placed.
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; namespace PunchOut { public partial class Form1 : Form { bool blockAttack = false; // this is the player block boolean // below is the enemy attack lists List<string> enemyAttacks = new List<string> { "left", "right", "block" }; // rnd is the new random class used to generate random numbers Random rnd = new Random(); // below is the enemy speed variable int enemySpeed = 5; // below int i will be used to check the enemy moves int i = 0; bool enemyBlocked; // this is the enemy attack block boolean int playerHealth = 100; // players total health int enemyHealth = 100; // enemys total health public Form1() { InitializeComponent(); playerLife.ForeColor = Color.Blue; // change the players progress bar to blue enemyLife.ForeColor = Color.Red; // change the enemy progress bar to red } private void enemyMoveEvent(object sender, EventArgs e) { } private void enemyPunchEvent(object sender, EventArgs e) { } private void keyisdown(object sender, KeyEventArgs e) { } private void keyisup(object sender, KeyEventArgs e) { } private void resetGame() { } } }
bool blockAttack = false; // this is the player block boolean
This is the block attack Boolean. There can be two values for this true or false and Booleans make it easier for us to check if the player is blocking the current attack or not.
// below is the enemy attack lists
List<string> enemyAttacks = new List<string> { “left”, “right”, “block” };
Above is a LIST called enemy attacks and it has a data type of string. We have three different attack for the opponent, left, right and block. We can use a list to store more than 1 item and then we can pull them as we need it. List provide a faster search of its indexes so we can randomise the moves as we need to for this game.
// rnd is the new random class used to generate random numbers
Random rnd = new Random();
Above we are creating a new instance of a random number generator called rnd. We will use this to randomly pick a move from the enemy attacks list.
// below is the enemy speed variable
int enemySpeed = 5;
Above is the integer called enemy speed it has a value of 5. This will be used to move the opponent side to side.
// below int i will be used to check the enemy moves
int i = 0;
Above is an empty integer called i. This will be linked to the random number generator and the enemy attacks list to pick a move for the opponent.
bool enemyBlocked; // this is the enemy attack block boolean
Above is the Boolean called enemy block, it will work the same way as the blocked attack Boolean, this will be used to check if the opponent has blocked your punches.
int playerHealth = 100; // players total health
int enemyHealth = 100; // enemys total health
These both integers above are keeping track of the player and opponents health. This is the default value at 100 for both.
public Form1()
{
InitializeComponent();
playerLife.ForeColor = Color.Blue; // change the players progress bar to blue
enemyLife.ForeColor = Color.Red; // change the enemy progress bar to red
}
The two highlighted line in the Form1() function are setting the opponent and player progress bar colours. For the player we are setting it to blue and for the opponent we are setting it to Red.
private void resetGame()
{
}
Above is the reset game function, this is a empty function we will show you what to add to this later in the tutorial, make sure you have followed the tutorial accurately and don’t miss out any of the brackets or semi colons.
Enemy Move Event
This event will run with the enemy move timer. First we are linking the enemy boxers left with the enemy speed. This will start animating the enemy boxer. After that we have two if statements 1 for the player health and 1 for the enemy health, if their health values are greater than 1 then we will continue to show it on the progress bars. We want the enemy boxer to move side to side but not go too far away from player so the limit is 480 from the right and 315 from the left We will animate the enemy boxer between these two values, if it reaches any of these values then we will reverse the speed and bring him the other way. After that we have two more if statements one for the enemy health and 1 for the player health. This will determine who wins the game, if the enemy health is below 1 then we will stop two timers, show a message box and run the reset game function. The same will be done if the player health is below 1. The codes are commented so you can follow along easily.
private void enemyMoveEvent(object sender, EventArgs e) { //this event will control the enemy moving left and right enemyBoxer.Left += enemySpeed; // link the enemy speed to the enemys left // if the players health is greater 1 if (playerHealth > 1) { // then we link it to the player life progress bar playerLife.Value = Convert.ToInt32(playerHealth); } // if the enemy health is greater than 1 if (enemyHealth > 1) { // then we link it to the enemy life progress bar enemyLife.Value = Convert.ToInt32(enemyHealth); } // if the enemy goes between 480 and 315 // we will revserse the speed if (enemyBoxer.Left > 480) { // we move the enemy towards the left enemySpeed = -5; } // if the enemy left is less than 315 pixels if (enemyBoxer.Left < 315) { // we move the enemy towards the right enemySpeed = 5; } // if the enemy health is less than 1 if (enemyHealth < 1) { // you win and the enemy loses // stop both the timers enemyTimer.Stop(); enemyMove.Stop(); // show the final message MessageBox.Show("You Win, Click OK to Play Again.."); //run the reset game function resetGame(); } // if the player health is less than 1 if (playerHealth < 1) { // you lose and the enemy wins the game // stop both of the timers enemyTimer.Stop(); enemyMove.Stop(); // show the final message MessageBox.Show("Tough Rob Wins! Click ok to retry"); // run the reset game function resetGame(); } }
Enemy Punch Event
This event will trigger every second. First in this event we are going link the i integer with the random number generator and will choose a random attack from the enemy attacks list. Then we created a switch statement which will use the attack chosen from the list and follow instructions specific to them. First in the switch statement we are looking for the case “left”, this means if the left attack is chosen when the change the enemy boxer image to the enemy punch1 image, also we check if its colliding with the boxer AND the boxer is not blocking if this statement (by using ! before a boolean we are telling the program that this is not true for example !blockAttack means if its set to false with the exclamation symbol it will mean the player is blocking) is true then we do 20 damage to the players health. After that we tell the program that enemy boxer is not blocking and then break the loop. The second case is “right” if the right move is chosen then we change the enemy boxer image to the enemy punch2 image and then in the if statement we check if the enemy collides with the player AND the player is not blocking then we do 20 damage to the players health and finally we will set the enemy blocked to false. Lastly it’s the block move, if the random attack chosen is block then we will change the enemy boxer image to the block image and set the enemy blocked Boolean to true. Each line in the event is comment for ease of understanding.
private void enemyPunchEvent(object sender, EventArgs e) { // generate a random number and store in i // the random number will need to between 0 and the number attacks in the attacks list i = rnd.Next(0, enemyAttacks.Count); // below is the switch statement that will check which acion the enemy is taking switch (enemyAttacks[i].ToString()) { // if the attack is left case "left": // then we change the enemy to the punch 1 image enemyBoxer.Image = Properties.Resources.enemy_punch1; // we will also check if the player and enemy colliding and the blocking is set to false if (enemyBoxer.Bounds.IntersectsWith(boxer.Bounds) && !blockAttack) { // if so then we reduce 20 from the players health playerHealth -= 20; } enemyBlocked = false; // set the blocking to false break; // if the attack is right case "right": // then we change the nenemy to the punch 2 image enemyBoxer.Image = Properties.Resources.enemy_punch2; // we will also check if the player and enemy colliding and the blocking is set to false if (enemyBoxer.Bounds.IntersectsWith(boxer.Bounds) && !blockAttack) { // if so then we reduce 20 from the players health playerHealth -= 20; } enemyBlocked = false; // set the blocking to false break; // if the attack is block case "block": // then we change the enemy picture to block enemyBoxer.Image = Properties.Resources.enemy_block; // we change the boolean to true enemyBlocked = true; break; } }
Key is down event
This is the key down event, in this event we will control the player character the boxer. First we are checking if the down key is press then we show the boxer block image and set the block attack to true. The second if statement is checking if the left key is pressed, if so then we change the boxer image to the boxer left punch image, inside it there is another if statement which is checking if the player is colliding with the enemy boxer and the enemy boxer is not blocking then we do 5 damage to the opponent. We are doing the similar thing with the right key, if its pressed we change the boxer image to the boxer right punch and inside the other if statement we check if the enemy boxer and the player colliding and enemy blocked Boolean is not true then we do 5 damage to the enemy health.
private void keyisdown(object sender, KeyEventArgs e) { // if the player hits the down key if (e.KeyCode == Keys.Down) { // we change the player image to the block image boxer.Image = Properties.Resources.boxer_block; blockAttack = true; // change the block attack boolean to true } // if the player hits the left key if (e.KeyCode == Keys.Left) { // change the image to left punching picture boxer.Image = Properties.Resources.boxer_left_punch; // if the player and enemy collide with and the enemy blocked boolean is false if (enemyBoxer.Bounds.IntersectsWith(boxer.Bounds) && !enemyBlocked) { // the we do 5 damage to the enemy enemyHealth -= 5; } } // if the player hits the right key if (e.KeyCode == Keys.Right) { // change the player image to the righ punching one boxer.Image = Properties.Resources.boxer_right_punch; // if the player and enemy collide with and the enemy blocked boolean is false if (enemyBoxer.Bounds.IntersectsWith(boxer.Bounds) && !enemyBlocked) { // then we do 5 damage to the enemy enemyHealth -= 5; } } }
Key is up event
This is the key is up event, this event will trigger when the keys are released, so in this event we only have two instructions, first we will reset the player image back to the boxer stand and set the block attack Boolean to true.
private void keyisup(object sender, KeyEventArgs e) { // when the player will release the keys they press this event will trigger boxer.Image = Properties.Resources.boxer_stand; // we will reset player image back to stand blockAttack = false; // change the block attack boolean back to false }
Reset game function
This is the game reset function. This function runs when the player either wins or loses in the game. This function is really simple, we are starting both the timers up, then we are resetting the enemy boxer to its default position and then we are setting the enemy boxer image and the player boxer image. Lastly we are resetting the player and enemy health back to 100.
private void resetGame() { enemyTimer.Start(); // start the enemy punch timer enemyMove.Start(); // start the enemy move timer enemyBoxer.Left = 385; // reset the enemy left to 385 enemyBoxer.Top = 297; // reset the enemy top to 297 enemyBoxer.Image = Properties.Resources.enemy_stand; // show the enemy stand image boxer.Image = Properties.Resources.boxer_stand; // show the boxer stand image playerHealth = 100; // reset player health to 100 enemyHealth = 100; // reset enemy health to 100 }
lets debug the game click on the start button from the tool bar.
The game is working flawlessly. If you have followed the tutorial thus far then very well done, now you can try out making more moves for the boxer or the enemy boxer or improve it in any way you see fit, have a go and don’t be afraid you can always come back to this and check for errors. Moo Out.
I didn’t understand how you managed to change the color of the progress bar. Whatever I do, it is still green, and whatever I read they say things like “The standard progress bar does not support changing colors”, which actually seems to be the case. Of course, I can write my own progress bar manually, but I would like to know how come the line “playerLife.ForeColor = Color.Blue;” works for you while it doesn’t for me)))
I’m looking into it too atm.
Locate the following line of code within your solution (tipically in Program.cs):
Application.EnableVisualStyles();
Comment out this line. Now the color of the progress bar will change as expected, but the style of your controls will also change a little. I’m curremtly trying to find a better solution for this myself.
So basically this line his NOT in this code, it has something to do with the color defaulting to the windows theme I read, if the visual style is enabled and also on default it will be green. Still searching on how to fix it.
Final Solution I found:: Most Relevant.
As the description of the ForeColor property says, it’s the color of the text. Do you see any text? The bar color is not modifyable because the control is painted by the system.
As far as i am aware the only way to change the color is to un-check the Use Visual Styles option in your projects properties (Application Tab), however that will give your controls an old ugly look too.
Basically its due to newer versions of Visual Studio and Windows.
This tutorial his older dont forget.
EDIT:: The Line Application.EnableVisualStyles(); is actually there inside Program.CS if you look in your right project menu, just click on Program.CS to open it’s code page. Then comment it out of the code. 🙂
WORKS A CHARM 🙂 Simply commenting out the line Application.EnableVisualStyles(); will give you nice life bars with the color described in the code, has well has making the life bar “cells” or instead of a full bar, little squares, which is very nice. Have fun 🙂