Моделирование нивелира (XNA)
Дополнительные материалы к занятию можно скачать
здесь.
При производстве различных строительных работ часто используется инструмент ватерпас, или нивелир, в котором по положению пузырька воздуха в жидкости можно судить о горизонтальности поверхности. В книге Чарльза Петзолда [25] описывается приложение XNA, моделирующее поведение пузырька воздуха в жидкости в зависимости от положения устройства. Предлагается воспроизвести этот проект.
Итак, вначале создаем новое приложение Practice_18 XNA Windows Phone 7.
Далее, необходимо добавить к проекту папку Images.
Затем вставляем в эту папку картинку, имитирующую пузырек Bubble.bmp, после чего подключаем эту картинку к проекту:
Затем подключаем библиотеку Microsoft.Devices.Sensors
Далее, требуется изменить файл Game1.cs:
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 Practice_18
{
public class Game1 : Microsoft.Xna.Framework.Game
{
const float BUBBLE_RADIUS_MAX = 25;
const float BUBBLE_RADIUS_MIN = 12;
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
Vector2 screenCenter;
float screenRadius;
Texture2D bubbleTexture;
Vector2 bubbleCenter;
Vector2 bubblePosition;
float bubbleScale;
Vector3 accelerometerVector;
object accelerometerVectorLock = new object();
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
TargetElapsedTime = TimeSpan.FromTicks(333333);
}
protected override void Initialize()
{
Accelerometer accelerometer = new Accelerometer();
accelerometer.ReadingChanged += OnAccelerometerReadingChanged;
try
{
accelerometer.Start();
}
catch
{
}
base.Initialize();
}
protected override void LoadContent()
{
spriteBatch = new SpriteBatch(GraphicsDevice);
Viewport viewport = this.GraphicsDevice.Viewport;
screenCenter = new Vector2(viewport.Width / 2, viewport.Height / 2);
screenRadius = Math.Min(screenCenter.X, screenCenter.Y) - BUBBLE_RADIUS_MAX;
bubbleTexture = this.Content.Load<Texture2D>("Images/Bubble");
bubbleCenter = new Vector2(bubbleTexture.Width / 2, bubbleTexture.Height / 2);
}
void OnAccelerometerReadingChanged(object sender, AccelerometerReadingEventArgs args)
{
lock (accelerometerVectorLock)
{
accelerometerVector = new Vector3((float)args.X, (float)args.Y,
(float)args.Z);
}
}
protected override void UnloadContent()
{
}
protected override void Update(GameTime gameTime)
{
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
this.Exit();
Vector3 accVector;
lock (accelerometerVectorLock)
{
accVector = accelerometerVector;
}
bubblePosition = new Vector2(screenCenter.X + screenRadius * accVector.Y,
screenCenter.Y + screenRadius * accVector.X);
float bubbleRadius = BUBBLE_RADIUS_MIN + (1 - accVector.Z) / 2 *
(BUBBLE_RADIUS_MAX - BUBBLE_RADIUS_MIN);
bubbleScale = bubbleRadius / (bubbleTexture.Width / 2);
base.Update(gameTime);
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.Navy);
spriteBatch.Begin();
spriteBatch.Draw(bubbleTexture, bubblePosition, null, Color.White, 0,
bubbleCenter, bubbleScale, SpriteEffects.None, 0);
spriteBatch.End();
base.Draw(gameTime);
}
}
}
Листинг
.
Метод LoadContent загружает растровое изображение, используемое для моделирования нивелира. Метод Update осуществляет доступ к вектору акселерометра и вычисляет положение "пузырька" на основании компонентов X и Y. На основании величины Z вычисляется масштаб "пузырька", имитируя отображение реального пузырька при различном положении резервуара с жидкостью.




