上一篇:使用Silverlight制作简单的小游戏—Jewellery (Part 2)
实现Jewel类。Jewel类是继承于虚类JewelBase的,让我们先来看一下当前JewelBase的定义。
public abstract class JewelBase { #region Properties public double Width { get; set; } public double Height { get; set; } public int IndexX { get; set; } public int IndexY { get; set; } public int Kind { get; set; } #endregion public event EventHandler Click; #region Abstract Methods public abstract void Initialize(Canvas panel); public abstract void MoveTo(int x, int y); public abstract void Destroy(); #endregion }
动画过程用Storyboard来实现,在每次动画结束后,通知JewelEvent类。改进一下JewelBase中的abstract方法,如下:
public virtual void MoveTo(int x, int y) { Storyboard board = this.GetMoveAnimation(x, y); board.Completed += new EventHandler(moveBoard_Completed); board.Begin(); } private void moveBoard_Completed(object sender, EventArgs e) { JewelEvent.Add(JewelEventNames.Moved, this); // move finish } public virtual void Destroy() { Storyboard board = this.GetDestroyAnimation(); board.Completed += new EventHandler(destroyBoard_Completed); board.Begin(); } private void destroyBoard_Completed(object sender, EventArgs e) { JewelEvent.Add(JewelEventNames.Destroy, this); // destroy finish } #region Abstract Methods public abstract void Initialize(Canvas panel); protected abstract Storyboard GetMoveAnimation(int x, int y); protected abstract Storyboard GetDestroyAnimation(); #endregion
好了,接下来就是在Jewel中实现这3个abstract方法。
这里使用SL中的Image显示图片,在Initialize方法中,主要是初始化Image的位置、大小,以及根据Kind选择图片源,并绑定Image的MouseLeftButtonDown事件,转化为JewelBase的Click事件,这样Jewel就可以响应用户的点击事件了。对于Jewel的Size,这里使用ScaleTransform来控制,所以要在Initialize中恢复Jewel的Size。
public override void Initialize(Canvas canvas) { if (this.image == null) { this.image = new Image(); this.image.Width = this.Width; this.image.Height = this.Height; // use ScaleTransform to control Jewel's size this.image.RenderTransform = new ScaleTransform() { CenterX = this.Width / 2, CenterY = this.Height / 2, ScaleX = 1.0, ScaleY = 1.0 }; this.image.MouseLeftButtonDown += new MouseButtonEventHandler(rect_MouseLeftButtonDown); canvas.Children.Add(this.image); } Canvas.SetLeft(this.image, this.IndexX * this.Width); Canvas.SetTop(this.image, this.IndexY * this.Height); // reset ScaleTransform st = (ScaleTransform)this.image.RenderTransform; st.ScaleX = 1.0; st.ScaleY = 1.0; switch (this.Kind) { // set Image.Source } }
GetMoveAnimation方法和GetDestroyAnimation方法类似,就是构建并返回一个Storyboard实例。看下代码就好了。:)
#region GetMoveAnimation Method protected override Storyboard GetMoveAnimation(int x, int y) { Storyboard board = new Storyboard(); DoubleAnimation animation = new DoubleAnimation() { From = Canvas.GetLeft(this.image), To = x * this.Width, Duration = new Duration(TimeSpan.FromMilliseconds(speed)) }; Storyboard.SetTarget(animation, this.image); Storyboard.SetTargetProperty(animation, new PropertyPath("(Canvas.Left)")); board.Children.Add(animation); animation = new DoubleAnimation() { From = Canvas.GetTop(this.image), To = y * this.Height, Duration = new Duration(TimeSpan.FromMilliseconds(speed)) }; Storyboard.SetTarget(animation, this.image); Storyboard.SetTargetProperty(animation, new PropertyPath("(Canvas.Top)")); board.Children.Add(animation); return board; } #endregion #region GetDestroyAnimation Method protected override Storyboard GetDestroyAnimation() { Storyboard board = new Storyboard(); DoubleAnimation animation = new DoubleAnimation() { From = 1.0, To = 0.0, Duration = new Duration(TimeSpan.FromMilliseconds(moveSpeed)) }; Storyboard.SetTarget(animation, this.image.RenderTransform); Storyboard.SetTargetProperty(animation, new PropertyPath("(ScaleX)")); board.Children.Add(animation); animation = new DoubleAnimation() { From = 1.0, To = 0.0, Duration = new Duration(TimeSpan.FromMilliseconds(moveSpeed)) }; Storyboard.SetTarget(animation, this.image.RenderTransform); Storyboard.SetTargetProperty(animation, new PropertyPath("(ScaleY)")); board.Children.Add(animation); return board; } #endregion
这就是整个Jewel类,再运行一下程序,我们会看到一个布满Jewel的Canvas,并且已经可以运行了。不过,这里还差一个部分要说,就是实现IJewelSelector接口,使得用户在点击Jewel时,可以看到一个闪烁的外框。这里利用动态变化的虚线框,来实现一个被选择的效果。在Selected方法中显示,在Unselected中隐藏。这里只贴出来动画的实现,具体的实现请看本文最后附加的源代码。
this.selectedLine = new Rectangle(); this.selectedLine.StrokeThickness = 2; this.selectedLine.Stroke = new SolidColorBrush(Colors.Orange); DoubleCollection dc = new DoubleCollection() { 1, 2 }; this.selectedLine.StrokeDashArray = dc; this.selectedLine.StrokeDashOffset = 0; this.selectedLine.StrokeDashCap = PenLineCap.Round; canvas.Children.Add(this.selectedLine); // set animation Storyboard board = new Storyboard(); DoubleAnimation animation = new DoubleAnimation() { From = 0, To = 3, Duration = new Duration(TimeSpan.FromMilliseconds(300)), RepeatBehavior = RepeatBehavior.Forever, }; Storyboard.SetTarget(animation, this.selectedLine); Storyboard.SetTargetProperty(animation, new PropertyPath("(StrokeDashOffset)")); board.Children.Add(animation); board.Begin();
完结。
源代码:Jewellery.zip