Tick机制
public class Ticker {
public void tick() {
}
}
游戏服务器程序内部都会统一设计所谓的tick机制,这个机制一般来说有两个用途,一是许多业务模块都会有定时处理的需求,如:游戏中一天时间的轮转;二是游戏服务器内部会有一些日常主动驱动的事件,如:水,火山熔浆动画,这些都在tick中处理。关于tick机制的实现和其中一些问题, 我们将来会详细介绍和探讨,对于现在, 我们只需从整体结构上知道tick机制的存在和重要性。
Bitmap(位图)
又称栅格图(Raster graphics),是使用像素阵列(Pixel-array/Dot-matrix點陣)来表示的图像。
根据位深度,可将位图分为1、4、8、16、24及32位图像等。每个像素使用的信息位数越多,可用的颜色就越多,颜色表现就越逼真,相应的数据量越大。例如,位深度为 1 的像素位图只有两个可能的值(黑色和白色),所以又称为二值位图。位深度为 8 的图像有 28(即 256)个可能的值。位深度为 8 的灰度模式图像有 256 个可能的灰色值。
RGB图像由三个颜色通道组成。8 位/像素的 RGB 图像中的每个通道有 256 个可能的值,这意味着该图像有 1600 万个以上可能的颜色值。有时将带有 8 位/通道 (bpc) 的 RGB 图像称作 24 位图像(8 位 x 3 通道 = 24 位数据/像素)。通常使用24位RGB组合数据位表示的的位图称为真彩色位图。
RGB
位图颜色的一种编码方法,用红(Red)、绿(Green)、蓝(Blue)三原色的光学强度来表示一种颜色。这是最常见的位图编码方法,可以直接用于屏幕显示。
Alpha通道
在原有的图片编码方法基础上,增加像素的透明度信息。图形处理中,通常把RGB三种颜色信息称为红通道、绿通道和蓝通道,相应的把透明度称为Alpha通道。多数使用颜色表的位图格式都支持Alpha通道。
色彩深度[编辑]
色彩深度又叫色彩位数,即位图中要用多少个二进制位来表示每个点的颜色,是分辨率的一个重要指标。常用有1位(单色),2位(4色,CGA),4位(16色,VGA),8位(256色),16位(增强色),24位和32位(真彩色)等。色深16位以上的位图还可以根据其中分别表示RGB三原色或CMYK四原色(有的还包括Alpha通道)的位数进一步分类,如16位位图图片还可分为R5G6B5,R5G5B5X1(有1位不携带信息),R5G5B5A1,R4G4B4A4等等。
Bitmap Class
本引擎所有的图形操作都是通过Bitmap与Screen或图形缓存来完成。我们会发现, Bitmap其实是非常简单。我们从介绍Bitmap类的定义开始。每个像素Pixel为一个32bit 的整数, 因此可以支持24位RGB组合数据位和Alpha通道。 所有的Pixel保存在一个数组结构Pixels中。
public class Bitmap {
protected int width;
protected int height;
protected int[] pixels;
public Bitmap(int width, int height) {
this.width = width;
this.height = height;
this.pixels = new int[width * height];
}
public int getWidth() {
return width;
}
public int getHeight() {
return height;
}
public int[] getPixels() {
return pixels;
}
}
Screen
屏幕实质上就是一大Bitmap.
public class Screen extends Bitmap {
public Screen(int width, int height) {
super(width, height);
}
public void render(Ticker ticker, Bitmap bitMap) {
this.putBitmap(bitMap, 0, 0);
}
}
Drawing a Bitmap
以上介绍了Bitmap, 接下我们介绍如何将将一个Bitmap 画到另外一个Bitmap,最常见的,比如,将Bitmap画到屏幕上,对应左上角的位置为(offX, offY)
透明色
public void putBitmap(Bitmap bitmap, int offX, int offY) {
int w = bitmap.getWidth();
int h = bitmap.getHeight();
int[] p = bitmap.getPixels();
int[] screenPixels = super.pixels;
int posX = 0, posY = 0;
for (int y = 0; y < h; y++) {
posY = offY + y;
if (posY < 0 || posY >= super.height) {
continue;
}
int screenRowOffset = posY * width;
int bitmapRowOffset = y * w;
for (int x = 0; x < w; x++) {
posX = offX + x;
if (posX < 0 || posX >= super.width) {
continue;
}
screenPixels[screenRowOffset + posX] = p[bitmapRowOffset + x];
}
}
}
Scanning a Bitmap
该函数是putBitmap函数的反向函数,用于获取对应bitmap覆盖的屏幕位置。 注意该返回对象时通过传参数实现的。
public void getBitMap(BitMap bitmap, int offX, int offY) {
int w = bitmap.getWidth();
int h = bitmap.getHeight();
int[] bitMapPixels = bitmap.getPixels();
int[] screenPixels = super.pixels;
int posX = 0, posY = 0;
int pixel;
for (int y = 0; y < h; y++) {
posY = offY + y;
if (posY < 0 || posY >= super.height) {
continue;
}
int screenRowOffset = posY * width;
int bitmapRowOffset = y * w;
for (int x = 0; x < w; x++) {
posX = offX + x;
if (posX < 0 || posX >= super.width) {
continue;
}
pixel = screenPixels[screenRowOffset + posX];
if(pixel!=0){
bitMapPixels[bitmapRowOffset + x] = pixel;
}
}
}
}
Load Image
读取图像文件并保存到Bitmap。
public class ImageLoader {
public static BitMap floors = load("/tex/floors.png");
private static BitMap load(String filename) {
try {
URL url = ImageLoader.class.getResource(filename);
BufferedImage img = ImageIO.read(url);
int w = img.getWidth();
int h = img.getHeight();
BitMap result = new BitMap(w, h);
int[] pixels = result.getPixels();
img.getRGB(0, 0, w, h, pixels, 0, w);
return result;
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
主程序
缓冲策略
public void createBufferStrategy(int numBuffers)
生成多缓冲(Multi-buffering)策略, 多缓冲(Multi-buffering)的方式可以显著地改善渲染性能。它将始终根据该缓冲区数参数来创建 bufferstrategy 。首先尝试翻页的缓冲区交换(page-flipping) 策略,然后使用加速缓冲区尝试blitting 策略,最后使用不加速的blitting 策略。
BufferStrategy bs = this.getBufferStrategy();
if (bs == null) {
this.createBufferStrategy(3);
return;// skip one render
}
BufferImage and Raster DataBuffer
生成和屏幕一样尺寸的图像缓存BufferedImage。 并用screenPixels指向对应缓存数据的的数组, 以方便程序的操作。
private BufferedImage screenImage;
private int[] screenPixels;
this.screenImage = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
DataBufferInt buffer = (DataBufferInt) screenImage.getRaster().getDataBuffer();
this.screenPixels = buffer.getData();
DrawImage
Bitmap floors = ImageLoader.sprites;
this.screen.render(ticker,floors);
for (int i = 0; i < this.screen.getPixels().length; i++) {
this.screenPixels[i] = this.screen.getPixels()[i];
}
Graphics g = bs.getDrawGraphics();
g.drawImage(this.screenImage, 0, 0, WIDTH * SCALE, HEIGHT * SCALE, null);
g.dispose();
bs.show();
- 获取Bitmap对象
- 将Bitmap对象画到对应的屏幕对象
- 通过循环,将Screen Bitmap 像素设置到 屏幕缓存像素数组
- 将屏幕缓存像素数组显示。