Цель работы: Научиться обрабатывать касания экрана в XNA, управлять расположением экранных объектов
Сенсорная панель в телефонах на базе Windows Phone 7 может одновременно принимать информацию от 4-х точек касания, кроме обычных касаний можно обрабатывать жесты. Здесь мы рассмотрим различные варианты обработки обычных касаний.
Создадим новый стандартный проект, назовем его P5_1. Добавим в проект изображение, переменные для хранения текстуры и позиции изображения в игровом окне, загрузим его в методе LoadContent. Вот, как выглядит текст программы после модификации (листинг 11.1.).
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Input.Touch;
using Microsoft.Xna.Framework.Media;
namespace P5_1
{
/// <summary>
/// Это главный тип игры
/// </summary>
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";
graphics.IsFullScreen = true;
// Частота кадра на Windows Phone по умолчанию — 30 кадров в секунду.
TargetElapsedTime = TimeSpan.FromTicks(333333);
// Дополнительный заряд аккумулятора заблокирован.
InactiveSleepTime = TimeSpan.FromSeconds(1);
}
/// <summary>
/// Позволяет игре выполнить инициализацию, необходимую перед запуском.
/// Здесь можно запросить нужные службы и загрузить неграфический
/// контент. Вызов base.Initialize приведет к перебору всех компонентов и
/// их инициализации.
/// </summary>
protected override void Initialize()
{
// ЗАДАЧА: добавьте здесь логику инициализации
base.Initialize();
}
/// <summary>
/// LoadContent будет вызываться в игре один раз; здесь загружается
/// весь контент.
/// </summary>
protected override void LoadContent()
{
// Создайте новый SpriteBatch, который можно использовать для отрисовки текстур.
spriteBatch = new SpriteBatch(GraphicsDevice);
mySprite = Content.Load<Texture2D>("ball");
// ЗАДАЧА: используйте здесь this.Content для загрузки контента игры
}
/// <summary>
/// UnloadContent будет вызываться в игре один раз; здесь выгружается
/// весь контент.
/// </summary>
protected override void UnloadContent()
{
// ЗАДАЧА: выгрузите здесь весь контент, не относящийся к ContentManager
}
/// <summary>
/// Позволяет игре запускать логику обновления мира,
/// проверки столкновений, получения ввода и воспроизведения звуков.
/// </summary>
/// <param name="gameTime">Предоставляет моментальный снимок значений времени.</param>
protected override void Update(GameTime gameTime)
{
// Позволяет выйти из игры
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
this.Exit();
// ЗАДАЧА: добавьте здесь логику обновления
base.Update(gameTime);
}
/// <summary>
/// Вызывается, когда игра отрисовывается.
/// </summary>
/// <param name="gameTime">Предоставляет моментальный снимок значений времени.</param>
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
spriteBatch.Begin();
spriteBatch.Draw(mySprite, position, Color.White);
spriteBatch.End();
base.Draw(gameTime);
}
}
}
Теперь добавим в метод Update код, который будет изменять позицию выведенного
(рис 11.1) Игровое окно, проект P5_1
protected override void Update(GameTime gameTime)
{
// Позволяет выйти из игры
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
this.Exit();
//Получаем коллекцию объектов, содержащих информацию о касаниях экрана
TouchCollection touchLocations = TouchPanel.GetState();
//Перебираем коллекцию, присваивая объекту координаты касания
foreach (TouchLocation touchLocation in touchLocations)
{
if (touchLocation.State == TouchLocationState.Pressed)
{
position = touchLocation.Position;
}
}
base.Update(gameTime);
}
Рассмотрим код, который выполняет перемещение объекта. Для начала отметим, что объект типа представляет собой коллекцию, которая включает в себя объекты TouchLocation, которые представляют собой места касания экрана. Мы получаем эту коллекцию, обратившись к методу GetState() объекта TouchPanel, который представляет собой статический класс, позволяющий работать с сенсорной панелью. Коллекция touchLocations может либо не содержать ни одного объекта, это означает, что касания к экрану в данный момент не обнаружено, либо содержать до четырёх объектов типа TouchLocation, каждый из которых несет сведения об одном из четырёх допустимых касаний экрана.
Когда коллекция получена, мы входим в цикл foreach, где получаем каждый из объектов TouchLocation, находящийся в коллекции, после чего, если состояние объекта является Pressed (то есть – произошло касание экрана и палец пользователя всё еще касается экрана), устанавливаем позицию
Наш
Запустив пример на
В этом примере мы реализуем автоматическое пошаговое перемещение объекта к точке касания. Создадим стантартный игровой XNA-проект, назовем его P5_2, его код приведен в листинге 11.3.
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Input.Touch;
using Microsoft.Xna.Framework.Media;
namespace P5_2
{
/// <summary>
/// Это главный тип игры
/// </summary>
public class Game1 : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
private Texture2D mySprite;
private Vector2 position = new Vector2(150, 200);
private Vector2 newPosition = new Vector2();
private bool isTouched = false;
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
graphics.IsFullScreen = true;
// Частота кадра на Windows Phone по умолчанию — 30 кадров в секунду.
TargetElapsedTime = TimeSpan.FromTicks(333333);
// Дополнительный заряд аккумулятора заблокирован.
InactiveSleepTime = TimeSpan.FromSeconds(1);
}
/// <summary>
/// Позволяет игре выполнить инициализацию, необходимую перед запуском.
/// Здесь можно запросить нужные службы и загрузить неграфический
/// контент. Вызов base.Initialize приведет к перебору всех компонентов и
/// их инициализации.
/// </summary>
protected override void Initialize()
{
// ЗАДАЧА: добавьте здесь логику инициализации
base.Initialize();
}
/// <summary>
/// LoadContent будет вызываться в игре один раз; здесь загружается
/// весь контент.
/// </summary>
protected override void LoadContent()
{
// Создайте новый SpriteBatch, который можно использовать для отрисовки текстур.
spriteBatch = new SpriteBatch(GraphicsDevice);
mySprite = Content.Load<Texture2D>("ball");
// ЗАДАЧА: используйте здесь this.Content для загрузки контента игры
}
/// <summary>
/// UnloadContent будет вызываться в игре один раз; здесь выгружается
/// весь контент.
/// </summary>
protected override void UnloadContent()
{
// ЗАДАЧА: выгрузите здесь весь контент, не относящийся к ContentManager
}
/// <summary>
/// Позволяет игре запускать логику обновления мира,
/// проверки столкновений, получения ввода и воспроизведения звуков.
/// </summary>
/// <param name="gameTime">Предоставляет моментальный снимок значений времени.</param>
protected override void Update(GameTime gameTime)
{
// Позволяет выйти из игры
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
this.Exit();
//Получаем коллекцию объектов, содержащих информацию о касаниях экрана
TouchCollection touchLocations = TouchPanel.GetState();
//Перебираем коллекцию, присваивая объекту координаты касания
foreach (TouchLocation touchLocation in touchLocations)
{
if (touchLocation.State == TouchLocationState.Pressed)
{
newPosition = touchLocation.Position;
isTouched = true;
}
}
if (isTouched)
{
if (newPosition.X - position.X > 0)
{
position.X += 1;
}
else
{
if (newPosition.X != position.X)
{
position.X -=1;
}
}
if (newPosition.Y - position.Y > 0)
{
position.Y += 1;
}
else
{
if (newPosition.Y != position.Y)
{
position.Y -= 1;
}
}
if (position == newPosition)
{
isTouched = false;
}
}
base.Update(gameTime);
}
/// <summary>
/// Вызывается, когда игра отрисовывается.
/// </summary>
/// <param name="gameTime">Предоставляет моментальный снимок значений времени.</param>
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
spriteBatch.Begin();
spriteBatch.Draw(mySprite, position, Color.White);
spriteBatch.End();
base.Draw(gameTime);
}
}
}
(рис 11.2) Игровое окно, проект P5_2
Можно заметить, что в предыдущих примерах игровые объекты легко пересекали границы игрового поля. В реальных проектах обычно требуется, чтобы подвижный объект не пересекал этих границ. Это значит, что, во-первых – нам нужно узнать координаты границ экрана, а во-вторых – нужно создать такой код, отвечающий за перемещение объекта, который прежде чем переместить объект в новую позицию, проверял бы допустимость такого перемещения. Кроме того, для управления спрайтом в данном примере мы создадим экранный элемент управления.
Создадим новый игровой проект (P5_3), в целом, аналогичный P3_3, разработанному в лабораторной работе №3.
Этот проект содержит игровой компонент, который в нашем примере и будет содержать весь необходимый код. Код компонента вы можете видеть в листинге 11.4
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
namespace P5_3
{
/// <summary>
/// Это игровой компонент, реализующий интерфейс IUpdateable.
/// </summary>
public class spriteComp : Microsoft.Xna.Framework.DrawableGameComponent
{
//Изображение
private Texture2D sprTexture;
//Прямоугольник, ограничивающий спрайт
private Rectangle sprRectangle;
//Координата спрайта
private Vector2 sprPosition;
//Границы экрана
private Rectangle scrBounds;
//Направление движения спрайта
private Vector2 sprMove = new Vector2(0,0);
public spriteComp(Game game, ref Texture2D newTexture,
Rectangle newRectangle, Vector2 newPosition
)
: base(game)
{
sprTexture = newTexture;
sprRectangle = newRectangle;
sprPosition = newPosition;
//Работаем в портретном режиме, высота - 480, ширина - 800
scrBounds = new Rectangle(0, 0,
game.Window.ClientBounds.Height,
game.Window.ClientBounds.Width
);
}
/// <summary>
/// Позволяет игровому компоненту выполнить необходимую инициализацию перед\r\запуском.
Здесь можно запросить нужные службы и загрузить контент.
///
/// </summary>
public override void Initialize()
{
// ЗАДАЧА: добавьте здесь код инициализации
base.Initialize();
}
/// <summary>
/// Позволяет игровому компоненту обновиться.
/// </summary>
/// <param name="gameTime">Предоставляет моментальный снимок значений времени.</param>
public override void Update(GameTime gameTime)
{
//Изменение координат в соответствии с данными, имеющимися в sprMove
sprPosition.Y=sprPosition.Y+sprMove.Y;
sprPosition.X = sprPosition.X + sprMove.X;
//Если вышли за пределы экрана - исправляем
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);
}
//Метод для установки направления движения спрайта
public void Move(Vector2 move)
{
sprMove = move;
}
}
}
Раcсмотрим ключевые моменты этого кода. Здесь мы используем переменную scrBound, в которой храним прямоугольник, соответствующий экрану. Его мы будем использовать для проверки на пересечение спрайтом границы экрана. Мы заполняем данные этого прямоугольника в конструкторе компонента. Объект оперирует данными в следующей последовательности – Координата X левого верхнего угла, координата Y левого верхнего угла, ширина, высота. Свойство Height содержит высоту экрана в портретном режиме (800), Width – ширину (480), поэтому, для задания ширины прямоугольника мы используем свойство Height, для задания высоты – Width.
Переменная sprMove содержит скорость движения X и Y. По умолчанию она равна 0,0, то есть – Update мы прибавляем данные скорости по X и по Y, хранящиеся в данной переменной, к координатам
За изменение скорости движения Move. Он принимает, при вызове его из Vector2, значение этого параметра принимает переменная sprMove, которая, в дальнейшем, используется при перемещении
Рассмотрим теперь основной код игры. Код класса Game1 вы можете видеть в листинге 11.5.
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Input.Touch;
using Microsoft.Xna.Framework.Media;
namespace P5_3
{
/// <summary>
/// Это главный тип игры
/// </summary>
public class Game1 : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
spriteComp gameObject;
Texture2D texture;
//Изображение стрелок
Texture2D textureArrows;
//Шаг перемещения спрайта, то есть - скорость
float sprSpeed = 4;
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
graphics.IsFullScreen = true;
// Частота кадра на Windows Phone по умолчанию — 30 кадров в секунду.
TargetElapsedTime = TimeSpan.FromTicks(333333);
// Дополнительный заряд аккумулятора заблокирован.
InactiveSleepTime = TimeSpan.FromSeconds(1);
}
/// <summary>
/// Позволяет игре выполнить инициализацию, необходимую перед запуском.
/// Здесь можно запросить нужные службы и загрузить неграфический
/// контент. Вызов base.Initialize приведет к перебору всех компонентов и
/// их инициализации.
/// </summary>
protected override void Initialize()
{
// ЗАДАЧА: добавьте здесь логику инициализации
base.Initialize();
}
/// <summary>
/// LoadContent будет вызываться в игре один раз; здесь загружается
/// весь контент.
/// </summary>
protected override void LoadContent()
{
// Создайте новый SpriteBatch, который можно использовать для отрисовки текстур.
spriteBatch = new SpriteBatch(GraphicsDevice);
Services.AddService(typeof(SpriteBatch), spriteBatch);
texture = Content.Load<Texture2D>("BallandBats");
CreateNewObject();
textureArrows = Content.Load<Texture2D>("Arrows");
// ЗАДАЧА: используйте здесь this.Content для загрузки контента игры
}
protected void CreateNewObject()
{
gameObject = new spriteComp(this, ref texture,
new Rectangle(18, 9, 17, 88), new Vector2(100, 150));
Components.Add(gameObject);
}
/// <summary>
/// UnloadContent будет вызываться в игре один раз; здесь выгружается
/// весь контент.
/// </summary>
protected override void UnloadContent()
{
// ЗАДАЧА: выгрузите здесь весь контент, не относящийся к ContentManager
}
/// <summary>
/// Позволяет игре запускать логику обновления мира,
/// проверки столкновений, получения ввода и воспроизведения звуков.
/// </summary>
/// <param name="gameTime">Предоставляет моментальный снимок значений времени.</param>
protected override void Update(GameTime gameTime)
{
// Позволяет выйти из игры
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
this.Exit();
//Получаем коллекцию объектов, содержащих информацию о касаниях экрана
TouchCollection touchLocations = TouchPanel.GetState();
//Перебираем коллекцию, присваивая объекту координаты касания
foreach (TouchLocation touchLocation in touchLocations)
{
if (touchLocation.State == TouchLocationState.Pressed)
{
//Стрелка "Влево"
if (touchLocation.Position.X > 500 touchLocation.Position.X < 600
touchLocation.Position.Y > 380 touchLocation.Position.Y < 480)
{
gameObject.Move(new Vector2(-sprSpeed,0));
}
//Стрелка "Вправо"
if (touchLocation.Position.X > 700 touchLocation.Position.X < 800
touchLocation.Position.Y > 380 touchLocation.Position.Y < 480)
{
gameObject.Move(new Vector2(sprSpeed, 0));
}
//Стрелка "Вниз"
if (touchLocation.Position.X > 600 touchLocation.Position.X < 700
touchLocation.Position.Y > 380 touchLocation.Position.Y < 480)
{
gameObject.Move(new Vector2(0, sprSpeed));
}
//Стрелка "Вверх"
if (touchLocation.Position.X > 600 touchLocation.Position.X < 700
touchLocation.Position.Y > 280 touchLocation.Position.Y < 380)
{
gameObject.Move(new Vector2(0, -sprSpeed));
}
}
if (touchLocation.State == TouchLocationState.Released)
{
gameObject.Move(new Vector2(0,0));
}
}
base.Update(gameTime);
}
/// <summary>
/// Вызывается, когда игра отрисовывается.
/// </summary>
/// <param name="gameTime">Предоставляет моментальный снимок значений времени.</param>
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
spriteBatch.Begin();
//Сначала выведем изображение стрелок
spriteBatch.Draw(textureArrows, new Rectangle(500, 280, 300, 200), Color.White);
//Игровой компонент будет выведен поверх изображения стрелок
base.Draw(gameTime);
spriteBatch.End();
}
}
}
Здесь мы используем изображение прямоугольника из изображения BallAndBats и изображение четырёх стрелок из изображения sprSpeed задаёт скорость движения
В методе Update мы пользуемся уже известным из прошлых примеров механизмом. Но здесь нет прямого воздействия координаты касания экрана на координаты Х или Y, положительное или отрицательное значение) и скорость (она задаётся единой для всех перемещений через переменную sprSpeed).
Обратите внимание – мы проверяем статус нажатия каждый цикл Update (30 раз в секунду, другими словами, в соответствии с настройками по умолчанию). Если нажатие зафиксировано – мы проверяем координаты, если координаты совпадают с одной из стрелок, выполняем перемещение Pressed. В этот момент мы устанавливаем желаемую скорость и направление перемещения
Если пользователь не убирает палец с экрана, неважно, перемещает он его или нет, состояние устанавливается в Moved. Нас, в данном случае, это состояние не интересует. При появлении события Pressed в соответствующей координате мы начинаем перемещение
Когда пользователь убирает палец со стрелки, объект, представляющий касание, переходит в состояние Released и мы передаем в объект gameObject информацию о том, что перемещение объекта следует остановить.
На рис. 11.3 вы можете видеть игровой экран проекта P5_3.
(рис 11.3) Игровое окно, проект P5_3
В этом примере (стандартный игровой XNA-проект, P5_4) мы реализуем функционал независимого управления двумя игровыми объектами. В реализации этого проекта используется следующий код игрового компонента, листинг 11.6.
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
namespace P5_4
{
/// <summary>
/// Это игровой компонент, реализующий интерфейс IUpdateable.
/// </summary>
public class spriteComp : Microsoft.Xna.Framework.DrawableGameComponent
{
//Изображение
private Texture2D sprTexture;
//Прямоугольник, ограничивающий спрайт
private Rectangle sprRectangle;
//Координата спрайта
private Vector2 sprPosition;
//Границы экрана
private Rectangle scrBounds;
//Направление движения спрайта
private Vector2 sprMove = new Vector2(0, 0);
public spriteComp(Game game, ref Texture2D newTexture,
Rectangle newRectangle, Vector2 newPosition
)
: base(game)
{
sprTexture = newTexture;
sprRectangle = newRectangle;
sprPosition = newPosition;
//Работаем в портретном режиме, высота - 480, ширина - 800
scrBounds = new Rectangle(0, 0,
game.Window.ClientBounds.Height,
game.Window.ClientBounds.Width
);
}
/// <summary>
/// Позволяет игровому компоненту выполнить необходимую инициализацию перед\r\запуском.
Здесь можно запросить нужные службы и загрузить контент.
///
/// </summary>
public override void Initialize()
{
// ЗАДАЧА: добавьте здесь код инициализации
base.Initialize();
}
/// <summary>
/// Позволяет игровому компоненту обновиться.
/// </summary>
/// <param name="gameTime">Предоставляет моментальный снимок значений времени.</param>
public override void Update(GameTime gameTime)
{
//Изменение координат в соответствии с данными, имеющимися в sprMove
sprPosition.Y = sprPosition.Y + sprMove.Y;
sprPosition.X = sprPosition.X + sprMove.X;
//Если вышли за пределы экрана - исправляем
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);
}
//Метод для установки направления движения спрайта
public void Move(Vector2 move)
{
sprMove = move;
}
}
}
Этот игровой компонент очень похож на компонент, рассмотренный в проекте P5_3. Здесь реализованы ограничения на перемещения
Рассмотрим код игры, который реализует данный пример, листинг 11.7.
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Input.Touch;
using Microsoft.Xna.Framework.Media;
namespace P5_4
{
/// <summary>
/// Это главный тип игры
/// </summary>
public class Game1 : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
spriteComp gameObject, gameObject1;
//Для хранения ID касаний
int gameObjectId, gameObjectId1;
Texture2D texture;
//Шаг перемещения спрайта, то есть - скорость
float sprSpeed = 4;
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
graphics.IsFullScreen = true;
// Частота кадра на Windows Phone по умолчанию — 30 кадров в секунду.
TargetElapsedTime = TimeSpan.FromTicks(333333);
// Дополнительный заряд аккумулятора заблокирован.
InactiveSleepTime = TimeSpan.FromSeconds(1);
}
/// <summary>
/// Позволяет игре выполнить инициализацию, необходимую перед запуском.
/// Здесь можно запросить нужные службы и загрузить неграфический
/// контент. Вызов base.Initialize приведет к перебору всех компонентов и
/// их инициализации.
/// </summary>
protected override void Initialize()
{
// ЗАДАЧА: добавьте здесь логику инициализации
base.Initialize();
}
/// <summary>
/// LoadContent будет вызываться в игре один раз; здесь загружается
/// весь контент.
/// </summary>
protected override void LoadContent()
{
// Создайте новый SpriteBatch, который можно использовать для отрисовки текстур.
spriteBatch = new SpriteBatch(GraphicsDevice);
Services.AddService(typeof(SpriteBatch), spriteBatch);
texture = Content.Load<Texture2D>("BallandBats");
CreateNewObject();
// ЗАДАЧА: используйте здесь this.Content для загрузки контента игры
}
protected void CreateNewObject()
{
gameObject = new spriteComp(this, ref texture,
new Rectangle(18, 9, 17, 88),
new Vector2(50, 150));
Components.Add(gameObject);
gameObject1 = new spriteComp(this, ref texture,
new Rectangle(17, 106, 17, 88),
new Vector2(750, 150));
Components.Add(gameObject1);
}
/// <summary>
/// UnloadContent будет вызываться в игре один раз; здесь выгружается
/// весь контент.
/// </summary>
protected override void UnloadContent()
{
// ЗАДАЧА: выгрузите здесь весь контент, не относящийся к ContentManager
}
/// <summary>
/// Позволяет игре запускать логику обновления мира,
/// проверки столкновений, получения ввода и воспроизведения звуков.
/// </summary>
/// <param name="gameTime">Предоставляет моментальный снимок значений времени.</param>
protected override void Update(GameTime gameTime)
{
// Позволяет выйти из игры
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
this.Exit();
//Получаем коллекцию объектов, содержащих информацию о касаниях экрана
TouchCollection touchLocations = TouchPanel.GetState();
//Перебираем коллекцию, присваивая объекту координаты касания
foreach (TouchLocation touchLocation in touchLocations)
{
//Если произошло касание
if (touchLocation.State == TouchLocationState.Pressed)
{
//Управление объектом, расположенным у левого края экрана, перемещение вверх
if (touchLocation.Position.X > 0 touchLocation.Position.X < 200
touchLocation.Position.Y>0touchLocation.Position.Y<240)
{
gameObjectId = touchLocation.Id;
gameObject.Move(new Vector2(0, -sprSpeed));
}
//Управление объектом, расположенным у левого края экрана, перемещение вниз
if (touchLocation.Position.X > 0 touchLocation.Position.X < 200
touchLocation.Position.Y > 240 touchLocation.Position.Y < 480)
{
gameObjectId = touchLocation.Id;
gameObject.Move(new Vector2(0, sprSpeed));
}
//Управление объектом, расположенным у правого края экрана, перемещение вверх
if (touchLocation.Position.X > 600 touchLocation.Position.X < 800
touchLocation.Position.Y > 0 touchLocation.Position.Y < 240)
{
gameObjectId1 = touchLocation.Id;
gameObject1.Move(new Vector2(0, -sprSpeed));
}
//Управление объектом, расположенным у правого края экрана, перемещение вниз
if (touchLocation.Position.X > 600 touchLocation.Position.X < 800
touchLocation.Position.Y > 240 touchLocation.Position.Y < 480)
{
gameObjectId1 = touchLocation.Id;
gameObject1.Move(new Vector2(0, sprSpeed));
}
}
//Если касание окончилось
if (touchLocation.State == TouchLocationState.Released)
{
if (touchLocation.Id == gameObjectId)
{
gameObject.Move(new Vector2(0, 0));
}
if (touchLocation.Id == gameObjectId1)
{
gameObject1.Move(new Vector2(0, 0));
}
}
}
base.Update(gameTime);
}
/// <summary>
/// Вызывается, когда игра отрисовывается.
/// </summary>
/// <param name="gameTime">Предоставляет моментальный снимок значений времени.</param>
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
spriteBatch.Begin();
base.Draw(gameTime);
spriteBatch.End();
}
}
}
Многие части этого кода, подобного этому, уже обсуждались выше. Здесь мы остановимся лишь на наиболее серьезных особенностях. Мы используем два игровых компонента – gameObject и gameObject1. Кроме того, мы используем две новых переменных – gameObjectId и gameObjectId1. Они хранят идентификаторы (Id) касаний. Для управления объектами мы используем четыре зоны экрана. Две зоны шириной 200 и высотой по 240 пикселей, расположенные в левой части экрана для управления одним объектом (gameObject), и такие же зоны вдоль правого края для управления другим (gameObject1).
Таким образом, если пользователь прикасается к верхней зоне у соответствующего края экрана, соответствующий gameObjectId или gameObjectId1 записывается идентификатор касания.
Этот идентификатор не изменяется всё время, когда пользователь касается экрана. Когда пользователь перестаёт касаться экрана, срабатывает проверка на то, что касание перешло в состояние Released. Если для какого-либо касания это условие выполняется, следует проверка идентификатора касания, когда обнаруживается, касание с каким идентификатором перешло в состояние Released, перемещение соответствующего
На рис. 11.4 вы можете видеть игровой экран проекта.
(рис 11.4) Игровое окно, проект P5_4
В этой лабораторной работе была рассмотрена методика обработки информации о касаниях экрана, методика управления экранными объектами на основе данной информации. Рассмотрены возможности использования данных от нескольких точек касания экрана для управления несколькими объектами, функции ограничения перемещения объектов.
Реализуйте управление тремя экранными объектами с использованием методик, описанных в данной лабораторной работе. Реализуйте ограничения для каждого из объектов.
К данной лабораторной работе прилагается видеоурок
и демонстрационный проект.
Для получения официальных документов о завершении программы дополнительного профессионального образования (удостоверения о повышении квалификации, дипломов о профессиональной переподготовке и MBA) необходимо предоставить:
Внимание! Вы можете не заказывать доставку бумажной версии официального документы, а скачать его в электронном виде и распечатать самостоятельно. Информация о выданном документе в течение 1 месяца загружается в Федеральную информационную систему «Федеральный реестр сведений о документах об образовании и (или) о квалификации, документах об обучении» - ФИС ФРДО.
Доступ на новый сайт осуществляется с использованием адреса электронной почты, который был указан вами при регистрации на "старом". Мы постарались перенести все ваши данные с прежнего ресурса, однако не исключена вероятность потери части информации.
При возникновении проблемы со входом, воспользуйтесь функцией сброса пароля
Если вы обнаружите несоответствия, пожалуйста, сообщите нам.