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

Устройства ввода, перемещение объектов

Управление несколькими объектами: система классов

Пожалуй, первая мысль, которая придет в голову при разработке раздельного управления двумя объектами - создать второй игровой компонент, отличающийся от первого лишь реакцией на нажатия клавиш. Например, первый будет управляться с помощью клавиш-стрелок, второй – с помощью традиционного для игр набора клавиш ASWD. Грамотнее всего в такой ситуации будет создать игровой компонент, который не содержит клавиатурных команд, после чего создать еще два компонента, каждый из которых унаследует исходный компонент и переопределит его метод, ответственный за обработку событий клавиатуры.

Создадим новый проект (P3_5), аналогичный проекту P2_3 (лишь отключим вывод фона). Игровой spriteComp будет служить основой для двух других компонентов. Изменим его код так, как показано в листинге 7.8.

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 P3_5
{
    /// <summary>
    /// This is a game component that implements IUpdateable.
    /// </summary>
    public class spriteComp : Microsoft.Xna.Framework.DrawableGameComponent
    {
        protected  Texture2D sprTexture;
        protected  Rectangle sprRectangle;
        protected  Vector2 sprPosition;
        protected  Rectangle scrBounds;
        
        public spriteComp(Game game, ref Texture2D newTexture,
            Rectangle newRectangle, Vector2 newPosition)
            : base(game)
        {
            sprTexture = newTexture;
            sprRectangle = newRectangle;
            sprPosition = newPosition;
            scrBounds = new Rectangle(0, 0,
                game.Window.ClientBounds.Width,
                game.Window.ClientBounds.Height);
            // TODO: Construct any child components here
        }

        public override void Initialize()
        {
            // TODO: Add your initialization code here

            base.Initialize();
        }
        public virtual void Move()
        {
            Check();
        }
        void Check()
        {
            if (sprPosition.X < scrBounds.Left)
            {
                sprPosition.X = scrBounds.Left;
            }
            if (sprPosition.X > scrBounds.Width - sprRectangle.Width)
            {
                sprPosition.X = scrBounds.Width - sprRectangle.Width;
            }
            if (sprPosition.Y < scrBounds.Top)
            {
                sprPosition.Y = scrBounds.Top;
            }
            if (sprPosition.Y > scrBounds.Height - sprRectangle.Height)
            {
                sprPosition.Y = scrBounds.Height - sprRectangle.Height;
            }
        }
        public override void Update(GameTime gameTime)
        {
            // TODO: Add your update code here
            Move();
            base.Update(gameTime);
        }
        public override void Draw(GameTime gameTime)
        {
            SpriteBatch sprBatch =
                (SpriteBatch)Game.Services.GetService(typeof(SpriteBatch));
            sprBatch.Draw(sprTexture, sprPosition, sprRectangle, Color.White);
            base.Draw(gameTime);
        }
    }
}
Листинг 7.8. Базовый компонент spriteComp

Обратите внимание на то, что этот компонент практически в точности похож на компонент, код которого приведен в листинге 7.7. Ключевое различие – удаление из метода Update() кода, связанного с перемещением. Этого кода здесь вовсе нет. Зато мы добавили в Update() вызов нового виртуального метода Move(). Из названия метода можно судить о том, что его планируется использовать для управления перемещением объекта. Метод не случайно объявлен с ключевым словом virtual – в дочерних классах мы переопределим этот метод для решения задач каждого из них. В родительском классе мы добавили в него вызов метода Check(). Этот метод одинаков для обоих объектов – он не допускает пересечения ими границ экрана.

Добавим в проект новый игровой компонент, назовем его gameObj1.cs и соответствующим образом модифицируем. В листинге 7.9. вы можете видеть его код, ниже читайте пояснения.

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 P3_5
{
    public class gameObj1 : spriteComp 
    {
        public gameObj1(Game game, ref Texture2D newTexture,
            Rectangle newRectangle, Vector2 newPosition)
            : base(game, ref newTexture , newRectangle , newPosition )
        {
            // TODO: Construct any child components here
        }
        public override void Move()
        {
            KeyboardState kbState = Keyboard.GetState();
            if (kbState.IsKeyDown(Keys.Up))
            {
                sprPosition.Y -= 5;
            }
            if (kbState.IsKeyDown(Keys.Down))
            {
                sprPosition.Y += 5;
            }
            if (kbState.IsKeyDown(Keys.Left))
            {
                sprPosition.X -= 5;
            }
            if (kbState.IsKeyDown(Keys.Right))
            {
                sprPosition.X += 5;
            }
            
            base.Move();
        }

        public override void Initialize()
        {
            // TODO: Add your initialization code here

            base.Initialize();
        }

        public override void Update(GameTime gameTime)
        {
            // TODO: Add your update code here
            base.Update(gameTime);
        }
        public override void Draw(GameTime gameTime)
        {
            base.Draw(gameTime);
        }
    }
}
Листинг 7.9. Класс gameObj1 – наследник spriteComp

Так как добавленный в игру компонент был изначально унаследован от GameComponent – он не имел переопределенного метода Draw(). Добавим этот метод в компонент.

Теперь модифицируем конструктор класса. Все, что нужно сделать здесь – получить те же параметры, что и базовый класс и передать их его конструктору.

Далее – переопределим метод Move() – а именно – добавим в него команды обработки ввода с клавиатуры. Это уже знакомые вам команды, которые меняют положение объекта на 5 пикселей в зависимости от нажатой клавиши-стрелки.

Добавим в проект еще один игровой компонент, назовем его gameObj2.cs, проведем с ним те же манипуляции, которые провели с компонентом gameObj1.cs, а вот метод Move() переопределим по-другому. Напомню, что нам нужно, чтобы этим компонентом можно было управлять не с помощью клавиш-стрелок, а клавишами ASWD. В листинге 7.10. вы можете видеть код этого класса.

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 P3_5
{
    
    public class gameObj2 : spriteComp
    {
        public gameObj2(Game game, ref Texture2D newTexture,
            Rectangle newRectangle, Vector2 newPosition)
            : base(game, ref newTexture, newRectangle, newPosition)
        {
            // TODO: Construct any child components here
        }
        public override void Move()
        {
            KeyboardState kbState = Keyboard.GetState();
            if (kbState.IsKeyDown(Keys.W))
            {
                sprPosition.Y -= 5;
            }
            if (kbState.IsKeyDown(Keys.S ))
            {
                sprPosition.Y += 5;
            }
            if (kbState.IsKeyDown(Keys.A ))
            {
                sprPosition.X -= 5;
            }
            if (kbState.IsKeyDown(Keys.D))
            {
                sprPosition.X += 5;
            }

            base.Move();
        }

        public override void Initialize()
        {
            // TODO: Add your initialization code here

            base.Initialize();
        }

        public override void Update(GameTime gameTime)
        {
            // TODO: Add your update code here
            base.Update(gameTime);
        }
        public override void Draw(GameTime gameTime)
        {
            base.Draw(gameTime);
        }
    }
}
Листинг 7.10. Класс gameObj2 – наследник spriteComp

Как видите, единственное отличие этого кода от кода компонента gameObj1 – это проверка на нажатие других клавиш.

Alina Lasskaja
Alina Lasskaja

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

Дмитрий Кацман
Дмитрий Кацман
Израиль
Андрей Веденин
Андрей Веденин
Россия, Белгород