酷勤网 – 程序员的那点事!

当前位置:首页 > 编程 > 移动开发 > 正文

Android 3D 游戏实现之再谈碰撞

浏览次数: 2012年03月24日 英特尔-软件网络 字号:

接着上一篇jpct-ae,发现已经过去半年,现在都2012了。笔者在这过去的半年里大部分是为了生计奔波,大四真是一个令人难忘的学期。几经辗转,终于在自己喜欢的岗位上尽职尽责了。既然已定了饭碗,就也不自量力学着别人著书立说,或也能青史留下一笔。现在就一起去看看怎么个“深入”法。

1,深入碰撞原理

jpct-ae引擎的碰撞分为:线碰撞、球体碰撞、随圆碰撞 三种,今天的代码原为jse版本,笔者将其转为android版并详加注释,希望对大家有帮助。

2,代码解析
01.package com.threed.jpct.example;
02.
03.import java.lang.reflect.Field;
04.
05.import javax.microedition.khronos.egl.EGL10;
06.import javax.microedition.khronos.egl.EGLConfig;
07.import javax.microedition.khronos.egl.EGLDisplay;
08.import javax.microedition.khronos.opengles.GL10;
09.
10.import android.app.Activity;
11.import android.opengl.GLSurfaceView;
12.import android.os.Bundle;
13.import android.view.KeyEvent;
14.
15.import com.threed.jpct.Camera;
16.import com.threed.jpct.Config;
17.import com.threed.jpct.FrameBuffer;
18.import com.threed.jpct.Light;
19.import com.threed.jpct.Logger;
20.import com.threed.jpct.Object3D;
21.import com.threed.jpct.Primitives;
22.import com.threed.jpct.RGBColor;
23.import com.threed.jpct.SimpleVector;
24.import com.threed.jpct.Texture;
25.import com.threed.jpct.World;
26.import com.threed.jpct.util.MemoryHelper;
27.
28./**
29. * 此示例展示了jpct-ae工作在android版本的碰撞检测
30. *
31. * @author ibm
32. *
33. */
34.public class Collision extends Activity {
35. private static Collision master = null; // activity对象
36. private GLSurfaceView mGLView; // SurfaceView的实现,它使用专用表面显示OpenGL渲染。
37. private MyRenderer renderer = null;// 自定义渲染
38.
39. private static final float DAMPING = 0.1f; // 重力
40. private static final float SPEED = 1f; // 速度
41. private static final float MAXSPEED = 1f; // 最大速度
42.
43. private FrameBuffer fb = null; // FrameBuffer对象
44. private World world = null; // World对象
45.
46. private Object3D plane = null; // 平面
47. private Object3D ramp = null; // 斜面
48. private Object3D cube = null; // 立方体
49. private Object3D cube2 = null; // 立方体
50. private Object3D sphere = null; // 球体
51.
52. private boolean up = false; // 方向上下左右
53. private boolean down = false;
54. private boolean left = false;
55. private boolean right = false;
56.
57. private SimpleVector moveRes = new SimpleVector(0, 0, 0);// 三维矢量
58. private SimpleVector ellipsoid = new SimpleVector(2, 2, 2);// 椭球
59.
60. private RGBColor back = new RGBColor(50, 50, 100); // 颜色
61.
62. private Camera cam; // 记录视野、位置及方向
63.
64. private long time = System.currentTimeMillis(); // 当前毫秒数
65. private long fps = 0; // 帧/秒
66.
67. protected void onCreate(Bundle savedInstanceState) {
68.
69. Logger.log("onCreate");
70.
71. if (master != null) {
72. copy(master);
73. }
74.
75. super.onCreate(savedInstanceState);
76. // 实例化GLSurfaceView
77. mGLView = new GLSurfaceView(getApplication());
78. // 使用自己实现的 EGLConfigChooser,该实现必须在setRenderer(renderer)之前
79. // 如果没有setEGLConfigChooser方法被调用,则默认情况下,视图将选择一个与当前android.view.Surface兼容至少16位深度缓冲深度EGLConfig。
80. mGLView.setEGLConfigChooser(new GLSurfaceView.EGLConfigChooser() {
81. public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display) {
82. int[] attributes = new int[] { EGL10.EGL_DEPTH_SIZE, 16,
83. EGL10.EGL_NONE };
84. EGLConfig[] configs = new EGLConfig[1];
85. int[] result = new int[1];
86. egl.eglChooseConfig(display, attributes, configs, 1, result);
87. return configs[0];
88. }
89. });
90.
91. // 实例化MyRenderer
92. renderer = new MyRenderer();
93. // 设置View的渲染器,同时启动线程调用渲染,以至启动渲染
94. mGLView.setRenderer(renderer);
95. // 设置一个明确的视图
96. setContentView(mGLView);
97.
98. }
99.
100. @Override
101. protected void onPause() { // puase
102. super.onPause();
103. mGLView.onPause();
104. }
105.
106. @Override
107. protected void onResume() { // resume
108. super.onResume();
109. mGLView.onResume();
110. }
111.
112. @Override
113. protected void onStop() {// stop
114. super.onStop();
115. }
116.
117. @Override
118. public boolean onKeyDown(int keyCode, KeyEvent event) { // 按键处理,当上下左右中的一个按下时,则将相应的变量置true
119. switch (keyCode) {
120. case KeyEvent.KEYCODE_DPAD_UP:
121. up = true;
122. break;
123. case KeyEvent.KEYCODE_DPAD_DOWN:
124. down = true;
125. break;
126. case KeyEvent.KEYCODE_DPAD_LEFT:
127. left = true;
128. break;
129. case KeyEvent.KEYCODE_DPAD_RIGHT:
130. right = true;
131. break;
132. }
133. return super.onKeyDown(keyCode, event);
134. }
135.
136. @Override
137. public boolean onKeyUp(int keyCode, KeyEvent event) { // 当松开按键时,才会
138. up = false;
139. down = false;
140. left = false;
141. right = false;
142. return super.onKeyUp(keyCode, event);
143. }
144.
145. private void copy(Object src) {
146. try {
147. // 打印日志
148. Logger.log("Copying data from master Activity!");
149. // 返回一个数组,其中包含目前这个类的的所有字段的Filed对象
150. Field[] fs = src.getClass().getDeclaredFields();
151. // 遍历fs数组
152. for (Field f : fs) {
153. // 尝试设置无障碍标志的值。标志设置为false将使访问检查,设置为true,将其禁用。
154. f.setAccessible(true);
155. // 将取到的值全部装入当前类中
156. f.set(this, f.get(src));
157. }
158. } catch (Exception e) {
159. // 抛出运行时异常
160. throw new RuntimeException(e);
161. }
162.
163. }
164.
165. protected boolean isFullscreenOpaque() {
166. return true;
167. }
168.
169. class MyRenderer implements GLSurfaceView.Renderer {
170.
171. public MyRenderer() {
172. Config.maxPolysVisible = 500; // 最多绘制500个多边形
173. Config.farPlane = 1500; // 最远的合适平面为1500
174. Config.glTransparencyMul = 0.1f;// 在jpct-ae中修改参数计算透明度,公式为trans=offset+objTrans*mul,默认的偏移量为0.1f
175. Config.glTransparencyOffset = 0.1f;// 偏移量,默认为0.1f
176. Config.useVBO = true;// 使用顶点缓冲区代替普通的顶点数组,在某些机器上会变快,默认为true(新版本改为true,原为false)
177. Texture.defaultTo4bpp(true);// ??
178. Texture.defaultToMipmapping(true);// 所有的纹理默认使用mipmaps,默认设置是false
179. }
180.
181. public void onSurfaceChanged(GL10 gl, int w, int h) {
182. if (fb != null) {// 如果fb不为null
183. fb.dispose(); // 销毁清理
184. }
185. fb = new FrameBuffer(gl, w, h); // 在使用前创建一个宽w,高h,内容为支持opengl
186. // 1.0/1.1的FrameBuffer
187. world = new World();// 创建一个新的"世界"。world就像充满对象与光线空的房间
188. if (master == null) { // 如果master对象为空
189. plane = Primitives.getPlane(20, 10); // 得到平面
190. plane.rotateX((float) Math.PI / 2); // 从jpct-ae的坐标旋转到正常坐标系
191. ramp = Primitives.getCube(20); // 得到立方体
192. ramp.rotateX((float) Math.PI / 2);
193. sphere = Primitives.getSphere(30); // 得到球体
194. sphere.translate(-50, 10, 50);
195. cube2 = Primitives.getCube(20);// 立方体
196. cube2.translate(60, -20, 60);
197. cube = Primitives.getCube(2); // 我们可操作的cube,参数表示立方体的缩放
198. cube.translate(-50, -10, -50);
199.
200. plane.setCollisionMode(Object3D.COLLISION_CHECK_OTHERS); // 设置碰撞模式为被碰撞
201. ramp.setCollisionMode(Object3D.COLLISION_CHECK_OTHERS);
202. sphere.setCollisionMode(Object3D.COLLISION_CHECK_OTHERS);
203. cube2.setCollisionMode(Object3D.COLLISION_CHECK_OTHERS);
204. cube.setCollisionMode(Object3D.COLLISION_CHECK_SELF); // 设置碰撞模式为主动碰撞
205.
206. world.addObject(plane); // 将"物体"放到"世界"里
207. world.addObject(ramp);
208. world.addObject(cube);
209. world.addObject(sphere);
210. world.addObject(cube2);
211.
212. Light light = new Light(world); // 为这个"世界"带来光照
213. light.setPosition(new SimpleVector(0, -80, -0)); // 设置光照坐标系
214. light.setIntensity(140, 120, 120); // 设置光照强度
215.
216. cam = world.getCamera(); // 得到当前的Camera
217. cam.moveCamera(Camera.CAMERA_MOVEOUT, 100); // 相对于当前位置向后移动100
218. cam.moveCamera(Camera.CAMERA_MOVEUP, 100); // 向上移动100
219.
220. world.setAmbientLight(20, 20, 20);// 设置环境光
221. MemoryHelper.compact(); // 回收内存
222. if (master == null) { // 实例化Collision对象
223. Logger.log("Saving master Activity!");
224. master = Collision.this;
225. }
226. }
227. }
228.
229. public void onSurfaceCreated(GL10 gl, EGLConfig config) {
230. }
231.
232. public void onDrawFrame(GL10 gl) {
233. move(); // 移动
234.
235. cam.setPositionToCenter(cube);
236. cam.align(cube);
237. cam.rotateCameraX((float) Math.toRadians(30));
238. cam.moveCamera(Camera.CAMERA_MOVEOUT, 100);
239.
240. fb.clear(back);
241. world.renderScene(fb);
242. world.draw(fb);
243. fb.display();
244.
245. if (System.currentTimeMillis() - time >= 1000) {
246. Logger.log(fps + "fps");
247. fps = 0;
248. time = System.currentTimeMillis();
249. }
250. fps++;
251. }
252.
253. public void move() { // 碰撞与移动的设定
254. if (up) { // 按向上方向键
255. SimpleVector t = cube.getZAxis(); // 取得cube的Z轴
256. t.scalarMul(SPEED);// 向里移动
257. moveRes.add(t);
258. }
259. if (down) {
260. SimpleVector t = cube.getZAxis();
261. t.scalarMul(-SPEED); // 向外移动
262. moveRes.add(t);
263. }
264. if (left) {
265. cube.rotateY((float) Math.toRadians(-1));// 向左旋转
266. }
267. if (right) {
268. cube.rotateY((float) Math.toRadians(1)); // 向右旋转
269. }
270.
271. // avoid high speeds;
272. if (moveRes.length() > MAXSPEED) {
273. moveRes.makeEqualLength(new SimpleVector(0, 0, MAXSPEED)); // 设定最大长度为MAXSPEED
274. }
275. cube.translate(0, -0.02f, 0);// 向上移动0.02f
276. moveRes = cube.checkForCollisionEllipsoid(moveRes, ellipsoid, 8); // 设置碰撞
277. cube.translate(moveRes); // 旋转
278.
279. // 重力感应
280. SimpleVector t = new SimpleVector(0, 1, 0);
281. t = cube.checkForCollisionEllipsoid(t, ellipsoid, 1);
282. cube.translate(t);
283.
284. // 阻尼- -#,考虑的还真周到
285. if (moveRes.length() > DAMPING) { // 如果按上方向键或下方向键,产生阻尼
286. moveRes.makeEqualLength(new SimpleVector(0, 0, DAMPING));
287. } else {
288. moveRes = new SimpleVector(0, 0, 0); // 否则不产生
289. }
290. }
291. }
292.}

本文来源:原文链接

无觅相关文章插件,快速提升流量