- 浏览: 148207 次
- 性别:
- 来自: 南京
最新评论
-
rex0654335:
一下4年过去了
华为面试小结 -
qalong:
楼主好人啊,连资料都附带了
BOX2D的选择建议 -
zzmmzzzzm:
...
Unity3D做2D横版游戏小demo(源码) -
Perfect_ff:
新手非常需要这样的demo啊
Unity3D做2D横版游戏小demo(源码) -
leecong1p:
ttsszzyy 写道请问楼主这句代码是用来判断什么的 ...
斜45度地图简介、坐标系转换以及数据碰撞
好吧,你该知道为什么我这叫跳票工厂,其实这玩意还没做完。不过高度图、场景漫游、公告板技术都有,就差碰撞了,希望给需要的朋友提供一点借鉴价值,手机游戏有这么点东西也够做游戏了。话说M3G现在不太吃香,所以果断停止钻研,打算投奔更底层的OpenGL怀抱。
运行截图
几点要说明的:
1)公告板技术(如果你还不了解什么是公告板就去百度一下),一个面就能做一棵树,并且看上去效果还不错。优点是一个面,非常节省资源,缺点是你必须对所有的面进行对齐处理,但往往有的时候很难去判断哪些面在可视范围以内而需要对齐,其中就可能涉及到复杂的判定,况且对齐操作也需要一点点开销。所以大部分3D手机游戏用两个交叉面来做一棵树,开销稍微多了一点,但这样不管在X、Z轴的哪个方向看效果都不错,也比一个面的树更立体一些,更大的优点就是这棵树放到场景里就行,不需要进行对齐操作。
2)高度图场景的漫游,漫游的原理主要是根据摄像机当前位置,得到在高度图中对应位置的高度值,然后根据所在面四个顶点的Y值,插值法求出当前点的高度。但是插值法是有误差的,当四边形尺寸越大时误差越明显。本程序中使用的算法还有一点问题,研究的朋友自己解决一下吧。:)
主要代码在下面贴出,感兴趣的朋友也可以加我一起讨论。
游戏开发讨论群:50184572
我的QQ:350751373
创建高度图的代码
import java.io.IOException; import javax.microedition.lcdui.Image; import javax.microedition.m3g.Appearance; import javax.microedition.m3g.CompositingMode; import javax.microedition.m3g.Group; import javax.microedition.m3g.Image2D; import javax.microedition.m3g.IndexBuffer; import javax.microedition.m3g.Loader; import javax.microedition.m3g.Mesh; import javax.microedition.m3g.PolygonMode; import javax.microedition.m3g.Texture2D; import javax.microedition.m3g.Transform; import javax.microedition.m3g.TriangleStripArray; import javax.microedition.m3g.VertexArray; import javax.microedition.m3g.VertexBuffer; public class HeightMap { //高度信息数组 private short[] heightMap; //地图数据尺寸 private int mapWidth; private int mapHeight; //保存地图所有的多边形 private Mesh[][] map; //地图编码纹理 private Texture2D landTexture; //高度图扩大到地图尺寸的比例(正常0.20 or 0.10) private float resolution = 0.1f; //高度比例 private short heightResolution = 10; //每块地图数据代表的3D单位距离 private float perUnit = 1f; public HeightMap(String heightMapImgSrc, String textureImgSrc, float perUnit) throws IOException { if (resolution <= 0.0001f || resolution > 1.0f) throw new IllegalArgumentException("Resolution too small or too large"); this.perUnit = perUnit; // 加载文件 Image img = Image.createImage(heightMapImgSrc); //加载并解析高度图 loadMapImage(img); //创建地图纹理 landTexture = createTexture(textureImgSrc); //根据高度图创建整个地图多边形 createQuads(); //按设置比例对地图所有面进行缩放、平移操作 setTransform(); } public HeightMap(short[] heightMap, int mapWidth, int mapHeight, String textureImgSrc, float perUnit) throws IOException { if (resolution <= 0.0001f || resolution > 1.0f) throw new IllegalArgumentException("Resolution too small or too large"); this.heightMap = heightMap; this.mapWidth = mapWidth; this.mapHeight = mapHeight; this.perUnit = perUnit; for (int i = 0; i < heightMap.length; i++) { heightMap[i] = (short) (heightMap[i] * heightResolution); } //创建地图纹理 landTexture = createTexture(textureImgSrc); //根据深度图创建整个地图多边形 createQuads(); //按设置比例对地图所有面进行缩放、平移操作 setTransform(); } private Mesh[][] getQuads() { return map; } public Group getMeshGroup() { Group group = null; try { group = new Group(); Mesh[][] map = getQuads(); for (int x = 0; x < getMapWidth() - 1; x++) { for (int y = 0; y < getMapHeight() - 1; y++) { group.addChild(map[x][y]); } } return group; } catch (Exception e) { System.out.println("Heightmap error: " + e.getMessage()); e.printStackTrace(); } return group; } public int getMapWidth() { return mapWidth; } public int getMapHeight() { return mapHeight; } public float getPositionHeight(float x, float z) { int col0 = (int) (x / perUnit); int row0 = (int) (z / perUnit); int col1 = col0 + 1; int row1 = row0 + 1; if (col1 > mapWidth) col1 = 0; if (row1 > mapHeight) row1 = 0; System.out.println(col0+","+row0+" "+col1+","+row1); float height00 = heightMap[col0 + row0 * mapWidth]; float height01 = heightMap[col1 + row0 * mapWidth + 1]; float height11 = heightMap[col1 + row1 * mapWidth]; float height10 = heightMap[col0 + row1 * mapWidth + 1]; float tx = x / perUnit - col0; float ty = z / perUnit - row0; float txty = tx * ty; float height = height00 * (1.0f + txty - tx - ty) + height01 * (tx - txty) + height11 * txty + height10 * (tx - txty); return height/510; } /** * 根据地图数据和高度数据创建整个地图所有的四边形 */ private void createQuads() { short[] heights = new short[4]; map = new Mesh[mapWidth][mapHeight]; for (int x = 0; x < (mapWidth - 1); x++) { for (int y = 0; y < (mapHeight - 1); y++) { //读取四个顶点高度 heights[0] = heightMap[x + y * mapWidth]; heights[1] = heightMap[x + y * mapWidth + 1]; heights[3] = heightMap[x + (y + 1) * mapWidth]; heights[2] = heightMap[x + (y + 1) * mapWidth + 1]; //根据四个顶点的高度图创造面 map[x][y] = createQuad(heights); } } } /** * 加载高度图,并解析出高度图的高度数据 * @param img 高度图图片 */ private void loadMapImage(Image img) { //根据图片尺寸创建像素信息数组 int[] data = new int[img.getWidth() * img.getHeight()]; //获得像素信息 img.getRGB(data, 0, img.getWidth(), 0, 0, img.getWidth(), img.getHeight()); int imgw = img.getWidth(); int imgh = img.getHeight(); //根据加载图片计算地图尺寸 mapWidth = (int) (resolution * imgw); mapHeight = (int) (resolution * imgh); //初始化高度图 heightMap = new short[mapWidth * mapHeight]; // Calculate height and width offset into image int xoff = imgw / mapWidth; int yoff = imgh / mapHeight; //设置网面每个顶点高度 for (int y = 0; y < mapHeight; y++) { for (int x = 0; x < mapWidth; x++) { heightMap[x + y * mapWidth] = (short) ((data[x * xoff + y * yoff * imgw] & 0x000000ff) * heightResolution); } } // Clear data data = null; img = null; System.gc(); } /** * 按设置比例对地图所有面进行缩放、平移操作 */ private void setTransform() { Transform localTransform = new Transform(); float scaleTimes = perUnit / 510;//地图拉伸倍数(createQuad创建的四边形边长是510) for (int x = 0; x < map.length - 1; x++) { for (int y = 0; y < map[x].length - 1; y++) { //归一化单位矩阵 localTransform.setIdentity(); //每个面平移到指定位置 localTransform.postTranslate(x * perUnit, 0.0f, y * perUnit); //localTransform.postTranslate(x * perUnit, 0.0f, (mapHeight - y) * -perUnit); //缩小网格 localTransform.postScale(scaleTimes, scaleTimes, scaleTimes); // localTransform.postMultiply(t); map[x][y].setTransform(localTransform); } } } /** * 根据高度图创建四边形 * @param heights 四个定点的高度 */ private Mesh createQuad(short[] heights) { //创建顶点数组 short[] POINTS = { -255, heights[0], -255, 255, heights[1], -255, 255, heights[2], 255, -255, heights[3], 255 }; VertexArray POSITION_ARRAY = new VertexArray(POINTS.length / 3, 3, 2); POSITION_ARRAY.set(0, POINTS.length / 3, POINTS); VertexBuffer vertexBuffer = new VertexBuffer(); vertexBuffer.setPositions(POSITION_ARRAY, 1.0f, null); //创建索引缓冲 int INDICES[] = new int[] { 0, 1, 3, 2 }; int[] LENGTHS = new int[] { 4 }; IndexBuffer indexBuffer = new TriangleStripArray(INDICES, LENGTHS); //创建外观模式 Appearance appearance = new Appearance(); //设置颜色融合模式:纹理替代,不融合 CompositingMode compositingMode = new CompositingMode(); compositingMode.setBlending(CompositingMode.REPLACE); appearance.setCompositingMode(compositingMode); //多边形拾选模式:只显示正面、平滑渲染、透视矫正 PolygonMode polygonmode = new PolygonMode(); polygonmode.setCulling(PolygonMode.CULL_FRONT); polygonmode.setPerspectiveCorrectionEnable(true); polygonmode.setShading(PolygonMode.SHADE_SMOOTH); appearance.setPolygonMode(polygonmode); //纹理映射 short[] TEXCOORDS = { 0, 0, 1, 0, 1, 1, 0, 1 }; VertexArray TEXCOORD_ARRAY = new VertexArray(TEXCOORDS.length / 2, 2, 2); TEXCOORD_ARRAY.set(0, TEXCOORDS.length / 2, TEXCOORDS); vertexBuffer.setTexCoords(0, TEXCOORD_ARRAY, 1.0f, null); //纹理贴图 appearance.setTexture(0, landTexture); Mesh mesh = new Mesh(vertexBuffer, indexBuffer, appearance); return mesh; } /* * 纹理贴图 */ private Texture2D createTexture(String textureImgSrc) { Image2D img = null; try { img = (Image2D) Loader.load(textureImgSrc)[0]; } catch (Exception e) { } Texture2D texture = new Texture2D(img); texture.setFiltering(Texture2D.FILTER_NEAREST, Texture2D.FILTER_NEAREST); //设置纹理重复 texture.setWrapping(Texture2D.WRAP_REPEAT, Texture2D.WRAP_REPEAT); return texture; } }
创建基于公告板技术树的代码
import javax.microedition.m3g.Appearance; import javax.microedition.m3g.CompositingMode; import javax.microedition.m3g.Group; import javax.microedition.m3g.Image2D; import javax.microedition.m3g.IndexBuffer; import javax.microedition.m3g.Mesh; import javax.microedition.m3g.Node; import javax.microedition.m3g.PolygonMode; import javax.microedition.m3g.Texture2D; import javax.microedition.m3g.TriangleStripArray; import javax.microedition.m3g.VertexArray; import javax.microedition.m3g.VertexBuffer; public class Tree { private Mesh tree; private Group cameraGroup; // the billboard aligns itself with this camera position public Tree(Image2D image2D, Group camGroup, float x, float z, float size) { cameraGroup = camGroup; //构造顶点缓冲 VertexBuffer vertexBuffer = makeGeometry(); //构造索引缓冲 int[] indicies = { 1, 2, 0, 3 }; // the billboard is one quad int[] stripLens = { 4 }; //三角带索引缓冲 IndexBuffer indexBuffer = new TriangleStripArray(indicies, stripLens); Appearance appearance = makeAppearance(image2D); tree = new Mesh(vertexBuffer, indexBuffer, appearance); float size2 = size * 0.5f; /* The mesh is 2-by-2 in size, and so the extra 0.5 factor in the scaling reduces it to 1-by-1. */ tree.scale(size2, size2, size2); tree.setTranslation(x, size2, z); tree.setAlignment(cameraGroup, Node.Z_AXIS, null, Node.NONE); /* The billboard alignment will be along its z-axis only, no y-axis alignment is employed. */ } /* The geometry defines a square resting on top of the XZ plane, * centered at (0,0), with sides of length 2. * There are no normals, but there are texture coords. */ private VertexBuffer makeGeometry() { /* Create vertices, starting at the bottom left and going counter-clockwise. */ short[] POINTS = { -1, -1, 0, 1, -1, 0, 1, 1, 0, -1, 1, 0 }; VertexArray POSITION_ARRAY = new VertexArray(POINTS.length / 3, 3, 2); POSITION_ARRAY.set(0, POINTS.length / 3, POINTS); // create texture coordinates using the same order as the vertices short[] TEXCOORDS = { 0, 1, 1, 1, 1, 0, 0, 0 }; VertexArray TEXCOORD_ARRAY = new VertexArray(TEXCOORDS.length / 2, 2, 2); TEXCOORD_ARRAY.set(0, TEXCOORDS.length / 2, TEXCOORDS); VertexBuffer vertexBuffer = new VertexBuffer(); vertexBuffer.setPositions(POSITION_ARRAY, 1.0f, null); // no size, bias vertexBuffer.setTexCoords(0, TEXCOORD_ARRAY, 1.0f, null); return vertexBuffer; } /* The image's alpha component will cause the square's * surface to be invisible at those locations. */ private Appearance makeAppearance(Image2D image2D) { Appearance appearance = new Appearance(); //使用透明的颜色融合 CompositingMode compositingMode = new CompositingMode(); compositingMode.setBlending(CompositingMode.ALPHA); appearance.setCompositingMode(compositingMode); //设置多边形模式:只显示背面,允许透视修正 PolygonMode polygonMode = new PolygonMode(); polygonMode.setPerspectiveCorrectionEnable(true); polygonMode.setCulling(PolygonMode.CULL_BACK); appearance.setPolygonMode(polygonMode); if (image2D != null) { Texture2D texture2D = new Texture2D(image2D); texture2D.setFiltering(Texture2D.FILTER_NEAREST, Texture2D.FILTER_NEAREST); texture2D.setWrapping(Texture2D.WRAP_CLAMP, Texture2D.WRAP_CLAMP); texture2D.setBlending(Texture2D.FUNC_REPLACE); // the texture with replace the surface appearance.setTexture(0, texture2D); } return appearance; } public Mesh getMesh() { return tree; } // align the board's z-axis with the current position of the cameraGroup node public void align() { tree.align(cameraGroup); } }
发表评论
-
斜45度地图简介、坐标系转换以及数据碰撞
2011-07-21 18:27 15502手机平台上开 ... -
推荐一些手机游戏开发会用到的网站
2011-07-07 17:53 2295像素图资源类(RPGmaker风格的精灵、地图图块等资源): ... -
动态的水波时钟源码
2011-04-11 22:51 1309在网上找粒子特效的资料,竟然发现我两年前做的一个小水波时钟的程 ... -
发几个自己早期的J2ME独立游戏
2011-02-23 12:40 1759由于大环境影响和精力有限,n久没做过独立游戏了,以 ... -
2D手机游戏的即时阴影效果
2011-02-01 00:09 3853转载要注明作者、出处哟。 前段时 ...
相关推荐
教程将详细介绍JSR-184的基本原理、核心功能以及实际应用案例,帮助读者掌握其编程技巧,实现高质量的3D画面呈现。 ##### Mascot Capsule v3:高性能3D引擎 Mascot Capsule v3是一款专为移动设备优化的3D引擎,...
在本文中,我们将深入探讨如何使用Java 2 Micro Edition(J2ME)平台进行3D场景设计,特别是创建和操作3D五角星。J2ME是Java的一个轻量级版本,主要用于移动设备和嵌入式系统,它提供了一种在这些受限环境中实现3D...
文件“065-066 J2ME3D编程.ppt”很可能包含关于这些主题的详细讲解,包括实例代码和演示,这对于深入理解J2ME中的3D编程至关重要。学习这些内容将帮助开发者克服J2ME平台上的3D图形挑战,创造出引人入胜的移动游戏和...
在J2ME 3D应用中,可以通过更新模型的位置、旋转和缩放来实现动态效果。同时,需要处理用户输入,如触摸屏事件,以实现交互式3D体验。 7. **性能优化** 由于J2ME平台的资源限制,性能优化是3D应用开发中的重要...
标题中的“一个J2ME的3D菜单”指的是在Java 2 Micro Edition(J2ME)平台上实现的一种具有三维效果的菜单系统。J2ME是Java的一个子集,主要用于开发移动设备、嵌入式系统等有限计算资源的平台,如早期的手机游戏和...
3. CANVAS组件:MIDP中的CANVAS类是实现3D图形的关键,它提供了自定义绘图的画布,开发者可以通过重写其draw()方法来绘制3D场景。 二、J2ME 3D核心技术 1. 3D模型:3D模型通常由顶点、法线和纹理坐标构成,通过JSR...
在 J2ME 中实现 3D 图形通常涉及到以下几个关键知识点: 1. **MIDP (Mobile Information Device Profile)**:这是 J2ME 为移动设备定义的一种配置,它提供了基础的用户界面组件、网络连接和文件存储等功能,是开发 ...
为了实现3D迷宫游戏,文章中采用了“立即模式”(Immediate Mode)的渲染方法。这种模式下,开发者可以直接控制图形的绘制,而不是依赖于图形库的缓存机制,从而在资源有限的环境下优化性能。同时,利用深度优先遍历...
通过研究这本书的随书源码,开发者不仅可以学习到J2ME3D游戏开发的基本概念和技术,还能掌握实际项目中的最佳实践,提升自己的编程能力。这些知识点对于想要进入移动游戏开发领域的程序员来说,是一份宝贵的资源。
在本文中,我们将深入探讨基于J2ME的3D游戏开发,以及如何利用J2ME实现各种不同类型的游戏。 **1. J2ME游戏框架** 在J2ME中开发3D游戏,通常会使用如MIDP(Mobile Information Device Profile)和CLDC(Connected ...
教程结构包括示例代码和详细的解释,帮助读者理解如何使用这些API来创建3D对象、管理场景、实现交互和动画效果。每篇文章都配有简单的示例,以便读者能够直观地看到每个方法的应用和结果。这种实践导向的学习方式有...
在J2ME中开发3D游戏,需要理解其核心组件CLDC (Connected Limited Device Configuration) 和MIDP (Mobile Information Device Profile),以及如何利用它们来创建3D环境。 起步篇首先介绍了J2ME的基本概念,包括CLDC...
本"J2ME中文输入Demo"旨在为开发者展示如何在J2ME环境中实现基本的中文输入功能。虽然这个Demo可能不完美,但其核心概念和方法对于理解和构建自己的中文输入解决方案是非常有价值的。 1. **TextBox与TextField** ...
J2ME并不直接支持复杂的3D图形处理,但开发者可以通过Java 2D API来模拟3D效果,如使用二维图像(精灵)和视图变换来构建三维场景。在这个游戏中,开发者可能利用了旋转、平移和缩放等2D变换来实现魔方的转动和视角...
【J2ME源码 3d_menu(代码)】是一个基于Java 2 Micro Edition (J2ME) 平台开发的项目,它提供了一个三维菜单的实现。J2ME是Java的一个子集,专为资源有限的移动设备如手机和嵌入式系统设计,用于开发和部署应用程序...
J2ME 3D手机游戏开发详解 完整版 分为3部分
由于移动设备的资源限制,性能优化在J2ME 3D游戏开发中尤为重要。这可能包括减少多边形数量、优化纹理贴图、使用适当的缓存策略以及避免不必要的计算。 **书籍资源** 提供的书籍很可能是关于J2ME 3D游戏开发的教程...
通过对【GameCarTerrain】这个文件的分析,我们可以深入学习如何在j2ME环境中实现3D场景的构造,如何创建动态的赛车运动,以及如何处理游戏中的碰撞检测和物理模拟。此外,通过查看源码,还可以学习到错误处理、资源...
在 J2ME 中,3D 图形的实现主要依赖于 OpenGL ES(Embedded Systems)的简化版本,称为 JSR-184 或者 M3G (Mobile 3D Graphics API)。这个API提供了创建、管理和渲染3D模型的基本功能,包括顶点坐标、纹理映射、光照...