Цель работы: Научиться обрабатывать данные
Устройства на Windows Phone имеют встроенный
Рассмотрим работу с акселерометром на примере, который получает данные с устройства и выводит сведения о них на экран.
Создадим новый стандартный игровой проект, подготовим его для вывода текста в игровое окно XNA, добавим новый ресурс .spritefont с именем MyFont. Для доступа к акселерометру нам понадобится, во-первых, подключить библиотеку
Для подключения библиотеки нужно сделать щелчок правой кнопкой мыши в Обозревателе решений по группе Ссылки в проекте P6_1, выбрать команду Добавить ссылку и в появившемся окне, на закладке .NET выбрать
(рис 12.1) Подключение библиотеки
В итоге окно Обозреватель решений должно принять вид, показанный на рис. 12.2
(рис 12.2) Окно Обозреватель решений
При работе с акселерометром нужно учитывать, что данные, которые можно от него получить, представляют собой трехмерный вектор, содержащий данные об ускорении устройства в гравитационных единицах. Например, (1,0,0). Если сопоставить эти данные с телефоном, то, если расположить телефон кнопками, расположенными под экраном, вниз, лицевой стороной к наблюдателю, окажется, что ось Y проходит вдоль длинной стороны экрана (положительное направление оси – вверх), X – вдоль короткой (положительное направление оси – вправо), ось Z располагается перпендикулярно экрану (положительное направление – в сторону наблюдателя). Это остаётся справедливым и при поворотах телефона.
Когда телефон неподвижен,
Таким образом, оказывается, например, если телефон лежит на горизонтальной поверхности неподвижно, экраном вверх, показания
Мы реализовали процедуру получения данных с
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;
using Microsoft.Devices.Sensors;
namespace P6_1
{
/// <summary>
/// Это главный тип игры
/// </summary>
public class Game1 : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
//Строка для вывода
string text;
//Для хранения позиции вывода текста
Vector2 textPosition=new Vector2(100,100);
//Для хранения шрифта
SpriteFont MyFont;
//Показатели акселерометра
Vector3 accVector;
//Акселерометр
Accelerometer accelerometer;
//Объект для блокировки
object accLock = new object();
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()
{
//Новый объект для работы с акселерометром
accelerometer = new Accelerometer();
//Задаем время обновления
accelerometer.TimeBetweenUpdates = TimeSpan.FromMilliseconds(1000);
//Подключаем обработчик события
accelerometer.CurrentValueChanged += new EventHandler<SensorReadingEventArgs
<AccelerometerReading>>(accelerometer_CurrentValueChanged);
//Пытаемся запустить акселерометр
try
{
accelerometer.Start();
}
catch
{
}
base.Initialize();
}
//Обработчик события акселерометра
void accelerometer_CurrentValueChanged(object sender, SensorReadingEventArgs<AccelerometerReading> e)
{
//Блокировка обеспечивает получение данных акселерометра в одном потоке
lock (accLock)
{
//Получаем данные
accVector = e.SensorReading.Acceleration;
}
}
///// <summary>
/// LoadContent будет вызываться в игре один раз; здесь загружается
/// весь контент.
/// </summary>
protected override void LoadContent()
{
// Создайте новый SpriteBatch, который можно использовать для отрисовки текстур.
spriteBatch = new SpriteBatch(GraphicsDevice);
//Загружаем шрифт
MyFont = Content.Load<SpriteFont>("MyFont");
}
/// <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();
//Блокировка обеспечивает чтение данных в одном потоке
lock (accLock)
{
//Записываем в строку для вывода строковое представление
//данных, полученных с акселерометра
text = accVector.ToString();
}
base.Update(gameTime);
}
/// <summary>
/// Вызывается, когда игра отрисовывается.
/// </summary>
/// <param name="gameTime">Предоставляет моментальный снимок значений времени.</param>
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
spriteBatch.Begin();
//Выводим строку
spriteBatch.DrawString(MyFont, text, textPosition, Color.Red,
0, new Vector2(0,0), 1.0f, SpriteEffects.None, 0.5f);
spriteBatch.End();
base.Draw(gameTime);
}
}
}
Рассмотрим ключевые моменты этого кода. Здесь мы собираемся вывести значение показаний accVector типа Vector3. Получение данных Update данных из переменной accVector, которые принадлежат различным результатам измерений показаний lock, критически важные операции, в нашем случае это – установка переменной accVector в обработчике события accelerometer_CurrentValueChanged и в методе Update.
В методе Initialize мы создаем новый объект типа , устанавливаем его параметр TimeBetweenUpdates, равный 1000 миллисекунд, то есть показатели
Для получения данных с CurrentValueChanged, которое происходит при поступлении новых данных с устройства. Этот обработчик реализован процедурой accelerometer_CurrentValueChanged, здесь мы получаем данные (они представлены в виде трёхмерного вектора) и записываем их в переменную accVector.
Прежде чем использовать Start() объекта . Попытка исполнить этот метод связана с работой с физическим устройством, здесь возможны ошибки, поэтому мы заключаем эту попытку в конструкцию try {} catch {}. Здесь можно настроить поведение программы в том случае, если данная попытка не удастся, то есть,
В методе Update мы приводим содержимое переменной accVector к текстовому виду и записываем полученную строку в переменную text, текст, содержащийся в которой, выводим на экран в методе Draw.
Запуск программы на реальном устройстве, рис. 12.3. позволит лучше понять, как именно работает
(рис 12.3) Показания акселерометра, устройство лежит на горизонтальной поверхности
Приложения, использующие физические
Запустим программу в эмуляторе, в панели инструментов эмулятора нажмем на кнопку >>, появится окно Дополнительные инструменты, в котором на вкладке
(рис 12.4) Эмуляция показаний акселерометра
Перемещать трехмерную модель телефона можно с помощью изменения положения красной точки с помощью мыши. Вот, например (рис. 12.5), как в эмуляторе выглядит положение телефона, похожее на то, в котором было сфотографировано устройство на рис. 12.3.
(рис 12.5) Эмуляция показаний акселерометра
В поле Ориентация в окне Дополнительные инструменты можно выбирать из нескольких предустановленных ориентаций устройства в пространстве.
В поле Записанные данные можно выбрать набор записанных данных Shake, эмулирующих тряску телефона, и, нажав на Воспроизведение, понаблюдать в окне эмулятора за реакцией программы на эти данные. Изображение телефона при воспроизведении данных не перемещается.
Рассмотрим пример, в котором показания
Сущность данного примера заключается в следующем. Мы получаем показания
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 P6_2
{
/// <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;
sprMove.X = 0;
}
if (sprPosition.X > scrBounds.Width - sprRectangle.Width)
{
sprPosition.X = scrBounds.Width - sprRectangle.Width;
sprMove.X = 0;
}
if (sprPosition.Y < scrBounds.Top)
{
sprPosition.Y = scrBounds.Top;
sprMove.Y = 0;
}
if (sprPosition.Y > scrBounds.Height - sprRectangle.Height)
{
sprPosition.Y = scrBounds.Height - sprRectangle.Height;
sprMove.Y = 0;
}
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;
//Ограничиваем скорость 5-ю пикселями
if (sprMove.X > 5) { sprMove.X = 5; }
if (sprMove.X < -5) { sprMove.X = -5; }
if (sprMove.Y > 5) { sprMove.Y = 5; }
if (sprMove.Y < -5) { sprMove.Y = -5; }
}
}
}
Здесь мы используем для установки двумерного вектора, задающего направление и скорость перемещения Move. В этот метод передаются данные, полученные с sprMove. Положительные значения увеличивают скорость
В процедуре Update мы прибавляем к позиции sprMove. Кроме того, мы контролируем пересечение объектом границ экрана. Если объект пересек границу, мы возвращаем его к границе и сбрасываем соответствующий показатель вектора sprMove, устанавливая скорость движения
Рассмотрим основной игры, листинг 12.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;
using Microsoft.Devices.Sensors;
namespace P6_2
{
/// <summary>
/// Это главный тип игры
/// </summary>
public class Game1 : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
spriteComp gameObject;
Texture2D texture;
//Показатели акселерометра
Vector3 accVector;
//Акселерометр
Accelerometer accelerometer;
//Блокировка
object accLock = new object();
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
//Задаем параметры экрана
graphics.PreferredBackBufferWidth = 800;
graphics.PreferredBackBufferHeight = 480;
//Фиксируем положение экрана
graphics.SupportedOrientations = DisplayOrientation.LandscapeLeft;
//Отображение игрового окна на полный экран, без строки состояния
graphics.IsFullScreen = true;
// Частота кадра на Windows Phone по умолчанию — 30 кадров в секунду.
TargetElapsedTime = TimeSpan.FromTicks(333333);
// Дополнительный заряд аккумулятора заблокирован.
InactiveSleepTime = TimeSpan.FromSeconds(1);
}
/// <summary>
/// Позволяет игре выполнить инициализацию, необходимую перед запуском.
/// Здесь можно запросить нужные службы и загрузить неграфический
/// контент. Вызов base.Initialize приведет к перебору всех компонентов и
/// их инициализации.
/// </summary>
protected override void Initialize()
{
accelerometer = new Accelerometer();
accelerometer.TimeBetweenUpdates = TimeSpan.FromMilliseconds(20);
accelerometer.CurrentValueChanged += new EventHandler<SensorReadingEventArgs
<AccelerometerReading>>(accelerometer_CurrentValueChanged);
try
{
accelerometer.Start();
}
catch
{
}
base.Initialize();
}
void accelerometer_CurrentValueChanged(object sender, SensorReadingEventArgs<AccelerometerReading> e)
{
lock (accLock)
{
accVector = e.SensorReading.Acceleration;
}
}
///// <summary>
/// LoadContent будет вызываться в игре один раз; здесь загружается
/// весь контент.
/// </summary>
protected override void LoadContent()
{
// Создайте новый SpriteBatch, который можно использовать для отрисовки текстур.
spriteBatch = new SpriteBatch(GraphicsDevice);
Services.AddService(typeof(SpriteBatch), spriteBatch);
texture = Content.Load<Texture2D>("BallandBats");
CreateNewObject();
}
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();
lock (accLock)
{
gameObject.Move(new Vector2(-accVector.Y, -accVector.X));
}
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();
}
}
}
Этот код похож на тот, который мы рассматривали в предыдущем примере. Здесь мы, однако, внесли некоторые изменения. Так, в конструкторе класса мы, используя команды graphics.PreferredBackBufferWidth = 800 и graphics.PreferredBackBufferHeight = 480 в явном виде задали ширину и высоту игрового экрана, кроме того, мы зафиксировали положение экрана в левосторонней ландшафтной ориентации командой graphics.SupportedOrientations = DisplayOrientation.LandscapeLeft. Результат этой команды заключается в том, что при повороте экрана не меняется автоматически его ориентация.
Код работы с акселерометром в данном примере тот же, что и в предыдущем. Главная разница заключается в том, что в методе Update мы вызываем метод Move() игрового объекта и передаем ему последние измеренные значения по осям X и Y, полученные с
На рис. 12.6 вы можете видеть результат запуска программы в эмуляторе.
(рис 12.6) Результаты запуска программы в эмуляторе
В этой лабораторной работе была рассмотрена методика получения и обработки показаний
Реализуйте управление экранным объектом с использованием
К данной лабораторной работе прилагается видеоурок
и демонстрационный проект.
Цель работы: Научиться обрабатывать данные
Устройства на Windows Phone имеют встроенный
Рассмотрим работу с акселерометром на примере, который получает данные с устройства и выводит сведения о них на экран.
Создадим новый стандартный игровой проект, подготовим его для вывода текста в игровое окно XNA, добавим новый ресурс .spritefont с именем MyFont. Для доступа к акселерометру нам понадобится, во-первых, подключить библиотеку
Для подключения библиотеки нужно сделать щелчок правой кнопкой мыши в Обозревателе решений по группе Ссылки в проекте P6_1, выбрать команду Добавить ссылку и в появившемся окне, на закладке .NET выбрать
(рис 12.1) Подключение библиотеки
В итоге окно Обозреватель решений должно принять вид, показанный на рис. 12.2
(рис 12.2) Окно Обозреватель решений
При работе с акселерометром нужно учитывать, что данные, которые можно от него получить, представляют собой трехмерный вектор, содержащий данные об ускорении устройства в гравитационных единицах. Например, (1,0,0). Если сопоставить эти данные с телефоном, то, если расположить телефон кнопками, расположенными под экраном, вниз, лицевой стороной к наблюдателю, окажется, что ось Y проходит вдоль длинной стороны экрана (положительное направление оси – вверх), X – вдоль короткой (положительное направление оси – вправо), ось Z располагается перпендикулярно экрану (положительное направление – в сторону наблюдателя). Это остаётся справедливым и при поворотах телефона.
Когда телефон неподвижен,
Таким образом, оказывается, например, если телефон лежит на горизонтальной поверхности неподвижно, экраном вверх, показания
Мы реализовали процедуру получения данных с
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;
using Microsoft.Devices.Sensors;
namespace P6_1
{
/// <summary>
/// Это главный тип игры
/// </summary>
public class Game1 : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
//Строка для вывода
string text;
//Для хранения позиции вывода текста
Vector2 textPosition=new Vector2(100,100);
//Для хранения шрифта
SpriteFont MyFont;
//Показатели акселерометра
Vector3 accVector;
//Акселерометр
Accelerometer accelerometer;
//Объект для блокировки
object accLock = new object();
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()
{
//Новый объект для работы с акселерометром
accelerometer = new Accelerometer();
//Задаем время обновления
accelerometer.TimeBetweenUpdates = TimeSpan.FromMilliseconds(1000);
//Подключаем обработчик события
accelerometer.CurrentValueChanged += new EventHandler<SensorReadingEventArgs
<AccelerometerReading>>(accelerometer_CurrentValueChanged);
//Пытаемся запустить акселерометр
try
{
accelerometer.Start();
}
catch
{
}
base.Initialize();
}
//Обработчик события акселерометра
void accelerometer_CurrentValueChanged(object sender, SensorReadingEventArgs<AccelerometerReading> e)
{
//Блокировка обеспечивает получение данных акселерометра в одном потоке
lock (accLock)
{
//Получаем данные
accVector = e.SensorReading.Acceleration;
}
}
///// <summary>
/// LoadContent будет вызываться в игре один раз; здесь загружается
/// весь контент.
/// </summary>
protected override void LoadContent()
{
// Создайте новый SpriteBatch, который можно использовать для отрисовки текстур.
spriteBatch = new SpriteBatch(GraphicsDevice);
//Загружаем шрифт
MyFont = Content.Load<SpriteFont>("MyFont");
}
/// <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();
//Блокировка обеспечивает чтение данных в одном потоке
lock (accLock)
{
//Записываем в строку для вывода строковое представление
//данных, полученных с акселерометра
text = accVector.ToString();
}
base.Update(gameTime);
}
/// <summary>
/// Вызывается, когда игра отрисовывается.
/// </summary>
/// <param name="gameTime">Предоставляет моментальный снимок значений времени.</param>
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
spriteBatch.Begin();
//Выводим строку
spriteBatch.DrawString(MyFont, text, textPosition, Color.Red,
0, new Vector2(0,0), 1.0f, SpriteEffects.None, 0.5f);
spriteBatch.End();
base.Draw(gameTime);
}
}
}
Рассмотрим ключевые моменты этого кода. Здесь мы собираемся вывести значение показаний accVector типа Vector3. Получение данных Update данных из переменной accVector, которые принадлежат различным результатам измерений показаний lock, критически важные операции, в нашем случае это – установка переменной accVector в обработчике события accelerometer_CurrentValueChanged и в методе Update.
В методе Initialize мы создаем новый объект типа , устанавливаем его параметр TimeBetweenUpdates, равный 1000 миллисекунд, то есть показатели
Для получения данных с CurrentValueChanged, которое происходит при поступлении новых данных с устройства. Этот обработчик реализован процедурой accelerometer_CurrentValueChanged, здесь мы получаем данные (они представлены в виде трёхмерного вектора) и записываем их в переменную accVector.
Прежде чем использовать Start() объекта . Попытка исполнить этот метод связана с работой с физическим устройством, здесь возможны ошибки, поэтому мы заключаем эту попытку в конструкцию try {} catch {}. Здесь можно настроить поведение программы в том случае, если данная попытка не удастся, то есть,
В методе Update мы приводим содержимое переменной accVector к текстовому виду и записываем полученную строку в переменную text, текст, содержащийся в которой, выводим на экран в методе Draw.
Запуск программы на реальном устройстве, рис. 12.3. позволит лучше понять, как именно работает
(рис 12.3) Показания акселерометра, устройство лежит на горизонтальной поверхности
Приложения, использующие физические
Запустим программу в эмуляторе, в панели инструментов эмулятора нажмем на кнопку >>, появится окно Дополнительные инструменты, в котором на вкладке
(рис 12.4) Эмуляция показаний акселерометра
Перемещать трехмерную модель телефона можно с помощью изменения положения красной точки с помощью мыши. Вот, например (рис. 12.5), как в эмуляторе выглядит положение телефона, похожее на то, в котором было сфотографировано устройство на рис. 12.3.
(рис 12.5) Эмуляция показаний акселерометра
В поле Ориентация в окне Дополнительные инструменты можно выбирать из нескольких предустановленных ориентаций устройства в пространстве.
В поле Записанные данные можно выбрать набор записанных данных Shake, эмулирующих тряску телефона, и, нажав на Воспроизведение, понаблюдать в окне эмулятора за реакцией программы на эти данные. Изображение телефона при воспроизведении данных не перемещается.
Рассмотрим пример, в котором показания
Сущность данного примера заключается в следующем. Мы получаем показания
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 P6_2
{
/// <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;
sprMove.X = 0;
}
if (sprPosition.X > scrBounds.Width - sprRectangle.Width)
{
sprPosition.X = scrBounds.Width - sprRectangle.Width;
sprMove.X = 0;
}
if (sprPosition.Y < scrBounds.Top)
{
sprPosition.Y = scrBounds.Top;
sprMove.Y = 0;
}
if (sprPosition.Y > scrBounds.Height - sprRectangle.Height)
{
sprPosition.Y = scrBounds.Height - sprRectangle.Height;
sprMove.Y = 0;
}
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;
//Ограничиваем скорость 5-ю пикселями
if (sprMove.X > 5) { sprMove.X = 5; }
if (sprMove.X < -5) { sprMove.X = -5; }
if (sprMove.Y > 5) { sprMove.Y = 5; }
if (sprMove.Y < -5) { sprMove.Y = -5; }
}
}
}
Здесь мы используем для установки двумерного вектора, задающего направление и скорость перемещения Move. В этот метод передаются данные, полученные с sprMove. Положительные значения увеличивают скорость
В процедуре Update мы прибавляем к позиции sprMove. Кроме того, мы контролируем пересечение объектом границ экрана. Если объект пересек границу, мы возвращаем его к границе и сбрасываем соответствующий показатель вектора sprMove, устанавливая скорость движения
Рассмотрим основной игры, листинг 12.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;
using Microsoft.Devices.Sensors;
namespace P6_2
{
/// <summary>
/// Это главный тип игры
/// </summary>
public class Game1 : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
spriteComp gameObject;
Texture2D texture;
//Показатели акселерометра
Vector3 accVector;
//Акселерометр
Accelerometer accelerometer;
//Блокировка
object accLock = new object();
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
//Задаем параметры экрана
graphics.PreferredBackBufferWidth = 800;
graphics.PreferredBackBufferHeight = 480;
//Фиксируем положение экрана
graphics.SupportedOrientations = DisplayOrientation.LandscapeLeft;
//Отображение игрового окна на полный экран, без строки состояния
graphics.IsFullScreen = true;
// Частота кадра на Windows Phone по умолчанию — 30 кадров в секунду.
TargetElapsedTime = TimeSpan.FromTicks(333333);
// Дополнительный заряд аккумулятора заблокирован.
InactiveSleepTime = TimeSpan.FromSeconds(1);
}
/// <summary>
/// Позволяет игре выполнить инициализацию, необходимую перед запуском.
/// Здесь можно запросить нужные службы и загрузить неграфический
/// контент. Вызов base.Initialize приведет к перебору всех компонентов и
/// их инициализации.
/// </summary>
protected override void Initialize()
{
accelerometer = new Accelerometer();
accelerometer.TimeBetweenUpdates = TimeSpan.FromMilliseconds(20);
accelerometer.CurrentValueChanged += new EventHandler<SensorReadingEventArgs
<AccelerometerReading>>(accelerometer_CurrentValueChanged);
try
{
accelerometer.Start();
}
catch
{
}
base.Initialize();
}
void accelerometer_CurrentValueChanged(object sender, SensorReadingEventArgs<AccelerometerReading> e)
{
lock (accLock)
{
accVector = e.SensorReading.Acceleration;
}
}
///// <summary>
/// LoadContent будет вызываться в игре один раз; здесь загружается
/// весь контент.
/// </summary>
protected override void LoadContent()
{
// Создайте новый SpriteBatch, который можно использовать для отрисовки текстур.
spriteBatch = new SpriteBatch(GraphicsDevice);
Services.AddService(typeof(SpriteBatch), spriteBatch);
texture = Content.Load<Texture2D>("BallandBats");
CreateNewObject();
}
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();
lock (accLock)
{
gameObject.Move(new Vector2(-accVector.Y, -accVector.X));
}
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();
}
}
}
Этот код похож на тот, который мы рассматривали в предыдущем примере. Здесь мы, однако, внесли некоторые изменения. Так, в конструкторе класса мы, используя команды graphics.PreferredBackBufferWidth = 800 и graphics.PreferredBackBufferHeight = 480 в явном виде задали ширину и высоту игрового экрана, кроме того, мы зафиксировали положение экрана в левосторонней ландшафтной ориентации командой graphics.SupportedOrientations = DisplayOrientation.LandscapeLeft. Результат этой команды заключается в том, что при повороте экрана не меняется автоматически его ориентация.
Код работы с акселерометром в данном примере тот же, что и в предыдущем. Главная разница заключается в том, что в методе Update мы вызываем метод Move() игрового объекта и передаем ему последние измеренные значения по осям X и Y, полученные с
На рис. 12.6 вы можете видеть результат запуска программы в эмуляторе.
(рис 12.6) Результаты запуска программы в эмуляторе
В этой лабораторной работе была рассмотрена методика получения и обработки показаний
Реализуйте управление экранным объектом с использованием
К данной лабораторной работе прилагается видеоурок
и демонстрационный проект.
Для получения официальных документов о завершении программы дополнительного профессионального образования (удостоверения о повышении квалификации, дипломов о профессиональной переподготовке и MBA) необходимо предоставить:
Внимание! Вы можете не заказывать доставку бумажной версии официального документы, а скачать его в электронном виде и распечатать самостоятельно. Информация о выданном документе в течение 1 месяца загружается в Федеральную информационную систему «Федеральный реестр сведений о документах об образовании и (или) о квалификации, документах об обучении» - ФИС ФРДО.
Доступ на новый сайт осуществляется с использованием адреса электронной почты, который был указан вами при регистрации на "старом". Мы постарались перенести все ваши данные с прежнего ресурса, однако не исключена вероятность потери части информации.
При возникновении проблемы со входом, воспользуйтесь функцией сброса пароля
Если вы обнаружите несоответствия, пожалуйста, сообщите нам.