silverlight游戏设计(四)角色/精灵篇之 -- 精灵的设计

本文介绍了一种基于Silverlight的游戏精灵设计方法,定义了精灵的接口及其实现,包括基本属性如位置、方向、可见性等,并实现了支持部件添加的精灵。

精灵的呈现基础

silverlight的那套api并不是一个为游戏设计的,你找不到现成的”精灵”相关的类。

最简单的精灵用一个Image就可以充当,但游戏中总是存在各式各样的精灵,不同精灵又有不同的逻辑,为了方便设计我们有必要定义一些接口。

呈现器接口—IPresenter

image

ExpandedBlockStart.gif IPresenter
namespace  Sopaco.Silverlight.GameFramewrok.Sprite
{
    
///   <summary>
    
///  呈现器
    
///   </summary>
     public   interface  IPresenter : IDisposable
    {
        
///   <summary>
        
///  用于标识咯咯呈现器
        
///   </summary>
         string  Id {  get set ; }
        
///   <summary>
        
///  
        
///   </summary>
        EmRoleBehavior CurrentBehavior {  get set ; }
        
///   <summary>
        
///  
        
///   </summary>
        EmRoleDir CurrentDir  {  get set ; }
        
///   <summary>
        
///  附加到容器中以显示
        
///   </summary>
         void  AttachOnContainer(Panel container);
        
///   <summary>
        
///  从容器中脱离
        
///   </summary>
         void  RemoveFromContainer();
        
///   <summary>
        
///  是否可见
        
///   </summary>
         bool  IsVisiable {  get set ; }
        
///   <summary>
        
///  是否启用特效
        
///   </summary>
         bool  IsEnableEffect {  get set ; }
        
///   <summary>
        
///  特效
        
///   </summary>
        Effect Effect {  get set ; }
        
///   <summary>
        
///  相对父容器的X轴偏移
        
///   </summary>
         double  X {  get set ; }
        
///   <summary>
        
///  相对父容器的Y轴偏移
        
///   </summary>
         double  Y {  get set ; }
        
///   <summary>
        
///  相对父容器的Z轴值
        
///   </summary>
         int  ZIndex {  get set ; }
        
///   <summary>
        
///  X偏移
        
///   </summary>
         double  OffsetX {  get set ; }
        
///   <summary>
        
///  Y偏移
        
///   </summary>
         double  OffsetY {  get set ; }
        
///   <summary>
        
///  运动控制模式
        
///   </summary>
        EmSpriteControlMode ControlMode {  get set ; }
        
///   <summary>
        
///  
        
///   </summary>
        PresenterResource Resource {  get set ; }
        
///   <summary>
        
///  显示的帧速
        
///   </summary>
        TimeSpan FrameFrequency {  get set ; }
        
///   <summary>
        
///  
        
///   </summary>
         void  SetViewSource(ImageSource source);

        
///   <summary>
        
///  ControlMode为RefreshOnPerFrame时调用此方法执行逻辑
        
///   </summary>
         void  OnFrame();
        
///   <summary>
        
///  播放一套完整的动画序列,直到将ControlMode设置为非AniSequenceMode值
        
///   </summary>
        
///   <param name="behavior"></param>
        
///   <param name="dir"></param>
        
///   <param name="?"></param>
         void  DoAniSequence(EmRoleBehavior behavior, EmRoleBehavior dir, AniTimes time, Action onAniCompleted);
    }
}

 

 

Id:精灵的标识值

CurrentBehavior:精灵动作

CurrentDir:精灵方向

IsVisiable:是否可见

IsEnableEffect:是否开启特Effect效

Effect:对呈现器进行渲染的BitmapEffect

X:相对呈现器父容器的X轴偏移

Y:相对呈现器父容器的Y轴偏移

ZIndex:Z轴权重值

OffsetX:在整个精灵容器内部X偏移

OffsetY:在整个精灵容器内部Y偏移

CenterX:X轴中心点偏移量

CenterY:Y轴中心点偏移量

ControlMode:运动模式。OnFrame/Story/混合

Resource:这里是精灵序列帧的图片资源,我从其精灵本身给分离出来了。

FrameFrequency:帧速设定

可添加部件的精灵

稍微玩过一些rpg游戏的人都知道,游戏中有个概念叫“装备”,顽疾通常会在通过打怪、任务、升级奖励等来得到新的装备,不同装备下角色的外观是不同的,同样的也会需求出现在”纸娃娃”、装备预览等需求上。我们在设计之处就应该考虑到这种复合的精灵角色,所以要进一步加入一个接口:IPartable。、

image

ExpandedBlockStart.gif IPartable
namespace  Sopaco.Silverlight.GameFramewrok.Sprite
{
    
///   <summary>
    
///  支持部件添加的呈现器
    
///   </summary>
     public   interface  IPartable : IPresenter
    {
        
void  AddPart(IPresenter part);
        
void  AddPart( string  partKey, IPresenter part);
        
void  RemovePart( string  partKey);
    }
}

 

 

 

 

进一步,具体的实现

 

image 

上面把接口定义好,接下来只需实现即可。对于silverlight,任何一个UIElement的子类都可以作为呈现器,而如果要添加部件的话很容易想到的是Canvas,因为Canvas一方面本身就是个容器,其次是一种绝对布局,我们可以通过设定UIElement对应的Canvas.LeftProperty调整其位置。有了这样的思路,具体实现如下:

ExpandedBlockStart.gif PresenterBase
namespace  Sopaco.Silverlight.GameFramewrok.Sprite
{
    
public   abstract   class  PresenterBase : IPresenter
    {
        
#region  Fields
        
private  Panel _preContainer;
        
private   bool  _isEnableEffect;
        
private   long  _preRefreshTimeTicks;
        
#endregion
        
#region  ctors
        
public  PresenterBase()
        {
            CurrentBehavior 
=  EmRoleBehavior.站立;
            CurrentDir 
=  EmRoleDir.默认;
        }
        
#endregion
        
protected   abstract  UIElement InnerUIElement {  get ; }

        
#region  IPresenter Members
        
public   virtual  EmRoleBehavior CurrentBehavior {  get set ; }
        
public   virtual  EmRoleDir CurrentDir {  get set ; }
        
public   string  Id 
        {
            
get
            
set ;    
        }
        
public   double  X
        {
            
get
            {
                
return  Canvas.GetLeft(InnerUIElement)  -  OffsetX;
            }
            
set
            {
                Canvas.SetLeft(InnerUIElement, value 
+  OffsetX);
            }
        }

        
public   double  Y
        {
            
get
            {
                
return  Canvas.GetTop(InnerUIElement)  -  OffsetY;
            }
            
set
            {
                Canvas.SetTop(InnerUIElement, value 
+  OffsetY);
            }
        }

        
public   double  OffsetX
        {
            
get ;
            
set ;
        }

        
public   double  OffsetY
        {
            
get ;
            
set ;
        }

        
public   int  ZIndex
        {
            
get
            {
                
return  Canvas.GetZIndex(InnerUIElement);
            }
            
set
            {
                Canvas.SetZIndex(InnerUIElement, value);
            }
        }

        
public   void  AttachOnContainer(Panel container)
        {
            RemoveFromContainer();
            container.Children.Add(container);
            _preContainer 
=  container;
        }

        
public   void  RemoveFromContainer()
        {
            
if  (_preContainer  !=   null )
                _preContainer.Children.Remove(InnerUIElement);
        }
        
public   bool  IsEnableEffect
        {
            
get
            {
                
return  _isEnableEffect;
            }
            
set
            {
                
if  (_isEnableEffect  ==  value)
                    
return ;
                _isEnableEffect 
=  value;
                InnerUIElement.Effect 
=  Effect;
            }
        }

        
public  System.Windows.Media.Effects.Effect Effect
        {
            
get ;
            
set ;
        }
        
public   bool  IsVisiable
        {
            
get
            {
                
return  InnerUIElement.Visibility.ToBoolean();
            }
            
set
            {
                InnerUIElement.Visibility 
=  value.ToVisibility();
            }
        }
        
public   abstract   void  SetViewSource(ImageSource source);
        
///   <summary>
        
///  呈现器的图片资源
        
///   </summary>
         public  PresenterResource Resource 
        {
            
get set
        }
        
public  TimeSpan FrameFrequency 
        {
            
get set
        }
        
public   virtual   void  OnFrame()
        {
            var span 
=  TimeSpan.FromTicks(DateTime.Now.Ticks  -  _preRefreshTimeTicks);
            
if  (span  >=  FrameFrequency)
            {
                RefreshOnFrameImmediately();
            }
        }
        
public   virtual   void  Dispose()
        {
            RemoveFromContainer();
            _preContainer 
=   null ;
        }

        
public   abstract  EmSpriteControlMode ControlMode 
        {
            
get set ;
        }
        
public   abstract   void  DoAniSequence(EmRoleBehavior behavior, EmRoleBehavior dir, AniTimes time, Action onAniCompleted);
        
///   <summary>
        
///  立即刷新
        
///   </summary>
         protected   abstract   void  RefreshOnFrameImmediately();
        
#endregion
    }
}

 

 

 

ExpandedBlockStart.gif AddPartablePresenter
namespace  Sopaco.Silverlight.GameFramewrok.Sprite
{
    
///   <summary>
    
///  可添加部件的呈现器
    
///   </summary>
     public   class  AddPartablePresenter : PresenterBase, IPartable
    {
        
#region  Fields
        
protected  Dictionary < string , IPresenter >  _parts  =   new  Dictionary < string , IPresenter > ();
        
public   static   readonly   string  DEFAULT_PARTKEY  =   " unipart " ;
        
private   static   int  autoId  =   0 ;
        
protected  EmSpriteControlMode _controlMode;
        
protected  Canvas _container  =   new  Canvas();
        
#endregion

        
#region  IPresenter  Members
        
public   override  EmSpriteControlMode ControlMode
        {
            
get
            {
                
return  _controlMode;
            }
            
set
            {
                _controlMode 
=  value;
            }
        }
        
public   override   void  SetViewSource(ImageSource source)
        {
            _container.Background 
=   new  ImageBrush()
            {
                ImageSource 
=  source
            };
        }
        
#endregion

        
#region  IPartable Members
        
public   void  AddPart(IPresenter part)
        {
            AddPart(CURRENT_DEFAULT_PARTKEY, part);
        }
        
public   void  AddPart( string  partKey, IPresenter part)
        {
            attachSelf(partKey, part);
        }
        
public   void  RemovePart( string  partKey)
        {
            deteachSelf(partKey);
        }
        
#endregion

        
#region  IDisposable Members

        
public   override   void  Dispose()
        {

            
base .Dispose();
        }

        
#endregion

        
protected   override  UIElement InnerUIElement
        {
            
get  {  return  _container; }
        }

        
#region  Private Helper Methods
        
private   void  attachSelf( string  partKey, IPresenter part)
        {
            part.AttachOnContainer(_container);
            _parts.Add(partKey, part);
        }
        
private   void  deteachSelf( string  partKey)
        {
            
if (_parts.ContainsKey(partKey))
            {
                _parts[partKey].RemoveFromContainer();
            }
            _parts.Remove(partKey);
        }
        
private   string  CURRENT_DEFAULT_PARTKEY
        {
            
get
            {
                
return   string .Format( " {0}-{1} " , DEFAULT_PARTKEY,  ++ autoId);
            }
        }
        
#endregion

        
public   override   void  DoAniSequence(EmRoleBehavior behavior, EmRoleBehavior dir, AniTimes time, Action onAniCompleted)
        {
            
throw   new  NotImplementedException();
        }

        
protected   override   void  RefreshOnFrameImmediately()
        {
            
foreach  (var part  in  _parts.Values)
            {
                part.OnFrame();
            }
        }
    }
}

 

 

ExpandedBlockStart.gif GameRole
namespace  Sopaco.Silverlight.GameFramewrok.Sprite
{
    
public   class  GameRole : AddPartablePresenter
    {
        
public   string  RoleId
        {
            
get ;
            
set ;
        }
        
public   override   void  OnFrame()
        {
            
if ( base .ControlMode  ==  EmSpriteControlMode.RefreshPerFrame)
            {
                
foreach  (var part  in   base ._parts.Values)
                {
                    part.OnFrame();
                }
            }
        }
        
public   override  EmRoleBehavior CurrentBehavior
        {
            
get
            {
                
return   base .CurrentBehavior;
            }
            
set
            {
                
base .CurrentBehavior  =  value;
                
// 更新所有部件的行为
                 foreach  (var part  in   base ._parts.Values)
                {
                    part.CurrentBehavior 
=  CurrentBehavior;
                }
            }
        }
        
public   override  EmRoleDir CurrentDir
        {
            
get
            {
                
return   base .CurrentDir;
            }
            
set
            {
                
base .CurrentDir  =  value;
                
// 更新所有部件的方向
                 foreach  (var part  in   base ._parts.Values)
                {
                    part.CurrentDir 
=  CurrentDir;
                }
            }
        }
        
#region  Private Helper Methods
        
#endregion
    }
}

 

 

转载于:https://www.cnblogs.com/wJiang/archive/2010/12/26/1917310.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值