今年上半年,微软Silverlight5 Beta发布,随之而来的是更多的惊喜与更加亮眼的新特性。
其中最令我在意的一点便是针对Xna 3D API的支持,虽然目前Silverlight5 Beta版中的Xna还只是完整Xna框架中的一个轻量子集,但自此之后web3D已再不是遥不可及的抽象概念~
本节我们就以一个古老的三段式框架为例,看Silverlight如何帮我们将Xna实实在在的嵌入到网页中 ^ ^
Silverlight中Xna 3D API的调用,以硬件加速为起始,以DrawingSurface为基础容器,因此我们首先要做的便是对这两者的显示支持。
1.在宿主网页中添加硬件加速支持。只需在Silverlight插件标签内嵌入如下代码即可 ^ ^
<
param
name
="EnableGPUAcceleration"
value
="true"
/>
2.Silverlight主页面MainPage.xaml中添加一个DrawingSurface元素。
<
Grid
x:Name
="LayoutRoot"
Background
="White"
>
<
DrawingSurface
Name
="_GameSurface"
/>
</
Grid
>
之后,只需为我们的_GameSurface注册一个Draw事件,便可在其函数体中获取3D设备并进行绘制了,相应方法的调用几乎跟Xna环境下一模一样。就好像下面这样:
void
_GameSurface_Draw(
object
sender, DrawEventArgs e)
{
//
清空渲染表面
e.GraphicsDevice.Clear(ClearOptions.Target
|
ClearOptions.DepthBuffer,
Color.Transparent,
1.0f
,
0
);
//
绘制图形
e.GraphicsDevice.DrawPrimitives(PrimitiveType.TriangleList,
0
,
1
);
//
强制重绘
e.InvalidateSurface();
}
用过Xna的朋友,看上面的代码是不是感觉挺眼熟?呵呵~
这里,为提高代码的重用性,我们仿Xna下的Game类,创建一个专属于Silverlight环境的SilverGame~
/*
-------------------------------------
代码清单:SilverGame.cs
来自:
http://www.cnblogs.com/kenkao
-------------------------------------
*/
using
System;
using
System.Net;
using
System.Windows;
using
System.Windows.Controls;
using
System.Windows.Documents;
using
System.Windows.Ink;
using
System.Windows.Input;
using
System.Windows.Media;
using
System.Windows.Media.Animation;
using
System.Windows.Shapes;
using
Microsoft.Xna.Framework;
using
Microsoft.Xna.Framework.Graphics;
using
Microsoft.Xna.Framework.Silverlight;
namespace
Microsoft.Xna.Framework
{
public
class
SilverGame
{
///
<summary>
///
初始GraphicsDeviceManager
///
</summary>
public
GraphicsDeviceManager Graphics
{
get
{
return
GraphicsDeviceManager.Current;
}
}
///
<summary>
///
Xna3D图形设备GraphicsDevice
///
</summary>
GraphicsDevice _GraphicsDevice;
public
GraphicsDevice GraphicsDevice
{
get
{
if
(_GraphicsDevice
==
null
)
return
GraphicsDeviceManager.Current.GraphicsDevice;
else
return
_GraphicsDevice;
}
set
{
_GraphicsDevice
=
value;
}
}
///
<summary>
///
渲染表面尺寸
///
</summary>
Vector2 _ActualSize;
public
Vector2 ActualSize
{
get
{
return
_ActualSize;
}
set
{
_ActualSize
=
value;
}
}
///
<summary>
///
渲染表面DrawingSurface
///
</summary>
DrawingSurface _GameSurface;
public
DrawingSurface GameSurface
{
get
{
return
_GameSurface; } }
///
<summary>
///
重置GraphicsDevice
///
</summary>
///
<param name="graphicsDevice"></param>
void
ResetDevice(GraphicsDevice graphicsDevice)
{ _GraphicsDevice
=
graphicsDevice; }
///
<summary>
///
重置渲染表面尺寸
///
</summary>
///
<param name="actualSize"></param>
void
ResetActualSize(Vector2 actualSize)
{ _ActualSize
=
actualSize; }
///
<summary>
///
构造方法
///
</summary>
///
<param name="GameSurface">
所关联的渲染表面
</param>
public
SilverGame(DrawingSurface GameSurface)
{
_GameSurface
=
GameSurface;
_ActualSize
=
new
Vector2((
float
)_GameSurface.ActualWidth, (
float
)_GameSurface.ActualHeight);
//
自动为渲染表面关联必要的事件
_GameSurface.Loaded
+=
new
RoutedEventHandler(_GameSurface_Loaded);
_GameSurface.Unloaded
+=
new
RoutedEventHandler(_GameSurface_Unloaded);
_GameSurface.Draw
+=
new
EventHandler
<
DrawEventArgs
>
(_GameSurface_Draw);
_GameSurface.SizeChanged
+=
new
SizeChangedEventHandler(_GameSurface_SizeChanged);
//
虚函数调用——初始化
this
.Initialize();
}
void
_GameSurface_Loaded(
object
sender, RoutedEventArgs e)
{
//
虚函数调用——加载资源
this
.LoadContent();
}
void
_GameSurface_Unloaded(
object
sender, RoutedEventArgs e)
{
//
虚函数调用——释放资源
this
.UnloadContent();
}
void
_GameSurface_SizeChanged(
object
sender, SizeChangedEventArgs e)
{
//
渲染表面大小改变时自动重置其尺寸
Size s
=
e.NewSize;
this
.ResetActualSize(
new
Vector2((
float
)s.Width, (
float
)s.Height));
}
void
_GameSurface_Draw(
object
sender, DrawEventArgs args)
{
//
重置图形设备
this
.ResetDevice(args.GraphicsDevice);
//
虚函数调用——更新
this
.Update(args.DeltaTime, args.TotalTime);
//
虚函数调用——渲染
this
.Draw(args.DeltaTime, args.TotalTime);
//
强制重绘
args.InvalidateSurface();
}
//
----一系列虚函数,供子类重写----
//
public
virtual
void
Initialize()
{ }
public
virtual
void
LoadContent()
{ }
public
virtual
void
UnloadContent()
{ }
public
virtual
void
Update(TimeSpan DeltaTime, TimeSpan TotalTime)
{ }
public
virtual
void
Draw(TimeSpan DeltaTime, TimeSpan TotalTime)
{ }
}
}
功能上还相当简单,不过没关系,后续我们会以它为基础,为整个工程添枝加叶 ^ ^
值得一提的是,SilverGame中对于已持有的Xna3D设备GraphicsDevice的处理方式。
工程构建之初,Silverlight体系会自动提供一个静态的图形设备,用于加载或生成诸如特效、纹理等资源,我们可以通过GraphicsDeviceManager.Current.GraphicsDevice获得。
而绘制过程中,处于DrawingSurface内部安全机制考虑,我们必须使用从事件体DrawEventArgs中获取的GraphicsDevice引用进行图形绘,如果此时再使用原来的静态设备进行绘制,将被视作非法操作~
SilverGame的处理方式使得这一过程对外透明化,用户通过GraphicsDevice属性获取到的图形设备将永远是合法的图形设备 ^ ^
SilverGame构建完毕之后,是工程范例的第三步:
3.引入SilverGame类,在此基础上派生其子类Game,作为游戏的主逻辑框架。
/*
-------------------------------------
代码清单:Game.cs
来自:
http://www.cnblogs.com/kenkao
-------------------------------------
*/
using
System;
using
System.Net;
using
System.Windows;
using
System.Windows.Controls;
using
System.Windows.Documents;
using
System.Windows.Ink;
using
System.Windows.Input;
using
System.Windows.Media.Imaging;
using
System.Windows.Media.Animation;
using
Microsoft.Xna.Framework;
using
Microsoft.Xna.Framework.Graphics;
using
Microsoft.Xna.Framework.Silverlight;
namespace
SilverXna
{
public
class
Game : SilverGame
{
public
Game(DrawingSurface GameSurface)
:
base
(GameSurface)
{ }
public
override
void
Initialize()
{
base
.Initialize();
}
public
override
void
LoadContent()
{
base
.LoadContent();
}
public
override
void
UnloadContent()
{
base
.UnloadContent();
}
public
override
void
Update(TimeSpan DeltaTime, TimeSpan TotalTime)
{
base
.Update(DeltaTime, TotalTime);
}
public
override
void
Draw(TimeSpan DeltaTime, TimeSpan TotalTime)
{
GraphicsDevice.Clear(ClearOptions.Target
|
ClearOptions.DepthBuffer,
new
Color(
100
,
149
,
237
,
255
),
1.0f
,
0
);
base
.Draw(DeltaTime, TotalTime);
}
}
}
与标准的Xna工程同样的处理手法,呵呵~ 之后是最后一步:
4.派生子类与主页面中的DrawingSurface进行关联~
/*
-------------------------------------
代码清单:MainPage.xaml.cs
来自:
http://www.cnblogs.com/kenkao
-------------------------------------
*/
using
System;
using
System.Collections.Generic;
using
System.Linq;
using
System.Net;
using
System.Windows;
using
System.Windows.Controls;
using
System.Windows.Documents;
using
System.Windows.Input;
using
System.Windows.Media.Animation;
using
System.Windows.Media.Imaging;
using
System.Windows.Shapes;
using
Microsoft.Xna.Framework;
using
Microsoft.Xna.Framework.Graphics;
using
Microsoft.Xna.Framework.Silverlight;
namespace
SilverXna
{
public
partial
class
MainPage : UserControl
{
Game _Game;
public
MainPage()
{
InitializeComponent();
_Game
=
new
Game(_GameSurface);
}
}
}
这样,一个无限复用的SilverXna框架就诞生了。结构仿Xna工程框架,古老而经典的三段式 ^ ^
来看效果:
久违了的那片蓝色,只不过宿主窗口已不再WinForm,而是实实在在的WebPage ^ ^
(注:如果看不到效果,请执行 右击--->Silverlight配置--->权限--->允许站点权限 即可)
最后再提醒大家一点,SilverXna工程中用到的一系列3D数据类型,需要微软官方提供的数学库最为基本支撑,后续的范例默认情况下都需要首先对其引入~
>> 以下点击下载:
http://files.cnblogs.com/kenkao/Microsoft.Xna.Framework.Math.rar
>> Silverlight5 Beta环境搭建资源及微软官方范例下载:
http://space.cnblogs.com/group/topic/47416/
以上,谢谢 ^ ^
==========================================================
后记:
Silverlight5 RC版于同一天发布,惊喜来的太快,令人措手不及 ^ ^
以下是本节SilverGame对象的更新版本:
SilverGame.cs
/*
-------------------------------------
代码清单:SilverGame.cs
来自:
http://www.cnblogs.com/kenkao
-------------------------------------
*/
using
System;
using
System.Net;
using
System.Windows;
using
System.Windows.Controls;
using
System.Windows.Documents;
using
System.Windows.Graphics;
using
System.Windows.Ink;
using
System.Windows.Input;
using
System.Windows.Media;
using
System.Windows.Media.Animation;
using
System.Windows.Shapes;
using
Microsoft.Xna.Framework;
using
Microsoft.Xna.Framework.Content;
using
Microsoft.Xna.Framework.Graphics;
namespace
Microsoft.Xna.Framework
{
public
class
SilverGame
{
///
<summary>
///
初始GraphicsDeviceManager
///
</summary>
public
GraphicsDeviceManager Graphics
{
get
{
return
GraphicsDeviceManager.Current;
}
}
///
<summary>
///
Xna3D图形设备GraphicsDevice
///
</summary>
GraphicsDevice _GraphicsDevice;
public
GraphicsDevice GraphicsDevice
{
get
{
return
GraphicsDeviceManager.Current.GraphicsDevice;
}
set
{
_GraphicsDevice
=
value;
}
}
ContentManager _Content;
public
ContentManager Content
{
get
{
return
_Content; } }
///
<summary>
///
渲染表面尺寸
///
</summary>
Vector2 _ActualSize;
public
Vector2 ActualSize
{
get
{
return
_ActualSize;
}
set
{
_ActualSize
=
value;
}
}
///
<summary>
///
渲染表面DrawingSurface
///
</summary>
DrawingSurface _GameSurface;
public
DrawingSurface GameSurface
{
get
{
return
_GameSurface; } }
///
<summary>
///
重置渲染表面尺寸
///
</summary>
///
<param name="actualSize"></param>
void
ResetActualSize(Vector2 actualSize)
{ _ActualSize
=
actualSize; }
///
<summary>
///
构造方法
///
</summary>
///
<param name="GameSurface">
所关联的渲染表面
</param>
public
SilverGame(DrawingSurface GameSurface)
{
_GameSurface
=
GameSurface;
_Content
=
new
ContentManager(
this
);
_ActualSize
=
new
Vector2((
float
)_GameSurface.ActualWidth, (
float
)_GameSurface.ActualHeight);
//
自动为渲染表面关联必要的事件
_GameSurface.Loaded
+=
new
RoutedEventHandler(_GameSurface_Loaded);
_GameSurface.Unloaded
+=
new
RoutedEventHandler(_GameSurface_Unloaded);
_GameSurface.Draw
+=
new
EventHandler
<
DrawEventArgs
>
(_GameSurface_Draw);
_GameSurface.SizeChanged
+=
new
SizeChangedEventHandler(_GameSurface_SizeChanged);
//
虚函数调用——初始化
this
.Initialize();
}
void
_GameSurface_Loaded(
object
sender, RoutedEventArgs e)
{
//
虚函数调用——加载资源
this
.LoadContent();
}
void
_GameSurface_Unloaded(
object
sender, RoutedEventArgs e)
{
//
虚函数调用——释放资源
this
.UnloadContent();
}
void
_GameSurface_SizeChanged(
object
sender, SizeChangedEventArgs e)
{
//
渲染表面大小改变时自动重置其尺寸
Size s
=
e.NewSize;
this
.ResetActualSize(
new
Vector2((
float
)s.Width, (
float
)s.Height));
}
void
_GameSurface_Draw(
object
sender, DrawEventArgs args)
{
//
虚函数调用——更新
this
.Update(args.DeltaTime, args.TotalTime);
//
虚函数调用——渲染
this
.Draw(args.DeltaTime, args.TotalTime);
//
强制重绘
args.InvalidateSurface();
}
//
----一系列虚函数,供子类重写----
//
public
virtual
void
Initialize()
{ }
public
virtual
void
LoadContent()
{ }
public
virtual
void
UnloadContent()
{ }
public
virtual
void
Update(TimeSpan DeltaTime, TimeSpan TotalTime)
{ }
public
virtual
void
Draw(TimeSpan DeltaTime, TimeSpan TotalTime)
{ }
}
}
更新说明:
1.原有的基于DrawingSurface的GraphicsDevice安全机制消除,统一由GraphicsDeviceManager.Current.GraphicsDevice获取即可。
2.片尾列出的dll库无需再从外部引用,直接由Silverlight系统环境即可找到该程序集。
3.命名空间有变动,取消了Microsoft.Xna.Framework.Silverlight明明空间,添加了System.Windows.Xna程序集。
4.其他变动请参见Silverlight RC官方的最新说明文档~