We write "Snake" for Windows Phone 7

Original author: Pasi Manninen
  • Transfer
About the Author:  Pasi Manninen develops mobile and web applications, is a Nokia Developer Champion and Adobe Community Professional, Adobe Certified Expert, and a Flex, Flash, and Flash Mobile Adobe Teacher. Graduated from the University of Jyväskylä (one of the largest universities in Finland) with a degree in Applied Mathematics or Computer Science.

Introduction


In this article, we will show you how to create a simple version of Snake for Windows Phone. It will be possible to move the snake in different directions using gestures. The application consists of a menu screen, the game itself and the final screen with the results of the game.



Windows Phone 7.1 SDK


To develop applications for devices running Windows Phone 7, you need to install the Windows Phone 7.1 SDK. You can download the latest version here .


Windows Phone Game


To start developing a new Windows Phone Game, start Microsoft Visual studio, create a new project and select the Windows Phone Game (4.0) Template. We will use SnakeIt as the project name.

image

In this example, we will use C # to develop our game.

Preparing Images for the Game


First, add simple graphic elements for food and the snake itself. We will use 25x25 images that can be repeated over the entire surface.

Food

Right-click Content in the browser for the SnakeIt project solution and select Add> New Item ...
Select Bitmap File and name it FootTile.bmp

image

Draw a 25x25 green rectangle to indicate the food. Remember to save the file.

image

Snake

Use the same technique to draw a red square of the snake itself. Name the image SnakeTile.bmp.

Game font


We can create the font for the game in the same way that we used to create the images. Right-click on the contents of the project in the solution
explorer , select Add> New Item ... Select Sprite Font and name it Segoe20.spritefont.

image

Double-click on the font in the Project Explorer and set its size to 20. Remember to save the font.

Creating a Food Class for Food


Right-click on the contents of the project in the solution explorer, select Add> New Item ... Select Code in the list of installed templates and create the Food class.

image

This class stores information about Texture (texture, type) and Position (position). The width and height dimensions are used to define collisions in the Game1 class.

using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
namespace SnakeIt
{
    class Food
    {
        // Texture representing the food
        public Texture2D Texture;
        // Position of the food relative to the upper left side of the screen
        public Vector2 Position;
        // Get the width of the food
        public int Width
        {
            get { return Texture.Width; }
        }
        // Get the height of the food
        public int Height
        {
            get { return Texture.Height; }
        }
        // Set Food Texture and Position
        public void Initialize(Texture2D texture, Vector2 position)
        {
            Texture = texture;
            Position = position;
        }
        // Draw Food to the Screen
        public void Draw(SpriteBatch spriteBatch)
        {
            spriteBatch.Draw(Texture, Position, null, Color.White, 0f, Vector2.Zero, 1f, SpriteEffects.None, 0f);
        }
    }
}


Creating a Snake Class


Create the Snake class just like you created the Food class.

Usable Namespaces


We will use the XNA Framework and the List class from Collections to handle all the tiles for our snake.
using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System.Collections.Generic;


The properties

To define a snake, we define several of its properties. We will load the snake image as a Texture texture and set the initial position of the snake in the middle of the screen (we will implement this later in the Game1 class). All snake cells will be stored in the snakeTiles list. The direction of movement of the snake will be controlled in the class Game1 using gestures.

// Текстура змейки
public Texture2D Texture;
// Начальное положение
public Vector2 Position;
// Ячейки для замейки
public List snakeTiles;
// Инкремент и скорость змейки
public float speed;
const float speedIncrement = 0.2f;
// Направление змейки // 1==влево, 2==вверх, 3==вправо, 4==вниз
public int direction;
// определено пересечение змейки с едой -> нужно добавить новую ячейку к змейке
public bool newTile;


Initialization

Game1 will initialize the Snake object. The snake texture will be loaded, its initial position will be set. All properties of the snake will be reset to the default properties at the first start and when the player wants to complete the game again. By default, the snake moves 5 pixels to the left and its head cell is created.

// Инициализация змейки
 public void Initialize(Texture2D texture, Vector2 position)
{
       Position = position;
       Texture = texture;
       Reset();
}
// Сброс (новая игра)
public void Reset()
{
      speed = 5f;
      direction = 1;
      Tile tile = new Tile(Texture, Position);
      snakeTiles = new List();
      snakeTiles.Add(tile);
      newTile = false;
}


Update

The game will call a method to update the snake every new game step. In this method, we find the position of the snake’s head (this is the first cell in the snakeTiles list). If we need to add a new cell to the snake (that is, when the food was eaten), we create a new cell for headPostion and add it to the snakeTiles list. Next, we only move the head of our snake, thus increasing its size. If new cells for the snake are no longer expected, then we will only move the last cell to the "head" of the snake, and we will move the snake to a new position.

public void Update() 
{
            // Положение головы змейки
            Vector2 headPosition = snakeTiles[0].Position;
            // Добавляем новую ячейку
            if (newTile)
            {
                // Создаём новую ячейку
                Tile tile = new Tile(Texture, headPosition);
                // Вставляём её в SnakeTiles (после HeadPosition, но с теми же координатами на экране)
                snakeTiles.Insert(1, tile);
            }
            // Перемещаем последнюю ячейку туда, где была "голова" змейки
            else if (snakeTiles.Count > 1)
            {
                Tile last = snakeTiles[snakeTiles.Count - 1];
                last.Position = headPosition;
                snakeTiles.RemoveAt(snakeTiles.Count-1);
                snakeTiles.Insert(0, last);
            }
            // Увеличиваем скорости при поедании вкусняшки
            if (newTile)
            {
                speed += speedIncrement;
                newTile = false;
            }
            // Перемещаем "головы" змейки на новое местоположение
            switch (direction)
            {
                case 1: snakeTiles[0].Position.X -= speed; break;
                case 2: snakeTiles[0].Position.Y -= speed; break;
                case 3: snakeTiles[0].Position.X += speed; break;
                case 4: snakeTiles[0].Position.Y += speed; break;
            }        
 }


Painting

Each snake cell is drawn in the Draw () method. This method is called from the Game1 class.

public void Draw(SpriteBatch spriteBatch)
{
            for (int i = 0; i < snakeTiles.Count; i++)
            {
                spriteBatch.Draw(snakeTiles[i].Texture, snakeTiles[i].Position, null, Color.White, 0f, Vector2.Zero, 1f, SpriteEffects.None, 0f);
            }
}


Tile class (nested class relative to Snake class)

Create a nested Tile class. This class will determine the snake's cell. Each cell has a Position and a Texture.

class Tile
{
        public Vector2 Position;
        public Texture2D Texture;
        public Tile(Texture2D texture, Vector2 position) {
            Position = position;
            Texture = texture;
        }
        // Ширина змейки
        public int Width
        {
            get { return Texture.Width; }
        }
        // Высота змейки
        public int Height
        {
            get { return Texture.Height; }
        }
}


Class Game1


The Game1 class is the main class for games based on Windows Phone XNA Games. This is where the initialization and loading of the contents of our game takes place. Gestures and collision detection are used in a game method called Update method. Draw checks the game mode according to the GameMode property and draws the corresponding screen.

Namespaces

Uses the usual XNA and Touch classes to define gestures.
using System;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Input.Touch;


The properties

We use the GraphicsDeviceManage class to get information about the current display. The SpriteBatch class is used to display information on the screen. We decided to use different game modes to control what is happening through the Draw () method: to draw a menu, the game itself or the game completion mode. This is a very simple way to handle drawing different modes on the screen. In addition, an exploded approach to solving this problem is possible (see link: Game State Management ). The current game mode is stored in the Mode property, all kinds of modes are defined as a GameMode enumeration.

// Информация о текущем экране
private GraphicsDeviceManager graphics;
// Объекты для вывода на экран
private SpriteBatch spriteBatch;
// Змейка
private Snake snake;
// Еда для змейки
private Food food;
// Шрифт
private SpriteFont segoe20;
// Положение счёта на экране
private Vector2 scorePosition;
// Счёт
private float score;
private const float FOOD_POINTS = 20;
// Текущий игровой режим
 GameMode Mode;
// Все игровые режимы
enum GameMode {Menu, Running, Complete}


Constructor

To get started, we connect to the GraphicsDeviceManage class and tell our directory with all Content sprites and fonts. The frame rate is set to 30 frames per second by default. We also need to enable Tap and Flick gestures. Different game modes are changed using the Tap gesture, the movement of the snake is controlled by the Flick gesture.

public Game1()
{
            // Менеджер графики
            graphics = new GraphicsDeviceManager(this);
            // Директория со спрайтами и шрифтами
            Content.RootDirectory = "Content";
            // 30 кадров в секунду по умолчанию для Windows Phone.
            TargetElapsedTime = TimeSpan.FromTicks(333333);
            // Увеличиваем время жизни библиотеки при блокировании устройства.
            InactiveSleepTime = TimeSpan.FromSeconds(1);
            // Определение жестов Tap и Flick
            TouchPanel.EnabledGestures = GestureType.Tap | GestureType.Flick;
 }


Game initialization

The Initialize method allows you to carry out any action to initialize the game and all its resources before starting the game itself. Here we set the game mode and create objects for food and the snake itself.

protected override void Initialize()
{
            // Устанавливаем режим игры в Menu, экран Menu будет нарисован методом Draw()
            Mode = GameMode.Menu;
            // Создаём змейку и еду для неё 
            snake = new Snake();
            food = new Food();
            // Начальные 0 очков
            score = 0f;
            base.Initialize();
}


Download sprites and fonts

LoadContent is called once to load all files. First, we connect to the graphics device using SpriteBatch so that later we can draw objects on the screen. Then we upload and create textures for food and snakes. At this point, the Initialize method is called on the corresponding Snake and Food classes. We also create our font and calculate the position to display the number of points.

protected override void LoadContent()
{
            // Создаём SpriteBatch для вывода текстур
            spriteBatch = new SpriteBatch(GraphicsDevice);
            // Текстура змейки и её расположение по центру экрана
            Vector2 snakePosition = new Vector2(
                GraphicsDevice.Viewport.TitleSafeArea.X + GraphicsDevice.Viewport.TitleSafeArea.Width / 2, 
                GraphicsDevice.Viewport.TitleSafeArea.Y + GraphicsDevice.Viewport.TitleSafeArea.Height / 2);
            snake.Initialize(Content.Load("SnakeTile"), snakePosition);
            // Текстура еды и расположение её случайным образом на экране
            Vector2 foodPosition = RandPosition();
            food.Initialize(Content.Load("FoodTile"), foodPosition);
            // Шрифт
            segoe20 = this.Content.Load("Segoe20");
            // Счётчик очков в левом верхнем углу
            scorePosition = new Vector2(20, 20);
}


Game update

Update implements the logic for updating the game: collision checking, response to input and playback of audio. Here we update the position of the snake and check for its collision with food, if the game is running. All gestures are checked every time this method is called, regardless of whether the game is running or not.

protected override void Update(GameTime gameTime)
{
            // Возможность выйти из игры
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
                this.Exit();
            if (Mode == GameMode.Running)
            {
                snake.Update();
                CheckCollision();
            }
            CheckGestures();
            base.Update(gameTime);
}


Check for collisions

The position of the food and the "head" of the snake is calculated into the corresponding Rectangle objects. After that, we can use the built-in intersect method to determine the intersection of the rectangles. In this case, we increase the number of points and create a food sprite in a random new position if eating by the snake is determined (we also tell the snake that she needs to update herself and add a new cell). The game is considered over if the snake's head goes beyond the screen.

private void CheckCollision()
{
            // Использование встроенной функции для проверки пересечения
            int snakeHeadX = (int)snake.snakeTiles[0].Position.X;
            int snakeHeadY = (int)snake.snakeTiles[0].Position.Y;
            Rectangle rectangle1 = new Rectangle(snakeHeadX, snakeHeadY, snake.snakeTiles[0].Width,  snake.snakeTiles[0].Height);
            Rectangle rectangle2 = new Rectangle((int)food.Position.X, (int)food.Position.Y, food.Width, food.Height);
            // Змейка и её еда
            if (rectangle1.Intersects(rectangle2))
            {
                // Добавление очков
                score += FOOD_POINTS;
                // Меняем положение спрайта еды
                food.Position = RandPosition();
                // Новая ячейка для змейки
                snake.newTile = true;
            }
            // Змейка относительно границ экрана
            if (snakeHeadX < 0 || 
                snakeHeadY < 0 ||
                snakeHeadX + snake.snakeTiles[0].Width > GraphicsDevice.Viewport.Width ||
                snakeHeadY + snake.snakeTiles[0].Height > GraphicsDevice.Viewport.Height)
            {
                Mode = GameMode.Complete;
            }
}


The method below is used to move the food sprite to a new random position:

private Vector2 RandPosition()
{
            // Случайное положение для еды
            Random random = new Random();
            Vector2 position = new Vector2(
            GraphicsDevice.Viewport.TitleSafeArea.X + random.Next(GraphicsDevice.Viewport.TitleSafeArea.Width - 45) + 20,
            GraphicsDevice.Viewport.TitleSafeArea.Y + random.Next(GraphicsDevice.Viewport.TitleSafeArea.Height - 45) + 20);
            return position;
}


Gesture check

Gestures will be checked in the Update method each time. First, we check if new gestures are available, and, if available, read them. We also get the Delta value if a Flick type gesture has been defined. The snake will then be moved in the appropriate direction. The player cannot move the snake in the opposite direction (the game will be over). The game mode changes if the Tap gesture is detected (starts a new game from the menu or restarts the game).

private void CheckGestures()
{
            // Доступны ли жесты?
            while (TouchPanel.IsGestureAvailable)
            {
                // Считываем жест
                GestureSample gesture = TouchPanel.ReadGesture();
                // Flick или Tap? 
                switch (gesture.GestureType)
                {
                    case GestureType.Flick:
                        // В какую сторону двигали пальцем?
                        Single x = gesture.Delta.X, y = gesture.Delta.Y;
                        // По горизонтали или по вертикали?
                        if (Math.Abs(x) > Math.Abs(y))
                        {
                            // left or right
                            if (x < 0)
                            {
                                if (snake.direction == 3 && snake.snakeTiles.Count() > 1) Mode = GameMode.Complete;
                                else snake.direction = 1; // Налево
                            }
                            else
                            {
                                if (snake.direction == 1 && snake.snakeTiles.Count() > 1) Mode = GameMode.Complete;
                                else snake.direction = 3; // Направо
                            }
                        }
                        else
                        {
                            // Вверх или вниз?
                            if (y < 0)
                            {
                                if (snake.direction == 4 && snake.snakeTiles.Count() > 1) Mode = GameMode.Complete;
                                else snake.direction = 2; // Вверх
                            }
                            else
                            {
                                if (snake.direction == 2 && snake.snakeTiles.Count() > 1) Mode = GameMode.Complete;
                                else snake.direction = 4; // Вниз
                            }
                        }
                        break;
                    case GestureType.Tap:
                        // Режим меняется с Menu на Running
                        if (Mode == GameMode.Menu) 
                        {
                            Mode = GameMode.Running;
                        }
                        // Режим меняется с Complete на Running снова
                        else if (Mode == GameMode.Complete)
                        {
                            snake.Reset();
                            score = 0f;
                            Mode = GameMode.Running;
                        }
                        break;
                }
            }
}


Display game

The Draw method is called when the game draws itself. In this example, only the blue background is used. This method checks the game mode and draws the corresponding screen. The text “FreeSnake, Tap the Screen to Start” is displayed when the game first loads. The snake, the food for the snake and the number of points are displayed when the user plays the game. Information about the points scored and the offer to play again appears at the end of the game.

protected override void Draw(GameTime gameTime)
{
            GraphicsDevice.Clear(Color.CornflowerBlue);
            // Начинаем рисовать
            spriteBatch.Begin();
            if (Mode == GameMode.Menu)
            {
                string GameStart = "FreeSnake\nTap the Screen to Start";
                Vector2 stringSize = segoe20.MeasureString(GameStart);
                spriteBatch.DrawString(segoe20, 
                    GameStart, 
                    new Vector2((GraphicsDevice.Viewport.Width - stringSize.X) / 2, (GraphicsDevice.Viewport.Height - stringSize.Y) / 2), Color.White);
            }
            else if (Mode == GameMode.Running)
            {
                // Рисуем змейку
                snake.Draw(spriteBatch);
                // Рисуем еду
                food.Draw(spriteBatch);
                // Рисуем число очков
                spriteBatch.DrawString(segoe20, "Score:"+score, scorePosition, Color.White);
            }
            else if (Mode == GameMode.Complete)
            {
                snake.Draw(spriteBatch);
                string GameOver = "Game Over\nScore : " + score +"\nTap the Screen to Restart";
                Vector2 stringSize = segoe20.MeasureString(GameOver);
                spriteBatch.DrawString(segoe20,
                    GameOver,
                    new Vector2((GraphicsDevice.Viewport.Width - stringSize.X) / 2, (GraphicsDevice.Viewport.Height - stringSize.Y) / 2), Color.White);
            }
            // Прекращаем рисовать
            spriteBatch.End(); 
            base.Draw(gameTime);
}


Conclusion


In this example, we showed the basic information that is required to create gesture games for Windows Phone.

The source code of the resulting game can be found here .

And one more thing


We also remind you that by May 20 applications for the contest “ Best Applications Free Promotion ” are received from Nokia and Microsoft. Submit your applications and games for Windows Phone 7 to get a chance to win a Nokia Lumia 800 smartphone and free promotion of your application on Nokia and Microsoft platforms.

Also popular now: