Быть может кто-то из Вас знает игру 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 – это проверка на нажатие других клавиш.