Android学习 - 游戏图片

根据系列图片绘制动画总结

一、采用系统提供的Animation类,用自带的方法

其中的animation.xml文件如下:

<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
    android:oneshot="false" >

    <item
        android:drawable="@drawable/a"
        android:duration="100"/>
    <item
        android:drawable="@drawable/b"
        android:duration="100"/>
    <item
        android:drawable="@drawable/c"
        android:duration="100"/>
    <item
        android:drawable="@drawable/d"
        android:duration="100"/>
    <item
        android:drawable="@drawable/e"
        android:duration="100"/>
    <item
        android:drawable="@drawable/f"
        android:duration="100"/>
    <item
        android:drawable="@drawable/g"
        android:duration="100"/>
    <item
        android:drawable="@drawable/h"
        android:duration="100"/>
    <item
        android:drawable="@drawable/i"
        android:duration="100"/>
    <item
        android:drawable="@drawable/j"
        android:duration="100"/>

</animation-list>
/** 拿到ImageView对象 **/
imageView = (ImageView) findViewById(R.id.imageView);
/** 通过ImageView对象拿到背景显示的AnimationDrawable **/
animationDrawable = (AnimationDrawable) imageView.getBackground();
animationDrawable.setOneShot(true);
/** 开始播放动画 **/
button0 = (Button) findViewById(R.id.button0);
button0.setOnClickListener(new OnClickListener() {
	@Override
	public void onClick(View arg0) {
		/** 播放动画 **/
		if (animationDrawable != null && !animationDrawable.isRunning()) {
			animationDrawable.start();
		}
	}
});

其中://设置单次播放animationDrawable.setOneShot(true);

二、提供了很多帧动画的图片,利用android绘图,可以绘制出人物走动的动画。

如上图,这种情况下,可以按照如下步骤,绘制动画:

1、根据人物上下左右行走,可以分为四段动画,可以定义一个长度为4的动画数组;

2、根据键盘上下左右键事件分别触发不同的动画。

主要绘制的语句如下:

mHeroAnim[ANIM_DOWN] = new Animation(context,new int []{R.drawable.hero_down_a,R.drawable.hero_down_b,R.drawable.hero_down_c,R.drawable.hero_down_d},true);

mHeroAnim[ANIM_LEFT] = new Animation(context,new int []{R.drawable.hero_left_a,R.drawable.hero_left_b,R.drawable.hero_left_c,R.drawable.hero_left_d},true);

mHeroAnim[ANIM_RIGHT]= new Animation(context,new int []{R.drawable.hero_right_a,R.drawable.hero_right_b,R.drawable.hero_right_c,R.drawable.hero_right_d},true);

mHeroAnim[ANIM_UP]   = new Animation(context,new int []{R.drawable.hero_up_a,R.drawable.hero_up_b,R.drawable.hero_up_c,R.drawable.hero_up_d},true);

三、只提供一张人物图片,就要采用程序来切割该图片,得到动画所需要的帧图像。

如上图,这种情况下,可以按照如下步骤,绘制动画:

1、通过该图片的宽度和高度,和定义的Tile的宽度和高度,可以切割出12张所需要的帧图像;

2、根据人物上下左右行走,可以分为四段动画,可以定义一个长度为4的动画数组;

3、根据键盘上下左右键事件分别触发不同的动画;

切割图片,以及绘制动画的主要代码如下:

// 利用程序来切割图片
Bitmap testmap = BitmapFactory.decodeResource(getResources(),
		R.drawable.enemy);
Bitmap[][] bitmap = new Bitmap[ANIM_COUNT][ANIM_COUNT];
int tileWidth = testmap.getWidth() / ANIM_COUNT;
int tileHeight = testmap.getHeight() / ANIM_COUNT;
int i = 0, x = 0, y = 0;
for (i = 0; i < ANIM_COUNT; i++) {
	y = 0;
	bitmap[ANIM_DOWN][i] = BitmapClipBitmap(testmap, x, y, tileWidth,
			tileHeight);
	y += tileHeight;
	bitmap[ANIM_LEFT][i] = BitmapClipBitmap(testmap, x, y, tileWidth,
			tileHeight);
	y += tileHeight;
	bitmap[ANIM_RIGHT][i] = BitmapClipBitmap(testmap, x, y, tileWidth,
			tileHeight);
	y += tileHeight;
	bitmap[ANIM_UP][i] = BitmapClipBitmap(testmap, x, y, tileWidth,
			tileHeight);
	x += tileWidth;
}
mTestAnim[ANIM_DOWN] = new Animation(this, bitmap[ANIM_DOWN], true);
mTestAnim[ANIM_LEFT] = new Animation(this, bitmap[ANIM_LEFT], true);
mTestAnim[ANIM_RIGHT] = new Animation(this, bitmap[ANIM_RIGHT], true);
mTestAnim[ANIM_UP] = new Animation(this, bitmap[ANIM_UP], true);

注意:以上后面两种方式分别采用了不同的绘制方法

第一种的绘制构造方法为:Animation(Contextcontext, int [] frameBitmapID, boolean isloop);

第二种的绘制构造方法为:Animation(Contextcontext, Bitmap [] frameBitmap, boolean isloop);

有了这些准备条件后,我们可以开始真正的绘制:

public void DrawAnimation(Canvas Canvas, Paint paint, int x, int y) {
	// 如果没有播放结束则继续播放
	if (!mIsend) {
		Canvas.drawBitmap(mframeBitmap[mPlayID], x, y, paint);
		long time = System.currentTimeMillis();
		if (time - mLastPlayTime > ANIM_TIME) {
			mPlayID++;
			mLastPlayTime = time;
			if (mPlayID >= mFrameCount) {
				// 标志动画播放结束
				mIsend = true;
				if (mIsLoop) {
					// 设置循环播放
					mIsend = false;
					mPlayID = 0;
				}
			}
		}
	}
}

这里采用了两个标志位来判断动画的状态,mIsend判断动画是否播放,true结束播放,false为播放动画;mIsloop判断动画是否循 环,true为循环,false为不循环;当然,动画循环的时候,动画肯定是播放的,于是mIsloop为true,则mIsend为false,由于每一组动画都为四张图片,所以mPlayID最多为4,当人物一组动作也就是一个动画完成后,表示4张图片都绘制了一遍,则要讲mPlayID置为0,表示 重新开始需要绘制四张图片代表一个动画。

我们在主类中如何通过按键来触发动画呢?需要通过实现onDraw()方法,并且不断的重绘,主要代码如下:

protected void onDraw(Canvas canvas) {
	canvas.drawBitmap(mMapImage, 0, 0, mPaint);
	canvas.save();
	canvas.clipRect(0, 0, 320, 30);
	mPaint.setColor(Color.WHITE);
	canvas.drawRect(0, 0, 480, 30, mPaint);
	mPaint.setColor(Color.RED);
	canvas.restore();

	/** 根据按键更新显示动画 **/
	if (mAllkeyDown) {
		if (mIskeyDown) {
			mAnimationState = ANIM_DOWN;
			canvas.drawText("按下下键,开始播放向下动画开始", 0, 20, mPaint);
		} else if (mIskeyLeft) {
			mAnimationState = ANIM_LEFT;
			canvas.drawText("按下左键,开始播放向左动画开始", 0, 20, mPaint);
		} else if (mIskeyRight) {
			mAnimationState = ANIM_RIGHT;
			canvas.drawText("按下右键,开始播放向右动画开始", 0, 20, mPaint);
		} else if (mIskeyUp) {
			mAnimationState = ANIM_UP;
			canvas.drawText("按下上键,开始播放向上动画开始", 0, 20, mPaint);
		}
		/** 绘制主角动画 **/
		mHeroAnim[mAnimationState].DrawAnimation(canvas, mPaint, 20, 100);
		mTestAnim[mAnimationState].DrawAnimation(canvas, mPaint, 100, 100);
	} else {
		/** 按键抬起后人物停止动画 **/
		mHeroAnim[mAnimationState].DrawFrame(canvas, mPaint, 20, 100, 0);
		mTestAnim[mAnimationState].DrawFrame(canvas, mPaint, 100, 100, 0);
		canvas.drawText("按键已经抬起动画停止", 0, 20, mPaint);
	}
	super.onDraw(canvas);
	invalidate();
}

这样,我们的动画绘制时时刻刻都在进行着。

我们可以通过控制上下左右按键,来控制标志:

public void setKeyState(int keyCode, boolean state) {
	switch (keyCode) {
	case KeyEvent.KEYCODE_DPAD_DOWN:
		mIskeyDown = state;
		break;
	case KeyEvent.KEYCODE_DPAD_UP:
		mIskeyUp = state;
		break;
	case KeyEvent.KEYCODE_DPAD_LEFT:
		mIskeyLeft = state;
		break;
	case KeyEvent.KEYCODE_DPAD_RIGHT:
		mIskeyRight = state;
		break;
	}
	mAllkeyDown = state;
}

地图绘制理解

地图绘制可以借助工具,得到相应的地图数组数据;有了地图数组数据,则可以从提供的地图库文件根据ID得到相应的地图块,然后画在屏幕上;

因为地图数组数据比较容易得到,再次不过多阐述,分析关键的绘图原理机制:

1、准备一张地图库文件(其中包含了所有地图上需要的图形元素,如图所示),所有的地图元素都从这里面切割出去,然后绘制成想要的东西;

2、可以由工具得到想要的地图数组数据,如下:

//第一层游戏View地图数组
public int [][]mMapView = {
         { 1, 1, 1, 1, 137, 137, 137, 1, 1, 1 },
         { 1, 1, 1, 1, 137, 137, 137, 1, 1, 1 },
         { 1, 1, 1, 1, 137, 137, 137, 1, 1, 1 },
         { 137, 137, 137, 137, 137, 137, 137, 137, 137, 137 },
         { 137, 137, 137, 137, 137, 137, 137, 137, 137, 137 },
         { 1, 1, 1, 1, 1, 1, 1, 1, 137, 137 },
         { 1, 1, 1, 1, 1, 1, 1, 1, 137, 137 },
         { 1, 1, 1, 1, 1, 1, 1, 1, 137, 137 },
         { 1, 1, 1, 1, 1, 1, 1, 1, 137, 137 },
         { 1, 1, 1, 1, 1, 1, 1, 1, 137, 137 },
         { 1, 1, 1, 1, 1, 1, 1, 1, 137, 137 },
         { 137, 137, 137, 137, 137, 137, 137, 137, 137, 137 },
         { 137, 137, 137, 137, 137, 137, 137, 137, 137, 137 },
         { 1, 1, 1, 1, 1, 137, 137, 137, 1, 1 },
         { 1, 1, 1, 1, 1, 137, 137, 137, 1, 1 }
};
//第二层游戏实体actor数组
     public int [][]mMapAcotor  = {
         { 102, 103, 103, 104, 0, 0, 0, 165, 166, 167 },
         { 110, 111, 111, ......
                     ......

3、通过2中的地图数组数据,我们可以代码中动态的切割上面的地图库文件来进行绘制;

private void DrawMap(Canvas canvas, Paint paint, Bitmap bitmap) {
	int i, j;
	for (i = 0; i < TILE_HEIGHT_COUNT; i++) {
		for (j = 0; j < TILE_WIDTH_COUNT; j++) {
			int ViewID = mMapView[i][j];
			int ActorID = mMapAcotor[i][j];
			// 绘制地图第一层
			if (ViewID > TILE_NULL) {
				DrawMapTile(ViewID, canvas, paint, bitmap, j * TILE_WIDTH,
						i * TILE_HEIGHT);
			}

			// 绘制地图第二层
			if (ActorID > TILE_NULL) {
				DrawMapTile(ActorID, canvas, paint, bitmap, j * TILE_WIDTH,
						i * TILE_HEIGHT);
			}
		}
	}
}

此处TILE_HEIGH_COUNT为纵向tile的数量,TILE_WIDTH_COUNT为横向tile的数量,viewId代表在地图库文件中的具体位置,actorId也是一样,那么通过一个id是如何找到在地图库文件中的位置的呢?我们来看看DrawMapTile()方法是如何实现的:

private void DrawMapTile(int id, Canvas canvas, Paint paint, Bitmap bitmap,
		int x, int y) {
	// 根据数组中的ID算出在地图资源中的XY 坐标
	// 因为编辑器默认0 所以第一张tile的ID不是0而是1 所以这里 -1
	id--;
	int count = id / mWidthTileCount;
	int bitmapX = (id - (count * mWidthTileCount)) * TILE_WIDTH;
	int bitmapY = count * TILE_HEIGHT;
	DrawClipImage(canvas, paint, bitmap, x, y, bitmapX, bitmapY,
			TILE_WIDTH, TILE_HEIGHT);
}

由此处代码可以看出,tileid在地图库文件中是按横向顺序排列的方式定义的,假如横排10个,竖排15个,现在有一个ID66tile,则应该在第7行的第7个位置。按照上面的算法,id-- = 65int count = 65/10=6;

Int bitmapX =(66-(6*10))*32 = 6*32,int bitmapY = 6*32,于是可以根据这个tilexy的具体值可以找到地图库文件中的一个矩形区域,然后接下来,变为想到的一个tile,于是整个地图便是由一个一个这样的tile得到而来。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值