开源DirectDraw 2D引擎MCDX试用笔记(二)

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

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

      playerTile = new CDXTile(cdxControl1.Screen, "player1.bmp",485716, MemTypes.SystemOnly);//16个图像帧
      playerTile.ColorKey 
= Color.FromArgb(2550255); //透明色=紫色

      player 
= new CDXSprite(playerTile,-1);

      player.Animation 
= new CDXAnimation();
//增加每个方向的动画关键帧
      
int[] animUp = new int[6{8,9,10,11,10,9};
      
int[] animDown = new int[6{0,1,2,3,2,1};
      
int[] animLeft = new int[6{4,5,6,7,6,5};
      
int[] animRight = new int[6{12,13,14,15,14,13};
//添加到管理器
      player.Animation.AddAnimation(
30false, animUp);
      player.Animation.AddAnimation(
30false, animDown);
      player.Animation.AddAnimation(
30false, animLeft);
      player.Animation.AddAnimation(
30false, animRight);

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

虽然修改很容易,但还是先得了解它机制;先看一下它是如何切分图形元素的;
            int i, x, y;

            
this.blockWidth = blockWidth;
            
this.blockHeight = blockHeight;
            
this.blockCount = blockCount;

            
if(this.blockCount == 0)
                
this.blockCount = (Width / blockWidth) * (Height / blockHeight);

            blockRects 
= new System.Drawing.Rectangle[this.blockCount];

            
for(i = 0, x = 0, y = 0; i < this.blockCount; i++, x += blockWidth)
            
{
                
if(x > Width - blockWidth)
                
{
                    x 
= 0;
                    y 
+= blockHeight;
                }


                blockRects[i] 
= new System.Drawing.Rectangle(x, y, blockWidth, blockHeight);
            }
这里可以看到它按指定的数目切割,并把Rect保存到blockRects数组内;现在可以看看Draw的方法实现:
            if(tile == 0 || tile > blockCount) return;

            
if(tile < 0)
                tile 
= animation.GetAnimationTile(tile);

            
base.Draw(surface, x, y, blockRects[tile], bltType);
哦,原来在这里已经屏蔽掉0了;修改一下就行:
      //if(tile == 0 || tile > blockCount) return;
      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 方法用到:
            int tileNum = tileNumber;

            
if(tileNum == 0 || tileNum > tile.BlockCount) return;

            
// Only calculate the tile animation if we are NOT using the
            
// Tile's animations.
            if(tileNum < 0 && !useTileAnimation)
                tileNum 
= animation.GetAnimationTile(tileNum);

            tile.Draw(x 
+ posX, y + posY, surface, bltType, tileNum);
看来这段代码中还是屏蔽了0;暂且不管这点先,至少 tile支持Draw索引0了;现在不用再看tile.Draw了,因为上面已经看过也改过了;看看animation.GetAnimationTile方法;来自CDXAnimation 类,具体代码如下:
            if(tile > 0return tile;

            tile 
= (-tile)-1;
            
if(tile >= animationData.Count) return 0;

            AnimationData animation 
= (AnimationData)animationData[tile];

            
int pos = (frameCounter / animation.frameRate) % (animation.anim.Length + animation.pause);
            
if( pos >= animation.anim.Length) pos = 0;

            
return animation.anim[pos];
哦,原来tile被传递过来进行了翻译;就是这句:
tile = (-tile)-1;

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


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

这个animationData就是由AddAnimation方法维护得
        public void AddAnimation(int frameRate, int pause, bool pingpong, int[] anim)
        
{
            
        }


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

        input.Update();
        
bool canDrawNextFrame = true;

        
if(input.KeyState(MCDX.Keys.UpArrow) == KeyStates.Press || input.KeyState(MCDX.Keys.UpArrow) == KeyStates.Repeat){
          player.TileNumber 
= -1;
          player.PosY 
-- ;
        }
else if(input.KeyState(MCDX.Keys.DownArrow) == KeyStates.Press || input.KeyState(MCDX.Keys.DownArrow) == KeyStates.Repeat){
          player.TileNumber 
= -2;
          player.PosY 
++ ;
        }
else if(input.KeyState(MCDX.Keys.LeftArrow) == KeyStates.Press || input.KeyState(MCDX.Keys.LeftArrow) == KeyStates.Repeat){
          player.TileNumber 
= -3;
          player.PosX 
-- ;
        }
else if(input.KeyState(MCDX.Keys.RightArrow) == KeyStates.Press || input.KeyState(MCDX.Keys.RightArrow) == KeyStates.Repeat){
          player.TileNumber 
= -4;
          player.PosX 
++ ;
        }
else{
          canDrawNextFrame 
=false;
        }


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

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


上回发的这个MCDX笔记,有兄弟说无法正常运行;我还是帖源码上来,不过我的MCDX做过部分修改,不保证到贵鸡里正常运行了;
点这里下载 
posted @ 2005-05-10 20:47  suifei  阅读(2549)  评论(0编辑  收藏  举报