分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow
也欢迎大家转载本篇文章。分享知识,造福人民,实现我们中华民族伟大复兴!
写在前面的话:
JAVA应用结构简单,易于编写,能够轻易完成高强度的复杂交互,并且安全性高,稳定性强,免费资源丰富,网络功能强大,拥有近乎完美的多线程机制。有必要的前提下,Java程序员甚至可以使用JNI直接与本地环境沟通,从而绕过虚拟机的性能制约。
而JAVA应用的跨平台特性,更(理论上)让其可以运行于任何系统和平台之上,最大限度的增加了程序的通用可能。
从本质上讲,无论你以Java开发桌面应用也好,网页应用也罢,其实并没有明显的界线存在。究其根本,无非是使用Applet/JApplet/JavaFX当做容器,抑或AWT/Swing/SWT当作容器的区别罢了。
快捷、灵活、通用、稳定,以上这些优势,原本足以让JAVA将成为未来网页游戏乃至中小型桌面游戏开发的主流语言之一。
然而,Java的运行效率问题,似乎却成了这一些美好前景的绊脚石。更直接的说,有一些人武断的认为,Java“缓慢”的运行速度,让它根本不适合作为游戏客户端之用。
即便自JDK1.6起Java的图形渲染能力已经有了显著提升,即便国外像RuneScape之类的Java3D网页游戏已经上线盈利很多年(PS:顺便鄙视下Jagex最近对RuneScape作的人物属性调整……),即便连NetBeans的运行速度都已经变得能同普通桌面程序不遑多让。但是,某些自2004年后或许从未接触过新技术的家伙,依旧乐此不疲的散布着有关Java性能的流言蜚语。
在某些落伍人士眼里,Java如同洪水猛兽,又好像是他们天生的对头。他们甚至宁愿选择某些行将就木的技术,他们甚至宁愿将某些只适合做低成本动画的东西视为命根,他们甚至宁愿花大力气去处理那些因为不支持实际多线程、CPU占用过高、硬件加速不到位、资源回收异常等等问题而引发的致命BUG,也不愿意去多了解一下Java。他们将一种原本可以带来巨大商业利益的语言视若等闲,他们宁愿让自己的雇主花费数倍的精力与财力去打造垃圾,也不愿意让雇主和公司拥有接触到更为优秀技术的机会。
不得不说,这即是Java的遗憾,更是某些落伍人士雇主及其公司,乃至整个游戏产业的遗憾。
当然,一味的指责他人,就成了抱怨,势必会犯“有嘴说别人,没嘴说自己”的民族通病。事实上,人们对于Java性能方面之所以会产生误解,除了旁人的傲慢与偏见外,自然也同Java自身的发展历程密不可分(具体原因我在其它的博文中已经阐述过很多次,此处不再赘述)。
但总体上讲,除了原Sun公司本身的不作为,以及Java偏向企业级开发,偏向服务器端开发的大环境影响外。Java进行游戏开发,或者说桌面开发的最大缺陷,就在于其图形开发方面,特别是有关于渲染优化方面,乃至整个Java游戏开发领域的书籍资料都严重匮乏。没错,相比浩如烟海的Java服务器端技术资料而言,Java游戏开发方面的资源凤毛麟角。在某个黑暗时期中,甚至连Java版的贪食蛇、俄罗斯方块、超级马里奥之类的资源都会被人视为经典。
不客气地说,如果凭那些东西就想让人树立对于Java游戏开发的信心,就算不等于痴人说梦,至少也是难于登天了。
而如果想要解决这个问题,那么更多的示例,以及更多的技术文章将必不可少。为此,笔者才会产生创作此系列博文的意愿,唯恨椽笔拙文,权作引玉之砖。
正文:BufferedImage与像素级渲染
常有人说Java图形渲染很慢?嗯,相对C/C++而言,Java2D固有的图像处理能力确实有待提高。
但是,这也仅仅局限于对比C/C++应用而言。
如果您是以其它什么东西与之比较,却得出Java渲染很慢的结论。那么,或者并不是出自Java本身的原因,而在于您并没能搞清楚该怎样正确的使用Java绘图。
况且,即便是相对于C/C++而谈,Java也并非相差到难以望其项背的地步。相对于某些行将就木的技术,至少我们除了异常积极的自行修改JRE,或者极端消极的等待JRE官方更新以外,还有使用OpenGL或者像素级优化这两条道路可走。
在本节当中,我们就先谈点基础的,来说说Java渲染的像素级优化吧。
像素与RGB:
像素是什么?简单的讲,像素就是色彩,像素是系统能够在计算机屏幕上显示的最小染色点。越高位的像素,其拥有的色板也就越丰富,越能表达颜色的真实感。
众所周知,图像是像素的复合,看似绚丽的形象,也无外是一个个肉眼难以分辨的细微颗粒集合罢了。
比如,在一些常见的Java图像处理中,我们经常会用到所谓的RGB24模式(24位三原色模式,在Java2D中以TYPE_INT_RGB表示),将Red,Green,Blue三种色彩加以混合,创造出唯一的色彩点并绘制到计算机之上。而这个色彩点,也就是所谓的像素。因为在RGB24中Red,Green,Blue三者都被分配有一个0~255的强度值,所以该RGB模式的极限机能就是256*256*256,即至多可以显示出16777216种颜色。
PS:关于16位的RGB565(Java2D中表示为TYPE_USHORT_565_RGB)以及RGB555(Java2D中表示为TYPE_USHORT_555_RGB)会在以后章节中涉及,大家此刻只要知道,使用24位以下的图形处理模式,在显示速度上虽然会有提高,视觉效果上却必然会有损失就可以了。
也许有网友会感叹。哇!16777216种颜色,这么多?难道都能用上吗?!
没错,16777216种颜色确实很多;事实上,这已非常接近于人类肉眼所能观察到的颜色数目极限, 所以我们又将它称之为真彩色。然而,人类的欲求却是无止境的,即便能够展现出16777216种颜色的RGB真彩模式,依旧有人嫌弃它的效果太差。
否则,在您计算机“颜色质量”一栏中,或许就不会再有32位这种“多余”的选择了。
正是因为人类天性的贪婪,当今2D、3D图形渲染中最为常见的ARGB模式,也就是32位真彩模式才会应运而生。
ARGB模式:
您问什么是ARGB?其实,它就是个穿了Alpha通道马甲的RGB。
事实上,较之最初的RGB模式,ARGB仅仅增加了一个名为Alpha的色彩通道。这是一个8位的灰度通道,用256级灰度来记录图像中的透明度信息,定义透明、不透明和半透明区域。通俗的说,你的ARGB图像是否透明,与底层图像的遮挡关系如何,都将由Alpha这个参数所决定。
在 Java2D中, TYPE_INT_ARGB象征着32 位十六进制数的ARGB色彩模式。
将“32 位十六进制数”的概念具象化后,也就是四对十六进制数字的序列。每个十六进制对定义四个颜色通道,即Red、Green、Blue和Alpha中每个颜色通道的强度,全以范围介于 0 到 255 之间的十进制数的十六进制表示法。(在16进制表示中,FF 是指全强度 ,最高的255。00 是指通道中无颜色,最低为0)
正如大家都知道的那样, 由于颜色值长度需要两位数字, 因此您需要填充一个通道, 例如用 01 代替 1,这样才可确保十六进制数中始终具有八个数字。还应确保指定十六进制数前缀 0x,这样才能被Java识别为16进制。
例如,白色 (全强度) 用十六进制记数法表示为: 0xFFFFFFFF。而黑色正好相反;它在红色、绿色和蓝色中的任何一个通道中都无颜色,结果就成了: 0xFF000000。请注意, Alpha 通道中的全强度意味着没有 Alpha (FF),也就是不透明, 而无强度 (00),则意味着全透明。
利用ARGB模式,我们可以轻易的创建出一些RGB所无法实现的艳丽图像,完成一些RGB所无法企及的缤纷效果。应该说,如果您只是想制作一个让人可以入目的画面,那么普通的RGB模式已然游刃有余,但如果您想百尺竿头更进一步,制作出一些让人心旷神怡的视觉盛宴,那就非ARGB不可。而一旦您开始使用ARGB,就与Alpha、Red、Green、Blue这四层色彩通道留下了不解之缘。
在Java中获得ARGB像素的方法如下:
public static int getARGB(int r, int g, int b, int alpha) {
return (alpha << 24) | (r << 16) | (g << 8) | b;
}
关于BufferedImage:
当我们需要使用像素级操作,当我们需要设定针对不同图像的不同色彩模式时,最直接有效的方法,就是使用BufferedImage。
事实上,就像深入优化Flash渲染必须利用BitmapData一样,没有对BufferedImage的相关了解,提高Java2D性能根本无从谈起,甚至不能说你会用Java2D。
当您想要创建BufferedImage,并对其中像素进行直接操作时,大体上有三种方式可选:
1、直接创建BufferedImage,导出DataBufferInt对象获取像素集合。
//创建一个640x480的BufferedImage,设定渲染模式为ARGB
BufferedImage image = new BufferedImage(640, 480,
BufferedImage.TYPE_INT_ARGB);
//获得当前BufferedImage的图像数据存储器,并转为DataBufferInt
DataBufferInt dataBuffer = ((DataBufferInt) image.getRaster()
.getDataBuffer());
//获得对应BufferedImage的像素数组
int[] pixels = dataBuffer.getData();
2、以int[]生成WritableRaster,以WritableRaster产生BufferedImage。
//设定BufferedImage的宽与高
int width = 640, height = 480;
int size = width * height;
//创建数组,用以保存对应BufferedImage的像素集合
int[] pixels = new int[size];
//以指定数组创建出指定大小的DataBuffer
DataBuffer dataBuffer = new DataBufferInt(pixels, size);
//创建一个WritableRaster对象,用以管理光栅
WritableRaster raster = Raster.createPackedRaster(dataBuffer, width, height,width, new int[] { 0xFF0000, 0xFF00, 0xFF }, null);
//创建一个24位的RGB色彩模型,并填充相应的R、G、B掩码
DirectColorModel directColorModel = new DirectColorModel(24, 0xFF0000, 0xFF00, 0xFF);
// 以下为32位RGB色彩模型
// DirectColorModel directColorModel = new DirectColorModel(32, 0xFF000000, 0xFF0000, 0xFF00, 0xFF);
//生成BufferedImage,预设Alpha,无配置
BufferedImage image = new BufferedImage(directColorModel, raster, true, null);
3、与方法2基本相同,唯一差别在于使用了SampleModel
int width = 640, height = 480;
int size = width * height;
int[] pixels = new int[size];
// 24位色彩模型
DirectColorModel directColorModel = new DirectColorModel(24, 0xFF0000,
0xFF00, 0xFF);
// 以SinglePixelPackedSampleModel构建像素包
SampleModel sample = new SinglePixelPackedSampleModel(
DataBuffer.TYPE_INT, width, height, new int[] { 0xFF0000,
0xFF00, 0xFF });
//生成DataBuffer
DataBuffer dataBuffer = new DataBufferInt(pixels, size);
//以SampleModel及DataBuffer生成WritableRaster
WritableRaster raster = Raster.createWritableRaster(sample, dataBuffer,
new Point(0, 0));
//生成BufferedImage
BufferedImage image = new BufferedImage(directColorModel, raster, true, null);
实际上,虽然表面上有所不同,但无论您采用以上何种方式获得BufferedImage及其对应的像素集合(PS:此处并非一定要获得像素的int[]形式,如short[]、byte[]等各式亦可,请根据实际需求决定),pixels对您而言都将成为一块保存有图像数据的内存区域,针对此pixels进行的任何修改,都将被直接反馈于BufferedImage之上。
得到了像素集合,我们又该如何将其应用到Java2D中呢?下面,我将介绍两个像素级Java渲染组件给大家参考。下面我们所使用到的一切操作,也都将围绕pixels这个以int[]形式出现的数组展开。
一、古董级的Processing
这是一套完整的,开源的,兼顾2D与3D方面的Java渲染组件。事实上,Processing在针对Java2D性能优化上的意义并不太大,因为它本来就不是为了解决性能问题而出现的。
Processing所做的,更多的是一种效果优化,一种对 Java 语言的延伸。它希望人们能利用它对Java的扩充,以简单高效的方式实现绚丽夺目的图形效果。应该说,Processing 将 Java 的语法简化并将其运算结果“感官化”,让使用者能很快享有声光兼备的交互式多媒体作品。
由于Processing运行于PApplet之上,而 PApplet 继承自Applet 。也就是说原本的 Processing 也是一种小程序,如果我们要将它应用在网页环境之外,要们就将PApplet插入到Frame/JFrame当中,要么就将其改写。
为了未来的演示更加方便,笔者选择了改写的道路,将其PGraphics渲染层直接封装。以下,是一个已经替换为Processing渲染的LGame示例:
- public class ProcessingBall extends Screen {
- class Ball {
- float x;
- float y;
- float speed;
- float gravity;
- float w;
- float life = 255;
- Ball(float tempX, float tempY, float tempW) {
- x = tempX;
- y = tempY;
- w = tempW;
- speed = 0;
- gravity = 0.1f;
- }
- void move() {
- speed = speed + gravity;
- y = y + speed;
- if (y > getHeight()) {
- speed = speed * -0.8f;
- y = getHeight();
- }
- }
- boolean finished() {
- life--;
- if (life < 0) {
- return true;
- } else {
- return false;
- }
- }
- void display(LPGraphics g) {
- g.fill(0, life);
- g.ellipse(x, y, w, w);
- }
- }
- private ArrayList balls;
- private int ballWidth = 48;
- PImage image=Utils.loadImage("system/image/logo.png");
- public ProcessingBall() {
- balls = new ArrayList();
- balls.add(new Ball(getWidth() / 2, 0, ballWidth));
- }
- public void draw(LPGraphics g) {
- g.background(255);
- for (int i = balls.size() - 1; i >= 0; i--) {
- Ball ball = (Ball) balls.get(i);
- ball.move();
- ball.display(g);
- if (ball.finished()) {
- balls.remove(i);
- }
- }
- }
- public void leftClick(MouseEvent e) {
- balls.add(new Ball(getMouseX(), getMouseY(), ballWidth));
- }
- public void middleClick(MouseEvent e) {
- }
- public void rightClick(MouseEvent e) {
- }
- public void onKey(KeyEvent e) {
- }
- public void onKeyUp(KeyEvent e) {
- }
- public static void main(String[] args) {
- GameScene frame = new GameScene("球体下落", 480, 360);
- Deploy deploy = frame.getDeploy();
- deploy.setScreen(new ProcessingBall());
- deploy.setShowFPS(true);
- deploy.setFPS(100);
- deploy.mainLoop();
- frame.showFrame();
- }
- }
二、新生代的PulpCore
项目地址:http://www.interactivepulp.com/pulpcore/
事实上,PulpCore在国外的Java圈中也算颇有名气,甚至连某位JavaFX开发者都曾以它和自己的项目作过比较。如果有朋友泡过http://www.javagaming.org/,想必应该知道,如果你在该论坛中寻求Java游戏框架,那么3D方面的优先推荐必然是JME,2D方面的优先推荐绝对是Slick2D,至于网页游戏开发方面,则必属PulpCore无疑。
在以OpenGL为绝对主流的javagaming上,一款以标准Java2D开发的框架,居然会受到如此推崇,PulpCore的技术价值我们可想而知。
下图为PulpCore提供的应用示例:
PS:虽然PulpCore所提供的示例多为小游戏,但该作者曾反复强调,PulpCore是一个开源的2D渲染和动画处理框架。
与Processing一样,启动PulpCore的CoreApplet继承自Applet,所以PulpCore依旧属于Applet实现,也就是默认情况下只能运行于网页之上。但相对于标准Applet应用,PulpCore却做了更多的优化,尤其注重用户体验与动画效果。应该说,Pulpcore是目前为止笔者所见过的,在不损失图像色彩的情况下最高效的Java2D解决方案。
关于图像渲染部分,PulpCore中有对应于标准Java2D的Graphics类,名为