|
Быть может кто-то из Вас знает игру Sims, к какому жанру она относиться? Жизненная симуляция, ролевая игра, там можно и дома строить..... |
Устройства ввода, перемещение объектов
Разработка игрового компонента с функциями перемещения и с ограничениями
Можно заметить, что в предыдущих примерах игровые объекты легко пересекали границы игрового поля. В реальных проектах обычно требуется, чтобы подвижный объект не пересекал этих границ. Это значит, что, во-первых – нам нужно узнать координаты границ экрана, а во-вторых – нужно создать такой код, отвечающий за перемещение объекта, который прежде чем переместить объект в новую позицию, проверял бы допустимость такого перемещения.
Создадим новый игровой проект (P3_4), аналогичный проекту P2_3, разработанному в лабораторной работе №2. Единственное отличие – мы не будем выводить фоновое изображение. Этот проект содержит игровой компонент, который в нашем примере и будет содержать весь необходимый код. Измененный код компонента вы можете видеть в листинге 7.7.
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_4
{
/// <summary>
/// This is a game component that implements IUpdateable.
/// </summary>
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);
}
}
}
Листинг
7.7.
Код компонента, рассчитанного на перемещения с ограничениями
В разделе объявления переменных мы добавили новую переменную – scrBounds типа Rectangle. В этой переменной мы будем хранить параметры игрового окна. Мы инициализируем эту переменную в конструкторе класса. В качестве левой верхней координаты прямоугольника, ограничивающего игровое окно, мы записали (0,0), в качестве ширины – ширину игрового поля, полученную с помощью команды game.Window.ClientBounds.Width. Здесь объект game был передан в конструктор при создании игрового объекта, объект Window – это окно игры, ClientBounds содержит информацию о параметрах окна, в частности, о ширине (Width) и высоте (Height).
В методе Update() мы получаем состояние клавиатуры и, если нажаты соответствующие клавиши-стрелки, модифицируем позицию спрайта на экране. Однако здесь, после модификации позиции, мы проводим серию проверок. Например, проверяем, не меньше ли новая координата X игрового объекта координаты X прямоугольника, соответствующего игровому окну. Если эта координата меньше, это значит, что объект, при перемещении в соответствующую позицию, окажется левее левой границы экрана. Поэтому, если проверяемое условие выполняется – мы приравниваем координату левой границы экрана координате объекта. При попытке пересечения левой границы экрана объект "упирается" в нее.
Немного сложнее выглядит проверка на пересечение правой границы экрана. Как вы знаете, координаты X и Y прямоугольника, ограничивающего наш объект, соответствуют его левой верхней точке. Объект имеет ширину и высоту, поэтому для проверки пересечения правой границы экрана, мы сравниваем новую позицию объекта с разностью ширины экрана с шириной объекта. Если оказывается, что новая позиция больше, чем вычисленная разность – объект устанавливается в позицию, координата X объекта устанавливается равной разности ширины экрана и ширины объекта – он "упирается" в правую границу экрана своей правой частью.
Таким же образом проверяется координата Y – на пересечение объекта верхней и нижней границ экрана.
Как видите, вся логика по перемещению объекта и по проверке на допустимость перемещения, содержится в игровом компоненте и не перегружает основной программный код. Такой подход имеет свои плюсы и минусы. Плюс заключается в удобстве использования подобной конструкции. Но если мы создадим несколько игровых объектов на основе игрового компонента, то окажется, что все они перемещаются одновременно по нажатию на клавиши-стрелки.
Одинаковый механизм перемещения был бы удобен, если бы мы создали алгоритм автоматического перемещения объекта, который перемещал бы каждый из них в соответствии с каким-то законом, например – случайным образом. Если же нам нужно создать несколько объектов, обладающих самостоятельным управлением, используя один и тот же класс, этот механизм будет нуждаться в переработке. Например, в игре Pong предусматривается управление двумя битами – два пользователя, сидя за одной клавиатурой, управляют каждый своей битой с использованием собственных клавиш. Рассмотрим механизмы организации управления несколькими объектами.