今天把原来的泡泡堂人物素材用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做过部分修改,不保证到贵鸡里正常运行了;
点这里下载
所有评论(0)