|
Быть может кто-то из Вас знает игру Sims, к какому жанру она относиться? Жизненная симуляция, ролевая игра, там можно и дома строить..... |
Устройства ввода, перемещение объектов
Управление несколькими объектами: система классов
Пожалуй, первая мысль, которая придет в голову при разработке раздельного управления двумя объектами - создать второй игровой компонент, отличающийся от первого лишь реакцией на нажатия клавиш. Например, первый будет управляться с помощью клавиш-стрелок, второй – с помощью традиционного для игр набора клавиш 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 – это проверка на нажатие других клавиш.