Windows Phone 7 Accelerometer Bubble Level 详解

                                                    Windows Phone 7 Accelerometer Bubble Level 详解

 

 

你可以在这里下载例子:

http://rorger.download.csdn.net/

 

最近在看Charles Petzold的一书,看到第5章的Accelerometer就卡住了,

因为之前没有接触过这类东西。

protected override void Update(GameTime gameTime) { // Allows the game to exit if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed) this.Exit(); Vector3 accVector; lock (accelerometerVectorLock) { accVector = accelerometerVector; } int sign = this.Window.CurrentOrientation == DisplayOrientation.LandscapeLeft ? 1 : -1; bubblePosition = new Vector2(screenCenter.X + sign * screenRadius * accVector.Y, screenCenter.Y + sign * 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); Viewport viewport = this.GraphicsDevice.Viewport; textPosition = new Vector2((viewport.Width - textSize.X) / 2, (viewport.Height - textSize.Y) / 2); }

 

其实最核心的内容就是这里了吧;

 int sign = this.Window.CurrentOrientation ==
                                            DisplayOrientation.LandscapeLeft ? 1 : -1;
           
            bubblePosition = new Vector2(screenCenter.X + sign * screenRadius * accVector.Y,
                                         screenCenter.Y + sign * screenRadius * accVector.X);

            float bubbleRadius = BUBBLE_RADIUS_MIN + (1 - accVector.Z) / 2 *
                                    (BUBBLE_RADIUS_MAX - BUBBLE_RADIUS_MIN);

 

accelemeroter 一下简称 acc

当手机向左旋转时,sign = 1 ;

acc(-1,0,0)

 

bubblePosition = (screenCenter.X + 0 ,screenCenter.Y + screenRadius * (-1)) ; //横坐标为中间,纵坐标为顶端

bubbleRadius = BUBBLE_RADIUS_MIN + (1 - 0) / 2 *(BUBBLE_RADIUS_MAX - BUBBLE_RADIUS_MIN);

//半径为MIN+1/2 (MAX-MIN);

 

 

当手机向右时,sing=-1;

acc(1,0,0)

bubblePosition = new Vector2(screenCenter.X + sign * screenRadius * accVector.Y, 
                            screenCenter.Y + sign * screenRadius * accVector.X)

                        =  (screenCenter.X+0,

                              screenCenter.Y+(-1)*screenRadius*1)

                        = (screenCenter.X,screenCenter.Y-screenRadius); //横坐标为中间screenCenter.X,纵坐标为顶端:screenCenter.Y-screenRadius

bubbleRadius=MIN+(1-0)/2 * (MAX-MIN) ;

 

 

 

(当手机向上,由于默认没有开启portraitup方向支持时,手机屏幕坐标是这样的:右上角为原点,x从上到下递增,y从右到左递增,更好的理解是:坐标和LandScapeLeft时一样,x从左到右递增,y从上到下递增;但是奇怪的事情发生了,如果手机转到LandScapeRight位置再转到portraitup时,坐标和LandScapeRight一样)

 

附上 图:

 

 Windows Phone 7 Accelerometer Bubble Level 详解_第1张图片

当手机向上时,sign = ?;

我为什么用?

因为sign的值有两种可能,如果是程序刚刚开始的话或这你由LandScapeLeft转向PortraitUp,而你的手机是portraitup,那么sign的值为1,相当于LandScapeLeft

acc(0,-1,0) //这个还是不变的

 bubblePosition = new Vector2(screenCenter.X + sign * screenRadius * accVector.Y,
screenCenter.Y + sign * screenRadius * accVector.X)

                         = (screenCenter.X + 1 * screenRadius * (-1),

                              screenCenter.Y + 1 * screenRadius * 0)

                         = (screenCenter.X-screenRadius,

                              screenCenter.Y );

bubbleRadius = MIN + 1/2 * (MAX-MIN);

                            //想象下,如果是LandScapeLeft,那么是左边中间,在Portrait位置看来就是顶端中间

 

 

 

如果你由LandScapeRight转向portraitup

sign=-1; //因为手机内部还是LandScapeRight方向.

acc(0,-1,0) //这个还是不变的

bubblePosition = new Vector2(screenCenter.X + sign * screenRadius * accVector.Y,
screenCenter.Y + sign * screenRadius * accVector.X)

                        = (screenCenter.X  + (-1)*screenRadius*(-1),

                             screenCenter.Y +0)

                        = (screenCenter.X+screenRadius,

                             screenCenter.Y)

bubbleRadius = MIN + 1/2 * (MAX-MIN);

 

//如果从LandScapeRight位置考虑,是右端中间,在PortraitUp位置看,那么就是顶端中间。

 

 

 

//如果是手机水平放置的话,面朝上

sign=?

///也就是说有可能是1和-1,道理同上

 

 

acc=(0,0,-1)

不管是1或者-1,由于x和y都是0;

所以有

bubblePosition = new Vector2(screenCenter.X + sign * screenRadius * accVector.Y,
screenCenter.Y + sign * screenRadius * accVector.X)

                        = (screenCenter.X + 0, screenCenter.Y + 0);

                        = (screenCenter.X,screenCenter.Y);

 

float bubbleRadius = BUBBLE_RADIUS_MIN + (1 - accVector.Z) / 2 *
(BUBBLE_RADIUS_MAX - BUBBLE_RADIUS_MIN);

                              = MIN + (1-(-1))/2*(MAX-MIN)

                              =MAX   //这是球的半径最大

 

//如果手机水平方式,面朝下,也许你把它举过头顶是个不错的主意

acc=(0,0,1)

 

bubblePosition = new Vector2(screenCenter.X + sign * screenRadius * accVector.Y,
screenCenter.Y + sign * screenRadius * accVector.X)

= (screenCenter.X + 0, screenCenter.Y + 0);

= (screenCenter.X,screenCenter.Y);

 

float bubbleRadius = BUBBLE_RADIUS_MIN + (1 - accVector.Z) / 2 *
(BUBBLE_RADIUS_MAX - BUBBLE_RADIUS_MIN);

= MIN + (1-1))/2*(MAX-MIN)

=MIN //这是球的半径最小

 

 

至此,关键的位置都已经具体讨论了;可是我的问题是,Charles Petzold 这个guy为什么这么写,我心好痒痒,好痒痒;

我想说一下的思路,他把球的活动范围限制在了正方形中,也许是为了方便吧,因为如果活动范围是整个屏幕,要去判断大小,而且对于例子展示没有什么益处。

然后主要就是

 

       bubblePosition的计算了:

bubblePosition = new Vector2(screenCenter.X + sign * screenRadius * accVector.Y,
screenCenter.Y + sign * screenRadius * accVector.X)

 

作者说:在计算X坐标的时候,使用到了accVector.Y,这看似弄混了,其实这是由于默认的屏幕方向在XNA中是portrait,这和acceleration vector是相反的。

注意:好好理解这句话吧:拿起手机(没有的也要想象),portraitup,然后伸出右手,做出右手坐标的手势。

手机和手一同逆时针旋转90度,看看,看看,看看吧;对于手机屏幕,x坐标是从左到右递增,而你的中指方向(代表向量y分量)和x坐标是相反的;手机屏幕y坐标是从上到下递增的,而你的食指方向(代表x分量)和y坐标是相反的。

自此,问题基本得到解决;

 

其实我还有这么一个最后的疑问,就是其它方向呢?作者到底是怎么想到用这种方式的呢?

要计算position,必须有参考点(screenCenter.X,screenCenter.Y)

然后必须计算移动的分量,该怎么计算移动分量呢?

比如x坐标方向,从左到右的变化范围是(screenCenter.X-screenRadius,screenCenter.X + screenRadius);

而accVector.Y的变化范围基本是 [-1,1]  (不过说实话,还可以大于1,小于-1)

刚刚好可以这样:

           screenCenter.X+accvector.Y*screenRadius

 

同理对于y坐标方向,变化范围是(screenCenter.Y-screenRadius,screenCenter.Y+screenRadius) 

     可以这样表示:      screenCenter.Y+accVector.X*screenRadius

但是这够了吗?

          

          对于LandScapeLeft情况,计算出来的坐标是(screenCenter.X,screenCenter.Y-screenRadius)满足;

          对于LandScapeRight情况,计算出来的坐标是(screenCenter.X,screenCenter.Y+screenRadius),不满足;

      其实可以知道,LandScapeLeft和LandScapeRight时,x坐标是符号相反,绝对值相等;

      要想两种方式有相同的显示效果,那么其中一个变号就可以了;显然是LandScapeRight时变号。

自此,搞定sign

 

 

原来我的不厌其烦,我对bubbleRadius的大小还是有疑问,作者怎么就知道这么写呢?

 

        float bubbleRadius = BUBBLE_RADIUS_MIN + (1 - accVector.Z) / 2 *
                                    (BUBBLE_RADIUS_MAX - BUBBLE_RADIUS_MIN);

 

这一行看似简单的代码对我这种粗人还是有些好理解,但是不知道为什么????

       

       思路:远的时候,最小;近的时候,最大。当水平朝上,最大,水平朝下,最小。近者大,而远者小。

                               MIN                  MAX

                中间的时候呢?    MIN+1/2(MAX-MIN) ;

                其它情况呢?

                变化范围:[MIN,MAX]

                由于  accVector.Z的变化范围是[-1,1];

                        但是我们想用的是-accVector.Z ,因为水平朝上时,z为-1,而球最大,故而用其反。

                那么就是  MIN+1/2(MAX-MIN) - accVector.Z*1/2*(MAX-MIN)

                           = MIN + (1-accVector.Z)*1/2*(MAX-MIN)

                           = MIN + (1-accVector.Z)/2*(MAX-MIN)   //窃笑,不知道有没有更简单的理解

 

这个代码挺疯狂的吧,或者是我太笨了,不过终究懂了。

先找范围,再找关系,最后化简;

 

 

酝酿了一周了:

        XNA屏幕坐标 ,y从上到下,x从左到右递增;

        当PortraitUP时,accelerometer坐标是右手坐标,手机旋转,坐标系也旋转。

 

 

后记:我想要全屏幕,以及我想把球的运动范围扩展到全屏幕,而不是正方形块中:

 

 

在设置IsFullScreen时要注意:不要在构造函数中设置,在Initialize函数中设置,否则会出现 accelrometer读取错误问题,在真机上尝试验证。

 

protected override void Initialize() { // TODO: Add your initialization logic here Accelerometer acc = new Accelerometer(); acc.ReadingChanged += new EventHandler<AccelerometerReadingEventArgs>(OnAccelerometerReadingChanged); try { acc.Start(); ; } catch (System.Exception ex) { } this.graphics.IsFullScreen = true; base.Initialize(); }

 

 

为windows增加  Vector2 screenRadius;

在LoadContent()函数中:增加

 screenRadius.X = screenCenter.X - BUBBLE_RADIUS_MAX;
            screenRadius.Y = screenCenter.Y - BUBBLE_RADIUS_MAX;

 

在Update函数中:

     bubblePosition.X = (screenCenter.X + screenRadius.X * acclerometer.Y * sign);
            bubblePosition.Y = (screenCenter.Y + screenRadius.Y * acclerometer.X * sign);

 

 

顺带更改图片:

 

 

 

 

你可以试试这个图片,蛮可爱的:

 

 

 

 

这要求你把背景的刷新颜色设置为黑色:

在draw()的 clear函数中:

GraphicsDevice.Clear(Color.Black);

 

 

protected override void Draw(GameTime gameTime) { GraphicsDevice.Clear(Color.Black); // TODO: Add your drawing code here spriteBatch.Begin(); spriteBatch.Draw(bubbleTexture, bubblePosition, null, Color.White, 0, bubbleCenter, scale, SpriteEffects.None, 0); spriteBatch.End(); base.Draw(gameTime); }

 

 

 

你可以在这里下载例子:

http://rorger.download.csdn.net/

 

 

 

你可能感兴趣的:(windows,vector,活动,手机,float,phone,initialization)