引言
游戏中的主角是精灵,我们可以把游戏中的一切对象均视作精灵;玩家大部分时间都在操控着游戏中对象进行移动。因而本节我们要实现的功能只有一个:通过鼠标控制对象移动。
1.1通过Storyboard创建对象移动动画(交叉参考: 让物体动起来①)
在序言中我们讲解了如何通过VisualStudio2010创建一个Silverlight4项目,那么我们首先打开这个项目,并将MainPage.xaml中名为LayoutRoot的Grid换成Canvas。
Canvas顾名思义是画布的意思,它是游戏开发中性能最高且最易于用做对象布局及移动的容器控件。
接下来打开MainPage.xaml后台代码MainPage.xaml.cs,创建一个名为rectangle的矩形对象:
/// <summary>
/// 填充色为绿色,宽、高各50的矩形
/// </summary>
Rectangle rectangle = new Rectangle() {
Fill = new SolidColorBrush(Colors.Green),
Width = 50,
Height = 50
};
然后在MainPage初始化后将该矩形对象(rectangle)作为子控件添加到LayoutRoot画布中,并为LayoutRoot注册(订阅)鼠标左键点击事件:
public MainPage() {
InitializeComponent();
//将矩形添加进画布容器中
LayoutRoot.Children.Add(rectangle);
//注册画布容器的鼠标左键点击事件
LayoutRoot.MouseLeftButtonDown += new MouseButtonEventHandler(LayoutRoot_MouseLeftButtonDown);
}
最后,要实现通过鼠标左键点击来控制对象移动,我们还得在LayoutRoot_MouseLeftButtonDown方法体中编写相应的移动动画实现逻辑(在整个画布任意位置点击左键时,矩形对象rectangle即向该点移动):
private void LayoutRoot_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) {
//获取点击处相对于容器的坐标位置
Point p = e.GetPosition(LayoutRoot);
//创建移动用的动画故事板
Storyboard storyboard = new Storyboard();
//创建X轴方向动画
DoubleAnimation xAnimation = new DoubleAnimation() {
//起点
From = Canvas.GetLeft(rectangle),
//终点
To = p.X,
//花费时间
Duration = new Duration(TimeSpan.FromMilliseconds(500)),
};
//将X轴方向动画赋予rectangle
Storyboard.SetTarget(xAnimation, rectangle);
//设置X轴方向动画所影响的对象属性为Canvas.Left
Storyboard.SetTargetProperty(xAnimation, new PropertyPath("(Canvas.Left)"));
//将X轴方向动画添加进动画故事板中
storyboard.Children.Add(xAnimation);
//创建Y轴方向动画
DoubleAnimation yAnimation = new DoubleAnimation() {
From = Canvas.GetTop(rectangle),
To = p.Y,
Duration = new Duration(TimeSpan.FromMilliseconds(500)),
};
Storyboard.SetTarget(yAnimation, rectangle);
//设置Y轴方向动画所影响的对象属性为Canvas.Top
Storyboard.SetTargetProperty(yAnimation, new PropertyPath("(Canvas.Top)"));
storyboard.Children.Add(yAnimation);
//播放动画
storyboard.Begin();
}
以X轴方向动画实现为例(以上代码黄色部分),首先创建一个有起点、终点以及总耗时的DoubleAnimation:xAnimation,然后通过Storyboard.SetTarget(xAnimation,rectangle)这句将xAnimation动画过程绑定到矩形对象rectangle,并且通过Storyboard.SetTargetProperty(xAnimation,new PropertyPath(“(Canvas.Left)”))这行代码告诉xAnimation动画它影响的是对象(rectangle)的Canvas.Left属性。这两句话的写法是固定的,有兴趣的朋友可以将(Canvas.Left)换成Opacity试试(注意Opacity不需要括号),从运行结果去理解体会这两行代码的重要意义。
同样的,Y轴方向的动画依葫芦画瓢,唯一不同的是将Canvas.Left改成了Canvas.Top。
完成后在VisualStudio2010中按下Ctrl+F5进行编译运行(仅F5可进入调试运行):
通过本节的学习,一方面大家要学会使用Storyboard创建对象移动动画;另一方面也要掌握在Canvas画布容器中改变对象位置即X、Y坐标的方法分别是Canvas.SetLeft(对象,x坐标)和Canvas.SetTop(对象,y坐标)。
在Silverlight中除了可以使用Storyboard来创建移动动画外,还有另外两个选择:CompositionTarget和DispatcherTimer。
1.2通过CompositionTarget创建对象移动动画(交叉参考: 让物体动起来②)
CompositionTarget对象可以根据每个帧的回调来创建自定义动画。通俗的讲就是CompositionTarget创建的动画是基于画面每次刷新时触发的,与窗体刷新率保持一致,因而频率是相对固定的(随Silverlight应用程序的FPS而变化),人工无法介入控制。
那么如何使用它来实现1.1中一模一样的移动动画效果呢?
与1.1的步骤一样,我们首先创建一个矩形对象(当圆角半径(RadiusX、RadiusY)与相应的边长(Width、Height)相等时呈圆形),并在MainPage初始化后将之添加进画布同时注册画布鼠标左键点击事件:
/// <summary>
/// 填充色为蓝色,宽、高、圆角X、Y各50的矩形
/// </summary>
Rectangle rectangle = new Rectangle() {
Fill = new SolidColorBrush(Colors.Blue),
Width = 50,
Height = 50,
RadiusX = 50,
RadiusY = 50
};
public MainPage() {
InitializeComponent();
//将矩形添加进画布容器中
LayoutRoot.Children.Add(rectangle);
//注册画布容器的鼠标左键点击事件
LayoutRoot.MouseLeftButtonDown += new MouseButtonEventHandler(LayoutRoot_MouseLeftButtonDown);
}
因为是基于画面不停的刷新实现的对象位置改变,因此此时的鼠标左键事件中我们需要做的是记录鼠标移动的目的以及每次移动X、Y方向的速度增量(根据三角函数中的等边比例算出)和移动次数,同时依据具体情况注册/注销CompositionTarget.Rendering事件:
bool isRendering = false; //是否启动了刷新
double speed = 10; //每次移动10像素
double xSpeed, ySpeed; //X、Y方向的速度
int num; //需要移动次数
int count; //统计移动次数
private void LayoutRoot_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) {
if (!isRendering) {
CompositionTarget.Rendering += new EventHandler(Rendering);
isRendering = true;
}
Point start = new Point(Canvas.GetLeft(rectangle), Canvas.GetTop(rectangle));
Point end = e.GetPosition(LayoutRoot);
double distance = Math.Sqrt(Math.Pow((end.X - start.X), 2) + Math.Pow((end.Y - start.Y), 2));
xSpeed = (end.X - start.X) * speed / distance;
ySpeed = (end.Y - start.Y) * speed / distance;
num = (int)(distance / speed);
count = 0;
}
最后编写CompositionTarget_Rendering方法体逻辑实现矩形移动:
private void Rendering(object sender, EventArgs e) {
double x = Canvas.GetLeft(rectangle);
double y = Canvas.GetTop(rectangle);
Canvas.SetLeft(rectangle, x + xSpeed);
Canvas.SetTop(rectangle, y + ySpeed);
if (count == num) {
CompositionTarget.Rendering -= Rendering;
isRendering = false;
}
count++;
}
大体思路是:每次移动后记数count++,当移动到总次数num时将CompositionTarget.Rendering事件注销(取消订阅)掉,从而实现到达目的地时对象自动停止的效果