Опубликован: 14.08.2012 | Уровень: специалист | Доступ: платный
Самостоятельная работа 20:

Анимация, эффекты

Аннотация: В этой лабораторной работе мы поговорим о применении графических эффектов в играх и об анимации персонажей.

Цель работы: Научиться применять графические эффекты и приемы анимации при работе с трехмерной графикой в XNA

27.1. Анимация персонажей

Компьютерные игры наполнены анимированными персонажами. XNA содержит встроенные средства, поддерживающие базовые операции по анимации трехмерных персонажей. В частности, это средства для работы с так называемым скелетом персонажа. Скелет состоит из взаимосвязанных костей, управляя которыми можно анимировать модель. Создание анимированных моделей – это отдельная, достаточно трудоемкая задача, которая требует серьезных познаний в области 3D-моделирования. Для подготовки анимированных трехмерных моделей вы можете использовать практически любой 3D-редактор.

XNA содержит лишь базовые средства для управления скелетами объектов. Так, мы можем получить коллекцию костей объекта и проводить с ними какие-либо преобразования, вызывающие движение модели. Однако, такой подход ограничен – с его использованием весьма сложно создать реалистичное движение для сложных моделей. На основе базовых средств XNA разработаны библиотеки кода, которые содержат компоненты, позволяющие анимировать персонажи на более высоком уровне. В частности, одну из таких библиотек – XNAAnimation – можно найти на сайте http://www.codeplex.com/xnanimation.

Здесь мы рассмотрим базовый подход к анимации модели. Он заключается в следующем. Можно менять параметры отдельных костей модели и выводить ее на экран с учетом этих изменений. Мы использовали бесплатную модель Ballpen.fbx, взятую с сайта http://www.turbosquid.com.

Создадим новый проект P18_1. Загрузим в него модель Ballpen.fbx.

Код проекта сосредоточен в классе Game1.cs, его код вы можете найти в листинге 27.1.

using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Input.Touch;

namespace P20_1
{
    /// <summary>
    /// Это главный тип игры
    /// </summary>
    public class Game1 : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        //Матрицы
        Matrix viewMatrix;
        Matrix projMatrix;
        //Модель
        Model pen;

        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
            graphics.IsFullScreen = true;
            // Частота кадра на Windows Phone по умолчанию — 30 кадров в секунду.
            TargetElapsedTime = TimeSpan.FromTicks(333333);

            // Дополнительный заряд аккумулятора заблокирован.
            InactiveSleepTime = TimeSpan.FromSeconds(1);
        }

        /// <summary>
        /// Позволяет игре выполнить инициализацию, необходимую перед запуском.
        /// Здесь можно запросить нужные службы и загрузить неграфический
        /// контент.  Вызов base.Initialize приведет к перебору всех компонентов и
        /// их инициализации.
        /// </summary>
        protected override void Initialize()
        {
            // ЗАДАЧА: добавьте здесь логику инициализации

            base.Initialize();
        }

        /// <summary>
        /// LoadContent будет вызываться в игре один раз; здесь загружается
        /// весь контент.
        /// </summary>
        protected override void LoadContent()
        {
            //Загрузка модели
            pen = Content.Load<Model>("ballpen");
            //Соотношение сторон
            float aspectRatio = (float)graphics.GraphicsDevice.Viewport.Width /
               (float)graphics.GraphicsDevice.Viewport.Height;
            //Устанавливаем камеру
            viewMatrix = Matrix.CreateLookAt(new Vector3(0, 30, 80), new Vector3(-32, 0, 0), new Vector3(0, 1, 0));
            //Устанавливаем проекционную матрицу
            projMatrix = Matrix.CreatePerspectiveFieldOfView(MathHelper.ToRadians(45.0f), aspectRatio, 1.0f, 1000.0f);
        }

        /// <summary>
        /// UnloadContent будет вызываться в игре один раз; здесь выгружается
        /// весь контент.
        /// </summary>
        protected override void UnloadContent()
        {
            // ЗАДАЧА: выгрузите здесь весь контент, не относящийся к ContentManager
        }

        /// <summary>
        /// Позволяет игре запускать логику обновления мира,
        /// проверки столкновений, получения ввода и воспроизведения звуков.
        /// </summary>
        /// <param name="gameTime">Предоставляет моментальный снимок значений времени.</param>
        protected override void Update(GameTime gameTime)
        {
            // Позволяет выйти из игры
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
                this.Exit();
            //Перемещение частей ручки
            PenMove();
            base.Update(gameTime);
        }
        void PenMove()
        {
            //Поворот зажима - он представлен родительской костью сети №3
            //Умножим его матрицу трансформации на матрицу поворота по оси X
            pen.Meshes[3].ParentBone.Transform = pen.Meshes[3].ParentBone.Transform * 
                   Matrix.CreateRotationX(MathHelper.ToRadians(-1.0f));

            TouchCollection touchLocations = TouchPanel.GetState();
            foreach (TouchLocation touchLocation in touchLocations)
            {
                //Кнопка ручки перемещается при прикосновении к экрану
                if (touchLocation.State == TouchLocationState.Pressed)
                {
                    //При прикосновении к левой части экрана
                    //выходит из ручки
                    if (touchLocation.Position.X < 400)
                    {
                        //Умножим матрицу трансформации родительской костью сети №1
                        //На матрицу трансляции, перемещающей ее на 2 позиции влево по оси Х
                        pen.Meshes[1].ParentBone.Transform = pen.Meshes[1].ParentBone.Transform * 
                                Matrix.CreateTranslation(new Vector3(-20, 0, 0));
                    }
                    //При прикосновении к правой части экрана - входит в ручку
                    else
                    {
                        //Умножим матрицу трансформации родительской кости сети №1
                        //На матрицу трансляции, перемещающую ее на 2 позиции по оси X вправо
                        pen.Meshes[1].ParentBone.Transform = pen.Meshes[1].ParentBone.Transform * 
                              Matrix.CreateTranslation(new Vector3(20, 0, 0));
                    }
                }
            }

        }

        /// <summary>
        /// Вызывается, когда игра отрисовывается.
        /// </summary>
        /// <param name="gameTime">Предоставляет моментальный снимок значений времени.</param>
        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.CornflowerBlue);

            //Новый массив матриц размером, соответствующим количеству
            //костей в скелете модели
            Matrix[] absoluteTransformations = new Matrix[pen.Bones.Count];
            //Скопировать матрицы трансформации костей в массив матриц
            pen.CopyAbsoluteBoneTransformsTo(absoluteTransformations);

            foreach (ModelMesh mesh in pen.Meshes)
            {
                foreach (BasicEffect effect in mesh.Effects)
                {
                    effect.LightingEnabled = true;
                    effect.EnableDefaultLighting();
                    effect.Projection = projMatrix;
                    effect.View = viewMatrix;
                    //Установим новую мировую матрицу для родительской кости текущей сети
                    //это приводит к перемещению кнопки и к перемещению зажима
                    //Так же здесь мы уменьшаем модель, применяя коэффициент масштабирования 0,15
                    effect.World = absoluteTransformations[mesh.ParentBone.Index] * Matrix.CreateScale(0.15f);
                }
                //Выводим подготовленную сеть
                mesh.Draw();
            }

            base.Draw(gameTime);
        }
    }
}
Листинг 27.1. Код класса Game1

На рис. 27.1 вы можете видеть игровой экран проекта.

Игровой экран проекта

Рис. 27.1. Игровой экран проекта
Гулич Анна
Гулич Анна
Невозможно пройти тесты, в окне с вопросами пусто
Сашечка Огнев
Сашечка Огнев
Россия, Красноярский край
Андрей Корягин
Андрей Корягин
Россия, Пенза, Вазерская средняя школа, 2001