netlib.narod.ru< Назад | Оглавление | Далее >

Начинаем

Теперь у вас установлены и настроены все необходимые утилиты, так что пришло время запачкать руки кодированием. В данном разделе вы создадите простой проект с помощью шаблонов XNA Studio. Затем вы слегка измените код и добавите функциональность в методы Update и Draw. В следующей главе вы создадите свою первую игру и узнаете о классе SpriteBatch.

Ваш первый проект

Создайте новый проект XNA, выбрав команду New Project в меню File. В качестве типа проекта выберите Windows Game и введите имя вашего первого проекта, например, Hello World, либо оставьте предлагаемое по умолчанию имя WindowsGame1 (рис. 1.10). Как видите, здесь также можно быстро создать игру на основании набора для начинающих.


Рис. 1.10

Рис. 1.10


Новый проект состоит из двух исходных файлов: Game1.cs и Program.cs. Файл Program содержит следующие строки кода:

using (Game1 game = new Game1())
{
    game.Run();
} // using

Класс Game1 содержит методы Initialize, Update и Draw, о которых я упоминал ранее. Метод Initialize ничего не делает, а метод Update просто проверяет, нажата ли кнопка Back на первом подключенном игровом пульте.

Сейчас нас интересует только метод Draw, в котором выполняется только одна строка кода, окрашивающая фон в указанный цвет:

graphics.GraphicsDevice.Clear(Color.CornflowerBlue);

F5 и вперед

Если нажать F5, проект будет запущен (это то же самое, что выбрать команду Start Debugging в меню Debug), и вы увидите окно, фон которого окрашен в васильковый цвет, указанный в методе Draw (рис. 1.11).


Рис. 1.11

Рис. 1.11


Если чувствуете, что пора сделать что-нибудь, измените Color на Color.Green и нажмите F5 снова. Теперь у окна зеленый фон. У метода Clear графического устройства есть другие перегрузки, которые могут использоваться для очиски буфера глубины и буфера трафарета, которая в случае задания цвета выполняется автоматически. Например, позднее в этой книге нам потребуется очистить буфер глубины, не меняя цветов фона. Для этого просто используйте следующую строку кода:

graphics.GraphicsDevice.Clear(ClearOptions.DepthBuffer,
                              Color.Green, 1, 0);

По умолчанию параметру ClearOptions присваивается значение ClearOptions.Target | ClearOptions.DepthBuffer, означающее, что будут очищены фон окна и буфер глубины. Между прочим, если вы еще не знаете, что значит | между параметрами ClearOptions, то этот оператор используется для объединения нескольких параметров.

Изменяем код

Вместо того, чтобы остановиться на достигнутом, давайте подумаем какие полезные улучшения можно внести в код. Скорее всего, вы хотите, чтобы работу программы можно было завершать нажав клавишу Escape. По умолчанию XNA добавляет в метод Update следующие строки кода, обеспечивающие выход при нажатии кнопки Back на игровом пульте Xbox:

// Выход по умолчанию для Xbox 360 и Windows
if (GamePad.GetState(PlayerIndex.One).Buttons.Back ==
         ButtonState.Pressed)
    this.Exit();

С классом Input мы ближе познакомимся в главе 3, «Вспомогательные классы». Пока вы будете использовать быстрый и грязный способ получения доступа к клавиатуре. Если модифицировать код показанным ниже образом, выход из приложения будет происходить также и при нажатии клавиши Escape:

// Получаем текущее состояние клавиатуры и пульта
GamePadState  gamePad  = GamePad.GetState(PlayerIndex.One);
KeyboardState keyboard = Keyboard.GetState();
// Back или Escape - выход из игры на Xbox 360 и Windows
if (gamePad.Buttons.Back == ButtonState.Pressed ||
             keyboard.IsKeyDown(Keys.Escape))
    this.Exit();

Как видите, состояния игрового пульта и клавиатуры помещаются в отдельные переменные для упрощения доступа. Если вы снова нажмете F5, то теперь завершить работу приложения можно будет нажатием клавиши Escape.

Давайте двинемся еще дальше, и загрузим в нашу игру графику. Более подробно спрайты будут обсуждаться в главе 2. Идея состоит в том, чтобы отобразить небольшую фоновую текстуру и замостить ею весь экран. Затем добавим простые возможности управления с клавиатуры и игрового пульта, чтобы фон перемещался как в гоночных играх с видом сверху и блочных движках, которые часто используются в двухмерных ролевых играх. Для более сложных блочных движков вам может потребоваться больше текстур, таких как камни, трава, вода и земля, и, кроме того, могут понадобиться переходные текстуры, которые вы будете располагать, например, между травой и водой. Для этого потребуется немного больше текстур и свой код, но это не должно вызвать особых трудностей. Если вы действительно интересуетесь блочными движками, то без труда найдете необходимую информацию по этой теме в Интернете.

Для первого несложного проекта мы просто добавим текстуру, изображенную на рис. 1.12.


Рис. 1.12

Рис. 1.12


Для загрузки данной текстуры (CityGroundSmall.jpg) в вашу игру просто перетащите ее в окно Solution Explorer вашего проекта. Затем щелкните по имени файла в списке компонентов проекта и выберите Properties. Вы должны увидеть окно, показанное на рис. 1.13.


Рис. 1.13

Рис. 1.13


Обычно вы видите параметры построения и ряд параметров для копирования файла содержимого в выходной каталог (это если вы включаете файл .dll или .xml). Но если XNA Studio обнаружит один из поддерживаемых форматов файлов содержимого, вы увидите дополнительные параметры XNA. Наиболее важные из них — Asset Name, Content Importer и Content Processor. Asset Name используется позже при загрузке содержимого; у каждого файла содержимого должно быть собственное уникальное значение Asset Name. Для Content Importer вы в данном случае выбираете Texture, но также возможны варианты Model Importer для файлов .x и Effect Importer для файлов .fx.

У параметра Content Processor может быть много различных значений; например, для текстуры сейчас вы можете выбрать DXT, DXT mip-mapped или Sprite 32bpp. DXT — это формат со сжатием, используемый также в файлах .dds и хорошо приспособленный для игровых текстур, поскольку обеспечивает сжатие с коэффициентом 1:6 (или 1:4, если в текстуре есть прозрачные пиксели). Это означает, что в том же объеме пространства жесткого диска и видеопамяти вы сможете хранить в шесть раз больше текстур. Для двухмерных спрайтов обычно лучше не использовать сжатие, чтобы видеть их в полном размере и использование 32-разрядного формата обеспечит наилучшее качество. Мы подробнее поговорим о конвейере содержимого позже в этой главе.

Если вы нажмете F5 или построите проект (F6), содержимое будет обработано и в выходном каталоге появится новый файл CityGroundSmall.xnb. В окне с результатами построения появится следующая строка:

Building CityGroundSmall.jpg -> bin\x86\Debug\CityGroundSmall.xnb

Финальная вещь, котороую нам надо выполнить — загрузка импортированной текстуры. Можно сделать это в методе Initialize и использовать новую переменную вашего класса backgroundTexture. Для загрузки текстуры вы используете имя компонента (asset name), назначенное ранее (в действительности оно генерируется автоматически на основании имени файла, перетащенного в ваш проект). Для визуализации текстуры на экране вам потребуется класс SpriteBatch, обсуждающийся в следующей главе. Обычно вы устанавливаете режим альфа-смешивания, помещаете текстуры в спрайты и отображаете все на экране.

Texture2D   backgroundTexture;
SpriteBatch sprites;

protected override void Initialize()
{
    backgroundTexture = content.Load<Texture2D>("CityGroundSmall");
    sprites = new SpriteBatch(graphics.GraphicsDevice);
    base.Initialize();
} // Initialize()

Чтобы отобразить фоновую текстуру вы начинаете обработку спрайтов и визуализируете текстуру спрайта в методе Draw:

protected override void Draw(GameTime gameTime)
{
    graphics.GraphicsDevice.Clear(Color.Green);

    sprites.Begin();
    sprites.Draw(backgroundTexture, Vector2.Zero, Color.White);
    sprites.End();
    base.Draw(gameTime);
} // Draw(gameTime)

Визуализация фоновой текстуры происходит в точке (0, 0) поверх зеленого фона. Параметры цвета позволяют перекрашивать спрайты, но сейчас это неважно.

Если вы сейчас нажмете F5, то увидите результат, показанный на рис. 1.14.


Рис. 1.14

Рис. 1.14


Финальная вещь, которую мы добавим к первому проекту, — возможность прокрутки фона с помощью клавиш управления курсором или игрового пульта, и визуализация состоящего из блоков полноразмерного прокручиваемого фона. Для получения данных от игрового пульта и клавиатуры мы немного модифицируем метод Update:

float scrollPosition = 0;

protected override void Update(GameTime gameTime)
{
    // Получаем текущее состояние пульта и клавиатуры
    GamePadState gamePad = GamePad.GetState(PlayerIndex.One);
    KeyboardState keyboard = Keyboard.GetState();

    // Back или Escape - выход из игры на Xbox 360 и Windows
    if (gamePad.Buttons.Back == ButtonState.Pressed ||
                             keyboard.IsKeyDown(Keys.Escape))
        this.Exit();

    // Перемещаемся на 400 пикселей в секунду
    float moveFactorPerSecond = 400 *
    (float)gameTime.ElapsedRealTime.TotalMilliseconds / 1000.0f;

    // Перемешаемся вверх или вниз, если нажаты соответствующие
    // клавиши управления курсором или кнопки пульта
    if (gamePad.DPad.Up == ButtonState.Pressed ||
                           keyboard.IsKeyDown(Keys.Up))
        scrollPosition += moveFactorPerSecond;
    if (gamePad.DPad.Down == ButtonState.Pressed ||
                         keyboard.IsKeyDown(Keys.Down))
        scrollPosition -= moveFactorPerSecond;
    base.Update(gameTime);
} // Update(gameTime)

Первые строки остались неизменными. Затем вы вычисляете, на сколько пикселей надо переместить изображение в данном кадре. Если кадр формируется 1 секунду, movefactorPerSecond будет равно 400; для 60 кадров в секунду значение будет 400/60. Поскольку здесь используются числа с плавающей запятой, а не целые, частота кадров может достигать нескольких тысяч, и движение вверх или вниз при нажатии клавиш все равно будет осуществляться со скоростью 400 пикселей в секунду.

Если пользователь нажимает клавиши перемещения вверх или вниз, меняется значение переменной scrollPosition. Потом, в методе рисования, вы визуализируете каждый блок фона и прибавляете scrollPosition к его координате Y для перемещения фона вверх и вниз.

protected override void Draw(GameTime gameTime)
{
    graphics.GraphicsDevice.Clear(Color.Green);

    sprites.Begin();

    int resolutionWidth = graphics.GraphicsDevice.Viewport.Width;
    int resolutionHeight = graphics.GraphicsDevice.Viewport.Height;

    for (int x = 0; x <= resolutionWidth / backgroundTexture.Width; x++)
        for (int y = -1; y <= resolutionHeight / backgroundTexture.Height; y++)
        {
            Vector2 position = new Vector2(
                             x * backgroundTexture.Width,
                             y * backgroundTexture.Height +
                             ((int)scrollPosition) % backgroundTexture.Height);
            sprites.Draw(backgroundTexture, position, Color.White);
        } // for for
    sprites.End();
    base.Draw(gameTime);
} // Draw(gameTime)

Теперь можете запустить ваш проект и перемещаться вверх и вниз. Совсем неплохо для первого небольшого приложения, не так ли?


netlib.narod.ru< Назад | Оглавление | Далее >

Сайт управляется системой uCoz