C# Tutorial – Create a Simple Battle Ship Game in Visual Studio

In this tutorial we will show you how to create a Simple old school battle ship game in visual studio using C# programming language. This game is a complicated one and can be a little daunting for the beginners. If you are unclear about some of the concepts then try out few other tutorials here and come back to this, it will still be here when you are ready. In this game you will create an AI player where you can play against them to win your sea battles.  The old joke “you sunk my battle ship”, may apply here but it’s entirely up to you.

Lesson Objectives –

  1. Complete the simple battle ship game in visual studio
  2. Use custom background on the windows form
  3. AI make decisions in the game
  4. Player controls their ships from list of moves
  5. Keep track of AI movements
  6. Using windows GUI to create a game
  7. Using LIST arrays in C#
  8. Using LOOPs in C#
  9. Searching indexes of the list arrays and matching them to integers
  10. Using System Diagnostics show system debug information in the outputs window
  11. Using multiple timers and controlling them dynamically
  12. Showing customised win, lose and draw message box

 

Full Video Tutorial

 
Download the BattlShip game assets here.

Download Battleship Project on GitHub

 

Assets Description
This is the custom-made background image we will use in our game. This has the positions for the player and the enemy. It also has the player move and enemy move tabs on the top. We will go through this tutorial showing you how to incorporate this image to the game
This is the HIT image. When an attack was successful then we will change the buttons image to this, meaning if the player or enemy hits the target this image will show as feedback that attack was successful.
This is the MISS image. This image will show when an attack was unsuccessful.

To start let’s load up visual studio. We will be using Visual Studio 2017, you can use any of the version you choose it should work the same. Since we are not using any external libraries or game engines there no need to worry about compatibilities.

To start lets make a new Windows Form Application, name this project BattleShip-Game and click OK.

Properties Window is located on the bottom left of the screen, in this window we are able to set different options and change settings for the current form and elements we chose to work with. every single component which is available inside of visual studio has its own properties and events that can be changed inside of this window. So lets this window be your friend in the development.

While the form is selected let’s make some changes to the Form properties.

Change the Size of the Form to 1081, 624 and Text to BattlShip Game MOOICT.

With that done you will notice the form changes to the settings you inputted in the properties window. Now it’s time to import the resources for this game. In the same properties window find the background image option.

You will see it states (none) in the box, now click on the three dotted button to open the dialog box below.

This is the resource importer window. We can click on the import button here to load up the images you downloaded from MOOICT.

Locate the images you downloaded from MOOICT, select them all and click open.

This will import all of the images for this game, now select the background image and click OK.

As you can see the background has now been applied to the game, but it doesn’t look right, its repeating itself and also doesn’t fit properly in the form we created.

Under the background image option you will see the Background Image Layout option, change it to Stretch and it will fit the image to full screen on the form. Try it out.

This properties window is very helpful and we will be using it a lot in this project.

We need the ToolBox to add the necessary components for this game, now often times the tool box is visible in the left of the screen sometimes it hiding. If you can’t find it then click on View –> ToolBox and it will show up on the screen.

Caution – Before setting off and adding lots of components for this game, keep in mind we need lots of buttons and other components to be added so we can get the desired effects from it. Since there are lots of them please take your time to add them and make sure you follow this tutorial slowly, if you rush it and miss something, that might come back to cause more problems as you move further.

This we need to add to this game

Labels 5 Labels Total
Buttons 33 Buttons Total [Yea for Real lol]

16 for the player

16 for the enemy

1 for the Attack

Combo Box Only 1
Timer 2 Timers Total

Find the label from the Tool Box and drag 4 of them to the screen and position them to the screen shot below

Now we need to make the following changes to each of these labels. Click on individual labels and go to the properties window to make the following changes.

Label 1 –Select it and Change the following in the properties for it

Name – playerScore

Font – Size 16 BOLD

Text – 00

Label 2 – Select it and Change the following in the properties for it

Name – enemyScore

Font – Size 16 BOLD

Text – 00

Label 3 – Select it and Change the following in the properties for it

Name – enemyMoves

Back Colour – Transparent

Font – Size 16 BOLD

Fore Colour – White

Text – A1

Label 4 – Select it and Change the following in the properties for it

Name – roundsText

Back Colour – Transparent

Font – Size 12 BOLD

Fore Colour – White

Text – Rounds

Label 4 – Select it and Change the following in the properties for it

Name – helpText

Back Colour – Transparent

Font – Size 9 BOLD

Fore Colour – Light Green

Text – 1) Click on 3 Different Buttons Above to Start

This is the view on the game screen so far.

Now let’s add a Combo Box

Combo Box– Select it and Change the following in the properties for it

Name – enemyLocationList

Drop Down Style – Drop Down List

Drop Down Width – 95

Font – Size 12 Bold

Now lets add our first button to the game. This button will be used to allow the player to attack a enemy location from the drop down list we did earlier.

Button 1– Select it and Change the following in the properties for it

Name – attackButton

Size – 80, 40

Font – BOLD

Text – Attack

Now its time to Add the player buttons. There will be 16 buttons added for the player, so make sure you are thorough and if you feel you have missed something come back to this double check.

Let’s drag and drop a button to the W1 location of the player section

Button – Select it and Change the following in the properties for it

Name – w1 – (make sure its lowercase)

Size – 75, 55

Text – W1 – (make sure its uppercase)

Now you can simply copy and paste it to the other locations changing its name and text only without needing to do much else. Now when we move it to the W2 location the name will change to w2 and text will change to W2.

Here we added all the buttons, changed the NAME and TEXT properties according to the buttons location presented in the game. Make sure you place them within the boundaries of the background image grid.

Now we follow the similar instruction to make the enemy position buttons.

Once again remember to follow these instructions very carefully because you do not want to mess up the names for the buttons. This issue can lead to more issues further down so road so fix any you might have right now.

Lets add our first button to the enemy’s position grid.

Below the A1 button has been added its name is a1, Size – 75, 55 and Text is A1. Its like what we did for the player earlier.

See the table below to see how we did it. Change the name and text options in the properties menu for each button. Do them one by one to reduce the chance of an error.

Now all the enemy’s buttons been added.

Reminder

Make sure you did the following for each button

1 – changed its name to a lowercase a1, a2, b1, b2, or so on

2 – changed its text to the uppercase letters of the button

3 – placed the button in the appropriate grid

With all this done we can move on to our next objective

Now we need to add 2 timers to the form.

From the tool box drag 1 timer to the form

This is the first time added to the form. Change the following in the properties window for this timer.

Change the name to enemyPlayTimer and interval to 1000. We want this time to run once every second when activated. The lower the number faster the timer events will execute.

Now add another timer to the form, change the following for this timer.

Change the name to enemyPositionPicker, change enabled to True and change interval to 500. We want this timer to run when the form loads and run faster than the last one.

Now you will see that we have two timers added to the form and they should both looks like the screen shot above.

Now its time to start adding the events to the game.

First lets select all of the player buttons on the screen.

Drag across them and select them all.

While all of the buttons are selected – click on that little lightning bolt icon and you see the events window relative to the components picked on the form, in this case it’s all these buttons we selected. We want them all to fire up an event when one of them is clicked.

Find the click event and type playerPicksPosition and press enter. This will take you to the code view window, come back to the design view we need to add more events.

Select the attack button from the form, once again go back to the events window.

Type in attackEnemyPosition and press enter. Once again come back to the design view once you have done so.

Now lets add the events for the timers

First click on the and go to the events window

Inside the Tick event type enemyAttackPlayer and press enter.

We need to add an event for the second timer have in this game tool. Click on the enemyPositionPicker timer and go to the events window.

 

In the Tick event type enemyPicksPositions and press enter. This will conclude our journey on adding events for this game.

With these events added this is what the code view looks like now.

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 BattleShip_Game
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void playerPicksPosition(object sender, EventArgs e)
        {

        }

        private void attackEnemyPosition(object sender, EventArgs e)
        {

        }

        private void enemyAttackPlayer(object sender, EventArgs e)
        {

        }

        private void enemyPicksPositions(object sender, EventArgs e)
        {

        }
    }
}

This is the empty functions at the moment. You can run the game and it will not do anything because no instructions been given for this game yet. We are going to start writing some of it now.

Add the highlighted code into the places you see below –

// each line with the double slashes in-front is a comment line. They will be used to explain the code.

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;

using System.Diagnostics; // allows us to create a debug log in the outputs window

namespace BattleShip_Game
{
    public partial class Form1 : Form
    {
        List<Button> playerPosition; // create a list for all the player position buttons
        List<Button> enemyPosition; // create a list for all the enemy position buttons
        Random rand = new Random(); // create a new instance for the random class called rand
        int totalShips = 3; // number of total player ships
        int totalenemy = 3; // number of total enemy ships
        int rounds = 10; // total rounds to play each will play 5 rounds
        int playerTotalScore = 0; // default player score
        int enemyTotalScore = 0; // default enemy score

        public Form1()
        {
            InitializeComponent();
        }

        private void playerPicksPosition(object sender, EventArgs e)
        {

        }

        private void attackEnemyPosition(object sender, EventArgs e)
        {

        }

        private void enemyAttackPlayer(object sender, EventArgs e)
        {

        }

        private void enemyPicksPositions(object sender, EventArgs e)
        {

        }

        private void loadbuttons()
        {

        }

     }
}

using System.Diagnostics; This line will allow us to use the System Diagnostics class from C#, we will be asking our AI to pick its position on the array of buttons, but we will not know which buttons it picked to test out the game mechanics. C# has just the thing for us we can call the diagnostics class and use the debug.log to output the moves AI picked in the outputs window and test the game. It’s an useful tool for programmers and I recommend you use it in your big projects that can save lots of time and energy.

List<Button> playerPosition and enemyPosition are both dynamic array of buttons. Notice we mention <Button> in the list we can call anything we want to make an array but for this game we have lots of buttons and we need a way to organise and use them efficiently. This is why we are using the LIST data type for the buttons.

Random rand = new Random(); This is a Random number generator class build into C#, we will be using this to allow the AI to randomly pick 3 positions for the enemyPosition array.

int totalShips is for the user. By using this golabl int variable we will be able to allow the user to only pick 3 buttons from the playerPosition array. The same logic will be used for the int totalenemy.

int rounds, int playerScore and enemyScore are to keep track of the rounds played and how much the player or the enemy scored in the game.

loadbuttons() function will be used to load all of the buttons into the playerPosition and enemyPosition arrays. We need a function to do it so it’s more organised in the code and not scattered around.

Form1() – Add the highlighted code into the form1 function.

        public Form1()
        {
            InitializeComponent();
            loadbuttons(); // load the buttons for enemy and player to the system
            attackButton.Enabled = false; // disable the player attack button
            enemyLocationList.Text = null; // nullify the enemy location drop down box
        }

The public Form1() is a default function for the Windows Form Application. It loads up all of the necessary components for the Application. We will use this to set up the default values for the game.

First we are running the loadbuttons() function which will load all of the buttons to the array, then we are disabling the attack button because we want the player to pick their position before attacking enemy locations and we are emptying the enemyLocationList combo box so there is nothing in it.

loadButtons() – Add the highlighted code into the loadButtons() function

 

        private void loadbuttons()
        {
            // this function will load all the buttons into the lists we declared above
            // we load all of the player and enemy buttons first
            playerPosition = new List<Button> { w1, w2, w3, w4, x1, x2, x3, x4, y1, y2, y3, y4, z1, z2, z3, z4 };
            enemyPosition = new List<Button> { a1, a2, a3, a4, b1, b2, b3, b4, c1, c2, c3, c4, d1, d2, d3, d4 };

            // this loop will go through each of the enemy position button
            // then it will add them to the enemy location drop down list for us
            // it will also remove all Tags from the enemy location buttons
            for (int i = 0; i < enemyPosition.Count; i++)
            {
                enemyPosition[i].Tag = null;
                enemyLocationList.Items.Add(enemyPosition[i].Text);
            }
        }

Above is the load button function. As you can we are loading all of the player and enemy buttons to the array. Each array holds 16 buttons. By doing this we can automate many of the instruction for example the loop below buttons list is the loop that’s adding all of the enemy positions to the enemyLocationList combo box. We can do that if we have the information organized.

playerPicksPosition Event

        private void playerPicksPosition(object sender, EventArgs e)
        {
            //this function will let the player pick 3 positions on the map
            // in the beginning of the game this is how we allow the player to pick 3 positions

            if (totalShips > 0)
            {
                // if total ships is more than 0 then we check
                var button = (Button)sender;
                // which button was clicked
                button.Enabled = false;
                // disable that button
                button.Tag = "playerShip";
                // put a tag on it called playership
                button.BackColor = System.Drawing.Color.Blue;
                // change the colour to blue
                totalShips--;
                // decrease the total ships by 1
            }
            if (totalShips == 0)
            {
                // if the player has picked their all 3 ships 
                // then we do the following
                attackButton.Enabled = true;
                // activate the attack button
                attackButton.BackColor = System.Drawing.Color.Red;
                // give it a background colour of red
                helpText.Top = 55;
                // move the help text to top 55
                helpText.Left = 230;
                // move the help text to left 230
                helpText.Text = "2) Now pick a attack position from the drop down";
                // change the help text to above
            }
        }

Above is the playerPicksPosition event function. This function will run each time the player will click on their own button. In this function we have two IF statements, let go through them first. The first IF statement is checking is the totalShips integer has a greater value than 0 meaning it has more than 1 then we allow the instructions inside to run. First it will check which button was clicked and store it in the local variable called button. Then we will disable that button and give it a tag of playership. Tags are useful to identify an object when we have multiple objects in the program. In this if statement when the button is clicked we will give it a background colour of blue so its easier to identify it and then we will reduce 1 from the total ships integer. The logic here is we want the player to only be able to select 3 buttons so we gave total ships integer a value of 3, each time the player picks a button total ships integer reduces by 1 and when it gets to 0 it will fire up the second if statement.

The second if statement is checking if the total ships 0 then we enable the attack button, give it a background colour RED. The help text which shows that player needs to select 3 buttons now will be moved to the top and will say 2) Now Pick a attack position from the drop down. In any application you need to have a way for the player to understand and use your application. They can’t guess it really so lets give them some information to play the game better.

attackEnemyPosition event

        private void attackEnemyPosition(object sender, EventArgs e)
        {
            // this function will allow the player to make the moves on the enemy location
            // we need to check if the player can choose a location from the drop down list
            if (enemyLocationList.Text != "")
            {
                // if the location is appropriately picked then we do the following
                var attackPos = enemyLocationList.Text;
                // create a variable called attack pos and give it the value of the text selected from the drop down menu
                attackPos = attackPos.ToLower();
                // change the string to a lower case to match the button name
                int index = enemyPosition.FindIndex(a => a.Name == attackPos);
                // in this int we will run the index of the enemy location and search for the string the player picked
                // once its found it will be saved inside the index local variable


                // in the if statement below we will link that index number to the enemy position list
                // and we need to check if we have more rounds to player
                // if so we do the following
                if (enemyPosition[index].Enabled && rounds > 0)
                {

                    rounds--;
                    //reduce 1 from the rounds
                    roundsText.Text = "Rounds " + rounds;
                    // update the rounds text

                    if (enemyPosition[index].Tag == "enemyship")
                    {
                        // if that location the player picked has a enemyship tag in it then we do the following
                        enemyPosition[index].Enabled = false;
                        // disable that button
                        enemyPosition[index].BackgroundImage = Properties.Resources.fireIcon;
                        //change the background image to the fire icon
                        enemyPosition[index].BackColor = System.Drawing.Color.DarkBlue;
                        // change the background colour to dark blue
                        playerTotalScore++;
                        // increase 1 to the player score 
                        playerScore.Text = "" + playerTotalScore;
                        // update the player score on the player label
                        enemyPlayTimer.Start();
                        // start the cpu timer so the enemy can make its move
                    }
                    else
                    {
                        // if player picks a location that isn't where the enemy ship is
                        // then do the following
                        enemyPosition[index].Enabled = false;
                        // we disable that  button
                        enemyPosition[index].BackgroundImage = Properties.Resources.missIcon;
                        // change the background image to miss icon
                        enemyPosition[index].BackColor = System.Drawing.Color.DarkBlue;
                        // change the background to dark blue
                        enemyPlayTimer.Start();
                        // start the cpu time so the enemy can make its move
                    }

                }


            }
            else
            {
                // if player doesn't pick a location from the drop down list, alert them to do so
                MessageBox.Show("Choose a location from the drop down list. ");
            }
        }

Attack enemy position event is triggered when the attack button is clicked by the player. We are going to put this whole thing inside an if statement. Logic behind this is when the player selects an option from the drop down menu we can attack that position but if the drop down list position is empty then we want to remind the player to select a location from the list. We are using the lists find index function to search for the button location selected from the list. You can read more about lists and how to use them here – http://www.csharp-examples.net/list/ .

There is a if statement in this function the logic is when the player attacks a position we need to check if that attack position has a tag of enemyship if it does then we change the icon to the fire image we imported earlier, disable that button, add 1 to the player score and we will start the enemy play timer.

If that tag doesn’t match the position the player attacked then we will disable that button and we will give it a miss icon as a background and then we will star the enemy play timer.

enemyAttackPlayer event

        private void enemyAttackPlayer(object sender, EventArgs e)
        {
            // this function is for the CPU to make a move on the player

            // if the player position is more than 0 and there are more rounds to play
            // then we will do the following inside this if statement
            if (playerPosition.Count > 0 && rounds > 0)
            {

                rounds--; // reduce a round from the total
                roundsText.Text = "Rounds " + rounds; // show the updated number to the rounds label

                int index = rand.Next(playerPosition.Count); // create a new int index and place a random player button

                if (playerPosition[index].Tag == "playerShip")
                {
                    // if the index has a tag of playership then we do the following

                    playerPosition[index].BackgroundImage = Properties.Resources.fireIcon;
                    // change its icon to the fire icon


                    enemyMoves.Text = "" + playerPosition[index].Text;
                    // show which button was attacked
                    playerPosition[index].Enabled = false;
                    //disable the button
                    playerPosition[index].BackColor = System.Drawing.Color.DarkBlue;
                    //change the background colour to dark blue
                    playerPosition.RemoveAt(index);
                    // remove this button from the player position list so it won't get attacked again by the CPU
                    enemyTotalScore++;
                    // add 1 to the enemy score
                    enemyScore.Text = "" + enemyTotalScore;
                    // show the enemy score on the label
                    enemyPlayTimer.Stop();
                    //stop the time for the CPU
                }
                else
                {
                    // if the player tag isn't of playership 
                    // then we do the following
                    playerPosition[index].BackgroundImage = Properties.Resources.missIcon;
                    //show the miss icon on the button
                    enemyMoves.Text = "" + playerPosition[index].Text;
                    // update the enemy attack location on label 2
                    playerPosition[index].Enabled = false;
                    // diable the button cpu attacked
                    playerPosition[index].BackColor = System.Drawing.Color.DarkBlue;
                    //change the background colour to dark blue
                    playerPosition.RemoveAt(index);
                    // remove this button from the list so it wont get attacked again by the cpu
                    enemyPlayTimer.Stop();
                    // stop the cpu time. 
                }

            }

            // below is the if statement thats checking whether we won, drew or lost the game

            // if rounds are less than 1 OR player score is more than 2 OR enemy score is more than 2

            if (rounds < 1 || playerTotalScore > 2 || enemyTotalScore > 2)
            {
                if (playerTotalScore > enemyTotalScore)
                {
                    // if player score is more than enemy score player wins
                    MessageBox.Show("You Win", "Winning");
                }
                if (playerTotalScore == enemyTotalScore)
                {
                    // if player and enemy scores the the same its a draw
                    MessageBox.Show("No one wins this", "Draw");
                }
                if (enemyTotalScore > playerTotalScore)
                {
                    // if enemy score is more than player then enemy winds
                    MessageBox.Show("Haha! I Sunk Your Battle Ship", "Lost");
                }
            }
        }

Above is the enemy attack player event. This event will be triggered by the enemy play timer. We want this timer to select a random location from the play positions array and attack it. If that position is where the player hid their ships then it will sink or it will show the miss icon. That’s the overall idea behind this event. This function is also responsible for checking the rounds and the player and enemy scores. We also have placed several if statements in the bottom of the function to check if we have won, drew or lost the game against the CPU. All of the codes are commented in the function check carefully.

enemyPicksPositions event

        private void enemyPicksPositions(object sender, EventArgs e)
        {
            // this function will allow the CPU to pick 3 positions on the MAP
            // we need to make sure that the enemy CPU will pick 3 positions on the map

            int index = rand.Next(enemyPosition.Count);
            // create a local variable called index and choose a random button from the enemy position list

            if (enemyPosition[index].Enabled == true && enemyPosition[index].Tag == null)
            {
                // when we find the buttons we need to check if they are enabled and they dont have a tag yet
                enemyPosition[index].Tag = "enemyship";
                // now add a tag called enemy ship to the button
                totalenemy--;
                // and we will reduce the total enemy by 1

                Debug.WriteLine("Enemy Position  " + enemyPosition[index].Text);
                // the line above will show us inthe debug window which buttons the enemy chose
                // this can help us figure out if the game is working as intended
            }
            else
            {
                // if the top condition dont match then we will run it again to select the 3 positions and tags
                index = rand.Next(enemyPosition.Count);
            }
            if (totalenemy < 1)
            {
                // if the cpu has selected the 3 positions then we can stop the timer
                enemyPositionPicker.Stop();
            }
        }

Above is the enemy picks position event. This event is responsible for the CPU to pick its three positions from the array of buttons. This event will be triggered when the form is loaded. In this event we will use the random number generator we included in the program earlier and we will pick a random button from the array of enemy position buttons when it will pick a button it will add a tag called enemyship to that specific button and it will reduce the total enemy by 1. This is the same logic we used when we wanted that player to pick three positions. Lastly if the total enemy is below one then we can stop the timer and we are ready to play.

Click on the start button to start debugging the game.

Enemy positions are showing up on the outputs window. These are positions the CPU chose randomly. This is made possible by the system diagnostics class we imported earlier. See how it works, you can use this class on any other project you might be working on. It helps save lots of time.

We picked three locations and we are able to select a position from the drop down menu.

Enemy is also attacking out locations, if we manage to hit one from the enemy it changes the icon to fire and if we miss it changes the icon to the cross.

First screen above is where we drew the game with the CPU and the second screen is showing we won.

This screen is showing the enemy won the game.

If you have successfully followed us to here then very well done. You should be proud of the accomplishment. It takes a lot of work to complete a project but have patience and learn from the errors along the way.

Full source code for the game is below. Enjoy and MOO out.

 




8 responses to “C# Tutorial – Create a Simple Battle Ship Game in Visual Studio”

  1. charlie says:

    if (enemyPosition[index].Enabled && rounds > 0 ) system.argumentoutofrangeexception: ‘Index was out of range. Must be non-negative and less than the size of the collection

  2. John says:

    I have the same error as Charlie

  3. Anhar Ali says:

    Hi this error means that index has either gone over the number of buttons enabled on the enemy position or it has gone below it. The code from the attack enemy position event check the line before the if statement where we have declared the index variable it’s on page 11. I think it might have happened because it cannot find any buttons.

  4. Beth says:

    Does this still work?

  5. Anhar Ali says:

    Yes.

  6. John says:

    Hello, my code is now running and the game works well except for the fact that the enemy does not appear to be placing any ships – I miss every time because there are no ships to hit on the enemy board so the computer always wins. What could be causing this?

  7. slots says:

    the code is working however I can only pick 3 buttons before cpu picks 3, if cpu picked 3 buttons before me then Im unable to pick all 3 and the game never starts… no idea whats wrong… i have also detected a typo in enemyPicksPosition => if (totalEnemyShips > 1) this should be if (totalEnemyShips < 1) otherwise enemy will only pick 1 button.

  8. rosieeemaryyy says:

    Does anyone know a way to do this without buttons? 😛