使用调色板进行手机游戏开发

调色板贴图与位图贴图的特点描述(j2meImageSymbianCFbsBimap

 
Graphics.drawImage();

J2me的贴图函数drawImage()以及Symbian c++的贴图函数GC.Bitblt()函数贴图的好处:(以下只说j2me)

1.  简单,贴图函数算法全部内部实现,只需要进行函数参数调用。

2.  J2me平台可以使用game包(虽然我从来不用:

但是,这种简单的贴图函数却有不少的缺点

1.  底层被封装,使得开发人员不能对底层数据进行操作.(比如alpha混合,灰度,对象换色)

2.  占用内存大,以现在的主流彩色手机为例子,一般的彩屏手机为4096色、65000色甚至24万色,4096色格式的444位模式,65000色为565的格式,那么,每一个象素必须占用16为,即2byte,更不用说24万色模式了。

3.  贴图速度慢,对于单个位图的绘画,J2ME平台上的绘画速度是和贴图的次数相关,这样就限制了游戏画面的细腻度,所以经常可以看见很多游戏使用32X32的块图。

 

调色板贴图描述:

缺点

1.  实现复杂, 前期开发时间长。必须自己实现图片的绘画,包括总共8个方向的翻转。(做的我吐血,但是好处多多)

2.  速度的不确定,比如,在nokia平台,以前的老40CPU比较慢,自己实现的象素贴图就非常慢,明显不如系统的贴图函数,但在6600,761060平台就基本持平了。

 

好处就多了:

1.  支持象素级的访问,alpha混合,人物变色,角色透明等都很简单了,而不需要象png图片一样非要存一个alpha通道,并且永远不能变.

2.  占用内存小,因为一个象素只占用一个byte,所以一般用调色板做一张图片大体只需要原来位图占用内存的一半。

3.  速度快,这个快有点不绝对,相对的来说,如果游戏使用的图层越多,那么用Graphics.drawImage()肯定就会非常慢。在此我对比我做的一个游戏,在nokia 7610平台,采用8层背景图层,加上大约10个角色贴图,不采用任何的优化算法,耗时100-120ms之间。

4.  可以完全杜绝j2me的内存出错这个bug。当然,自己必须实现游戏的内存管理。

 

另外:可能会有人疑问,png图片是经过压缩的,但自己做的调色板完全不用png,那打包的jar文件不就很大么?完全没问题,因为png图片与jar文件的压缩算法都是ziplz77压缩算法,所以当你的txt文件存储进jar中时会进行压缩,压缩比基本上与png一样。

 

下面说一下我的调色板游戏实现方法:

J2me平台上,可以用midp2.0Graphics.drawRGB将象素绘画到屏幕上(midp1.0中就只能使用厂商的api了,比如nokiadg.drawPixels()),一般这个只需要调用一次,也就是将象素贴到屏幕上。

 

游戏中使用两种图片: (为了容易理解,我用类进行封装)

1.  对应Graphics.drawRGB的屏幕位图:

class RGBImage{

    public int imageWidth;

public int imageHeight;

public int[] imageData;//长度 = imageWidth* imageHeight;

};

2.  对应调色板的图片集合

class PalletteImages {

public int[128] palette;

public int imageNumbers;

public int[] imageSize;

public int[] imageDataFromIndex;

public byte[] data;

};

为什么要调色板为128呢?因为java中的byte-127 – +127,要用256色就必须算加法,如果不想用,就只能用0-127,所以就定义为128的长。根据我的使用经历,128色完全够用。

ImageSize存储每一张图片的大小,例如:总共有20张图,那么imageSize的长度就起码为20*2 = 40。第n张图的尺寸宽度=imageSize[n*2],高度 = imageSize[n*2+1]

ImageDataFromIndex存储每一张图片在data数据中的开始位置。

data存储图片的索引数据,存储为如下格式:

图片1索引1,图片1索引2………. 图片1索引n,

图片2索引1,图片2索引2………. 图片2索引m,

.

.

.

图片d索引1,图片d索引2………. 图片d索引g

 

另外,如果游戏中可以不使用线程(比如nokia的手机就可以不用),也尽量不要用。因为java虚拟机中本身也有个时钟周期(此时钟周期非CPU的时钟周期,只是我随便叫个名字而已),并且比线程的时钟周期精确度高。

比如在nokia平台

  
 
Thread:

int threadDelay;//帧时间

public class GameCanvas extends FullCanvas implements Runnable{

       public void run(){

              //游戏处理

              …………………….

              try{

                     Thread.sleep(threadDelay);

}catch(Exception e){}

}

};

一般只能运行大约10fps66007610symbian 7.0平台,N708.0平台可能会快些)。

 

如果这样做:

long nextTime, currentTime;

int threadDelay;//帧时间

Boolean isThreadRun = true;

public void loopRun(){

    nextTime = System.currentTimeMillis();

    while(isThreadRun){

      currentTime = System.currentTimeMillis();

      if(currentTime>=nextTime){

        //游戏处理

              ………………..

        timeProcess = System.currentTimeMillis() – currentTime;

        if(timeProcess>=threadDelay){

          nextTime = currentTime+timeProcess+1;

        }else nextTime = currentTime+threadDelay;

      }

    }

 }

那么可以运行到13fps66007610symbian 7.0平台),速度提升非常客观。