Возможно вы искали: 'Rise 2: Resurrection'

May 31 2025 02:15:24
  • Как сделать 8Gamers.Ru домашней страницей?
  • Игры
    • База данных по играх
    • Игровые новости
    • Игровая индустрия
    • Обзоры на игры
    • Прохождения игр
    • Гайды к играм
    • Превью о играх
    • Игровые тизеры
    • Игровые арты
    • Игровые обои
    • Игровые скриншоты
    • Игровые обложки
    • Игровые трейлеры
    • Игровое видео
    • Вышедшие игры
    • Ближайшие релизы игр
  • Кино и ТВ
    • База данных по кино
    • Статьи о кино
    • Постеры
    • Кадры из кино
    • Кино трейлеры
    • Сегодня в кино
    • Скоро в кино
  • Комиксы и манга
    • Манга по алфавиту
    • База данных по комиксах
    • Читать онлайн комиксы
    • Читать онлайн манга
    • База персонажей
  • Читы и коды
    • Чит-коды для PC игр
    • Чит-коды для консольных игр
    • Трейнеры
    • Коды Game Genie
  • Моддинг
    • Модификации
    • Карты к играм
    • Программы для моддинга
    • Статьи о моддинге
  • Геймдев
    • Всё о создании игр
    • Список движков
    • Утилиты в помощь игроделу
    • Конструкторы игр
    • Игровые движки
    • Библиотеки разработки
    • 3D-модели
    • Спрайты и тайлы
    • Музыка и звуки
    • Текстуры и фоны
  • Рецензии
    • Игры
    • Кино
    • Аниме
    • Комиксы
    • Мангу
    • Саундтреки
  • Саундтреки
    • Лирика
  • Файлы
    • Патчи к играм
    • Русификаторы к играм
    • Сохранения к играм
    • Субтитры к кино
  • Медиа
    • Видео
    • Фото
    • Аудио
    • Фан-арты
    • Косплей
    • Фото с виставок
    • Девушки из игр
    • Рисунки
    • Рисуем онлайн
    • Фотохостинг
  • Юмор
    • Анекдоты
    • Афоризмы
    • Истории
    • Стишки и эпиграммы
    • Тосты
    • Цитаты
  • Флеш
    • Азартные
    • Аркады
    • Бродилки
    • Гонки
    • Для девочек
    • Для мальчиков
    • Драки
    • Квесты
    • Леталки
    • Логические
    • Мультфильмы
    • Открытки
    • Приколы
    • Разное
    • Спорт
    • Стратегии
    • Стрелялки
Статистика

Статей: 87772
Просмотров: 96425698
Игры
Injustice:  Gods Among Us
Injustice: Gods Among Us
...
Dark Souls 2
Dark Souls 2
Dark Souls II - вторая часть самой хардкорной ролевой игры 2011-2012 года, с новым героем, сюжето...
Battlefield 4
Battlefield 4
Battlefield 4 - продолжение венценосного мультиплеер-ориентированного шутера от первого ли...
Кино
Steins;Gate
Steins;Gate
Любители японской анимации уже давно поняли ,что аниме сериалы могут дать порой гораздо больше пи...
Ку! Кин-дза-дза
Ку! Кин-дза-дза
Начинающий диджей Толик и всемирно известный виолончелист Владимир Чижов встречают на шумной моск...
Обзоры на игры
• Обзор Ibara [PCB/PS2] 18407
• Обзор The Walking ... 18853
• Обзор DMC: Devil M... 19921
• Обзор на игру Valk... 15921
• Обзор на игру Stars! 17810
• Обзор на Far Cry 3 18000
• Обзор на Resident ... 16063
• Обзор на Chivalry:... 17561
• Обзор на игру Kerb... 18021
• Обзор игры 007: Fr... 16667
Превью о играх
• Превью к игре Comp... 18003
• Превью о игре Mage... 14502
• Превью Incredible ... 14763
• Превью Firefall 13523
• Превью Dead Space 3 16378
• Превью о игре SimC... 14772
• Превью к игре Fuse 15479
• Превью Red Orche... 15589
• Превью Gothic 3 16388
• Превью Black & W... 17402
Главная » Статьи » Всё о XNA » Устройства ввода, перемещение объектов

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


В этой лабораторной работе мы ознакомимся с основными способами работы с устройствами ввода. В частности, поговорим о перемещении объектов, обсудим работу с различными устройствами ввода, вопросы автоматического перемещения объектов, а так же – вопросы, касающиеся работы в оконном и полноэкранном режимах.

Цель работы:
  • Научиться работать с устройствами ввода информации
Задачи работы
  • Научиться получать данные о состоянии мыши и клавиатуры
  • Научиться перемещать игровые объекты в соответствии с параметрами, полученными от устройства ввода
  • Научиться перемещать игровые объекты в автоматическом режиме, используя средства игрового цикла
  • Научиться организовывать управление несколькими объектами для применения в играх, в которые могут играть два игрока, пользующиеся одним компьютером
  • Научиться узнавать и изменять размеры игрового окна
  • Научиться переводить программу в полноэкранный режим, настраивать разрешение экрана при работе в таком режиме
  • Научиться предотвращать пересечение объектом границ экрана при перемещении объекта
Обработка состояния клавиатуры

Создадим новый стандартный проект, назовем его P3_1. Добавим в проект изображение, переменные для хранения текстуры и позиции изображения в игровом окне, загрузим его в методе LoadContent. Вот, как выглядит текст программы после модификации (листинг 3.1.).

Листинг 3.1. Код класса Game1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
 
namespace P3_1
{
    /// 
    /// This is the main type for your game
    /// 
    public class Game1 : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;
        private Texture2D MySprite;
        private Vector2 position = new Vector2(150, 200);
 
        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
        }
 
        protected override void LoadContent()
        {
            spriteBatch = new SpriteBatch(GraphicsDevice);
            MySprite = Content.Load<Texture2D>("ball");
        }
 
        protected override void Update(GameTime gameTime)
        {
            // Allows the game to exit
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
                this.Exit();
 
            base.Update(gameTime);
        }
 
 
        protected override void Draw(GameTime gameTime)
        {
            graphics.GraphicsDevice.Clear(Color.CornflowerBlue);
 
            spriteBatch.Begin();
            spriteBatch.Draw(MySprite, position, Color.White);
            spriteBatch.End();
 
            base.Draw(gameTime);
        }
    }
}

 

Теперь добавим в метод Update код, который будет изменять позицию выведенного спрайта в соответствии с изменением состояния клавиатуры. В частности, будет реагировать на клавиши-стрелки, перемещая объект в соответствующем направлении. На рис. 3.1. вы можете видеть внешний вид игрового окна.


Рис. 3.1. Игровое окно

Для того, чтобы настроить перемещение спрайта по клавиатурным командам, нам понадобится такой код (листинг 3.2.).

Листинг 3.2. Код, реализующий чтение состояния клавиатуры и перемещение спрайта
1
2
3
4
5
6
7
8
9
10
     KeyboardState kbState = Keyboard.GetState();
 
     if (kbState.IsKeyDown(Keys.Up))
         position.Y -= 1;
     if (kbState.IsKeyDown(Keys.Down))
         position.Y += 1;
     if (kbState.IsKeyDown(Keys.Left))
         position.X -= 1;
     if (kbState.IsKeyDown(Keys.Right))
         position.X += 1;

 

Здесь мы сначала создали переменную kbState типа KeyboardState, в которую записали текущее состояние клавиатуры, вызвав метод GetState() объекта KeyBoard. Этот метод возвращает состояние клавиатуры.

После этого мы проверили, с помощью метода IsKeyDown, была ли нажата клавиша-стрелка «Вверх». Наименования клавиш хранятся в перечислении Keys. В нашем случае клавиша-стрелка «вверх» символизируется именем Keys.Up. Если клавиша нажата – изменим координату Y позиции объекта, вычтя из нее 1. Позиция изменится и при следующем выводе спрайта он переместится на 1 пиксель вверх. Точно так же обрабатываются другие клавиши-стрелки. Keys.Down – это клавиша «вниз», если она нажата, к координате Y прибавляется единица и объект перемещается вниз. Keys.Left – это клавиша «влево» - объект перемещается влево – от его координаты X отнимается единица. Keys.Right – это клавиша «вправо» - объект перемещается вправо, к его координате X прибавляется 1.

Если нажать и удерживать одну из клавиш – объект будет непрерывно перемещаться в указанном направлении. Если, не отпуская нажатую клавишу, нажать другую, объект изменит направление или остановится. Например, нажав одновременно клавиши «вверх» и «влево», мы заставим объект двигаться по диагонали влево и вверх. А если в то время, как нажата клавиша «вверх» мы нажмем и клавишу «вниз» - объект остановится – нажатие «вверх» вычитает единицу из его позиции, нажатие «вниз» - прибавляет единицу, в результате объект оказывается неподвижным.
С помощью метода IsKeyUp объекта kbState мы проводим проверку, обратную методу IsKeyDown – то есть этот метод возвращает True, если клавиша не нажата, и False – если нажата.

Для перемещения объекта мы модифицируем его координаты на игровом поле. Можно заметить, что модификация ведется с шагом в 1. Это значение можно назвать скоростью перемещения объекта. Увеличив шаг изменения координаты по нажатию клавиши, можно увеличить скорость перемещения.

Можно заметить, что описанный подход к перемещению объекта по клавиатурным командам работает, однако если сложность игровой программы увеличится – он оказывается неудобным. Поэтому ниже мы рассмотрим пример использование управляемого с клавиатуры игрового компонента, унаследованного от  DrawableGameComponent. Такой подход делает удобным не только клавиатурное управление, но и автоматическое управление объектом, делает возможным удобное применение ограничений на управление объектом, обработку столкновений объектов (этот вопрос будет рассмотрен на следующем занятии) и другие задачи. Однако, стоит отметить, что принципы управления объектами с клавиатуры даже при управлении игровым компонентом, сохраняются.

Теперь рассмотрим управление игровым объектом с помощью мыши.

Обработка состояния мыши

Создадим новый стандартный игровой проект (P3_2), модифицируем его таким образом, чтобы он соответствовал коду, приведенному в листинге 3.1. – то есть – подготовим все для рассмотрения концепций работы с мышью. Теперь добавим в код метода Update() такой код (листинг 3.3.).

Листинг 3.3. Код, реализующий чтение состояния мыши и перемещение объекта
1
2
3
MouseState mState = Mouse.GetState();
position.X = mState.X;
position.Y = mState.Y;

 


Для начала мы создали переменную mState типа MouseState – она хранит состояние мыши, полученное с помощью метода GetState() объекта Mouse. Теперь мы приравниваем координату X позиции спрайта текущей координате X мыши, то же самое делаем с координатой Y.

Запустив на выполнение данный пример, можно заметить, что спрайт перемещается в соответствии с перемещениями мыши, при выходе указателя мыши за пределы игрового окна, спрайт так же «уходит» с экрана. Ниже мы рассмотрим пример, показывающий, как избежать такого «ухода».

Состояние мыши, помимо её координат, содержит и другую информацию. В частности – данные о нажатии клавиш, о состоянии колёсика прокрутки. Создадим пример, который демонстрирует перемещение спрайта к позиции игрового окна, в которой мы щёлкнули мышью.

Создадим новый стандартный игровой проект (P3_3), код которого аналогичен листингу 3.1.

Добавим в раздел объявления переменных класса две переменных (листинг. 3.4.).

Листинг 3.4. Определение факта нажатия на левую кнопку мыши
1
2
bool is_MouseLB_Pressed = false;
Vector2 new_position = new Vector2();

 

Первую переменную – is_MouseLB_Pressed будем устанавливать в True при нажатии на левую кнопку мыши, в переменную new_position будем записывать координаты, в которых произошло нажатие.

Добавим в метод Initialise() класса Game1 код, который отобразит указатель мыши в игровом окне. По умолчанию при перемещении мыши в пределы игрового окна указатель исчезает. Код, приведенный в листинге 3.5. позволяет отобразить указатель.

Листинг 3.5. Код для отображения указателя мыши в игровом окне
1
2
3
4
5
protected override void Initialize()
{
    base.Initialize();
    this.IsMouseVisible = true;
}

 

Здесь объект this представляет собой текущий игровой объект. Его свойство IsMouseVisible при установке в True включает отображение указателя в игровом окне.

Теперь дополним метод Update() так, как показано в коде, приведенном в листинге 3.6.

Листинг 3.6. Автоматическое перемещение объекта к месту щелчка мыши
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
protected override void Update(GameTime gameTime)
        {
            // Allows the game to exit
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
                this.Exit();
            MouseState mState = Mouse.GetState();
            if (mState.LeftButton ==ButtonState .Pressed)
            {
                is_MouseLB_Pressed = true;
                new_position.X = mState.X;
                new_position .Y = mState .Y;
            }
            if (is_MouseLB_Pressed)
            {
                if (new_position .X -position .X >0)
                {
                    position .X +=1;
                }
                else
                {
                    position .X-=1;
                }
                if (new_position .Y-position .Y>0)
                {
                    position .Y+=1;
                }
                else
                {
                    position .Y -=1;
                }             
                if (position == new_position)
                {
                    is_MouseLB_Pressed = false;
                }
            }
        }

 


Сначала мы получаем текущее состояние мыши и сохраняем его в переменной mState. Далее проверяем, была ли нажата левая кнопка мыши. Для этого используем свойство mState.LeftButton и проверяем его равенство ButtonState.Pressed. Если равенство выполняется – устанавливаем переменную is_MouseLB_Pressed в True и записываем в переменную new_Position значения координат мыши в момент нажатия левой кнопки.

Далее, если переменная is_MouseLB_Pressed установлена в True, сравниваем текущую позицию объекта и позицию, в которой мы щелкнули левой кнопкой. Если разность координаты X новой и текущей позиций больше нуля, это значит, что объект расположен левее новой позиции и для перемещения к ней его координата X должна быть увеличена. Если разность меньше нуля – объект находится правее, его координата X будет уменьшена. Точно так же сравниваем координаты Y и модифицируем их. В конце мы проверяем, достиг ли объект заданной позиции. Если да – устанавливаем is_MouseLB_Pressed в False – это значит, что на следующем шаге цикла Update() мы не будем модифицировать координаты – объект достиг заданной позиции.

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

Как упоминалось выше, подход с размещением кода перемещения игрового объекта в основном коде программы неудобен при разработке реальных проектов. Поэтому ниже мы рассмотрим пример разработки самостоятельного игрового объекта, содержащего собственный код, отвечающий за его перемещение. Здесь же мы реализуем проверку на допустимость следующего шага перемещения.

Разработка игрового компонента с функциями перемещения и с ограничениями

Можно заметить, что в предыдущих примерах игровые объекты легко пересекали границы игрового поля. В реальных проектах обычно требуется, чтобы подвижный объект не пересекал этих границ. Это значит, что, во-первых – нам нужно узнать координаты границ экрана, а во-вторых – нужно создать такой код, отвечающий за перемещение объекта, который прежде чем переместить объект в новую позицию, проверял бы допустимость такого перемещения.

Создадим новый игровой проект (P3_4), аналогичный проекту P2_3, разработанному в лабораторной работе №2. Единственное отличие – мы не будем выводить фоновое изображение. Этот проект содержит игровой компонент, который в нашем примере и будет содержать весь необходимый код. Измененный код компонента вы можете видеть в листинге 3.7.

Листинг 3.7. Код компонента, рассчитанного на перемещения с ограничениями
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Content;
 
namespace P3_4
{
    /// 
    /// This is a game component that implements IUpdateable.
    /// 
    public class spriteComp : Microsoft.Xna.Framework.DrawableGameComponent
    {
        private Texture2D sprTexture;
        private Rectangle sprRectangle;
        private Vector2 sprPosition;
        private 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 override void Update(GameTime gameTime)
        {
            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;
            }
 
            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;
            }
 
            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);
        }
    }
}

 


В разделе объявления переменных мы добавили новую переменную – scrBounds типа Rectangle. В этой переменной мы будем хранить параметры игрового окна. Мы инициализируем эту переменную в конструкторе класса. В качестве левой верхней координаты прямоугольника, ограничивающего игровое окно, мы записали (0,0), в качестве ширины – ширину игрового поля, полученную с помощью команды game.Window.ClientBounds.Width. Здесь объект game был передан в конструктор при создании игрового объекта, объект Window – это окно игры, ClientBounds содержит информацию о параметрах окна, в частности, о ширине (Width) и высоте (Height).

В методе Update() мы получаем состояние клавиатуры и, если нажаты соответствующие клавиши-стрелки, модифицируем позицию спрайта на экране. Однако здесь, после модификации позиции, мы проводим серию проверок. Например, проверяем, не меньше ли новая координата X игрового объекта координаты X прямоугольника, соответствующего игровому окну. Если эта координата меньше, это значит, что объект, при перемещении в соответствующую позицию, окажется левее левой границы экрана. Поэтому, если проверяемое условие выполняется – мы приравниваем координату левой границы экрана координате объекта. При попытке пересечения левой границы экрана объект «упирается» в нее.

Немного сложнее выглядит проверка на пересечение правой границы экрана. Как вы знаете, координаты X и Y прямоугольника, ограничивающего наш объект, соответствуют его левой верхней точке. Объект имеет ширину и высоту, поэтому для проверки пересечения правой границы экрана, мы сравниваем новую позицию объекта с разностью ширины экрана с шириной объекта. Если оказывается, что новая позиция больше, чем вычисленная разность – объект устанавливается в позицию, координата X объекта устанавливается равной разности ширины экрана и ширины объекта – он «упирается» в правую границу экрана своей правой частью.

Таким же образом проверяется координата Y – на пересечение объекта верхней и нижней границ экрана.

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

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

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

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

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

Листинг 3.8. Базовый компонент spriteComp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Content;
 
namespace P3_5
{
    /// 
    /// This is a game component that implements IUpdateable.
    /// 
    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);
        }
    }
}

 

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

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

Листинг 3.9. Класс gameObj1 – наследник spriteComp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
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);
        }
    }
}

 

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

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

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

Листинг 3.10. Класс gameObj2 – наследник spriteComp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
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);
        }
    }
}

 

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

Теперь перейдем к основному файлу игры – коду Game1. Для наглядности он приведен полностью (листинг 3.11.).

Листинг 3.11. Код Game1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
 
namespace P3_5
{
    /// 
    /// This is the main type for your game
    /// 
    public class Game1 : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;
        gameObj1  gameObject;
        gameObj2 gameObject2;
        Texture2D texture;
 
        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
        }
 
        protected override void Initialize()
        {
            // TODO: Add your initialization logic here
 
            base.Initialize();
        }
 
        protected override void LoadContent()
        {
            // Create a new SpriteBatch, which can be used to draw textures.
            spriteBatch = new SpriteBatch(GraphicsDevice);
            Services.AddService(typeof(SpriteBatch), spriteBatch);
            texture = Content.Load<Texture2D>("BallandBats");
            CreateNewObject();
            // TODO: use this.Content to load your game content here
        }
 
        protected void CreateNewObject()
        {
            gameObject = new gameObj1 (this, ref texture,
                new Rectangle(18, 9, 17, 88), 
                new Vector2(100, 150));
            Components.Add(gameObject1);
            gameObject2 = new gameObj2(this, ref texture,
                new Rectangle(17, 106, 17,88), 
                new Vector2(200, 150));
            Components.Add(gameObject2);
        }
 
        protected override void UnloadContent()
        {
            // TODO: Unload any non ContentManager content here
        }
 
        protected override void Update(GameTime gameTime)
        {
 
            // TODO: Add your update logic here
 
            base.Update(gameTime);
        }
 
        protected override void Draw(GameTime gameTime)
        {
            graphics.GraphicsDevice.Clear(Color.CornflowerBlue);
 
            // TODO: Add your drawing code here
            spriteBatch.Begin();
            base.Draw(gameTime);
            spriteBatch.End();
        }
    }
}

 

Для начала мы объявили пару объектных переменных – одну типа gameObj1, вторую – gameObj2. Далее, после загрузки игрового контента, мы выполнили метод CreateNewObject(), который содержит код для создания двух объектов. После создания мы регистрируем каждый из них в списке игровых компонентов.

Как видите, в коде основной программы мы лишь загружаем ресурсы и создаем игровые объекты, после чего вся работа по управлению ими ведется с помощью кода, находящегося в этих же объектах. На рис. 3.2. вы можете видеть игровое окно с двумя выведенными в нем объектами, которые управляются раздельно.


Рис. 3.2. Игровое окно с двумя игровыми компонентами

Еще один подход к управлению несколькими объектами заключается в создании упрощенного, в плане управления, объекта, которому лишь передаются новые координаты, вычисленные после обработки ввода в основной программе.
Рассмотрим такой подход.

Централизованное управление несколькими объектами

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

Листинг 3.12. Код класса spriteComp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Content;
 
namespace P3_6
{
    public class spriteComp : Microsoft.Xna.Framework.DrawableGameComponent
    {
        protected Texture2D sprTexture;
        public Rectangle sprRectangle;
        public Vector2 sprPosition;
 
 
        public spriteComp(Game game, ref Texture2D newTexture,
            Rectangle newRectangle, Vector2 newPosition)
            : base(game)
        {
            sprTexture = newTexture;
            sprRectangle = newRectangle;
            sprPosition = newPosition;
 
            // TODO: Construct any child components here
        }
 
        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)
        {
            SpriteBatch sprBatch =
                (SpriteBatch)Game.Services.GetService(typeof(SpriteBatch));
            sprBatch.Draw(sprTexture, sprPosition, sprRectangle, Color.White);
            base.Draw(gameTime);
        }
    }
}

 

Обратите внимание на то, что класс содержит лишь несколько свойств, собственный конструктор и команды для вывода изображения на экран в методе Draw(). Свойства sprRectangle и sprPosition объявлены с модификатором доступности Public – они пригодятся нам для управления поведением объекта из объекта класса Game1.

Вот как выглядит код класса Game1. Вся логика по перемещению объектов и по проверке допустимости перемещения реализована в нём.

Листинг 3.13. Код класса Game1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
 
namespace P3_6
{
    public class Game1 : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;
        spriteComp  gameObject1, gameObject2;
        Texture2D texture;
        Rectangle scrBounds;
        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
        }
 
        protected override void Initialize()
        {
            // TODO: Add your initialization logic here
 
            base.Initialize();
        }
 
        protected override void LoadContent()
        {
            // Create a new SpriteBatch, which can be used to draw textures.
            spriteBatch = new SpriteBatch(GraphicsDevice);
            Services.AddService(typeof(SpriteBatch), spriteBatch);
            texture = Content.Load<Texture2D>("BallandBats");
            scrBounds = new Rectangle(0, 0,
                this.Window.ClientBounds.Width,
                this.Window.ClientBounds.Height);
            CreateNewObject();
        }
 
        protected void CreateNewObject()
        {
            gameObject1 = new spriteComp (this, ref texture,
                new Rectangle(18, 9, 17, 88),
                new Vector2(100, 150));
            Components.Add(gameObject1);
            gameObject2 = new spriteComp (this, ref texture,
                new Rectangle(17, 106, 17, 88),
                new Vector2(200, 150));
            Components.Add(gameObject2);
        }
 
        void Test (spriteComp spr, Rectangle scr)
        {
            if (spr.sprPosition.X < scr.Left)
            {
                spr.sprPosition.X = scr.Left;
            }
            if (spr.sprPosition.X > scr.Width - spr.sprRectangle.Width)
            {
                spr.sprPosition.X = scr.Width - spr.sprRectangle.Width;
            }
            if (spr.sprPosition.Y < scr.Top)
            {
                spr.sprPosition.Y = scr.Top;
            }
            if (spr.sprPosition.Y > scr.Height - spr.sprRectangle.Height)
            {
                spr.sprPosition.Y = scr.Height - spr.sprRectangle.Height;
            }
        }
 
        void MoveUp(spriteComp spr)
        {
            spr.sprPosition.Y -= 5;
        }
        void MoveDown(spriteComp spr)
        {
            spr.sprPosition.Y += 5;
        }
        void MoveLeft(spriteComp spr)
        {
            spr.sprPosition.X -= 5;
        }
        void MoveRight(spriteComp spr)
        {
            spr.sprPosition.X += 5;
        }
 
        protected override void Update(GameTime gameTime)
        {
            KeyboardState kbState = Keyboard.GetState();
            if (kbState.IsKeyDown(Keys.Up))
            {
                MoveUp(gameObject1);
            }
            if (kbState.IsKeyDown(Keys.Down))
            {
                MoveDown(gameObject1);
            }
            if (kbState.IsKeyDown(Keys.Left))
            {
                MoveLeft(gameObject1);
            }
            if (kbState.IsKeyDown(Keys.Right))
            {
                MoveRight(gameObject1);
            }
            Test(gameObject1, scrBounds);
            if (kbState.IsKeyDown(Keys.W))
            {
                MoveUp(gameObject2);
            }
            if (kbState.IsKeyDown(Keys.S))
            {
                MoveDown(gameObject2);
            }
            if (kbState.IsKeyDown(Keys.A))
            {
                MoveLeft(gameObject2);
            }
            if (kbState.IsKeyDown(Keys.D))
            {
                MoveRight(gameObject2);
            }
            Test(gameObject2, scrBounds);
            base.Update(gameTime);
        }
 
        protected override void Draw(GameTime gameTime)
        {
            graphics.GraphicsDevice.Clear(Color.CornflowerBlue);
 
            spriteBatch.Begin();
            base.Draw(gameTime);
            spriteBatch.End();
        }
    }
}

 

Для перемещения объектов класса spriteComp мы модифицируем их свойства sprPosition из кода объекта Game1. Для удобства мы создали четыре процедуры – Up, Down, Left, Right – каждая из них принимает на входе объект типа spriteComp и модифицирует соответствующую координату, хранящуюся в свойстве sprPosition этого объекта. Эти процедуры вызываются после анализа состояния клавиатуры в методе Update(). После этого вызывается метод Test(), который принимает на входе объект типа spriteComp и объект типа Rectangle, который хранит параметры экрана. В методе производятся проверки допустимости новых значений, при нарушении объектом границ, координаты модифицируются.

Теперь рассмотрим еще один способ организации управления и работы с объектами.

Автоматическое перемещение объекта: несколько автономных объектов без создания объектных переменных

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

Разработаем следующую программу. На игровой экран должно выводиться случайное количество игровых объектов (в диапазоне от 50 до 200), в случайных позициях в пределах границ экрана. Каждый из них перемещается в случайном направлении на случайное число шагов (в диапазоне от 50 до 200). Объекты не могут пересекать границы экрана. При каждом новом шаге цвет объекта должен случайным образом изменяться

Создадим новый игровой проект (P3_7), аналогичный P2_3. Модифицируем его код. В листинге 3.14. вы можете видеть код компонента spriteComp.

Листинг 3.14. Код компонента spriteComp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Content;
 
namespace P3_7
{
    /// 
    /// This is a game component that implements IUpdateable.
    /// 
    public class spriteComp : Microsoft.Xna.Framework.DrawableGameComponent
    {
        protected Texture2D sprTexture;
        protected Rectangle sprRectangle;
        protected Vector2 sprPosition;
        protected Rectangle scrBounds;
        //Для генерирования случайных чисел
        protected Random randNum;
        //Количество шагов, которое пройдет спрайт
        protected int stepNumber;
        //Координата, к которой он будет двигаться
        protected Vector2 newPosition;
        //Цвет спрайта
        protected Color sprColor;
        //Скорость перемещения
        protected Vector2 speed;
 
        public spriteComp(Game game, ref Texture2D newTexture,
            Rectangle newRectangle, int Seed)
            : base(game)
        {
            sprTexture = newTexture;
            sprRectangle = newRectangle;
            //Инициализируем счетчик
            randNum = new Random(Seed);
 
            scrBounds = new Rectangle(0, 0,
                game.Window.ClientBounds.Width,
                game.Window.ClientBounds.Height);
            //Устанавливаем стартовую позицию спрайта
            sprPosition.X = (float)randNum.NextDouble() * (scrBounds.Width - sprRectangle.Width);
            sprPosition.Y = (float)randNum.NextDouble() * (scrBounds.Height  - sprRectangle.Height);
            //Колишество шагов равно нулю
            stepNumber = 0;
            //Зададим случайный цвет для придания изображению
            //соответствующего оттенка
            sprColor = new Color((byte)randNum.Next(0, 255), (byte)randNum.Next(0, 255), (byte)randNum.Next(0, 255));
            //Переменная для хранения скорости пока пуста
            speed = new Vector2 ();
            // TODO: Construct any child components here
        }
 
        public override void Initialize()
        {
            // TODO: Add your initialization code here
 
            base.Initialize();
        }
        //Перемещение спрайта
        public virtual void Move()
        {
            //Если выполнены не все шаги
            if (stepNumber > 0)
            {
                //уменьшим переменную, хранящую число шагов
                stepNumber--;
                //Модифицируем координаты в соответствии с положением
                //объекта относительно желаемой координаты
                //и в соответствии со скоростью
                if (sprPosition.X < newPosition.X) sprPosition.X += speed.X;
                if (sprPosition.X > newPosition.X) sprPosition.X -= speed.X;
                if (sprPosition.Y < newPosition.Y) sprPosition.Y += speed.Y;
                if (sprPosition.Y > newPosition.Y) sprPosition.Y -= speed.Y;
            }
            //Если предыдущий шаг завершен, переменная хранит 0
            if (stepNumber ==0)
            {
                //Установим случайное количество шагов
                stepNumber = randNum.Next(50, 200);
                //Сгененируем случайную целевую позицию
                newPosition.X = (float)randNum.NextDouble() * (scrBounds.Width - sprRectangle.Width);
                newPosition.Y = (float)randNum.NextDouble() * (scrBounds.Height - sprRectangle.Height);
                //Установим новую скорость
                speed.X = randNum.Next(1, 5);
                speed.Y = randNum.Next(1, 5);
                //Зададим новый цвет спрайта
                sprColor = new Color((byte)randNum.Next(0, 255), (byte)randNum.Next(0, 255), (byte)randNum.Next(0, 255));
 
            }
            //Вызов проверки на допустимость перемещения
            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)
        {
            //Вызов метода для перемещения спрайта
            Move();
            base.Update(gameTime);
        }
        public override void Draw(GameTime gameTime)
        {
            SpriteBatch sprBatch =
                (SpriteBatch)Game.Services.GetService(typeof(SpriteBatch));
            sprBatch.Draw(sprTexture, sprPosition, sprRectangle, sprColor);
            base.Draw(gameTime);
        }
    }
}

 

Текст снабжен комментариями, которые достаточно ясно освещают его особенности.

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

Листинг 3.15. Код класса Game1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
 
namespace P3_7
{
    /// 
    /// This is the main type for your game
    /// 
    public class Game1 : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;
        Texture2D texture;
        Random randNum;
 
        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
        }
 
        protected override void Initialize()
        {
            // TODO: Add your initialization logic here
 
            base.Initialize();
        }
 
        protected override void LoadContent()
        {
            // Create a new SpriteBatch, which can be used to draw textures.
            spriteBatch = new SpriteBatch(GraphicsDevice);
            Services.AddService(typeof(SpriteBatch), spriteBatch);
            texture = Content.Load<Texture2D>("BallandBats");
            randNum = new Random();
            CreateNewObject();
            // TODO: use this.Content to load your game content here
        }
 
        protected void CreateNewObject()
        {
            //Цикл от 1 до случайного числ в диапазоне 50,200
            for (int i = 0; i < randNum .Next (50,200); i++)
            {
                //Добавляем в список компонентов новый компонент класса spriteComp
                Components.Add(new spriteComp(this, ref texture,
                new Rectangle(16, 203, 17, 17), i));
            }          
        }
 
        protected override void UnloadContent()
        {
        }
 
        protected override void Update(GameTime gameTime)
        {
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
                this.Exit();
 
            base.Update(gameTime);
        }
 
        protected override void Draw(GameTime gameTime)
        {
            graphics.GraphicsDevice.Clear(Color.CornflowerBlue);
 
            // TODO: Add your drawing code here
            spriteBatch.Begin();
            base.Draw(gameTime);
            spriteBatch.End();
        }
    }
}

 

В целом код этого класса уже хорошо знаком вам по предыдущим примерам. Поэтому обратите особое внимание на процедуру CreateNewObject(). Она содержит циклический вызов метода Add объекта Components, который добавляет в список игровых объектов новый объект типа spriteComp. Номер итерации передается в объект для инициализации генератора случайных чисел. Если принудительно не инициализировать генераторы случайных чисел созданных объектов разными значениями – это приведет к неправильной работе программы – все объекты будут выведены в одной и той же позиции (если объектов много – то в нескольких позициях).

Такой подход позволяет создавать нужное количество объектов, не заботясь о создании объектных переменных. На одной из следующих занятий мы рассмотрим методы работы с такими объектами. На рис. 3.3. вы можете видеть игровое окно проекта P3_7.


Рис. 3.7. Игровое окно, выводящее автоматически созданные объекты

Работа с игровым манипулятором

Для работы с игровым манипулятором служит объект GamePad. Сохранить состояние объекта можно в переменной типа GamePadState. Эта переменная хранит информацию об элементах управления, которые расположены на устройстве. Надо отметить, что игровой манипулятор поддерживает вибрацию – разрабатывая игру, рассчитанная на управление манипулятором, включая в нужный момент вибрацию можно сделать ее интереснее.

Вопросы

1) В переменную типа KeyboardState можно сохранить информацию о
  • a. Состоянии мыши
  • b. Состоянии клавиатуры
  • c. Состоянии игрового манипулятора
  • d. Состоянии графического устройства
2) Какую клавишу символизирует перечисления Keys.Up?
  • a. Клавиша-стрелка «вниз»
  • b. Клавиша-стрелка «влево»
  • c. Клавиша-стрелка «вправо»
  • d. Клавиша-стрелка «вверх»
3) В переменную типа MouseState можно сохранить информацию о
  • a. Состоянии мыши
  • b. Состоянии клавиатуры
  • c. Состоянии игрового манипулятора
  • d. Состоянии графического устройства
4) 4) В переменную типа GamePadState можно сохранить информацию о
  • a. Состоянии мыши
  • b. Состоянии клавиатуры
  • c. Состоянии игрового манипулятора
  • d. Состоянии графического устройства
5) Параметр IsMouseVisible объекта типа Game позволяет
  • a. Отображать и скрывать указатель мыши
  • b. Настраивать разрешение игрового экрана
  • c. Создать объект типа Mouse
  • d. Отображать и скрывать игровое окно
6) Можно ли организовать управление несколькими игровыми объектами с одной клавиатуры?
  • a. Да
  • b. Нет
7) Какой фундаментальный игровой механизм позволяет организовать автоматическое перемещение объектов?
  • a. Наследование кода
  • b. Игровой цикл
  • c. Свойства класса
  • d. Игровые компоненты
8) Охарактеризуйте следующую команду: Components.Add(new spriteComp(this, ref texture,new Rectangle(16, 203, 17, 17), i));
  • a. Это неверная команда
  • b. Эта команда позволяет добавить к списку игровых компонентов новый компонент
  • c. Эта команда нужна для проверки наличия среди игровых компонентов нужного компонента
  • d. Эта команда позволяет удалить компонент из списка игровых компонентов
9) Переменная sprPosition хранит текущую позицию спрайта. Переменная newPosition хранит позицию, в которую спрайт должен переместиться. Если координата X текущей позиции спрайта больше, чем координата X желаемой позиции, какая команда приведет к сокращению расстояния между позициями?
  • a. sprPosition.X += 1;
  • b. sprPosition.X -= 1;
10) Переменная sprPosition хранит текущую позицию спрайта. Переменная newPosition хранит позицию, в которую спрайт должен переместиться. Если координата Y текущей позиции спрайта меньше, чем координата Y желаемой позиции, какая команда приведет к сокращению расстояния между позициями?
  • a. sprPosition.Y += 1;
  • b. sprPosition.Y -= 1;
1989 Прочтений •  [Устройства ввода, перемещение объектов] [08.08.2012] [Комментариев: 0]
Добавил: Ukraine Vova
Ссылки
HTML: 
[BB Url]: 
Похожие статьи
Название Добавил Добавлено
• Устройства ввода, перемещение объектов Ukraine Vova 08.08.2012
Ни одного комментария? Будешь первым :).
Пожалуйста, авторизуйтесь для добавления комментария.

Проект входит в сеть сайтов «8Gamers Network»

Все права сохранены. 8Gamers.NET © 2011 - 2025

Статьи
Рецензия на Pressure
Рецензия на Pressure
Чтобы обратить на себя внимание, начинающие маленькие разработчики, как правило, уходят в жанры, ...
Рецензия на Lost Chronicles of Zerzura
Рецензия на Lost Chron...
Игры, сделанные без любви и старания, похожи на воздушный шар – оболочка есть, а внутри пусто. Lo...
Рецензия на The Bridge
Рецензия на The Bridge
«Верх» и «низ» в The Bridge — понятия относительные. Прогуливаясь под аркой, можно запросто перей...
Рецензия на SimCity
Рецензия на SimCity
Когда месяц назад состоялся релиз SimCity, по Сети прокатилось цунами народного гнева – глупые ош...
Рецензия на Strategy & Tactics: World War 2
Рецензия на Strategy &...
Название Strategy & Tactics: World War II вряд ли кому-то знакомо. Зато одного взгляда на ее скри...
Рецензия на игру Scribblenauts Unlimited
Рецензия на игру Scrib...
По сложившейся традиции в информационной карточке игры мы приводим в пример несколько похожих игр...
Рецензия на игру Walking Dead: Survival Instinct, The
Рецензия на игру Walki...
Зомби и продукция-по-лицензии — которые и сами по себе не лучшие представители игровой биосферы —...
Обратная связь | RSS | Донейт | Статистика | Команда | Техническая поддержка