Need help with loading 200 imageboximages.

Battleship game, and need to update all squares on each players board.

  • (2 Pages)
  • +
  • 1
  • 2

19 Replies - 1518 Views - Last Post: 02 June 2010 - 10:02 AM Rate Topic: -----

#1 Guest_Kyle*


Reputation:

Need help with loading 200 imageboximages.

Posted 29 May 2010 - 04:06 PM

So currently I am working on a school project where we learn C# by ourselves and make a game of our choice. My group has decided to create a game of "battleship". The problem we are having is that we need to update every single square (on a 10x10 image box board) with an image, but the way in which we are doing it is EXTREAMLY lengthy and inefficient.

We have created an enumerated type array of all the possiblities in a givin square (ship directions, if the user shoots and misses, ect ect). Now for us to sucessfully print each square we have been using the following code.


switch (square)
{
case 0:
//switch into the possiblities of what can be in this square
switch (playersSquares[0, 0])
{
case ShipPart.topShip: square00.Image = ShipTopImage.Image;
break;
case ShipPart.bottomShip: square00.Image = ShipBottomImage.Image;
break;
case ShipPart.leftShip: square00.Image = ShipLeftImage.Image;
break;
case ShipPart.rightShip: square00.Image = ShipRightImage.Image;
break;
case ShipPart.middleHorizontal: square00.Image = ShipHMiddleImage.Image;
break;
case ShipPart.middleVirticle: square00.Image = ShipVMiddleImage.Image;
break;
case ShipPart.empty: square00.Image = EmptyImage.Image;
break;
case ShipPart.miss: square00.Image = ShipMissImage.Image;
break;
case ShipPart.hit: square00.Image = ShipHitImage.Image;
break;
}
break;
case 1:
//switch into the possiblities of what can be in this square
switch (playersSquares[0, 1])
{
case ShipPart.topShip: square01.Image = ShipTopImage.Image;
break;
case ShipPart.bottomShip: square01.Image = ShipBottomImage.Image;
break;
case ShipPart.leftShip: square01.Image = ShipLeftImage.Image;
break;
case ShipPart.rightShip: square01.Image = ShipRightImage.Image;
break;
case ShipPart.middleHorizontal: square01.Image = ShipHMiddleImage.Image;
break;
case ShipPart.middleVirticle: square01.Image = ShipVMiddleImage.Image;
break;
case ShipPart.empty: square01.Image = EmptyImage.Image;
break;
case ShipPart.miss: square01.Image = ShipMissImage.Image;
break;
case ShipPart.hit: square01.Image = ShipHitImage.Image;
break;
}
break;
case 2:
//switch into the possiblities of what can be in this square
switch (playersSquares[0, 2])
{
case ShipPart.topShip: square02.Image = ShipTopImage.Image;
break;
case ShipPart.bottomShip: square02.Image = ShipBottomImage.Image;
break;
case ShipPart.leftShip: square02.Image = ShipLeftImage.Image;
break;
case ShipPart.rightShip: square02.Image = ShipRightImage.Image;
break;
case ShipPart.middleHorizontal: square02.Image = ShipHMiddleImage.Image;
break;
case ShipPart.middleVirticle: square02.Image = ShipVMiddleImage.Image;
break;
case ShipPart.empty: square02.Image = EmptyImage.Image;
break;
case ShipPart.miss: square02.Image = ShipMissImage.Image;
break;
case ShipPart.hit: square02.Image = ShipHitImage.Image;
break;
}
break;
}




As you can see we would need to create 200 cases the way we are doing it and would cause us lots of unesacary code. This code works by a function that generates a loop and sends the value (0,1,2,3,4,5,ectect) to this function. it then changes each square respectivly.

What I was thinking could work was doing sqaure[row,col].image but I KNOW this doesn't work. What we are trying to get around is the fact that ever imagebox has a differnt code (square00, square01, square02, ect ect) and we can't figure out how to load the images faster/easier. Does anyone have a suggestion that would find a way to update the images on my board?

I'm using Microsoft visual studio 2008 express. If you need anymore information about my code please let me know! (I did the math and if I do the code the way im doing it I will have to create 4600 lines of code to generate the pictures in both the human and the computers boards.)
If needed I will attach/send you the full length of my code if you do not understand.

Is This A Good Question/Topic? 0

Replies To: Need help with loading 200 imageboximages.

#2 Sergio Tapia  Icon User is offline

  • D.I.C Lover
  • member icon

Reputation: 1253
  • View blog
  • Posts: 4,168
  • Joined: 27-January 10

Re: Need help with loading 200 imageboximages.

Posted 29 May 2010 - 04:23 PM

Can you describe the game mechanics for us, not code; just how the game is supposed to work. Is this battleship? I can't really tell.
Was This Post Helpful? 0
  • +
  • -

#3 Guest_Kyle*


Reputation:

Re: Need help with loading 200 imageboximages.

Posted 29 May 2010 - 04:37 PM

This is battleship, I said that in the breif description but not the other part sorry. Basically the game board consists of a 10x10 grid of image boxes. In each image box hold what the box could hold. I have this definied by an enumerated type of the following...
 public enum ShipPart
        {
            topShip=0,           //this is the top head of the ship (^). It has a value code of 0.
            bottomShip=1,        //this is the bottom part of the ship (_). It has a value code of 1.
            leftShip=2,          //this is the left part of the ship (<). It has a value code of 2.
            rightShip=3,         //this is the right part of the ship (>). It has a value code of 3.
            middleHorizontal=4,  //this is a middle part of the ship (=). It has a value code of 4.
            middleVirticle=5,    //this is the virticle part of the ship (||). It has a value code of 5.
            empty=6,             //this is when nothing occupies the square ( ) [everything looks like this at the beginning It has a value code of 6.
            miss=7,              //this is if a shot is taken and the square holds a miss. It has a value code of 7.
            hit=8                //this is if a ship has been hit. It has a value code of 8.
        }



Now what I was planning was to just reload each square (based on an arrary I created and has stored what image will be shown in it) independly in a function, but if I do it this way, I have a large amount of code that seems like it could be done quite more simply.

The game will allow the user to place their ships, and then play the actual game (this part I have down). What I need advice on is the "refreshing" of the image in each square. I dont want to write a case statement for every single square, but I may have to. Does this help further explain?
Was This Post Helpful? 0

#4 elbielefeld  Icon User is offline

  • D.I.C Head

Reputation: 70
  • View blog
  • Posts: 217
  • Joined: 18-May 10

Re: Need help with loading 200 imageboximages.

Posted 29 May 2010 - 08:16 PM

Best way to draw the battleground is to use 1 Picturebox. You can create 1 image and always draw to that image using GDI+.
At first we need a BattleGround, so create a class:

    public class BattleGround
    {
        public Bitmap Image { get; set; }
        public Graphics Graphics { get; set; }

        public BattleGround()
        {
            //Constructor
            Image = new Bitmap(511, 511);
            Graphics = Graphics.FromImage(Image); //Create GDI+ graphics object
            DrawBattleGroundBorders(); //Initialize the borders
        }

        public void DrawBattleGroundBorders()
        {
            for (int i = 0; i < 11; i++)
            {
                Graphics.DrawLine(Pens.Black, 0, i * 50 + i, Image.Width, i * 50 + i);
                Graphics.DrawLine(Pens.Black, i * 50 + i, 0, i * 50 + i, Image.Height);
            }
        }

        public void DrawBattleGroundField(Image image, Point position)
        {
            if (position.X < 10 && position.Y < 10)
            {
                Graphics.DrawImage(image, position.X * 50 + position.X + 1, position.Y * 50 + position.Y + 1);
            }
        }
    }



The class exposes some methods to draw to the battlefields image.

Then we see that all battleships have something common, so we create an abstract class:
The Battleship class
    public abstract class Battleship
    {
        public abstract void Draw(BattleGround battleGround); //Draw method

        public Point Position { get; set; } //The Battleships position
        public Orientation Orientiation { get; set; } //The Battleships orientation
    }

//Sample class: BigBattleship, inherits Battleship
    public class BigBattleship: Battleship
    {        
        public override void Draw(BattleGround battleGround)
        {
            //ToDo: Create drawing procedure
            //use battleGround.DrawBattleGroundField to draw each 50x50 pixel part of the ship
            //use this.Position and this.Orientation to know where to draw
        }
    }



Also, we know each player has a list of ships. You can add/remove Battleships from the BattleshipList class.
It also has a DrawShips method, which instructs all ships in this list to draw themselfes to the specified battleground.
The BattleshipList class, which inherits List<Battleship>
    public class BattleshipList: List<Battleship>
    {
        public void DrawShips(BattleGround battleGround)
        {
            foreach (Battleship battleShip in this)
            {
                battleShip.Draw(battleGround);
            }
        }
    }



So now everything is set up and we can start adding some ships and show our results.
Create a form and add a picturebox with 511x511 pixel size (50*50px for each image and 11px border).

    public partial class Form1 : Form
    {
        BattleGround battleGround = new BattleGround(); //Our BattleGround
        
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            BattleshipList player1Battleships = new BattleshipList(); //Create new BattleshipList for Player1
            BigBattleship newBattleship = new BigBattleship(); //Create a new BigBattleship
            newBattleship.Position = new Point(1, 1); //Set Position
            newBattleship.Orientiation = Orientation.Horizontal; //Set Orientation
            player1Battleships.Add(newBattleship); //Add to player1's ships

            player1Battleships.DrawShips(battleGround); //Draw player1's ships to the battleground
            pictureBox1.Image = battleGround.Image; //refresh picturebox
        }
    }



You won't see the added Battleship, because the Draw method of the BigBattleship class does nothing.
Each Battleship is responsible of drawing itself. So the Battleship has to know, where it was hit. This is something I leave up to you.

You could make the BattleshipList class a property of the Battleground class and maybe create a player class:
So each player has a battleground. Each battleground has a BattleshipList.

Additionally you will have to find a way to know if a ship exists at a specific position. You can add a "bool IsHit(Point position)" function to the abstract Battleship class, so all Battleships implement this function. The BattleshipList class can then provide a "Battleship GetHitBattleship(Point position)" method which loops through the battleships and checks if the IsHit function returns true.

I hope this little introduction to oject-oriented programming helps you.
Was This Post Helpful? 1
  • +
  • -

#5 Momerath  Icon User is offline

  • D.I.C Lover
  • member icon

Reputation: 1012
  • View blog
  • Posts: 2,444
  • Joined: 04-October 09

Re: Need help with loading 200 imageboximages.

Posted 29 May 2010 - 08:18 PM

I'd create an interface for the things that could be in the square, with at least one method for displaying it. I'd create a class of objects that implement this interface, one for each thing that can be in a spot.
 public Interface IObject {
    Draw(int i, int j)
}


You'd then define an array of IObjects, and your draw code would all be the same:
IObject[,] myBoard = new IObject[10,10];

... other code

public void DisplayBoard() {
    for (int i = 0; i < 10; i++) {
        for (int j = 0; j < 10; j++) {
            myBoard[i,j].Draw(i, j);
        }
    }
}


If you do the background correctly then the blank object could just return from the Draw() method saving you a lot of time.

Well, actually I'd do it with a List of objects instead of an array, but this matches more with what you have :)

This post has been edited by Momerath: 29 May 2010 - 10:45 PM

Was This Post Helpful? 1
  • +
  • -

#6 FlashM  Icon User is offline

  • D.I.C Lover
  • member icon

Reputation: 382
  • View blog
  • Posts: 1,195
  • Joined: 03-December 09

Re: Need help with loading 200 imageboximages.

Posted 29 May 2010 - 11:02 PM

When a player hits a squares, you shouldn't check for all the possibilities what might be inside this square, but you should have some array from which you would instantly know what exactly hides under this square and respond to this by drawing the corresponding image to this square. This way it would be much less code and your code would be more optimal and execute faster.
Was This Post Helpful? 0
  • +
  • -

#7 Guest_Kyle*


Reputation:

Re: Need help with loading 200 imageboximages.

Posted 30 May 2010 - 12:41 AM

First of all thank you all for looking over what I have asked and responding with such understanding.

elbielefeld - I really liked looking at your response (since I am learning C#), but sadly I have 0 knowledge of anything you basically said. I understand the concepts of OOP, and how everything runs but where I get lost is when you call/say draw, abstract, and graphics. I also do not understand many of the keywords you used, and how they work within C#. I will look what you have done more over later in my time (tomorrow, as it is 2:32 AM my time currently).

Momerath - Looking over what you said, it looks more appropriate to my current skill level in C#. Now again, I am lost with your use of the word "interface" and what it exactly does. I also sense that I would have to write more code since it sounds like your assuming I have a underlying understanding of how you were proceeding (sorry but I don't. I'll have to research this as well as elbielefelds idea). I also don't exactly understand what you mean by "drawing the background correctly" and by "blank object". I think you mean the empty part of the board (at game start or new game) but am unsure.

FlashM - Exactly! This is why I asked to find a different way. Like I said, I knew it was extremely inefficient, as well as lengthy so I decided to ask if there was a better way (it seems there is but wow, talk about mind blowing). So hopefully I fix this problem up!

Anyways, I think I'm going to look into elbielefeld's example to further my understanding of "draw" and how it will work better in my game. From what I understand one picturebox will be the start (with all empty squares) then afterwards load an image into a picture box of my 100. This is done by the draw function which I'm guessing would read in what kind of ship is in each space.

Once again, thanks for the help and I hope to hear more comments back soon!
Was This Post Helpful? 0

#8 FlashM  Icon User is offline

  • D.I.C Lover
  • member icon

Reputation: 382
  • View blog
  • Posts: 1,195
  • Joined: 03-December 09

Re: Need help with loading 200 imageboximages.

Posted 30 May 2010 - 01:23 AM

How do you build your map of ship positions? Does a user chooses where his ships will be placed or do you auto-generate this?
Was This Post Helpful? 0
  • +
  • -

#9 elbielefeld  Icon User is offline

  • D.I.C Head

Reputation: 70
  • View blog
  • Posts: 217
  • Joined: 18-May 10

Re: Need help with loading 200 imageboximages.

Posted 30 May 2010 - 06:31 AM

Hi Kyle,
as you can see in the BattleGround class, we create an Image property. We basically want to draw on the same image (The BattleGround image) all the time and show this image in a picturebox.
The drawing itself is done with the Graphics-class provided by GDI+ in the System.Drawing namespace. http://msdn.microsof...em.drawing.aspx We create this Graphics object with the line
Graphics = Graphics.FromImage(Image); //Create GDI+ graphics object


in the BattleGrounds constructor. As you can see, it is "connected" to the BattleGrounds image property. So everything you draw with the graphics object will be drawn on the image. The graphics object exposes methods to draw lines, rectangles, text, other images and so on: Graphics object methods

Abstract
An abstract class is a base class. It provides properties, methods and so on that all derived classes must have. Like every Battleship must have a position, orientation, and a draw method. In the BattleshipList for example you see, that it only creates a list of the abstract class Battleship. The list does not care, if the Battleship is a BigBattleship, SmallBattleship or whatever. But it knows each Battleship has a position, orientation and a draw method.
http://msdn.microsof...hc5(VS.80).aspx
An Interface is something similar. You can see the differences here:
http://www.codeproje...interfaces.aspx
Was This Post Helpful? 1
  • +
  • -

#10 Guest_Kyle*


Reputation:

Re: Need help with loading 200 imageboximages.

Posted 30 May 2010 - 10:24 AM

FlashM - The user gets to choose their placement of the ship, and the computer is randomly generated. I have also already written this code. I can see now that if I want to make my showing of the ships in an easier manner that I will have to rewrite accordingly.

elbielefeld - So what I've to do to make my program much more efficient would be to create one picture box. With this picture box I must make a draw method that will draw the shape of the ship ONTO this one picture board with coordinates that it receives. My next question would be from your following code.
    public abstract class Battleship 
    { 
        public abstract void Draw(BattleGround battleGround); //Draw method 
 
        public Point Position { get; set; } //The Battleships position 
        public Orientation Orientiation { get; set; } //The Battleships orientation 
    } 
 
//Sample class: BigBattleship, inherits Battleship 
    public class BigBattleship: Battleship 
    {         
        public override void Draw(BattleGround battleGround) 
        { 
            //ToDo: Create drawing procedure 
            //use battleGround.DrawBattleGroundField to draw each 50x50 pixel part of the ship 
            //use this.Position and this.Orientation to know where to draw 
        } 
    }



I've read the articles you've posted and they make more sense to me now. Now I have to ask with "public Point Position { get; set; }" how does it take in the coordinates/display one of many images in a picture box? I just read up on get and set but am unsure on how this would be called/run. I also have to ask what I would go about to create the drawing procedure. Would this be where I would draw the image I want to the coordinates I want (but since I have physical pictures just loading them to the coordinates)? I see how you draw the borders pixel by pixel, so is this how I would have to draw the image I want to load? Also I see that you stated that I had to do
Image = new Bitmap(511, 511); 



Can I not just create an image box on my form1[design]? If I must create it this way, would I have to find the coordinates on the form to where I want to create this image?

Once again thanks for responding, and sorry for the jumbled mess of my response. It's rather hard to grasp everything. Hope to hear back!
Was This Post Helpful? 0

#11 Guest_Kyle*


Reputation:

Re: Need help with loading 200 imageboximages.

Posted 30 May 2010 - 11:27 AM

Sorry, re-reading your code I can see where I would draw each 50x50 ship peice. My other questions do however still stand.
Was This Post Helpful? 0

#12 Guest_Kyle*


Reputation:

Re: Need help with loading 200 imageboximages.

Posted 30 May 2010 - 12:29 PM

PLEASE IGNORE MY PREVIOUS 3 POSTS

Wow, I feel like such an idiot right now. I COMPLETLY understand how the image is being created, stored, refreshed, and all of those sorts. The only problems I have with what you have explained (very well actually thank you) is the following.
newBattleship.Position = new Point(1, 1); //Set Position 
newBattleship.Orientiation = Orientation.Horizontal; //Set Orientation 
player1Battleships.Add(newBattleship); //Add to player1's ships



If I want the user to be able to pick any square they want, so how do I use/get the coordinates of their click? Would I just use position.X, and position.Y? I believe this would be done by a mouse click method on the image box, but I donít know what would give me the coordinates of their click.

Back to successfully drawing the board... When you say image in...
public void DrawBattleGroundField(Image image, Point position) 
        { 
            if (position.X < 10 && position.Y < 10) 
            { 
                Graphics.DrawImage(image, position.X * 50 + position.X + 1, position.Y * 50 + position.Y + 1); 
            } 
        } 
//other code section...

//ToDo: Create drawing procedure
//use battleGround.DrawBattleGroundField to draw each 50x50 pixel part of the ship 
//use this.Position and this.Orientation to know where to draw 



Is that the image I want to put in that cordinate? If so, do I just send the resource location for it? Or load it directly from a different image?

Also when you say use this.Position and this.Orinentation, what values are gained from this/usage. I'm guessing this.Position will give me the coordinates (in terms of x, y?), and I've no idea what this.Orinentation would do (I understand that it will give me horizontal, or vertical but is given to me in what way?).
Was This Post Helpful? 0

#13 elbielefeld  Icon User is offline

  • D.I.C Head

Reputation: 70
  • View blog
  • Posts: 217
  • Joined: 18-May 10

Re: Need help with loading 200 imageboximages.

Posted 30 May 2010 - 12:56 PM

get/set means it is a property (property accessor). You could also use "public Point Position". You could combine them with access modifiers, if needed http://msdn.microsof...sc7(VS.80).aspx but in this case I think it is not neccessary.
As you can see in the sample you can access the Position and Orientation properties for the BigBattleship class, as they are inherited by the Battleship class:
BigBattleship newBattleship = new BigBattleship(); //Create a new BigBattleship
newBattleship.Position = new Point(1, 1); //Set Position
newBattleship.Orientiation = Orientation.Horizontal; //Set Orientation



In the above example, lets assume the BigBattleship is 3 fields in lenght in the Battleground (back, middle, front).
You need to call DrawBattleGroundField(Image image, Point position) 3 times:
battleGround.DrawBattleGroundField(backImageHorizontal, Position); //Draw back part of the ship at the ships position in the battleground
battleGround.DrawBattleGroundField(middleImageHorizontal, Point.Add(Position, new Size(1, 0))); //Draw middle part one field to the right (as orientation is horizontal)
battleGround.DrawBattleGroundField(frontImageHorizontal, Point.Add(Position, new Size(2, 0))); //Draw front part


So the position is basically the position of the back part of the ship in the battleground. Not the position of all parts. After the ship has been drawn to the battleground image, you have to manually update the picturebox so the changed image is visible.
Was This Post Helpful? 2
  • +
  • -

#14 elbielefeld  Icon User is offline

  • D.I.C Head

Reputation: 70
  • View blog
  • Posts: 217
  • Joined: 18-May 10

Re: Need help with loading 200 imageboximages.

Posted 30 May 2010 - 01:27 PM

View PostKyle, on 30 May 2010 - 07:29 PM, said:

If I want the user to be able to pick any square they want, so how do I use/get the coordinates of their click? Would I just use position.X, and position.Y? I believe this would be done by a mouse click method on the image box, but I donít know what would give me the coordinates of their click.

You know each 51th pixel is the border, so you check if the clicked coordinates can be divided by 51 without remainder. If not, you divide the coordinates by 51 to get the position in the battleground:
http://msdn.microsof...fzs(VS.80).aspx
        private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
        {
            if (e.X % 51 == 0 || e.Y % 51 == 0)
            {
                MessageBox.Show("You clicked on the border.");
            }
            else
            {
                Point positionclicked = new Point(e.X / 51, e.Y / 51);
                MessageBox.Show("You clicked on " + positionclicked.ToString());
            }
        }



View PostKyle, on 30 May 2010 - 07:29 PM, said:

Is that the image I want to put in that cordinate? If so, do I just send the resource location for it? Or load it directly from a different image?

The DrawBattleGroundField(Image image, Point position) wants an image and a position as the parameters. You can use Image.FromFile(path) to load an image from disk. Best way would be that each derived class from Battleship, like BigBattleship has some static (http://msdn.microsof...cdx(VS.71).aspx fields for the images:

    public class BigBattleship: Battleship
    {
        private static Image frontImageHorizontal = Image.FromFile("PathToFrontHorizontal");
        private static Image middleImageHorizontal = Image.FromFile("PathToMiddleHorizontal");
        private static Image backImageHorizontal = Image.FromFile("PathToBackHorizontal");

        public override void Draw(BattleGround battleGround)
        {
            //ToDo: Create drawing procedure
            //use battleGround.DrawBattleGroundField to draw each 50x50 pixel part of the ship
            //use this.Position and this.Orientation to know where to draw
        }
    }


Was This Post Helpful? 0
  • +
  • -

#15 Guest_Kyle*


Reputation:

Re: Need help with loading 200 imageboximages.

Posted 30 May 2010 - 06:08 PM

Quote

Also, we know each player has a list of ships. You can add/remove Battleships from the BattleshipList class.


I do not understand where this list is created/how I can change it to what I need. Is it just adding methods to
 public class BattleshipList: List<Battleship> 
    { 
        public void DrawShips(BattleGround battleGround) 
        { 
            foreach (Battleship battleShip in this) 
            { 
                battleShip.Draw(battleGround); 
            } 
        } 
    }


Or do I need to complelty make a new class? Another question I have is, did you really mean to use mousedown in
        private void pictureBox1_MouseDown(object sender, MouseEventArgs e) 
        { 
            if (e.X % 51 == 0 || e.Y % 51 == 0) 
            { 
                MessageBox.Show("You clicked on the border."); 
            } 
            else 
            { 
                Point positionclicked = new Point(e.X / 51, e.Y / 51); 
                MessageBox.Show("You clicked on " + positionclicked.ToString()); 
            } 
        }


Why didn't you use mouse_click?
Was This Post Helpful? 0

  • (2 Pages)
  • +
  • 1
  • 2