2 PictureBox
Tim Young edited this page 2017-10-03 02:17:24 +02:00

PictureBoxes

It is easiest if you use one PictureBox for the whole game, or at least only use them on one form. Creating and destroying PictureBoxes means you need to create and destroy the SpriteControllers that go with them. This is actually both messy, and very hard to do. If you can, design your game with only one SpriteController. You can have part of your window that is “menu” area, and part that is for displaying the score. When your game is over, replace the background and display a “you have won / lost” sprite.

In my AdventureDemo game, I tried to use multiple PictuerBoxes on multiple forms. This seemed like a good idea at the time, but I quickly decided that I should have found a way to do it with just the one. Well, it would have been OK to do it with two of them, but not to destroy them and open a new window with a new set of PictureBoxes.

Part of it is simply the inefficiency of needing to load all the sprites every time you create a new PictureBox. The other bit of it is the pain of trying to destroy the old controller. The inefficiency of loading sprites is easily remedied by using Linked Controllers or a SpriteDatabase

One very odd bit of behavior I had, at one time, was if I exited the game in the middle of a battle, my party sprites would continue to get “hit” by the enemies, even though their window had been closed and the enemies had been “destroyed.” I tried to get rid of a lot of stuff, but simply closing the window does not actually get rid of all the variables that had been part of that.

It is a lot simpler to program a game if it is all within one form. While you can develop games using multiple forms, things can get very messy. The SpriteLibrary was designed for use with one form, and bouncing between different forms can result in some very strange behavior. In my AdventureDemo (http://www.codeproject.com/Articles/1110409/Using-SpriteLibrary-to-develop-a-Role-Playing-Game), I used multiple forms. That was a bad idea. If I closed the main game window during a battle, the game exited and the game-menu popped up. Then, the sprites continued to fight, even though they were technically gone. The party continued to take damage, and sometimes die. It was a little disconcerting. The game is a lot simpler to deal with if you only have one form. This means you draw your menu on the same PictureBox that you have your game running on. You can change the PictureBox background, so you have a different looking window when the window is up, or you can leave it be. It does not really matter too much. But, please, try using putting it all in one Form if possible.

Having multiple PictureBoxes works fairly well, particularly with linked sprite-controllers and / or a SpriteDatabase. Both of those allow you to define a sprite once but use it on multiple picture boxes.

So, to sum all of this up. Try to only have one window, and the picture-boxes on that one window. If you need to have multiple PictureBoxes on one window, that is not too much of a problem. But, do not try to open new windows with new PictureBoxes and new sprite-controllers. That can end up with some rather odd behavior.

The PictureBox Background

The background is actually a critical part of the sprite-controller. Because the controller takes portions of the background to write over the sprites to “erase” them, the background must be solid. A transparent, or empty sprite controller will give you all sorts of grief. And, always have your background image set before creating the SpriteController. (see replacing a background below for what you need to do if you do not set it beforehand). I like to set the BackgroundImageLayout at the same time, as it makes sure that I get it correct. The Sprite Controller needs it to be ImageLayout.Stretch. Also, you will save yourself some grief if you make a duplicate of a resource instead of using the resource itself.

MainDrawingArea.BackgroundImage = new Bitmap(Properties.Resources.Background);
MainDrawingArea.BackgroundImageLayout = ImageLayout.Stretch;
MySpriteController = new SpriteController(MainDrawingArea);

The background size drastically affects the speed of the sprites. Sprites move in pixels per amount of time. If you have a huge background that is squished into a small PictureBox, then a low speed may not even be noticeable. But, if the background image is very small, the sprite may go zipping across a lot faster than you would expect.

The background size also affects memory usage and update speeds. For your first program that uses a sprite controller, use something that is in the 800x600 range. (600x600 or 800x800 if you want a square.) You can adjust it from there. The SpriteController can handle things that are fairly large, or fairly small.

Why the background and not the foreground?

PictureBoxes allow you to have both a background and a foreground. The reason the SpriteController uses the background is so you can use the foreground as a foreground. This makes it relatively easy to do things like drawing a select-box around sprites. Or, if your game has you looking out a space-ship view-screen, you can have your window there and the space-ships flying around behind the window. Having a foreground is really awesome.

Replacing the Background

Replacing the background image is actually a lot more complex than you might imagine. Once you use the below code, it can be done without any problem. But you need to do it this way, or it just goofs up in a number of small ways. You need to tell the sprite controller that you are replacing the background image, and you need to change the image to that image as well. Because the Images are actually pointers to memory where the image sets, changes to one image will affect the other image. This goofs things up, so what we do is duplicate the image twice, and tell the sprite controller to use one of the copies and then set the background to be the other one of the two copies. Finally, we tell the PictureBox to invalidate itself. That does everything that is needed.

void ReplaceBackground(Image NewBackground)
        {
            if (MyController == null) return;
            if (NewBackground == null) return;

            Image OneImage = new Bitmap(NewBackground);
            MyController.ReplaceOriginalImage(OneImage);

            Image TwoImage = new Bitmap(NewBackground);
            pb_map.BackgroundImage = TwoImage;
            pb_map.Invalidate();
        } 

Code for resizing the PictureBox

You do not need much code for resizing. What you want to do is to have the picturebox anchored to the window so that the picturebox will resize when the window does. The sprite library should handle the resizing of the image within the picturebox quite nicely. You may want to put a limit on how small, or how large the window can go. But the easiest way to do that is by setting the Form.MaximumSize and Form.MinimumSize.

private void Form1_ResizeEnd(object sender, EventArgs e)
        {
            MainDrawingArea.Invalidate();
        }