开源DirectDraw 2D引擎MCDX试用笔记(二)
刚吃了晚饭,看了会儿成龙的《重案组》,继续研究MCDX.
今天把原来的泡泡堂人物素材用MCDX绘制看看,并仔细研究了一下CDXAnimation 类,发现运行结果并不是我想要的;首先我还是这样编写了代码:
看似一切正常;图像素材的结构为:4x4 ,分别是 下、左、上、右 ,索引为 0~15 共16帧画面;这个是原图:
那么按键盘DOWN的时候按我的设置值应该是从 0 播放到 3 ,再从3 退回到 1 ;但是最终结果总是发现第0帧不显;检查MCDX自带的sample的素材可以看出第0帧就是空的;这个是MCDX的素材:,看样子是刻意这样处理的,那我的元素显然不符合MCDX的标准了,但总不至于要我修改素材吧,那可是件痛苦的事情,还是修改MCDX的CDXTile类吧;
虽然修改很容易,但还是先得了解它机制;先看一下它是如何切分图形元素的;
这里可以看到它按指定的数目切割,并把Rect保存到blockRects数组内;现在可以看看Draw的方法实现:
哦,原来在这里已经屏蔽掉0了;修改一下就行:
这里的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 方法用到:
看来这段代码中还是屏蔽了0;暂且不管这点先,至少 tile支持Draw索引0了;现在不用再看tile.Draw了,因为上面已经看过也改过了;看看animation.GetAnimationTile方法;来自CDXAnimation 类,具体代码如下:
哦,原来tile被传递过来进行了翻译;就是这句:
tile = (-tile)-1;
最终通过tile作为索引从名为animationData得ArrayList中取回关键帧得结构AnimationData;结构描述如下:
综上;现在控制播放动画没问题了;可以结合键盘控制来完成这个sprite程序了;
canDrawNextFrame是为了避免没有按键得情况下它还自动播放动画,不控制是不对的。
虽然搞清楚了这些细节,但从使用角度来说是不是有点麻烦;何不干脆提供一个SetAnimationStartPos之类得方法直接制定播放起始关键帧呢?真还不知道里面还有多少弯弯道道等着去找……
上回发的这个MCDX笔记,有兄弟说无法正常运行;我还是帖源码上来,不过我的MCDX做过部分修改,不保证到贵鸡里正常运行了;
点这里下载
今天把原来的泡泡堂人物素材用MCDX绘制看看,并仔细研究了一下CDXAnimation 类,发现运行结果并不是我想要的;首先我还是这样编写了代码:
playerTile = new CDXTile(cdxControl1.Screen, "player1.bmp",48, 57, 16, MemTypes.SystemOnly);//16个图像帧
playerTile.ColorKey = Color.FromArgb(255, 0, 255); //透明色=紫色
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(3, 0, false, animUp);
player.Animation.AddAnimation(3, 0, false, animDown);
player.Animation.AddAnimation(3, 0, false, animLeft);
player.Animation.AddAnimation(3, 0, false, animRight);
playerTile.ColorKey = Color.FromArgb(255, 0, 255); //透明色=紫色
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(3, 0, false, animUp);
player.Animation.AddAnimation(3, 0, false, animDown);
player.Animation.AddAnimation(3, 0, false, animLeft);
player.Animation.AddAnimation(3, 0, false, animRight);
看似一切正常;图像素材的结构为:4x4 ,分别是 下、左、上、右 ,索引为 0~15 共16帧画面;这个是原图:
那么按键盘DOWN的时候按我的设置值应该是从 0 播放到 3 ,再从3 退回到 1 ;但是最终结果总是发现第0帧不显;检查MCDX自带的sample的素材可以看出第0帧就是空的;这个是MCDX的素材:,看样子是刻意这样处理的,那我的元素显然不符合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);
}
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);
}
if(tile == 0 || tile > blockCount) return;
if(tile < 0)
tile = animation.GetAnimationTile(tile);
base.Draw(surface, x, y, blockRects[tile], bltType);
if(tile < 0)
tile = animation.GetAnimationTile(tile);
base.Draw(surface, x, y, blockRects[tile], bltType);
//if(tile == 0 || tile > blockCount) return;
if(tile>blockCount)return;
if(tile>blockCount)return;
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);
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);
if(tile > 0) return 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)-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)-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;
}
{
/**//// <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方法维护得
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();
}
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();
}
虽然搞清楚了这些细节,但从使用角度来说是不是有点麻烦;何不干脆提供一个SetAnimationStartPos之类得方法直接制定播放起始关键帧呢?真还不知道里面还有多少弯弯道道等着去找……
上回发的这个MCDX笔记,有兄弟说无法正常运行;我还是帖源码上来,不过我的MCDX做过部分修改,不保证到贵鸡里正常运行了;
点这里下载