Silverlight 2.5D RPG游戏技巧与特效处理:(十八)开场卷轴与动态窗口

    第一眼往往能起到决定性作用,这不仅是对人来说。优秀的游戏同样需要一个华丽而盛大的开场,以中国式古风古韵之柔情传承,配以卷轴展开壮丽山河之气势磅礴,云中漫步于旅仙境渐入开场,相信如此美好的初体验定能捕获无数玩家的心:华美的开端能不让人雀跃祈盼后续之旷世奇章吗?

实现开场卷轴的方案大致三类:随机移动、往复移动及无线延展。其中随机移动即宽大的背景在游戏视窗中任意移动,碰撞到边缘时再向随机方向弹回;往复移动即背景画卷以横向或纵向来回移动;而本节我要给大家展示的是无限延展的开场画卷效果。

无限延展运动的画卷给人最大的震撼就是恢弘而无穷无尽,我们需要事先准备一副可左右对合拼接且尺寸大于游戏最大可能视口的图片。作为可全屏操作的Silverlight网游来说,图片的宽度至少得大于2000px以满足目前几乎所有客户端分辨率。至于原理很简单,两张一样的画卷图片紧挨着向同一方向连续移动,当第一张超出游戏屏幕时立刻再返回到第二张的末尾继续跟随移动,由此自然而然便形成了无限延展而连贯的动态画卷背景效果:

当然,仅仅是空灵的卷轴似乎还无法体现宏大的游戏开场气势,我们还可以赋予它灿烂的阳光、飘渺的浮石、成群的飞燕等额外动画,外加整体隐约镂空的云层,然后将单独的背景卷轴搭配上这些动画最终封装成LoginBackground控件,由此开场卷轴便大功告成:

LoginBackground
     ///   <summary>
    
///  背景的顺序
    
///   </summary>
     public   enum  BackgourndIndex {
        First 
=   0 ,
        Second 
=   1 ,
    }

    
///   <summary>
    
///  登陆部分的动画背景
    
///   </summary>
     public   sealed   class  LoginBackground : EntityObject {

        AnimationBase sunnyAnimation 
=   new  AnimationBase() { Loop  =   true , Z  =   2 , };
        AnimationBase pumiceAnimation 
=   new  AnimationBase() { Loop  =   true , Z  =   2 , };
        AnimationBase flyBirds 
=   new  AnimationBase() { Loop  =   true , Z  =   2 , };
        AnimationBase flowLightAnimation 
=   new  AnimationBase() { Loop  =   true , Z  =   2 , };

        
public  LoginBackground() {
            Source 
=  GlobalMethod.GetImage( " UI/ScrollPicture.jpg " , UriType.Project);
        }

        
///   <summary>
        
///  播放完一副的时间(毫秒)
        
///   </summary>
         public   static   int  Interval  =   20000 ;

        Storyboard storyboard;
        BackgourndIndex index;
        
///   <summary>
        
///  开始卷轴运动
        
///   </summary>
         public   void  Run(BackgourndIndex index,  double  start,  double  end) {
            
this .index  =  index;
            storyboard 
=   new  Storyboard();
            storyboard.Children.Add(GlobalMethod.CreateDoubleAnimation(
this " (Canvas.Left) " , start, end, TimeSpan.FromMilliseconds(index  ==  BackgourndIndex.First  ?  Interval:Interval * 2 ),  null ));
            storyboard.Completed 
+=   new  EventHandler(storyboard_Completed);
            storyboard.Begin();
        }

        
void  storyboard_Completed( object  sender, EventArgs e) {
            Storyboard storyboard 
=  sender  as  Storyboard;
            storyboard.Completed 
-=  storyboard_Completed;
            storyboard 
=   new  Storyboard();
            storyboard.Children.Add(GlobalMethod.CreateDoubleAnimation(
this " (Canvas.Left) " , RealWidth  -   6 - RealWidth, TimeSpan.FromMilliseconds(Interval  *   2 ),  null ));
            storyboard.Completed 
+=  storyboard_Completed;
            storyboard.Begin();
        }

        
///   <summary>
        
///  显示内部动画
        
///   </summary>
         public   void  DisplayAnimation() {
            CreateAnimation(sunnyAnimation, 
14 new  Point( 680 0 ));
            CreateAnimation(pumiceAnimation, 
67 new  Point( 810 25 ));
            CreateAnimation(flyBirds, 
69 new  Point( 570 410 ));
            CreateAnimation(flowLightAnimation, 
68 new  Point( 1760 105 ));
        }

        
void  CreateAnimation(AnimationBase animation,  int  code, Point position) {
            animation.Code 
=  code;
            animation.Position 
=  position;
            EventHandler handler 
=   null ;
            animation.Disposed 
+=  handler  =   delegate  {
                animation.Disposed 
-=  handler;
                
this .Children.Remove(animation);
            };
            
this .Children.Add(animation);
            animation.HeartStart();
        }

        
public   override   void  Dispose( object  sender, EventArgs e) {
            sunnyAnimation.Dispose(sunnyAnimation,
null );
            pumiceAnimation.Dispose(pumiceAnimation, 
null );
            flyBirds.Dispose(flyBirds, 
null );
            flowLightAnimation.Dispose(flowLightAnimation, 
null );
            storyboard.Stop();
            
base .Dispose(sender, e);
        }

    }

画卷展开后,接下来便是进入游戏正题。为了提高用户体验,我将所有窗体都设计为继承自WindowsBase附带透明拖动、渐显切入模式的九宫格控件,每个窗体所需UI素材部分不同(记录在Login.xml配置文件中),因此按照动态加载原则,每此弹出新的窗口前都先分析并下载该窗口所需资源,完成后再以动画形式切入,其中配以伪模态Loading环,最终的效果连贯而不失精致(以语言选择窗体LanguageChoicer为例)

LanguageChoicer
     ///   <summary>
    
///  游戏语言选择
    
///   </summary>
     public   sealed   class  LanguageChoicer : WindowBase {

        
///   <summary>
        
///  提交
        
///   </summary>
         public   event  MouseButtonEventHandler Submit;

        
public  LanguageChoicer() {
            
this .Loaded  +=  (s, e)  =>  {
                QueueParallelDownloader queueDownloader 
=   new  QueueParallelDownloader();
                queueDownloader.DownloadCompleted 
+=   new  OpenReadCompletedEventHandler(queueDownloader_OpenReadCompleted);
                queueDownloader.OpenReadAsync(GetResourceList(
" LanguageChoicer " ),  null false 300 );
            };
        }

        
void  queueDownloader_OpenReadCompleted( object  sender, OpenReadCompletedEventArgs e) {
            QueueParallelDownloader queueDownloader 
=  sender  as  QueueParallelDownloader;
            queueDownloader.DownloadCompleted 
-=  queueDownloader_OpenReadCompleted;
            Canvas body 
=   new  Canvas() {
                Width 
=   254 ,
                Height 
=   200 ,
                Background 
=   new  ImageBrush() { ImageSource  =  GlobalMethod.GetImage( " UI/105.png " , UriType.Web) }
            };
            RadioButton[] languages 
=   new  RadioButton[ 5 ];
            languages[
0 =   new  RadioButton() {
                Tag 
=   " zh-cn " ,
                Content 
=   new  TextBlock() {
                    Text 
=   " 简体中文 " ,
                    Style 
=  Application.Current.Resources[ " TextStyle0 " as  Style,
                    TextWrapping 
=  TextWrapping.Wrap,
                    Foreground 
=   new  SolidColorBrush(Color.FromArgb( 255 239 255 208 )),
                },
                FontSize 
=   14 ,
                GroupName 
=   " Language " ,
                IsChecked 
=   true ,
            };
            languages[
1 =   new  RadioButton() {
                Tag 
=   " zh-tw " ,
                Content 
=   new  TextBlock() {
                    Text 
=   " 繁體中文 " ,
                    Style 
=  Application.Current.Resources[ " TextStyle0 " as  Style,
                    TextWrapping 
=  TextWrapping.Wrap,
                    Foreground 
=   new  SolidColorBrush(Color.FromArgb( 255 239 255 208 )),
                },
                FontSize 
=   14 ,
                GroupName 
=   " Language " ,
            };
            languages[
2 =   new  RadioButton() {
                Tag 
=   " us " ,
                Content 
=   new  TextBlock() {
                    Text 
=   " English " ,
                    Style 
=  Application.Current.Resources[ " TextStyle0 " as  Style,
                    TextWrapping 
=  TextWrapping.Wrap,
                    Foreground 
=   new  SolidColorBrush(Color.FromArgb( 255 239 255 208 )),
                },
                FontSize 
=   14 ,
                GroupName 
=   " Language "
            };
            languages[
3 =   new  RadioButton() {
                Tag 
=   " jp " ,
                Content 
=   new  TextBlock() {
                    Text 
=   " 日本語 " ,
                    Style 
=  Application.Current.Resources[ " TextStyle0 " as  Style,
                    TextWrapping 
=  TextWrapping.Wrap,
                    Foreground 
=   new  SolidColorBrush(Color.FromArgb( 255 239 255 208 )),
                },
                FontSize 
=   14 ,
                GroupName 
=   " Language "
            };
            languages[
4 =   new  RadioButton() {
                Tag 
=   " kr " ,
                Content 
=   new  TextBlock() {
                    Text 
=   " 한국의 " ,
                    Style 
=  Application.Current.Resources[ " TextStyle0 " as  Style,
                    TextWrapping 
=  TextWrapping.Wrap,
                    Foreground 
=   new  SolidColorBrush(Color.FromArgb( 255 239 255 208 )),
                },
                FontSize 
=   14 ,
                GroupName 
=   " Language "
            };
            
for  ( int  i  =   0 ; i  <=  languages.GetUpperBound( 0 ); i ++ ) {
                body.Children.Add(languages[i]);
                Canvas.SetLeft(languages[i], 
86 ); Canvas.SetTop(languages[i],  - 5   +  i  *   35 );
            }
            ImageButton closer 
=   new  ImageButton() {
                TotalWidth 
=   93 ,
                TotalHeight 
=   27 ,
                Background 
=   new  ImageBrush() { ImageSource  =  GlobalMethod.GetImage( " UI/106.png " , UriType.Web), Stretch  =  Stretch.None },
                Text 
=   " 提交(OK) " ,
                TextStyle 
=  Application.Current.Resources[ " TextStyle1 " as  Style,
                TextSize 
=   14 ,
                TextHasEffect 
=   true ,
                TextEffectColor 
=  Colors.Black,
                TextBrush 
=   new  SolidColorBrush(Colors.LightGray),
                TextHoverBrush 
=   new  SolidColorBrush(Colors.White),
            };
            body.Children.Add(closer); Canvas.SetLeft(closer, 
73 ); Canvas.SetTop(closer,  167 );
            closer.Click 
+=  (s1, e1)  =>  {
                
// LoginManager.loading.Show();
                 for  ( int  i  =   0 ; i  <=  languages.GetUpperBound( 0 ); i ++ ) {
                    
if  (languages[i].IsChecked.Value) {
                        ParallelDownloader downloader 
=   new  ParallelDownloader();
                        OpenReadCompletedEventHandler handler 
=   null ;
                        downloader.OpenReadCompleted 
+=  handler  =  (s2, e2)  =>  {
                            Infos[
" Language " =  XElement.Load(e2.Result  as  Stream);
                            
if  (Submit  !=   null ) { Submit( this , e1); }
                            
// LoginManager.loading.Hide();
                        };
                        downloader.OpenReadAsync(
string .Format(GlobalMethod.WebPath( " Language/{0}.xml " ), languages[i].Tag.ToString()), DownloadPriority.Highest,  null false 0 );
                        
break ;
                    }
                }
            };
            StyleBox styleBox 
=   new  StyleBox() {
                HeadHeight 
=   60 ,
                BodyHeight 
=   200 ,
                FootHeight 
=   15 ,
                NorthCenterWidth 
=   74 ,
                CenterWidth 
=   254 ,
                CenterEdgeWidth 
=   30 ,
                SouthCenterWidth 
=   228 ,
                NorthEdgeImageSource 
=  GlobalMethod.GetImage( " UI/100.png " , UriType.Web),
                NorthImageSource 
=  GlobalMethod.GetImage( " UI/101.png " , UriType.Web),
                CenterEdgeImageSource 
=  GlobalMethod.GetImage( " UI/102.png " , UriType.Web),
                SouthEdgeImageSource 
=  GlobalMethod.GetImage( " UI/103.png " , UriType.Web),
                SouthImageSource 
=  GlobalMethod.GetImage( " UI/104.png " , UriType.Web),
                CenterContent 
=  body,
            };
            styleBox.HeadText.Foreground 
=   new  SolidColorBrush(Colors.White);
            styleBox.HeadText.Text 
=   " 选 择 语 言 " ;
            styleBox.HeadText.FontSize 
=   14 ;
            styleBox.HeadText.Margin 
=   new  Thickness( 0 - 20 0 0 );
            Body 
=  styleBox;
            
base .OnResourceReady( this , e);
        }
    }

额外需要说明一下,作为Silverlight网页游戏来说,多国语言(本地化)实现起来相当简单。游戏开端当玩家选择一种语言后,按照第十七节的方式首先将该语言包下载到本地并缓存,游戏中一切需要显示文字的地方都将从这里获取并解析。当然,特别要注意一些细节问题比如同一单词不同语言下长度不同,可能导致界面变形或超出范围,配合上一些偏移和字体尺寸参数可轻松解决。

下一节我会为大家继续讲解游戏登陆部分,其中的WCF+数据库操作将是重头大戏。相信《梦隋唐Online》这部强势作品的发布势将掀起新一轮Silverlight网游革命让世界仰望中国页游技术质的飞跃!

本系列源码请到目录中下载

在线演示地址:http://silverfuture.cn

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值