摘要: 当用户选择本地模型,应用程序导航到GamePage页面,用Silverlight内容来显示XNA模型。本次任务将演示如何创建Silverlight/XNA混合应用程序......
当用户选择本地模型,应用程序导航到GamePage页面,用Silverlight内容来显示XNA模型。本次任务将演示如何创建Silverlight/XNA混合应用程序。 实现整合功能的关键组件是SharedGraphicsDeviceManager类,该类让应用程序开发者使用XNA绘制的直接模式来代替Silverlight绘制的保留模式。 当您安装WindowsPhone Development Tools,两个工程模板支持Silverlight/XNA混合模式的应用程序,SilverlightforWindowsPhone文件夹下的Windows Phone 3D Graphics Application模板和XNAGameStudio4.0文件夹下的WindowsPhoneRichGraphicsApplication(4.0)模板。 提示:这些模板在标准的Windows Phone Application模板基础上增加了一些小的改进。首先在App.xaml.cs中声明SharedGraphicsDeviceManager变量;其次,App类实现IServiceProvider接口为了模拟纯粹XNA应用程序的行为。IServiceProvider.GetService方法返回存在于ApplicationLifetimeObjects集合中的对象。 1. 为了在Silverlight页面中,显示3D XNA模型。打开GamePage.xaml.cs文件,添加OnNavigatedTo方法: C# protectedoverridevoidOnNavigatedTo(NavigationEventArgse) { //SetthesharingmodeofthegraphicsdevicetoturnonXNArendering SharedGraphicsDeviceManager.Current.GraphicsDevice.SetSharingMode(true); base.OnNavigatedTo(e); } 2. 只有这一页需要XNA渲染,因此你需要在离开该页面前关闭XNA渲染。添加OnNavigatedFrom方法: C# protectedoverridevoidOnNavigatedFrom(NavigationEventArgse) { //SetthesharingmodeofthegraphicsdevicetoturnoffXNArendering SharedGraphicsDeviceManager.Current.GraphicsDevice.SetSharingMode(false); base.OnNavigatedFrom(e); } 3. 通过SharedGraphicsDeviceManager的操作打开XNA渲染模式,让操作系统使用XNA渲染取代Silverlight渲染,但是不需要实际打开XNA游戏循环。Windows Phone Mango使用GameTimer类,用来运行XNA引擎并将一些标准的Microsoft.Xna.Framework.Game生命周期方法作为事件暴露出来,使你的应用程序可以被控制。 在绘制任何XNA内容之前,你不得不创建GameTimer类型,并启动游戏引擎。在GamePage类中,声明GameTimer的变量timer。 C# publicpartialclassGamePage:PhoneApplicationPage { GameTimertimer; … } 找到GamePage构造函数,创建实际的对象,注册Update和Draw事件。设置GameTimer的UpdateInterval属性,指定触发Update事件的时间间隔,设备触发Draw事件的时间间隔与此相同。 C# publicGamePage() { InitializeComponent(); //Createatimerforthispage timer=newGameTimer(); timer.UpdateInterval=TimeSpan.FromTicks(333333); timer.Update+=timer_Update; timer.Draw+=timer_Draw; } privatevoidtimer_Update(objectsender,GameTimerEventArgse) { } privatevoidtimer_Draw(objectsender,GameTimerEventArgse) { SharedGraphicsDeviceManager.Current.GraphicsDevice.Clear(Color.CornflowerBlue); } 4. 为了启动和关闭XNA引擎,在OnNavigatedTo方法中调用GameTimer的Start方法,在OnNavigatedFrom方法中调用Stop方法。 C# protectedoverridevoidOnNavigatedTo(NavigationEventArgse) { //SetthesharingmodeofthegraphicsdevicetoturnonXNArendering SharedGraphicsDeviceManager.Current.GraphicsDevice.SetSharingMode(true); //Startthegametimer timer.Start(); base.OnNavigatedTo(e); } protectedoverridevoidOnNavigatedFrom(NavigationEventArgse) { //Stopthegametimer timer.Stop(); //SetthesharingmodeofthegraphicsdevicetoturnoffXNArendering SharedGraphicsDeviceManager.Current.GraphicsDevice.SetSharingMode(false); base.OnNavigatedFrom(e); }
15. 在OnNavigatedTo方法中根据初始化xRotation和yRotation变量: C# protectedoverridevoidOnNavigatedTo(NavigationEventArgse) { … modelMetadata=app.ModelsStore[data["ID"]]; xRotation=modelMetadata.DefaultXRotation; yRotation=modelMetadata.DefaultYRotation; … } 16. 添加HandleInput方法读取用户输入到xRotation, yRotation, cameraFOV和prevLength变量中: C# privatevoidHandleInput() { while(TouchPanel.IsGestureAvailable) { GestureSamplegestureSample=TouchPanel.ReadGesture(); switch(gestureSample.GestureType) { caseGestureType.FreeDrag: xRotation+=gestureSample.Delta.X; yRotation-=gestureSample.Delta.Y; break; caseGestureType.Pinch: floatgestureValue=0; floatminFOV=80; floatmaxFOV=20; floatgestureLengthToZoomScale=10; Vector2gestureDiff=gestureSample.Position-gestureSample.Position2; gestureValue=gestureDiff.Length()/gestureLengthToZoomScale; if(null!=prevLength)//Skipthefirstpinchevent cameraFOV-=gestureValue-prevLength.Value; cameraFOV=MathHelper.Clamp(cameraFOV,maxFOV,minFOV); prevLength=gestureValue; break; caseGestureType.PinchComplete: prevLength=null; break; default: break; } } } 17. 编辑timer_Update方法来获取用户输入,并更新3D模型: C# privatevoidtimer_Update(objectsender,GameTimerEventArgse) { HandleInput(); floatyaw=MathHelper.Pi+MathHelper.PiOver2+xRotation/100;//rotationaroundthey-axis floatpitch=yRotation/100;//rotationaroundthex-axis floatfieldOfView=MathHelper.ToRadians(cameraFOV)/modelMetadata.FieldOfViewDivisor;//zoom … } 18. 在同一时间只有一个Readerer能够在屏幕上进行绘制。所以如果在你的应用程序中使用3D模型和其他XNA功能,那么XNA Renderer不会触发正规的Silverlight页面生命周期时间。Silverlight内容只是存在,但不会显示出来,因为XNA不会绘制它们。 XNA框架中使用一个新的对象来解决这个问题:UIElementRenderer。UIElementRenderer将Silverlight内容作为2D材质在XNA中显示,并且触发Silverlight事件。例如,当我们的用户触摸由UIElementRenderer生成的Silverlight按钮图片时,UIElementRenderer将会把输入信息传递给真实(不可见)的Silverlight按钮。 为了显示模型的名称和描述,使用UIElementRenderer来绘制Silverlight控件树。开始声明uiRenderer变量: C# publicpartialclassGamePage:PhoneApplicationPage { … UIElementRendereruiRenderer; … } 19. 为了展现整个控件树,当控件树改变时,你需要更新uiRenderer变量。在GamePage的LayoutUpdated事件中添加处理函数: C# publicGamePage() { … this.LayoutUpdated+=GamePage_LayoutUpdated; } privatevoidGamePage_LayoutUpdated(objectsender,EventArgse) { if(uiRenderer==null||LayoutRoot.ActualWidth>0&&LayoutRoot.ActualHeight>0) uiRenderer=newUIElementRenderer(LayoutRoot,(int)LayoutRoot.ActualWidth,(int)LayoutRoot.ActualHeight); } 20. XNA renderer只能在应用程序触发Draw事件之后,更新绘制。调用uiRenderer的Render方法来更新Silverlight UI,并在材质中进行重华。使用spriteBatch将材质绘制到屏幕上。 C# privatevoidtimer_Draw(objectsender,GameTimerEventArgse) { … //UpdatetheSilverlightUI uiRenderer.Render(); //Drawthesprite spriteBatch.Begin(); spriteBatch.Draw(uiRenderer.Texture,Vector2.Zero,Color.White); spriteBatch.End(); } 21. 最后,设置页面的DataContext,并添加GamePanel XAML可以绑定的所依赖的属性: C# publicGamePage() { … this.DataContext=this; } publicstringModelName { get{return(string)GetValue(ModelNameProperty);} set{SetValue(ModelNameProperty,value);} } //UsingaDependencyPropertyasthebackingstoreforModelName.Thisenablesanimation,styling,binding,etc... publicstaticreadonlyDependencyPropertyModelNameProperty= DependencyProperty.Register("ModelName",typeof(string),typeof(GamePage),null); publicstringModelDesc { get{return(string)GetValue(ModelDescProperty);} set{SetValue(ModelDescProperty,value);} } //UsingaDependencyPropertyasthebackingstoreforModelDesc.Thisenablesanimation,styling,binding,etc... publicstaticreadonlyDependencyPropertyModelDescProperty= DependencyProperty.Register("ModelDesc",typeof(string),typeof(GamePage),null); 22. 在OnNavigatedTo方法中,更新依赖属性值: C# protectedoverridevoidOnNavigatedTo(NavigationEventArgse) { … modelMetadata=app.ModelsStore[data["ID"]]; ModelName=modelMetadata.Name; ModelDesc=modelMetadata.Description; … } 23. 我们完成了本次动手实验。 |