Опубликован: 01.11.2011 | Уровень: специалист | Доступ: платный
Практическая работа 18:

Моделирование нивелира (XNA)

Аннотация: В данной работе мы разработаем модель нивелира, использующую методы OnAccelerometerReadingChanged и Update (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 вычисляется масштаб "пузырька", имитируя отображение реального пузырька при различном положении резервуара с жидкостью.


Игорь Белов
Игорь Белов
Россия, г. Ейск
Александр Гринёв
Александр Гринёв
Украина, Днепропетрвск, Шаг