刚吃了晚饭,看了会儿成龙的《重案组》,继续研究MCDX.

今天把原来的泡泡堂人物素材用MCDX绘制看看,并仔细研究了一下CDXAnimation 类,发现运行结果并不是我想要的;首先我还是这样编写了代码:

None.gif       playerTile  =   new  CDXTile(cdxControl1.Screen,  " player1.bmp " , 48 57 16 , MemTypes.SystemOnly);//16个图像帧
None.gif      playerTile.ColorKey 
=  Color.FromArgb( 255 0 255 ); //透明色=紫色
None.gif
None.gif      player 
=   new  CDXSprite(playerTile, - 1 );
None.gif
None.gif      player.Animation 
=   new  CDXAnimation();
//增加每个方向的动画关键帧
ExpandedBlockStart.gifContractedBlock.gif      
int [] animUp  =   new   int [ 6 dot.gif {8,9,10,11,10,9} ;
ExpandedBlockStart.gifContractedBlock.gif      
int [] animDown  =   new   int [ 6 dot.gif {0,1,2,3,2,1} ;
ExpandedBlockStart.gifContractedBlock.gif      
int [] animLeft  =   new   int [ 6 dot.gif {4,5,6,7,6,5} ;
ExpandedBlockStart.gifContractedBlock.gif      
int [] animRight  =   new   int [ 6 dot.gif {12,13,14,15,14,13} ;
None.gif//添加到管理器
None.gif      player.Animation.AddAnimation(
3 0 false , animUp);
None.gif      player.Animation.AddAnimation(
3 0 false , animDown);
None.gif      player.Animation.AddAnimation(
3 0 false , animLeft);
None.gif      player.Animation.AddAnimation(
3 0 false , animRight);

看似一切正常;图像素材的结构为:4x4 ,分别是 下、左、上、右  ,索引为 0~15 共16帧画面;这个是原图: player1.png
那么按键盘DOWN的时候按我的设置值应该是从 0 播放到 3 ,再从3 退回到 1 ;但是最终结果总是发现第0帧不显;检查MCDX自带的sample的素材可以看出第0帧就是空的;这个是MCDX的素材: Bug.png,看样子是刻意这样处理的,那我的元素显然不符合MCDX的标准了,但总不至于要我修改素材吧,那可是件痛苦的事情,还是修改MCDX的CDXTile类吧;

虽然修改很容易,但还是先得了解它机制;先看一下它是如何切分图形元素的;
None.gif              int  i, x, y;
None.gif
None.gif            
this .blockWidth  =  blockWidth;
None.gif            
this .blockHeight  =  blockHeight;
None.gif            
this .blockCount  =  blockCount;
None.gif
None.gif            
if ( this .blockCount  ==   0 )
None.gif                
this .blockCount  =  (Width  /  blockWidth)  *  (Height  /  blockHeight);
None.gif
None.gif            blockRects 
=   new  System.Drawing.Rectangle[ this .blockCount];
None.gif
None.gif            
for (i  =   0 , x  =   0 , y  =   0 ; i  <   this .blockCount; i ++ , x  +=  blockWidth)
ExpandedBlockStart.gifContractedBlock.gif            
dot.gif {
InBlock.gif                
if(x > Width - blockWidth)
ExpandedSubBlockStart.gifContractedSubBlock.gif                
dot.gif{
InBlock.gif                    x 
= 0;
InBlock.gif                    y 
+= blockHeight;
ExpandedSubBlockEnd.gif                }

InBlock.gif
InBlock.gif                blockRects[i] 
= new System.Drawing.Rectangle(x, y, blockWidth, blockHeight);
ExpandedBlockEnd.gif            }
这里可以看到它按指定的数目切割,并把Rect保存到blockRects数组内;现在可以看看Draw的方法实现:
None.gif              if (tile  ==   0   ||  tile  >  blockCount)  return ;
None.gif
None.gif            
if (tile  <   0 )
None.gif                tile 
=  animation.GetAnimationTile(tile);
None.gif
None.gif            
base .Draw(surface, x, y, blockRects[tile], bltType);
哦,原来在这里已经屏蔽掉0了;修改一下就行:
None.gif        // if(tile == 0 || tile > blockCount) return;
None.gif
       if (tile > blockCount) return ;
这里的Draw是调用的父类的方法,归根结底就是
Surface.DrawFast(destX, destY, surface, srcRect, DrawFastFlags.Wait | DrawFastFlags.SourceColorKey);

经过修改已经可以正确显示我的素材图像了;

虽然目前已经有了‘良好’的开始,但还有几个小细节需要注意;还是回头看看先的代码:
player = new CDXSprite(playerTile,-1);
参数2是TileNumber,为什么是-1 ,还有TileNumber究竟有什么用,什么地方用到?

刚开始我自己都摸不着头脑,看它自己带的CHM发现基本上什么都没说,只是告诉你,这个是一个名为TileNumber的int类型参数;但是它的源码倒是有稍微‘详细’点的注解(可以用VS.net自带的“生成注解WEB页”功能把这些信息提取出来),不过要彻底明白还是得看源码;
首先还是打开CDXSprite类,看看这个tileNumber究竟传给谁;原来还是 Draw 方法用到:
None.gif              int  tileNum  =  tileNumber;
None.gif
None.gif            
if (tileNum  ==   0   ||  tileNum  >  tile.BlockCount)  return ;
None.gif
None.gif            
//  Only calculate the tile animation if we are NOT using the
None.gif            
//  Tile's animations.
None.gif
             if (tileNum  <   0   &&   ! useTileAnimation)
None.gif                tileNum 
=  animation.GetAnimationTile(tileNum);
None.gif
None.gif            tile.Draw(x 
+  posX, y  +  posY, surface, bltType, tileNum);
看来这段代码中还是屏蔽了0;暂且不管这点先,至少 tile支持Draw索引0了;现在不用再看tile.Draw了,因为上面已经看过也改过了;看看animation.GetAnimationTile方法;来自CDXAnimation 类,具体代码如下:
None.gif              if (tile  >   0 return  tile;
None.gif
None.gif            tile 
=  ( - tile) - 1 ;
None.gif            
if (tile  >=  animationData.Count)  return   0 ;
None.gif
None.gif            AnimationData animation 
=  (AnimationData)animationData[tile];
None.gif
None.gif            
int  pos  =  (frameCounter  /  animation.frameRate)  %  (animation.anim.Length  +  animation.pause);
None.gif            
if ( pos  >=  animation.anim.Length) pos  =   0 ;
None.gif
None.gif            
return  animation.anim[pos];
哦,原来tile被传递过来进行了翻译;就是这句:
tile  =  ( - tile) - 1 ;

最终通过tile作为索引从名为animationData得ArrayList中取回关键帧得结构AnimationData;结构描述如下:
None.gif      public   struct  AnimationData
ExpandedBlockStart.gifContractedBlock.gif    
dot.gif {
ExpandedSubBlockStart.gifContractedSubBlock.gif        
/**//// <summary>The animation frame rate.</summary>
InBlock.gif        public int frameRate;
ExpandedSubBlockStart.gifContractedSubBlock.gif        
/**//// <summary>The length between frames.</summary>
InBlock.gif        public int pause;
ExpandedSubBlockStart.gifContractedSubBlock.gif        
/**//// <summary>Whether or not the animation uses a ping-pong cycle</summary>
InBlock.gif        public bool pingpong;
ExpandedSubBlockStart.gifContractedSubBlock.gif        
/**//// <summary>An array of tile indexes that comprise the animation frames.</summary>
InBlock.gif        public int[] anim;
ExpandedBlockEnd.gif    }


这个animationData就是由AddAnimation方法维护得

这个animationData就是由AddAnimation方法维护得
None.gif          public   void  AddAnimation( int  frameRate,  int  pause,  bool  pingpong,  int [] anim)
ExpandedBlockStart.gifContractedBlock.gif        
dot.gif {
InBlock.gif            
ExpandedBlockEnd.gif        }


综上;现在控制播放动画没问题了;可以结合键盘控制来完成这个sprite程序了;

None.gif         input.Update();
None.gif        
bool  canDrawNextFrame  =   true ;
None.gif
ExpandedBlockStart.gifContractedBlock.gif        
if (input.KeyState(MCDX.Keys.UpArrow)  ==  KeyStates.Press  ||  input.KeyState(MCDX.Keys.UpArrow)  ==  KeyStates.Repeat) dot.gif {
InBlock.gif          player.TileNumber 
= -1;
InBlock.gif          player.PosY 
-- ;
ExpandedBlockStart.gifContractedBlock.gif        }
else   if (input.KeyState(MCDX.Keys.DownArrow)  ==  KeyStates.Press  ||  input.KeyState(MCDX.Keys.DownArrow)  ==  KeyStates.Repeat) dot.gif {
InBlock.gif          player.TileNumber 
= -2;
InBlock.gif          player.PosY 
++ ;
ExpandedBlockStart.gifContractedBlock.gif        }
else   if (input.KeyState(MCDX.Keys.LeftArrow)  ==  KeyStates.Press  ||  input.KeyState(MCDX.Keys.LeftArrow)  ==  KeyStates.Repeat) dot.gif {
InBlock.gif          player.TileNumber 
= -3;
InBlock.gif          player.PosX 
-- ;
ExpandedBlockStart.gifContractedBlock.gif        }
else   if (input.KeyState(MCDX.Keys.RightArrow)  ==  KeyStates.Press  ||  input.KeyState(MCDX.Keys.RightArrow)  ==  KeyStates.Repeat) dot.gif {
InBlock.gif          player.TileNumber 
= -4;
InBlock.gif          player.PosX 
++ ;
ExpandedBlockStart.gifContractedBlock.gif        }
else dot.gif {
InBlock.gif          canDrawNextFrame 
=false;
ExpandedBlockEnd.gif        }

None.gif
ExpandedBlockStart.gifContractedBlock.gif        
if (canDrawNextFrame  &&  player.Animation != null ) dot.gif {
InBlock.gif          player.NextFrame();
InBlock.gif          player.Animation.NextFrame();
ExpandedBlockEnd.gif        }
canDrawNextFrame是为了避免没有按键得情况下它还自动播放动画,不控制是不对的。

虽然搞清楚了这些细节,但从使用角度来说是不是有点麻烦;何不干脆提供一个SetAnimationStartPos之类得方法直接制定播放起始关键帧呢?真还不知道里面还有多少弯弯道道等着去找……


上回发的这个MCDX笔记,有兄弟说无法正常运行;我还是帖源码上来,不过我的MCDX做过部分修改,不保证到贵鸡里正常运行了;
点这里下载 

转载于:https://www.cnblogs.com/Chinasf/articles/152661.html

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐