WPF/Silverlight深度解决方案:(十九)Silverlight实用小技巧合集①

    Silverlight游戏开发中时常会碰上一些看似简单,可做时却发现挺棘手的问题。于是我打算通过一个小系列将平时较常用以及朋友们提问较多的问题进行归纳,同时分享我自己的解决方案,旨为大家提供更多实用且可行的参考,避免弯路。

一)知己知彼,轻松获取客户端相关参考信息

客户的机器配置各不相同,这我们确实无法控制。然而程序是活的,我们可以像做脚本及插件那样去适应不同的配置,从而使得每位客户都能获得都最佳体验效果,这也是未来游戏设计所需考虑到的重要环节之一。

    首先以获取客户端IP地址为例,我们可以通过在在页面中的Silverlight对象中添加以下参数:

<object data="data:application/x-silverlight-2," type="application/x-silverlight-2"  width="800" height="580">

……

     <param name="initParams" value="<%= String.Format("{0}={1}","ClientIP", Request.UserHostAddress) %>" />

……

</object>

然后在后台即可通过Application.Current.Host.InitParams["ClientIP"]读取客户端IP地址。

同时还可通过HtmlPage.BrowserInformation获取客户端浏览器的相关信息,比如通过HtmlPage.BrowserInformation.ProductNameHtmlPage.BrowserInformation.ProductVersion分别获取客户浏览器的类型及版本。

至于如还想获取客户端CPU及显卡等硬件信息则需借助比如Javascript提升浏览器权限后再读取。

或许SilverlightOOB模式及提升权限后也能做到,本人暂时还未能找到相关的API,望知道的朋友不吝赐教。

以下是该示例的Demo

获取 Microsoft Silverlight

二)取其精华,实现JavascriptsetIntervalsetTimeout

只要是用过Javascript的朋友都会对setIntervalsetTimeout流连忘返,没错,实在是太好用了。游戏中的中毒、冰冻、石化等等这些BuffDeBuff以及技能的冷却都需要对过程进行计时。当然有朋友将setInterval和setTimeout编写成了C#。不过这些代码还不能整体移植到Silverlight中直接处理UI逻辑,于是我将其进行了如下改造:

         readonly   int  interval  =   1000 // 间隔时间(毫秒)
         ///   <summary>
        
///  模拟Javascript中的setTimeout在指定时间过后执行指定的方法
        
///   </summary>
        
///   <param name="action"> 方法 </param>
        
///   <param name="interval"> 间隔(毫秒) </param>
         public   void  setTimeout(Action action,  double  interval) {
            EventHandler handler 
=   null ;
            DispatcherTimer dispatcherTimer 
=   new  DispatcherTimer() { Interval  =  TimeSpan.FromMilliseconds(interval) };
            dispatcherTimer.Tick 
+=  handler  =   delegate  {
                dispatcherTimer.Tick 
-=  handler;
                dispatcherTimer.Stop();
                action();
            };
            dispatcherTimer.Start();
        }

        DispatcherTimer timer 
=   new  DispatcherTimer();
        EventHandler handler 
=   null ;
        
///   <summary>
        
///  模拟Javascript中的setInterval在指定时间内重复执行指定的方法
        
///   </summary>
        
///   <param name="action"> 方法 </param>
        
///   <param name="interval"> 间隔(毫秒) </param>
         public   void  setInterval(Action action,  double  interval) {
            clearInterval();
            timer.Interval 
=  TimeSpan.FromMilliseconds(interval);
            timer.Tick 
+=  handler  =   delegate  { action(); };
            timer.Start();
        }

        
///   <summary>
        
///  模拟Javascript中的clearInterval停止setInterval
        
///   </summary>
         public   void  clearInterval() {
            timer.Tick 
-=  handler;
            timer.Stop();
        }

    使用的话和Js中一摸一样:

    setTimeout(方法, interval); setInterval(方法, interval);

    其中的Action可改成带返回值的Func,适用范围非常广;另外,我还为事件做了释放操作,更有利于封装处理,比如执行多少次停止,停止时触发Complete事件等均可轻松拓展;同时还增加了对JavascriptclearInterval函数的模仿,可自由控制setInterval的启动/停止。

以下是该示例的Demo,每次间隔都会触发数字+1

获取 Microsoft Silverlight

三)借力用力,通过SilverXFlash动画转成Silverlight控件

不可否认,十数年积累下的Flash设计师比Silverlight的多很多且不乏优秀之才;网络上随处可见漂亮的Flash动画,在学习之初或者作为项目中的简单辅助,我们完全可以通过SilverX这款软件将没有复杂AS代码的Flash动画(比如LoadingWaitinglogin等简单又漂亮的小动画)的swf文件直接转换成Silverlightxaml控件,老好用了。目前该软件仍在不断升级中,对于更复杂的Flash支持也将越来越好,作者深有体会,更期待完美版本的出现~。当前依旧存在的主要缺点有:转换后的文件容量会变大,颜色有些丢失,性能相对差些,并且好象不购买的话转出的只有xap而无源码,当然我们是可以解压出其中的dll直接使用的。

以下是我随便找到的一些swf小动画转换成xap后的Demo

获取 Microsoft Silverlight 获取 Microsoft Silverlight 获取 Microsoft Silverlight 获取 Microsoft Silverlight 获取 Microsoft Silverlight 获取 Microsoft Silverlight 获取 Microsoft Silverlight

四)绿色体验,华而实用的九宫格控件

九宫格在Flash中已家喻户晓,它的好处不言而喻,资源的复用,动态局部搭配,轻松换肤等等。然而对于刚起步的Silverlight来说九宫格着实比较陌生。过兄早期就已公布过一些有趣的布局控件,包括九宫格。而游戏中的面板都是通过九宫格实现的,以下是我所编写的九宫格控件StyleBox,继承自可拖动的FloatableWindow

ExpandedBlockStart.gif 代码
using  System;
using  System.Windows;
using  System.Windows.Controls;
using  System.Windows.Input;
using  System.Windows.Media;
using  System.Windows.Media.Animation;

namespace  Demo19_3 {

    
///   <summary>
    
///  可浮动窗体
    
///   </summary>
     public   abstract   class  FloatableWindow : Canvas {

        
///   <summary>
        
///  3D整型坐标点
        
///   </summary>
         public   struct  Point3D {
            
public   int  X,
                       Y,
                       Z;
            
public  Point3D( int  x,  int  y,  int  z) {
                X 
=  x;
                Y 
=  y;
                Z 
=  z;
            }
        }

        
///   <summary>
        
///  获取或设置中心
        
///   </summary>
         public   virtual  Point Center {  get set ; }

        
///   <summary>
        
///  获取或设置X、Y坐标
        
///   </summary>
         public   virtual  Point Coordinate {
            
get  {  return   new  Point(Canvas.GetLeft( this +  Center.X, Canvas.GetTop( this +  Center.Y); }
            
set  { Canvas.SetLeft( this , value.X  -  Center.X); Canvas.SetTop( this , value.Y  -  Center.Y); }
        }

        
///   <summary>
        
///  获取或设置Z层次深度
        
///   </summary>
         public   int  Z {
            
get  {  return  Canvas.GetZIndex( this ); }
            
set  { Canvas.SetZIndex( this , value); }
        }

        ContentControl HeadContent 
=   new  ContentControl(),
                         BodyContent 
=   new  ContentControl(),
                         FootContent 
=   new  ContentControl(),
                         CloserContent 
=   new  ContentControl();

        
///   <summary>
        
///  设置头部对象
        
///   </summary>
         public   object  Head {
            
set  { HeadContent.Content  =  value; }
        }

        
///   <summary>
        
///  设置身体对象
        
///   </summary>
         public   object  Body {
            
set  { BodyContent.Content  =  value; }
        }

        
///   <summary>
        
///  设置脚部对象
        
///   </summary>
         public   object  Foot {
            
set  { FootContent.Content  =  value; }
        }

        
///   <summary>
        
///  设置关闭按钮对象
        
///   </summary>
         public   object  Closer {
            
set  { CloserContent.Content  =  value; }
        }

        
public   double  HeadHeight {
            
get  {  return  HeadContent.Height; }
            
set  { HeadContent.Height  =  value; }
        }

        
public   double  BodyHeight {
            
get  {  return  BodyContent.Height; }
            
set  { BodyContent.Height  =  value; }
        }

        
public   double  FootHeight {
            
get  {  return  FootContent.Height; }
            
set  { FootContent.Height  =  value; }
        }

        
///   <summary>
        
///  设置头部空间位置
        
///   </summary>
         public  Point3D HeadPosition {
            
set  {
                Canvas.SetLeft(HeadContent, value.X);
                Canvas.SetTop(HeadContent, value.Y);
                Canvas.SetZIndex(HeadContent, value.Z);
            }
        }

        
///   <summary>
        
///  设置身体空间位置
        
///   </summary>
         public  Point3D BodyPosition {
            
set  {
                Canvas.SetLeft(BodyContent, value.X);
                Canvas.SetTop(BodyContent, value.Y);
                Canvas.SetZIndex(BodyContent, value.Z);
            }
        }

        
///   <summary>
        
///  设置脚部空间位置
        
///   </summary>
         public  Point3D FootPosition {
            
set  {
                Canvas.SetLeft(FootContent, value.X);
                Canvas.SetTop(FootContent, value.Y);
                Canvas.SetZIndex(FootContent, value.Z);
            }
        }

        
///   <summary>
        
///  设置关闭按钮空间位置
        
///   </summary>
         public  Point3D CloserPosition {
            
set  {
                Canvas.SetLeft(CloserContent, value.X);
                Canvas.SetTop(CloserContent, value.Y);
                Canvas.SetZIndex(CloserContent, value.Z);
            }
        }

        
///   <summary>
        
///  动画飞向
        
///   </summary>
        
///   <param name="fromX"> 起点X </param>
        
///   <param name="toX"> 目标X </param>
        
///   <param name="fromY"> 起点Y </param>
        
///   <param name="toY"> 目标Y </param>
        
///   <param name="speed"> 速度倍数 </param>
         public   void  AnimationFlyTo( double  fromX,  double  toX,  double  fromY,  double  toY,  double  speed) {
            Storyboard storyboard 
=   new  Storyboard();
            storyboard.Completed 
+=  (s, e)  =>  {
                Storyboard sb 
=  s  as  Storyboard;
                sb 
=   null ;
            };
            
int  duration  =  Convert.ToInt32(Math.Sqrt(Math.Pow((toX  -  fromX),  2 +  Math.Pow((toY  -  fromY),  2 ))  *  speed);
            DoubleAnimation xAnimation 
=   new  DoubleAnimation() {
                From 
=  fromX,
                To 
=  toX,
                Duration 
=   new  Duration(TimeSpan.FromMilliseconds(duration))
            };
            Storyboard.SetTarget(xAnimation, 
this );
            Storyboard.SetTargetProperty(xAnimation, 
new  PropertyPath( " (Canvas.Left) " ));
            storyboard.Children.Add(xAnimation);
            DoubleAnimation yAnimation 
=   new  DoubleAnimation() {
                From 
=  fromY,
                To 
=  toY,
                Duration 
=   new  Duration(TimeSpan.FromMilliseconds(duration))
            };
            Storyboard.SetTarget(yAnimation, 
this );
            Storyboard.SetTargetProperty(yAnimation, 
new  PropertyPath( " (Canvas.Top) " ));
            storyboard.Children.Add(yAnimation);
            storyboard.Begin();
        }

        
///   <summary>
        
///  关闭事件
        
///   </summary>
         public   event  MouseButtonEventHandler Closed;

        
static   int  z;  // 层次
         public  FloatableWindow() {
            
this .Children.Add(HeadContent);
            
this .Children.Add(BodyContent);
            
this .Children.Add(FootContent);
            
this .Children.Add(CloserContent);
            
// 设置可拖动方法
             bool  isMouseCaptured  =   false // 是否捕获了鼠标
            Point clickPoint  =   new  Point();  // 点击点
            HeadContent.MouseLeftButtonDown  +=  (s, e)  =>  {
                z
++ ;
                Canvas.SetZIndex(
this , z);
                HeadContent.CaptureMouse();
                isMouseCaptured 
=   true ;
                clickPoint 
=  e.GetPosition(s  as  UIElement);
                e.Handled 
=   true ;
            };
            HeadContent.MouseLeftButtonUp 
+=  (s, e)  =>  {
                HeadContent.ReleaseMouseCapture();
                isMouseCaptured 
=   false ;
                e.Handled 
=   true ;
            };
            HeadContent.MouseMove 
+=  (s, e)  =>  {
                
if  (isMouseCaptured) {
                    TransformGroup transformGroup 
=   this .RenderTransform  as  TransformGroup;
                    
if  (transformGroup  ==   null ) {
                        transformGroup 
=   new  TransformGroup();
                    }
                    
if  (transformGroup  !=   null ) {
                        transformGroup.Children.Add(
new  TranslateTransform() {
                            X 
=  e.GetPosition( this ).X  -  clickPoint.X,
                            Y 
=  e.GetPosition( this ).Y  -  clickPoint.Y
                        });
                        
this .RenderTransform  =  transformGroup;
                    }
                }
            };
            CloserContent.MouseLeftButtonDown 
+=  (s, e)  =>  {
                
if  (Closed  !=   null ) {
                    Closed(
this , e);
                };
                e.Handled 
=   true ;
            };
        }

    }
}

 

ExpandedBlockStart.gif 代码
using  System.Windows;
using  System.Windows.Controls;
using  System.Windows.Media;
using  System.Windows.Media.Imaging;

namespace  Demo19_3 {

    
///   <summary>
    
///  九宫格控件
    
///   </summary>
     public   sealed   class  StyleBox : FloatableWindow {

        
internal  TextBlock HeadText  =   new  TextBlock() { HorizontalAlignment  =  HorizontalAlignment.Center, VerticalAlignment  =  VerticalAlignment.Center };
        Image northWestImage 
=   new  Image();
        Grid northCenterGrid 
=   new  Grid();
        Image northEastImage 
=   new  Image() { Projection  =   new  PlaneProjection() { RotationY  =   180  } };
        Image centerWestImage 
=   new  Image() { Stretch  =  Stretch.Fill };
        ContentControl center 
=   new  ContentControl();
        Image centerEastImage 
=   new  Image() { Stretch  =  Stretch.Fill, Projection  =   new  PlaneProjection() { RotationY  =   180  } };
        Image southWestImage 
=   new  Image();
        Image southCenterImage 
=   new  Image() { Stretch  =  Stretch.Fill };
        Image southEastImage 
=   new  Image() { Projection  =   new  PlaneProjection() { RotationY  =   180  } };
        Grid head 
=   new  Grid();
        Grid body 
=   new  Grid();
        Grid foot 
=   new  Grid();

        
public   object  CenterContent {
            
set  { center.Content  =  value; }
        }

        
public  BitmapImage NorthEdgeImageSource {
            
set  { northWestImage.Source  =  northEastImage.Source  =  value; }
        }

        
public  BitmapImage NorthImageSource {
            
set  { northCenterGrid.Background  =   new  ImageBrush() { ImageSource  =  value }; }
        }

        
public   double  NorthCenterWidth {
            
set  { northCenterGrid.Width  =  value; }
        }

        
public  BitmapImage CenterEdgeImageSource {
            
set  { centerWestImage.Source  =  centerEastImage.Source  =  value; }
        }

        
public   double  CenterWidth {
            
get  {  return  center.Width; }
            
set  { center.Width  =  value; }
        }

        
public   double  CenterEdgeWidth {
            
set  { centerWestImage.Width  =  centerEastImage.Width  =  value; }
        }

        
public  BitmapImage SouthEdgeImageSource {
            
set  { southWestImage.Source  =  southEastImage.Source  =  value; }
        }

        
public  BitmapImage SouthImageSource {
            
set  { southCenterImage.Source  =  value; }
        }

        
public   double  SouthCenterWidth {
            
set  { southCenterImage.Width  =  value; }
        }

        
public  StyleBox() {
            RowDefinition row 
=   new  RowDefinition();
            head.RowDefinitions.Add(row);
            ColumnDefinition[] col 
=   new  ColumnDefinition[ 3 ];
            
for  ( int  i  =   0 ; i  <   3 ; i ++ ) {
                col[i] 
=   new  ColumnDefinition();
                head.ColumnDefinitions.Add(col[i]);
            }
            head.Children.Add(northWestImage); Grid.SetColumn(northWestImage, 
0 );
            northCenterGrid.Children.Add(HeadText);
            head.Children.Add(northCenterGrid); Grid.SetColumn(northCenterGrid, 
1 );
            head.Children.Add(northEastImage); Grid.SetColumn(northEastImage, 
2 );
            
this .Head  =  head;

            row 
=   new  RowDefinition();
            body.RowDefinitions.Add(row);
            
for  ( int  i  =   0 ; i  <   3 ; i ++ ) {
                col[i] 
=   new  ColumnDefinition();
                body.ColumnDefinitions.Add(col[i]);
            }
            body.Children.Add(centerWestImage); Grid.SetColumn(centerWestImage, 
0 );
            body.Children.Add(center); Grid.SetColumn(center, 
1 );
            body.Children.Add(centerEastImage); Grid.SetColumn(centerEastImage, 
2 );
            
this .Body  =  body;

            row 
=   new  RowDefinition();
            foot.RowDefinitions.Add(row);
            
for  ( int  i  =   0 ; i  <   3 ; i ++ ) {
                col[i] 
=   new  ColumnDefinition();
                foot.ColumnDefinitions.Add(col[i]);
            }
            foot.Children.Add(southWestImage); Grid.SetColumn(southWestImage, 
0 );
            foot.Children.Add(southCenterImage); Grid.SetColumn(southCenterImage, 
1 );
            foot.Children.Add(southEastImage); Grid.SetColumn(southEastImage, 
2 );
            
this .Foot  =  foot;

            
this .Loaded  +=  (s, e)  =>  {
                BodyPosition 
=   new  Point3D() { Y  =  ( int )HeadHeight };
                FootPosition 
=   new  Point3D() { Y  =  ( int )HeadHeight  +  ( int )BodyHeight };
            };
        }

    }
}

同样的素材仅2.2KB可满足同一款游戏中几乎所有不同尺寸,不同位置及不同布局的面板需求,实实在在的完美绿色体验:

以下是该示例Demo,可随意拖动的九宫格面板:

获取 Microsoft Silverlight

    本节源码请到目录中下载,更多实用小技巧,敬请关注下回分解。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值