Click here to Skip to main content
Click here to Skip to main content

PacSnake

, 17 Jun 2005
Rate this:
Please Sign up or sign in to vote.
PacSnake is a mix of the classic PacMan game and the classic Snake game.

Sample Image - PacSnake.gif

Introduction

PacSnake is a game that is inspired by PacMan and the Snake game. The object of the game is to move the snake through the maze and eat all the food. When the snake hits his own body, it dies.

The game was very interesting to write because it uses a lot of different techniques (which are explained in more detail later).

  • XML: The game uses XML to read the different levels. It also uses XML file for skins and for storing/reading user preferences.
  • Graphics, obviously. It uses a backbuffer to write graphics to screen, so the screen doesn't flicker each time it's repainted.
  • Object oriented: I tried to use an object oriented approach while developing the game.
  • Sounds: The game uses sounds.

The game uses level sets and skins:

  • Level sets: A level set consists of one or more levels. You can create you own levels, put them in a level set file and that you can play the new levels.
  • Skins: You can also create your own skins and put them in the game. A skin is a collection of graphics that decide how the game looks. You can for example make a 'fire' skin or a 'metal' skin.

The Classes

I'll explain each class (object) that the game uses here in detail:

Snake

The Snake object is responsible for moving the snake, checking for directions and collisions and for getting the snake images.

The Snake consists of an array of rectangles. Each rectangle represents a body part of the snake (head, body or tail). Each rectangle has a position and a direction. This way, it's possible for each body part to move in a different direction (when the snake turns in corners). Using rectangles, it's easy to detect is the snake bumps into itself and dies. Here's the piece of code that checks for collisions:

        /// <summary>
        /// Check if the head of the snake crashed into a body part
        /// </summary>
        /// <returns>True if snake bumps into itself, otherwise false</returns>
        public bool CheckCollision()
        {
            for (int i = 1; i < length; i++)
                if (body[i].IntersectsWith(body[0]))
                {
                    isDead = true;
                    return true;
                }

            return false;
        }

The code takes the rectangle that represents the snake's head (which is the first in the array) and checks if it overlaps with any of the other body parts. If so, game over!

GameData

This is a fairly simple class which keeps track of the current level, remembers the user's preferences like playing sounds or not, and updating/reading the setting to an XML file on disk. The last point is worth showing here:

        /// <summary>
        /// Reads the game variables from the savegame. If there's no savegame
        /// we use default values.
        /// </summary>
        public void ReadSavegame()
        {
            string filename = path + "\\savegame.xml";
            XmlDocument doc = new XmlDocument();
            
            if (File.Exists(filename))
            {
                doc.Load(filename);
                skinFilename = doc.SelectSingleNode("//Skin").InnerText;
            }
            else
            {
                skinFilename = path + "\\skins\\ice.xml";
                
                // Create new file savegame.xml
                XmlTextWriter writer = new XmlTextWriter(filename, null);
                writer.Formatting = Formatting.Indented;
                writer.Indentation = 2;
                writer.WriteProcessingInstruction("xml",
                    "version='1.0' encoding='ISO-8859-1'");
                writer.WriteStartElement("savegame");
                writer.Close();
                
                // Load XML document and create all elements
                doc.Load(filename);
                XmlNode root = doc.DocumentElement;
                XmlElement skin = doc.CreateElement("Skin");
                skin.InnerText = path + "\\skins\\ice.xml";
                
                // Add all elements to the root element
                root.AppendChild(skin);
                
                // Save file
                doc.Save(filename);
            }
        }

First we check if a savegame exists. A savegame doesn't exist when the game is started for the first time. In this case, we create an XML file and store the users preferences. In this case, we only have one setting, but there may come more settings in the future as the game gets bigger. It uses the XML namespace, and when you examine the code you can see it's pretty straightforward.

Level

An important part of the Level class is drawing the level. Here's the piece of code responsible for that:

        /// <summary>
        /// This method draws the level. It takes each item in the level and
        /// draws the correspoding image.
        /// </summary>
        public Bitmap Draw(int levelWidth, int levelHeight, Skin skin)
        {
            img = new Bitmap(levelWidth, levelHeight);
            g = Graphics.FromImage(img);
            
            g.DrawImage(skin.Background, 0, 0);

            // Draw the level
            for (int i = 0; i < width; i++)
            {
                for (int j = 0; j < height; j++)
                {
                    Image image = GetLevelImage(itemsInLevel[i, j], skin);

                    // No free space
                    if (image != null)
                        g.DrawImage(image, mazeOffsetX + i * 20,
                            mazeOffsetY + j * 20, 20, 20);
                    
                    Item item = itemsInLevel[i, j];
                    if (item.IsCandy && !item.IsCandyEaten)
                        g.DrawImage(skin.Food, item.Rect.X, item.Rect.Y);
                }
            }
            
            return img;
        }

First, we draw a background, which is stored in the Skin class. The level is stored in a two-dimensional array. This array consists of Item objects. An item object tells us which item of the level it holds (like a different wall or a piece of food). The array is read row by row, column by column, and for every item a corresponding image is drawn. The maze offsets you see in the code are for drawing the level in the center of the screen in case the level is smaller than the screen size.

LevelSetInfo

The LevelSetInfo class holds all the information about a certain level set. A level set consists of different levels that are stored in an XML file. This way you can create your own levels by putting them in an XML file and simply copying this file in the levels directory.

LevelSet

LevelSet inherits from LevelSetInfo and in this class we also add the levels. While we use the LevelSetInfo class for displaying the level set information on screen (we don't need to know how the levels look), we use the LevelSet for reading the levels when we actually want to play the game.

LevelSetInfoCollection

This class simply holds a collection of LevelSetInfo objects.

Skin

The game uses skins for graphics. This means that you can create your own graphics if you wish. The Skin class loads these graphics from the skin directory. The location of these graphic files are stored in an XML file. The class reads the location from the XML files and retrieves the graphics from disc.

SkinCollection

Holds a collection of skins that are found in the skins directory.

WinMM

This is a helper class for playing sounds. It is a class I found on the web and for more details about playing the sounds, check the website mentioned in the source of this class.

Board

Board is the main form of the game. It draws the level, snake, etc.. It also uses a timer to move the snake and it responds to key presses. This is showed in the following method:

        /// <summary>
        /// Handles the key presses. When the game is running it controls the
        /// snake. When the game is not running it controls the other keys to
        /// start the game, etc...
        /// </summary>
        private void AKeyDown(object sender, KeyEventArgs e) 
        {
            switch (gameData.GameStatus)
            {
                // If the game is in progress, we control the snake
                case GameStatus.InProgress:
                    switch (e.KeyData.ToString()) 
                    {
                        case "Left":
                            snake.DesiredDirection = MoveDirection.Left;
                            break;
                        case "Right":
                            snake.DesiredDirection = MoveDirection.Right;
                            break;
                        case "Up":
                            snake.DesiredDirection = MoveDirection.Up;
                            break;
                        case "Down":
                            snake.DesiredDirection = MoveDirection.Down;
                            break;
                        default:
                            // Don't respond on other key presses
                            break;
                    }
                    break;
                // If the snake has died we press a random key to restart
                case GameStatus.SnakeDied:
                    InitializeGame();
                    break;
                // If the level is finished we press a key to start next
                case GameStatus.LevelFinished:
                    // If this wasn't the last level, start next level
                    if (gameData.CurrentLevel < levelSet.NrOfLevelsInSet)
                    {
                        gameData.CurrentLevel++;
                        level = levelSet[gameData.CurrentLevel - 1];
                        InitializeGame();
                    }
                    else
                        gameData.GameStatus = GameStatus.WaitingForKey;
                    
                    break;
                // Level is ready to start, let's wait for a key
                case GameStatus.WaitingForKey:
                    gameData.GameStatus = GameStatus.InProgress;
                    gameTicker.Interval = level.Speed;
                    gameTicker.Enabled = true;
                    mnuSkin.Enabled = false;
                    break;
            }
        }

FormLevelSet

Before we start the game, we have to choose which level set we want to play. This is done by this form.

FormSkins

A simple form where we can choose which skin we want to use in the game.

Enjoy!

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

Share

About the Author

JasperB
Web Developer
Netherlands Netherlands
No Biography provided

Comments and Discussions

 
QuestionJust Say PinmemberAdhi Ahmad M9-May-14 10:55 
QuestionHello Pinmemberzahra199122-Jan-12 4:33 
GeneralIt isn't new... PinmemberIgen111-Oct-08 10:43 
GeneralNice job...and addictive PinmemberBert delaVega15-Apr-08 8:27 
GeneralQuestions regarding pac snake game Pinmemberadmirable28-Aug-06 22:41 
GeneralRe: Questions regarding pac snake game PinmemberJasperB29-Aug-06 23:49 
GeneralHelp!!! PinmemberDeadshadow5-Jul-06 21:11 
GeneralWebsite menu item causes exception PinmemberAshley van Gerven18-Jun-05 16:41 
GeneralRe: Website menu item causes exception PinmemberJasperB18-Jun-05 23:43 
GeneralRe: Website menu item causes exception PinmemberAhmed.mb19-Aug-06 1:05 
GeneralVery interesting concept PinmemberMike Ellison18-Jun-05 7:35 
GeneralRe: Very interesting concept PinmemberJasperB18-Jun-05 23:47 
GeneralGreat concept! : ) PinmemberJakob Lund Krarup18-Jun-05 5:08 
GeneralSystem.IO.IOException Pinmemberreinux17-Jun-05 23:37 
GeneralRe: System.IO.IOException PinmemberJasperB18-Jun-05 2:35 
GeneralRe: System.IO.IOException Pinmemberreinux18-Jun-05 2:44 
GeneralRe: System.IO.IOException PinmemberJasperB18-Jun-05 3:45 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web03 | 2.8.141216.1 | Last Updated 17 Jun 2005
Article Copyright 2005 by JasperB
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid