Спонсор: Microsoft
Опубликован: 10.04.2009 | Доступ: свободный | Студентов: 3247 / 243 | Оценка: 4.49 / 4.39 | Длительность: 17:21:00
Специальности: Программист
Самостоятельная работа 11:

Организация многоуровневых игр, конструктор уровней

Рассмотрим коды классов, которые используются в игре.

В листинге 15.1. приведен код класса Game1.

using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;

namespace P11_1
{
    
    public class Game1 : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;
        //Текстуры
        Texture2D txtBack, txtBrick1, txtBrick2, txtBat, txtBall;
        Texture2D txtBrBuild1, txtBrBuild2, txtBrBuild0;
        //Массивы для хранения данных об уровнях
        public byte[,] Layer1, Layer2, Layer3, UserLayer;
        //Прямоугольник для фона
        Rectangle recBack = new Rectangle(0, 0, 512, 640);
        //Прямоугольник для "блока"
        Rectangle recBrick = new Rectangle(0, 0, 64, 16);
        //Прямоугольник для "мяча"
        Rectangle recBall = new Rectangle(0, 0, 10, 10);
        //Прямоугольник для биты
        Rectangle recBat = new Rectangle(0, 0, 96, 16);
        //Номер текущего уровня
        //1 - первый
        //2 - второй
        //3 - третий
        //-1 - пользовательский
        int currentLayer;
        //Установлена в false, если программа находится в 
        //режиме игры, при установке в True включается
        //режим конструктора
        bool IsBuild;
        //Позиция указателя в режиме конструктора
        Vector2 PositionBuild;
        //Тип блока, который будет добавлен на игровое поле
        //при нажатии соответствующей клавиши в режиме 
        //конструктора
        byte typeOfBuildBlock;

        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
        }

        protected override void Initialize()
        {
            //Программа находится в игровом режиме
            IsBuild = false;
            //Позиция для указателя в режиме конструктора (0,0)
            PositionBuild = new Vector2(0, 0);
            //Тип блока по умолчанию в режиме конструктора - 1
            typeOfBuildBlock = 1;
            //пользовательский уровень по умолчанию пуст - ячейки
            //заполнены нулями
            UserLayer = new byte[40, 8]; 
            //Заполняем массивы для разных уровней
            //0 - пустая ячейка
            //1 - блок первого типа (уничтожимый)
            //2 - блок второго типа (неуничтожимый)
            Layer1 = new byte[40, 8]{
            {1,1,1,1,1,1,1,1},
            {0,1,0,1,0,1,0,1},
            {1,0,1,0,1,0,1,0},
            {0,1,0,1,0,1,0,1},
            {1,0,1,0,1,0,1,0},
            {0,1,0,1,0,1,0,1},
            {0,0,0,0,0,0,0,0},
            {2,0,0,2,0,0,2,0},
            {0,1,0,0,0,0,0,1},
            {0,0,1,0,0,0,1,0},
            {0,0,0,1,0,1,0,0},
            {0,0,0,0,1,0,0,0},
            {1,1,1,1,1,1,1,1},
            {0,0,0,0,0,0,0,0},
            {0,0,0,0,0,0,0,0},
            {0,0,0,0,0,0,0,0},
            {0,0,0,0,0,0,0,0},
            {0,0,0,0,0,0,0,0},
            {0,0,0,0,0,0,0,0},
            {0,0,0,0,0,0,0,0},
            {0,0,0,0,0,0,0,0},
            {0,0,0,0,0,0,0,0},
            {0,0,0,0,0,0,0,0},
            {0,0,0,0,0,0,0,0},
            {0,0,0,0,0,0,0,0},
            {0,0,0,0,0,0,0,0},
            {0,0,0,0,0,0,0,0},
            {0,0,0,0,0,0,0,0},
            {0,0,0,0,0,0,0,0},
            {0,0,0,0,0,0,0,0},
            {0,0,0,0,0,0,0,0},
            {0,0,0,0,0,0,0,0},
            {0,0,0,0,0,0,0,0},
            {0,0,0,0,0,0,0,0},
            {0,0,0,0,0,0,0,0},
            {0,0,0,0,0,0,0,0},
            {0,0,0,0,0,0,0,0},
            {0,0,0,0,0,0,0,0},
            {0,0,0,0,0,0,0,0},
            {0,0,0,0,0,0,0,0}
            };

            Layer2 = new byte[40, 8]{
            {0,0,0,0,0,0,0,0},
            {0,0,0,0,0,0,0,0},
            {0,0,0,0,0,0,0,0},
            {0,0,0,0,0,0,0,0},
            {0,0,0,0,0,0,0,0},
            {0,0,0,0,0,0,0,0},
            {0,0,0,0,0,0,0,0},
            {0,0,0,0,0,0,0,0},
            {0,0,0,0,0,0,0,0},
            {0,0,0,0,0,0,0,0},
            {0,0,0,0,0,0,0,0},
            {0,0,0,0,0,0,0,0},
            {0,0,0,0,0,0,0,0},
            {0,0,0,0,0,0,0,0},
            {0,0,0,1,2,1,0,0},
            {0,0,0,0,0,0,0,0},
            {0,0,0,0,0,0,0,0},
            {0,0,0,0,0,0,0,0},
            {0,0,0,0,0,0,0,0},
            {0,0,0,0,0,0,0,0},
            {0,0,0,0,0,0,0,0},
            {0,0,0,0,0,0,0,0},
            {0,0,0,0,0,0,0,0},
            {0,0,0,0,0,0,0,0},
            {0,0,0,0,0,0,0,0},
            {0,0,0,0,0,0,0,0},
            {0,0,0,0,0,0,0,0},
            {0,0,0,0,0,0,0,0},
            {0,0,0,0,0,0,0,0},
            {0,0,0,0,0,0,0,0},
            {0,0,0,0,0,0,0,0},
            {0,0,0,0,0,0,0,0},
            {0,0,0,0,0,0,0,0},
            {0,0,0,0,0,0,0,0},
            {0,0,0,0,0,0,0,0},
            {0,0,0,0,0,0,0,0},
            {0,0,0,0,0,0,0,0},
            {0,0,0,0,0,0,0,0},
            {0,0,0,0,0,0,0,0},
            {0,0,0,0,0,0,0,0}
            };

            Layer3 = new byte[40, 8]{
            {0,0,0,0,0,0,0,0},
            {0,0,0,0,0,0,0,0},
            {0,0,0,0,0,0,0,0},
            {0,0,0,0,0,0,0,0},
            {0,0,0,0,0,0,0,0},
            {0,0,0,0,0,0,0,0},
            {0,0,0,0,0,0,0,0},
            {0,0,0,0,0,0,0,0},
            {0,1,0,0,0,0,0,0},
            {0,0,0,0,0,0,0,0},
            {0,0,0,1,0,1,0,0},
            {0,0,0,0,0,0,0,0},
            {0,0,0,0,0,0,0,0},
            {0,0,0,0,0,0,0,0},
            {0,2,0,1,0,2,0,0},
            {0,0,0,0,0,0,0,0},
            {0,0,0,0,0,0,0,0},
            {0,0,0,0,0,0,0,0},
            {0,0,0,0,0,0,0,0},
            {0,0,0,0,0,0,0,0},
            {0,0,0,0,0,0,0,0},
            {0,0,0,0,0,0,0,0},
            {0,0,0,0,0,0,0,0},
            {0,0,1,0,0,0,1,0},
            {0,0,0,0,0,0,0,0},
            {0,0,0,0,0,0,0,0},
            {0,0,0,0,0,0,0,0},
            {0,0,0,0,0,0,0,0},
            {0,0,0,0,0,0,0,0},
            {0,0,0,0,0,0,0,0},
            {0,0,0,0,0,0,0,0},
            {0,0,0,0,0,0,0,0},
            {0,0,0,0,0,0,0,0},
            {0,0,0,0,0,0,0,0},
            {0,0,0,0,0,0,0,0},
            {0,0,0,0,0,0,0,0},
            {0,0,0,0,0,0,0,0},
            {0,0,0,0,0,0,0,0},
            {0,0,0,0,0,0,0,0},
            {0,0,0,0,0,0,0,0}
            };

            //Текущий уровень - 1
            currentLayer = 1;
            //Устанавливаем разрешение игрового окна
            //640х512
            graphics.PreferredBackBufferWidth = 512;
            graphics.PreferredBackBufferHeight = 640;
            graphics.ApplyChanges();
            base.Initialize();
        }

        /// <summary>
        /// LoadContent will be called once per game and is the place to load
        /// all of your content.
        /// </summary>
        protected override void LoadContent()
        {
            // Загружаем ресурсы
            spriteBatch = new SpriteBatch(GraphicsDevice);
            Services.AddService(typeof(SpriteBatch), spriteBatch);
            txtBack = Content.Load<Texture2D>("Back");
            txtBrick1 = Content.Load<Texture2D>("Brick1");
            txtBrick2 = Content.Load<Texture2D>("Brick2");
            txtBall = Content.Load<Texture2D>("Ball");
            txtBat = Content.Load<Texture2D>("Bat");
            txtBrBuild0 = Content.Load<Texture2D>("BrickBuild0");
            txtBrBuild1 = Content.Load<Texture2D>("BrickBuild1");
            txtBrBuild2 = Content.Load<Texture2D>("BrickBuild2");
            //Создаем уровень
            AddSprites(Layer1);
            //Добавляем биту и мяч
            addBallAndBAts();

        }
        //Процедура создания уровня
        //расставляет элементы в соответствии с
        //массивом
        void AddSprites(byte [,] RenderLayer)
        {
            //Просматриваем массив
            for (int i = 0; i < 40; i++)
            {
                for (int j = 0; j < 8; j++)
                {
                    if (RenderLayer[i, j] == 1)
                        Components.Add(new Brick1(this, ref txtBrick1, new Vector2(j, i), recBrick, 64, 16));
                    if (RenderLayer[i, j] == 2)
                        Components.Add(new Brick2(this, ref txtBrick2, new Vector2(j, i), recBrick, 64, 16));
                }
            }
        }
        //Процедура для установки биты и мяча
        void addBallAndBAts()
        {
            Components.Add(new Ball(this, ref txtBall, new Vector2(300, 550), recBall, 1, 1));
            Components.Add(new Bat(this, ref txtBat, new Vector2(300, (640 - 16)), recBat, 1, 1));
        }

        protected override void UnloadContent()
        {
            // TODO: Unload any non ContentManager content here
        }

        protected override void Update(GameTime gameTime)
        {
            //получим состояние клавиатуры
            KeyboardState kb = Keyboard.GetState();
            //если IsBuild = false и нажата клавиша A
            //переходим в режим конструктора уровней
            if (kb.IsKeyDown (Keys .A)&!IsBuild)
            {
                IsBuild = true;
                builder();
            }
            //Если находимся в режиме конструктора уровней
            if (IsBuild)
            {
                //При нажатой клавише "вверх" уменьшить текущую позицию Y
                //указателя на 1 если позиция больше 0
                if (kb.IsKeyDown(Keys.Up))
                {
                    if (PositionBuild.Y > 0) PositionBuild.Y--;
                }
                //При нажатой клавише "вниз" увеличить позицию
                //Y если она меньше 39
                if (kb.IsKeyDown(Keys.Down))
                {
                    if (PositionBuild.Y < 39) PositionBuild.Y++;
                }
                //При нажатой клавише "влево"
                //уменьшить позицию X если текущая позиция
                //больше 0
                if (kb.IsKeyDown(Keys.Left))
                {
                    if (PositionBuild.X >0) PositionBuild.X--;
                }
                //При нажатой клавише "вправо"
                //увеличить позицию X если текущая позиция
                //меньше 7
                if (kb.IsKeyDown(Keys.Right))
                {
                    if (PositionBuild.X < 7) PositionBuild.X++;
                }
                //Нажатие клавиши Z устанавливает тип блока в 0
                //этот блок предназначен для "стирания"
                //других блоков, то есть - для установки элемента 
                //массива, соответствующего текущему состоянию 
                //конструируемого уровня, в 0
                if (kb.IsKeyDown(Keys.Z))
                {
                    typeOfBuildBlock = 0;
                }
                //При нажатии клавиши X установим 1-й тип блока
                if (kb.IsKeyDown(Keys.X))
                {
                    typeOfBuildBlock = 1;
                }
                //При нажатии клавиши С установим 2-й тип блока
                if (kb.IsKeyDown(Keys.C))
                {
                    typeOfBuildBlock = 2;
                }
                //При нажатии клавиши W запишем в 
                //ячейку массива, соответствующую позиции указателя
                //текущий тип блока
                                if (kb.IsKeyDown (Keys .W ))
                {
                     UserLayer[(int)PositionBuild.Y, (int)PositionBuild.X] = typeOfBuildBlock; 
                }
                    //очищаем массив компонентов
                    Components.Clear();
                //выводим пользовательский уровень
                    AddSprites(UserLayer);
                //уничтожаем указатель и изменяем его в соответствии с типом выбранного блока
                    BrickBuilder br = null;
                    if (typeOfBuildBlock == 1)
                        br = new BrickBuilder(this, ref txtBrBuild1, PositionBuild, recBrick, 64, 16);
                    if (typeOfBuildBlock == 2)
                        br = new BrickBuilder(this, ref txtBrBuild2, PositionBuild, recBrick, 64, 16);
                    if (typeOfBuildBlock == 0)
                        br = new BrickBuilder(this, ref txtBrBuild0, PositionBuild, recBrick, 64, 16);
                    Components.Add(br);
                    //При нажатии клавиши W
                    //отключаем режим конструктора
                    //выводим пользовательский уровень
                    //и начинаем игру
                    if (kb.IsKeyDown(Keys.E))
                    {
                        IsBuild = false;
                        Components.Clear();
                        AddSprites(UserLayer);
                        addBallAndBAts();
                        currentLayer = -1;
                    }
            }
            //Если находимся в режиме игры
            //проверим - завершен ли текущий уровень
            //признак завершения уровня

            if (!IsBuild)
            {
                IsLayerCompleted();
            }
            base.Update(gameTime);
        }
        //Процедура старта конструктора уровней
        //очищаем набор компонентов
        //Создаем и выводим указатель
        public void builder()
        {
            Components.Clear();
            BrickBuilder br = new BrickBuilder (this, ref txtBrBuild1,PositionBuild, recBrick, 64, 16);
            Components.Add(br);
        }

        //Процедура проверки на завершенность
        //текущего уровня
        //Если на поле отсутствует мяч - игра начинается сначала
        //если на поле нет ни одного блока типа Brick1 - 
        //переход на следующий уровень или переход на первый уровень
        //с выводом надписи "Вы выиграли"

        public void IsLayerCompleted()
        {
            //Предположим, что на поле нет ни одного блока
            //типа Brick1
            bool f = false;
            //Предположим, что на поле нет мяча
            bool Ball = false;
            foreach (gBaseClass spr in this.Components)
            {
                //Если найден хотя бы один блок типа 1
                //установим F в True
                if (spr.GetType() == (typeof(Brick1)))
                {
                    f = true;
                }
                //Если найден мяч - установим Ball в True
                if (spr.GetType() == (typeof(Ball)))
                {
                    Ball = true;
                }
            }
            //Если мяч не обнаружен
            //игра начинается сначала
            if (!Ball)
            {
                Components.Clear();
                currentLayer = 1;
                AddSprites(Layer1);
                addBallAndBAts();
             }
                //иначе
            else
            {
                //Если не было найдено ни одного блока
                //типа Brick1
                if (!f)
                {
                    //Очистим набор компонентов
                    Components.Clear();
                    //Увеличим номер уровня
                    currentLayer++;
                    //в зависимости от номера
                    //запустим соответствующий уровень
                    if (currentLayer == 2)
                    {
                        AddSprites(Layer2);
                        addBallAndBAts();
                    }
                    if (currentLayer == 3)
                    {
                        AddSprites(Layer3);
                        addBallAndBAts();
                    }
                    //4 - если был пройден 3-й уровень
                    //0 - при прохождении пользовательского уровня
                    if (currentLayer == 4 | currentLayer == 0)
                    {
                        currentLayer = 1;
                        AddSprites(Layer1);
                        addBallAndBAts();
                        this.Window.Title = "Вы выиграли!";
                    }
                }
            }
        }

        protected override void Draw(GameTime gameTime)
        {
            spriteBatch.Begin();
            //выведем фоновое изображение
            spriteBatch.Draw(txtBack, recBack, Color.White);
            //Выведем игровые объекты
            base.Draw(gameTime);
            spriteBatch.End();
        }
    }
}
Листинг 15.1. Код класса Game1

В листинге 15.2. приведен код класса gBaseClass.

using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Storage;
using Microsoft.Xna.Framework.Content;

namespace P11_1
{
    public class gBaseClass : Microsoft.Xna.Framework.DrawableGameComponent
    {
        Texture2D sprTexture;
        public Vector2 sprPosition;
        public Rectangle sprRectangle;
        public gBaseClass(Game game, ref Texture2D _sprTexture,
            Vector2 _sprPosition, Rectangle _sprRectangle, int X_Coord, int Y_Coord)
            : base(game)
        {
            sprTexture = _sprTexture;
            //Здесь производится перевод индекса элемента массива
            //в координаты на игровом экране
            //Так как спрайты имеют различные размеры, для их размещения на экране
            //используются коэффициенты X_Coord и Y_Coord
            sprPosition.X = _sprPosition.X * X_Coord;
            sprPosition.Y = _sprPosition.Y * Y_Coord;
            sprRectangle = _sprRectangle;
        }
        public override void Draw(GameTime gameTime)
        {
            SpriteBatch sprBatch =
                (SpriteBatch)Game.Services.GetService(typeof(SpriteBatch));
            sprBatch.Draw(sprTexture, sprPosition, Color.White);
            base.Draw(gameTime);
        }
    }
}
Листинг 15.2. Код класса gBaseClass

В листинге 15.3. приведен код класса Bat. Он занимается обработкой перемещений биты по горизонтали и контролем за пересечением битой левой и правой границ экрана.

using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Storage;
using Microsoft.Xna.Framework.Content;

namespace P11_1
{
    public class Bat : gBaseClass
    {
        Rectangle scrBounds;
        //True для движения биты влево и False - вправо
        public bool direction;

        public Bat(Game game, ref Texture2D _sprTexture,
            Vector2 _sprPosition, Rectangle _sprRectangle, int x_c, int y_c)
            : base(game, ref _sprTexture, _sprPosition, _sprRectangle, x_c, y_c)
        {
            scrBounds = new Rectangle(0, 0,
              game.Window.ClientBounds.Width,
              game.Window.ClientBounds.Height);
            direction = true;
        }

        public override void Update(GameTime gameTime)
        {
            //Нажатия клавиш-стрелок влево и вправо
            //вызывают перемещение объекта в соответствующем
            //направлении
            KeyboardState kb = Keyboard.GetState();
            if (kb.IsKeyDown(Keys.Left))
            {
                sprPosition.X -= 2;
                direction = true;
            }
            if (kb.IsKeyDown(Keys.Right))
            {
                sprPosition.X += 2;
                direction = false;
            }
            //проверка на столкновение с границами экрана
            Check();

            base.Update(gameTime);
        }
        //Процедура проверки столкновения с левой
        //и правой границами экрана
        void Check()
        {
            if (sprPosition.X < scrBounds.Left)
            {
                sprPosition.X = scrBounds.Left;
               
            }
            if (sprPosition.X > scrBounds.Width - sprRectangle.Width)
            {
                sprPosition.X = scrBounds.Width - sprRectangle.Width;
                
            }
        }
    }
}
Листинг 15.3. Код класса Bat
Alina Lasskaja
Alina Lasskaja

Быть может кто-то из Вас знает игру Sims, к какому жанру она относиться? Жизненная симуляция, ролевая игра, там можно и дома строить.....