通常的概念中,2D也就是所谓的二维,也就是平面图形——即由X与Y坐标构成的图形,其内容由水平的X轴向与垂直的Y轴描绘确定,也就是由长和高的形成所谓的二维平面。
而所谓3D,也称之为三维。其图形内容除了有水平的X轴向与垂直的Y轴向外还有进深的Z轴,故称三维(XYZ),也就是由长、宽、高三项要素形成所谓的三维立体。
2D与3D的主要区别在于,3D可以包含360度的信息,能从各个角度去表现,构成近似于现实空间的有质感视角;而2D通常只能表现如表格、棋盘版的平面数据。 3D的立体感、光景效果要比二维平面图形要好的多,因为它的立体、光线、阴影都是相对真实存在的,而2D显然不具备这些优势。高拟真度、高自由度使得3D图形大受欢迎。
所以渐渐的3D图形开始成为主流,充斥于电影、电视乃至游戏的各个角落。但是,由于3D技术实现的复杂性及对用户环境的高要求,在所有领域都完全使用3D构图还并不现实,由此引发了另一种图形表现形式的出现——2.5D图形。
所谓的2.5D,介乎于模真的3D与完全平面的2D之间。即模拟了3D的空间感,也兼具2D的灵动简单,是一种“优势”的综合体。就我个人认为,诚然2.5D最早的出现动机只是为了2D到3D间过渡。但就其应用而讲,好的2.5D图形即有3D的自由度与质感,又能利用2D图形将漫画式人物塑造得惟妙惟肖,使其拥有纯3D还无法做到的优势。因此2.5D在现在乃至未来的一段较长时间里还会和3D并存,直到3D图形的开发效率及表现形式能彻底取代2.5D为止。
目前2.5D有两种大方向的实现思路:
一、纯2D模拟实现,是由2D人物及2D模拟3D场景:比较常见的如《神奇传说》、《皇家骑士团》、《超时空英雄传说》(PS:我从1开始玩的,也由此和宇峻游戏结缘,虽然我不是游戏开发人员,但遥想当年宇峻科技刚开张时,李玉山一个人写出超时空英雄传说1所有程序代码[虽然有部分是国外引擎改的]的功力我至今望尘莫及,其不愧为我等程序员之楷模)《魔力宝贝online》等,利用近大远小的视觉差模拟3D物体,令用户产生在使用3D图形的错觉,通常为一个左或右偏的45度角,当然也有偏55度或其他不同的角度可供选择。
二、2D+3D实现,是由3D场景加2D人物贴图:比如《MU奇迹online》、《RO仙境传说online》(PS:在RO中我练的高INT创造者,爱好是城战丢硫酸瓶毁对方装备……),由于场景采用3D绘制,可以360度自由旋转视角,真实感较强。纯2D的角色与遮挡关系处理简单。相对于纯3D来说代码量少且简单。美术方面工作量较少。比之纯3D占用系统资源也更少。
平心而论,个人比较推崇2D+3D哪种类RO的表现方式,但由于吾辈是Java程序员且非游戏开发人员并不熟悉Java3D的关系,只能采用Java2D来进行演示。
在当采用2D模拟3D实现2.5D(斜视角)时,我认为难点只有两个:
1.你要有美工帮你做好斜视的tile及role
2.你要转换2D坐标为2.5D坐标
对于第一点,神仙都爱莫能助……没有美工就自己画吧……
而对于第二点,也就是斜视图的坐标变换,大多数人最直接的想法可能就是利用三角函数。是的,从某种意义上说,俯视角度与正斜视角度的变化就是三角函数的应用,我也见过这类的45度斜视用例。但是,利用cos在Java中进行三角函数的运算,首先速度不能达到要求,其次图像衔接度结果并不理想,结果可能令图像有锯齿状偏移,所以我并不推荐使用。
对于如

类的菱形斜视图像,我们可以利用一个简单的行列运算获得俯视角度地砖的绘制坐标与斜视角度地砖的绘制坐标的变换,公式如下:
X:2.5D图形中X轴位置=(目标图像Width/2)*(2D图形中X-2D图形中Y)
Y:2.5D图形中Y轴位置=(目标图像Height/2)*(2D图形中X+2D图形中Y)/2
当然,这个公式并不是绝对的,尤其是在图像数据有所偏移时。比如斜视角的地砖的宽与高的比例理论上应该是2:1的关系,即如果高度是12的话,那么物体宽度就应该是24,这个在数学上讲和绘制地图上的时候是没有错的。但是问题出现在美工可能做不出来这么一个图(比如我,做了三个演示用图基准线全不一样|||)。
因为美工在画图的时候,肯定是要找一个基准线(一般是水平方向上的中分线,因为这个方向是高度,而高度的比例是单位1),然后对称的画图的,在开始的时候问题不会出现,但是在画到后面的时候就会发现,无论如何都没有办法把另一个方向上的顶点画出来,总是没有办法在指定的范围内相交。这是因为计算机的绘图是按照像素点一个个绘制出来的,总是没0.5个像素的时候,所以就出现了这个情况。于是,美工一般为了在指定的范围划出来一个菱形往往会画花2个像素,也就是24*12的图像很有可能会被画成22*12……
此时这是我们就需要增或者减公式中的数值,令基准线和图形的实际保持一致,大家可以自己推导。

演算后图形表现应如上图所示。
下面,我给出一个在Java中此公式的实际实现代码。
Test25D.java
packageorg.loon.framework.game.test;

importjava.awt.Color;
importjava.awt.Frame;
importjava.awt.Graphics;
importjava.awt.Image;
importjava.awt.Panel;
importjava.awt.Point;
importjava.awt.event.WindowAdapter;
importjava.awt.event.WindowEvent;

importorg.loon.framework.game.image.Bitmap;


/***//**
*<p>
*Title:LoonFramework
*</p>
*<p>
*Description:Java2.5D地图构建
*</p>
*<p>
*Copyright:Copyright(c)2007
*</p>
*<p>
*Company:LoonFramework
*</p>
*
*@authorchenpeng
*@email:ceponline@yahoo.com.cn
*@version0.1
*/

publicclassTest25DextendsPanel...{


/***//**
*
*/
privatestaticfinallongserialVersionUID=1L;

finalstaticintframeWidth=490;

finalstaticintframeHeight=330;

Bitmapfloor,tile,role;

Imagescreen;

Graphicsgraphics;


int[][]map=...{

...{1,1,1,1,1,1,1,1},

...{1,0,0,0,0,0,0,1},

...{1,0,1,0,0,0,0,1},

...{1,0,0,0,0,1,0,1},

...{1,0,0,0,0,0,0,1},

...{1,1,1,1,1,1,1,1}};


publicTest25D()...{

setBackground(Color.WHITE);

floor=newBitmap("./imagerpg/floor.gif");
tile=newBitmap("./imagerpg/tile.gif");
role=newBitmap("./imagerpg/obj.gif");
//定位为X=1,Y=2(由0开始)
role.setDrawXY(1,2);
screen=newBitmap(frameWidth,frameHeight).getImage();
graphics=screen.getGraphics();

}


publicvoidupdate(Graphicsg)...{
paint(g);
}


publicvoidpaint(Graphicsg)...{
intX,Y;
//将图像位置向x点坐标校正180,y点校正50
intoffsetX=180;
intoffsetY=50;
intfloorWidth=floor.getWidth();
intfloorHeight=floor.getHeight();
for(inti=0;i<map.length;i++)

for(intj=0;j<map[i].length;j++)...{
//转换为斜角坐标
Pointp=reviseXY(floorWidth,floorWidth,j,i,offsetX,offsetY);
X=p.x;
Y=p.y;

if(map[i][j]==0)...{
graphics.drawImage(floor.getImage(),X,Y,X+floorWidth,
Y+floorHeight,0,0,floorWidth,floorHeight,
this);
}
}
intblackWidth=tile.getWidth();
intblackHeight=tile.getHeight();
for(inti=0;i<map.length;i++)

for(intj=0;j<map[i].length;j++)...{

if(map[i][j]!=0)...{
Pointp=reviseXY(blackWidth,blackWidth,j,i,offsetX,offsetY);
X=p.x;
Y=p.y-(blackHeight-floorHeight);
graphics.drawImage(tile.getImage(),X,Y,X+blackWidth,
Y+blackHeight,0,0,blackWidth,blackHeight,
this);
}
}

//绘制移动角色
introleWidth=role.getWidth();
introleHeight=role.getHeight();
Pointp=reviseXY(roleWidth,roleWidth,role.getDrawX(),role.getDrawY(),offsetX,offsetY);
X=p.x;
Y=p.y-15;
graphics.drawImage(role.getImage(),X,Y,X+roleWidth,
Y+roleHeight,0,0,roleWidth,roleHeight,
this);
//在伪45度图像构建时,需要处理角色和建筑间的遮挡关系,我在这里只使用了简单的重绘
//即如果构成和角色相遮挡的物体,首先绘制角色,而后用建筑遮挡该角色。
//比如x+1=1即前方有物体存在时,重绘遮挡物以遮挡角色

if(map[role.getDrawY()][role.getDrawX()+1]==1)...{
p=reviseXY(blackWidth,blackWidth,role.getDrawX()+1,role.getDrawY(),offsetX,offsetY);
X=p.x;
Y=p.y-(blackHeight-floorHeight);
graphics.drawImage(tile.getImage(),X,Y,X+blackWidth,
Y+blackHeight,0,0,blackWidth,blackHeight,
this);
}


g.drawImage(screen,0,0,this);
}


/***//**
*修正为斜角坐标
*@paramwidth
*@paramx
*@paramy
*@paramoffsetX
*@paramoffsetY
*@return
*/

privatePointreviseXY(intwidth,intheight,intx,inty,intoffsetX,intoffsetY)...{
intx1=x*(width/2);
inty1=y*(height/2);
intnx=x1-y1;
intny=(x1+y1)/2;
returnnewPoint(nx+offsetX,ny+offsetY);
}


publicstaticvoidmain(String[]args)...{

java.awt.EventQueue.invokeLater(newRunnable()...{

publicvoidrun()...{
Framefrm=newFrame("Java2.5D地图构建");
frm.setResizable(false);
frm.setSize(frameWidth,frameHeight);
frm.add(newTest25D());

frm.addWindowListener(newWindowAdapter()...{

publicvoidwindowClosing(WindowEvente)...{
System.exit(0);
}
});
frm.setLocationRelativeTo(null);
frm.setVisible(true);
}
});
}

}
效果图如下:

明天晚上有时间再继续……赶紧睡觉……
分享到:
相关推荐
在Java版本2.5中,Selenium提供了丰富的API和功能,使得测试工程师能够编写出高效、可维护的自动化测试脚本。这篇文档将深入探讨Selenium Java 2.5版本中的关键知识点。 一、Selenium WebDriver API 在Selenium 2.5...
java游戏开发 小游戏 经典游戏 游戏源码 课程设计 java游戏开发 小游戏 经典游戏 游戏源码 课程设计 java游戏开发 小游戏 经典游戏 游戏源码 课程设计 java游戏开发 小游戏 经典游戏 游戏源码 课程设计 java游戏开发...
ArcGIS for Java API 2.5 是Esri公司推出的一款强大的地理信息系统开发工具,它专为Java开发者设计,用于构建地图应用、空间分析以及地理数据管理。这个API提供了丰富的类库和方法,使得开发者能够轻松地在Java环境...
12. **WebSocket支持**:尽管Java Servlet API 2.5不直接包含WebSocket规范,但后续的Servlet 3.1版本开始添加了WebSocket支持,使得在Servlet容器中实现双向通信成为可能。 总的来说,Java Servlet API 2.5是Java ...
Java Servlet2.5 的函数介绍
本文将详细讲解如何使用Java来解压和压缩tar包,同时解决在处理中文文件名时可能出现的乱码问题,主要关注`javatar-2.5.jar`库中的功能以及`TarUtil.java`类的应用。 首先,`javatar-2.5.jar`是一个专门用于处理tar...
【作品名称】:基于java实现的利用bp神经网络预测PM2.5 【适用人群】:适用于希望学习不同技术领域的小白或进阶学习者。可作为毕设项目、课程设计、大作业、工程实训或初期项目立项。 【项目介绍】:基于java实现...
3. **XML配置与注解配置的融合**:Spring 2.5引入了对Java注解的广泛支持,使得开发者可以选择使用XML配置或者注解配置,或者两者结合,更加灵活地定义bean和它们的依赖。 4. **Bean表达式语言(Bean Expression ...
Servlet 2.5 API是Java Web开发中的一个重要组成部分,它定义了服务器端应用程序与Web服务器交互的一系列接口和类。这个API文档详细介绍了如何使用这些组件来构建动态、交互式的Web应用。以下是对Servlet 2.5 API...
在IT行业中,游戏开发是一项充满挑战与创新的工作,尤其在2D与3D之间游走的2.5D游戏,更是受到众多开发者和玩家的喜爱。"Z25d: javafx 2.5d RPG 游戏"是一个使用JavaFX技术构建的2.5D角色扮演游戏(RPG)项目。本文...
在这个"cors-filter-2.5 + java-property-utils-1.9.1.zip"压缩包中,主要包含了两个关键组件:CORS Filter和Java Property Utils。 1. CORS Filter: CORS Filter是处理跨域请求的一种解决方案,它作为一个...
maven-plugin-tools-java-2.5.jar
### Struts2 + Spring2.5 + Spring3.2 实现登录模块的详细解析 #### 一、项目背景与架构概述 本项目旨在利用Struts2框架、Spring2.5和Spring3.2来实现一个登录系统。Struts2作为MVC框架负责处理用户的请求,而...
- **兼容性**:UDF 2.5在设计时充分考虑了与现有系统的兼容性,确保可以在多种操作系统和硬件平台上无缝运行。 - **扩展性**:为了适应不断变化的技术需求,UDF 2.5提供了良好的扩展性,可以通过文档变更通知(DCN...
Java 3DMenu 界面源码,有人说用到游戏中不错,其实平时我信编写Java应用程序时候也能用到吧,不一定非要局限于游戏吧,RES、SRC资源都有,都在压缩包内。 Java zip压缩包查看程序源码 1个目标文件 摘要:Java源码...
Spring框架是Java开发中的一个核心组件,它强调了依赖注入(Dependency Injection,DI)和面向切面编程(Aspect-Oriented Programming,AOP),为构建可测试、模块化且松耦合的应用提供了强大支持。 在Spring 2.5...
基于java的开发源码-P2P源码 Azureus 2.5.0.2(JAVA).zip 基于java的开发源码-P2P源码 Azureus 2.5.0.2(JAVA).zip 基于java的开发源码-P2P源码 Azureus 2.5.0.2(JAVA).zip 基于java的开发源码-P2P源码 Azureus 2.5....
通过一些现代化的技术,如.NET或Java的中间件,可以实现FOXPROW数据库与现代系统的集成,继续发挥其价值。 总结,FOXPROW 2.5b作为一款历史上的经典数据库开发工具,它在当时的Windows环境下发挥了重要作用,并且其...