- 裞ã®OpenGLã䜿çšãããŸããå®éãã²ãŒã ã®ããã°ã©ãã³ã°ã§ã¯æ¢è£œã®ãšã³ãžã³ãæãé »ç¹ã«äœ¿çšããããããããã¯åŠçèªèº«ã®ãããžã§ã¯ãã®ã³ã³ããã¹ãã§ã¯ããŸãæçšã§ã¯ãããŸããã ããžãã¹ã§çŽç²ãªOpenGLãèŠãããšãåºæ¬ãç解ããã®ã«è¯ããšäž»åŒµãã人ããããããããŸãããã2çªç®ã®æ¬ ç¹ããããŸãã
- ã¬ãã¹ã³ã¯éåžžã«ãããã«ããã§ãã ããã°ã©ãã³ã°ã«ç²ŸéããŠãããšã¯ãããå žåçãªå°åŠçã¯ãã¬ãã¹ã³ã§èª¬æãããŠããããšã®å€ããç解ããã®ã«ååãªåºç€ãæã£ãŠããŸããïŒããšãã°ãå€ãã¯å€§åŠã§ã®ã¿ãããªãã¯ã¹ãåããŸãïŒã
- ã¬ãã¹ã³ã®æåŸã«çµæãåºãŸãã-OpenGLããŒã«ã䜿çšããŠ3ã€ã®äžè§åœ¢ãæç»ããŸãã ããã¯å®éã®3Dã²ãŒã ãšã¯ããé¢ããŠãããããåŠçãç°¡åã«èœèãããããšãã§ããŸãã
ãã®ãããlibGDX for Androidã®äœ¿çšã®åºæ¬ã説æããã¬ãã¹ã³ãæºåããããšã«ããŸããããšã«ãããã®è³æãæºåããŠããã®ã§ãåæã«ããã«æçš¿ããŸã-ãã ãã®ã¬ãã¹ã³ã§ã¯ãAndroidåãã®æãã·ã³ãã«ãª3Dã²ãŒã ãäœæããŸããã¹ã¯ãªãŒã³ã·ã§ããã¯èšäºã®çŽ¹ä»ã§ã芧ããã ããŸãã ã ãããç«ã«ããããã
ãªãlibGDXãªã®ãïŒ ãŸããJavaããã°ã©ãã³ã°ãåŠçã«æãããããã³ãŒãã¯Javaã§ããå¿ èŠããããŸãã ããã«ãããéžæè¢ãçµã蟌ãŸããŸãã 第äºã«ãlibGDXã¯éåžžã«ç°¡åã«ç¿åŸã§ããŸããã ç§ã®ç¶æ³ã§ã¯ãããã¯ä»ã®æ¬ ç¹ãäžåã倧ããªå©ç¹ã§ãã
ã²ãŒã ã®ã¢ã€ãã¢ã¯éåžžã«ã·ã³ãã«ã§ããããªãã¯æŠåšã·ã¹ãã ãæ åœããæŠéæ©ã®å¯æ瞊士ã§ãã æµã®è¹ã®ãšã³ãžã³ãç §æºåšã®ç §æºã«ãããšããã¬ãŒã¶ãŒæŠåšã§æéããããŠæ®åœ±ããå¿ èŠããããŸãããæåã®ãã€ãããã¯å°Ÿãé¢ããªãããã«ããŸãã ã€ãŸããå®éã«ã¯ãã²ãŒã ãã¬ã€ã¯ãã¯ãªãã¯ããŠæéããšãããã¬ãŒãºã§èšè¿°ãããŸãã
ãã®ã¬ãã¹ã³ã§ã¯ãAndroid Studio 1.5ã®ã¿ãå¿ èŠã«ãªããŸãïŒããŒãžã§ã³ã¯ç°ãªãå ŽåããããŸããããã§ã¯ããã£ãä»äœ¿çšããããŒãžã§ã³ã瀺ããŸããïŒã
æåã«ãlibGDXãããããžã§ã¯ããäœæããããã®ãŠã£ã¶ãŒããããŠã³ããŒãããå¿ èŠããããŸããããã«ããããããžã§ã¯ãã®åæèšå®ã¿ã¹ã¯ãå€§å¹ ã«ç°¡çŽ åãããŸãïŒ libGDXãããžã§ã¯ãã®wikiæ瀺ã®ãªã³ã¯ããããŠã³ããŒãã§ããŸãïŒã ãããç§ãããã§è¡ã£ãèšå®ã§ãïŒ
çµæã®ãããžã§ã¯ããAndroid Studioã«ã€ã³ããŒãããã³ãŒãèªäœã®äœæ¥ãéå§ããŸãã ã¡ã€ã³ã®ã²ãŒã ã³ãŒãã¯MyGdxGame.javaãã¡ã€ã«ã«ãããŸãïŒãã®ã¯ã©ã¹ã«ç§ãšåãååãä»ããå ŽåïŒã ãã³ãã¬ãŒãã³ãŒããåé€ããŠãç¬èªã®ã³ãŒããæžãå§ããŸãã
public class MyGdxGame extends ApplicationAdapter { public PerspectiveCamera cam; final float[] startPos = {150f, -9f, 0f}; @Override public void create() { cam = new PerspectiveCamera(67, Gdx.graphics.getWidth(), Gdx.graphics.getHeight()); cam.position.set(startPos[0], startPos[1], startPos[2]); cam.lookAt(0, 0, 0); cam.near = 1f; cam.far = 300f; cam.update(); } }
ããã§ã¯ã67床ã®èŠéè§ïŒããªãé »ç¹ã«äœ¿çšãããå€ïŒã§æ°ããã«ã¡ã©ãäœæããç»é¢ã®å¹ ãšé«ãã®ã¢ã¹ãã¯ãæ¯ãèšå®ããŸãã 次ã«ãã«ã¡ã©ã®äœçœ®ããã€ã³ãïŒ150ã-9ã0ïŒã«èšå®ãã座æšã®äžå¿ãèŠãããã«æ瀺ããŸãïŒã²ãŒã ãã¬ã€ãæ§ç¯ãããã©ããããé 眮ããå Žæã ããã§ãïŒã æåŸã«ãupdateïŒïŒãŠãŒãã£ãªãã£ã¡ãœãããåŒã³åºããŠããã¹ãŠã®å€æŽãã«ã¡ã©ã«é©çšããŸãã
ããã§ãç§ãã¡ãèŠããã®ãæãããšãã§ããŸãã ãã¡ãããããçš®ã®3Dã¢ãã«ã䜿çšããããšãã§ããŸãããã¬ãã¹ã³ãç°¡åã«ããããã«ãåçŽãªãã©ãããã®ã¿ãæç»ããŸãã
public class MyGdxGame extends ApplicationAdapter { ... public Model model; public ModelInstance instance; @Override public void create() { ... ModelBuilder modelBuilder = new ModelBuilder(); model = modelBuilder.createCone(20f, 120f, 20f, 3, new Material(ColorAttribute.createDiffuse(Color.GREEN)), VertexAttributes.Usage.Position | VertexAttributes.Usage.Normal); instance = new ModelInstance(model); instance.transform.setToRotation(Vector3.Z, 120); } @Override public void dispose() { model.dispose(); } }
ããã§ã¯ãã³ãŒãã§ã¢ãã«ãäœæããããã«èšèšãããModelBuilderã®ã€ã³ã¹ã¿ã³ã¹ãäœæããŸãã 次ã«ã寞æ³ã20x120x20ã§ãé¢ã®æ°ã3ïŒæçµçã«ãã©ããããåŸãããïŒã®åçŽãªã³ãŒã³ã¢ãã«ãäœæããç·ã®ãããªã¢ã«ã«èšå®ããŸãã ã¢ãã«ãäœæãããšããå°ãªããšãUsage.Positionãæå®ããå¿ èŠããããŸãã Usage.Normalã¯ãã¢ãã«ã«æ³ç·ãè¿œå ãããããç §æãæ£ããæ©èœããŸãã
ã¢ãã«ã«ã¯ãç¬èªã®ãªãœãŒã¹ãæç»ããã³ç®¡çããããã«å¿ èŠãªãã¹ãŠãå«ãŸããŠããŸãã ãã ããæ£ç¢ºã«æç»ããå Žæã«é¢ããæ å ±ã¯å«ãŸããŠããŸããã ãã®ãããModelInstanceãäœæããå¿ èŠããããŸãã ããã«ã¯ãã¢ãã«ãã¬ã³ããªã³ã°ããããã®å Žæãå転ãã¹ã±ãŒã«ã®ãã©ã¡ãŒã¿ãŒã«é¢ããããŒã¿ãå«ãŸããŠããŸãã ããã©ã«ãã§ã¯ãïŒ0ã0ã0ïŒã§æç»ããããããïŒ0ã0ã0ïŒã§ã¬ã³ããªã³ã°ãããModelInstanceãäœæããã ãã§ãã ãã ããããã«ãtransform.setToRotationïŒïŒã¡ãœãããåŒã³åºããŠããã©ããããZ軞ã«æ²¿ã£ãŠ120床å転ãããŸãïŒããã¯ã«ã¡ã©ã®äœçœ®ããèŠãã»ããããããããã§ãïŒã
ã¢ãã«ã¯äœ¿çšåŸã«è§£æŸããå¿ èŠããããããDisposeïŒïŒã¡ãœããã«ã³ãŒããè¿œå ããŸãã
次ã«ãã¢ãã«ã€ã³ã¹ã¿ã³ã¹ãæç»ããŸãããã
public class MyGdxGame extends ApplicationAdapter { ... public ModelBatch modelBatch; @Override public void create() { modelBatch = new ModelBatch(); ... } @Override public void render() { Gdx.gl.glViewport(0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight()); Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT); modelBatch.begin(cam); modelBatch.render(instance); modelBatch.end(); } @Override public void dispose() { model.dispose(); modelBatch.dispose(); } }
ããã§ãCreate ModelBatchãcreateã¡ãœããã«è¿œå ããŸãããã®ã¡ãœããã¯ãã¢ãã«ã®ã¬ã³ããªã³ã°ãšåæåãè¡ããŸãã renderã¡ãœããã§ã¯ãç»é¢ãã¯ãªã¢ããmodelBatch.beginïŒcamïŒãåŒã³åºããModelInstanceãæç»ããŠãããmodelBatch.endïŒïŒãåŒã³åºããŠæç»ããã»ã¹ãå®äºããŸãã æåŸã«ãmodelBatchããªãªãŒã¹ããŠããã¹ãŠã®ãªãœãŒã¹ïŒäœ¿çšããã·ã§ãŒããŒãªã©ïŒãæ£ãããªãªãŒã¹ãããããã«ããå¿ èŠããããŸãã
ããªãè¯ãããã«èŠããŸãããå°ãã®ç §æã§ç¶æ³ãæ¹åã§ããå¯èœæ§ããããããè¿œå ããŸãããã
public class MyGdxGame extends ApplicationAdapter { ... public Environment environment; @Override public void create() { environment = new Environment(); environment.set(new ColorAttribute(ColorAttribute.AmbientLight, 0.4f, 0.4f, 0.4f, 1f)); environment.add(new DirectionalLight().set(0.8f, 0.8f, 0.8f, 10f, 10f, 20f)); ... } @Override public void render() { ... modelBatch.begin(cam); modelBatch.render(instance, environment); modelBatch.end(); } }
ããã§ãEnvironmentã®ã€ã³ã¹ã¿ã³ã¹ãè¿œå ããŸãã ãããäœæããã¢ã³ããšã³ãïŒæ£ä¹±ïŒã©ã€ãïŒ0.4ã0.4ã0.4ïŒãèšå®ããŸãïŒéæ床ã®å€ã¯ç¡èŠãããããšã«æ³šæããŠãã ããïŒã 次ã«ãè²ïŒ0.8ã0.8ã0.8ïŒããã³æ¹åïŒ10ã10ã20ïŒã®DirectionalLightïŒæåæ§ã©ã€ãïŒãäœæããŸãã ããã§ã¯ãã¹ãŠãéåžžã«æçœã§ãããã®ã®ãããªãã¯ãã§ã«äžè¬çãªå æºã«ç²ŸéããŠãããšæããŸãã æåŸã«ãã¬ã³ããªã³ã°äžã«ãäœæãããç°å¢ãã¢ãã«ãã³ãã©ãŒã«æž¡ããŸãã
ãŸã ã²ãŒã ãæžããŠããã®ã§ãéçãªç»åã«å°ãã®ãã€ããã¯ã¹ãè¿œå ããŠã害ã¯ãããŸããã å³é¢ããšã«ã«ã¡ã©ãå°ãåãããŠã¿ãŸãããã libGDXã¢ããªã±ãŒã·ã§ã³ã®ã©ã€ããµã€ã¯ã«ã«ã€ããŠããã§èšãã®ãé©åã§ãã éå§æã«createïŒïŒã¡ãœãããåŒã³åºãããŸãããã®ã¡ãœããã§ã¯ããã¹ãŠã®åæåãé 眮ããã®ãé©åã§ãã 次ã«ãrenderïŒïŒã¡ãœããã1ç§ãããNååŒã³åºãããŸããNã¯FPSã§ãã ãã®ã¡ãœããã¯ãçŸåšã®ãã¬ãŒã ãæç»ããŸãã ãããã£ãŠãã¢ããªã±ãŒã·ã§ã³ã«ãã€ãããºã ãè¿œå ããã«ã¯ãrenderïŒïŒã§ã²ãŒã ãªããžã§ã¯ãã®ãã©ã¡ãŒã¿ãŒãäœããã®æ¹æ³ã§å€æŽããã ãã§ãã
public class MyGdxGame extends ApplicationAdapter { ... final float bound = 45f; float[] pos = {startPos[0], startPos[1], startPos[2]}; float[] Vpos = new float[3]; final float speed = 2f; private float getSpeed() { return speed * Math.signum((float) Math.random() - 0.5f) * Math.max((float) Math.random(), 0.5f); } @Override public void create () { ... // initialize speed for (int i = 0; i < 3; i++){ Vpos[i] = getSpeed(); } } @Override public void render() { ... for (int i = 0; i < 3; i++) { pos[i] += Vpos[i]; if (pos[i] <= startPos[i] - bound) { pos[i] = startPos[i] - bound; Vpos[i] = getSpeed(); } if (pos[i] >= startPos[i] + bound) { pos[i] = startPos[i] + bound; Vpos[i] = getSpeed(); } } cam.position.set(pos[0], pos[1], pos[2]); cam.update(); modelBatch.begin(cam); modelBatch.render(instance, environment); modelBatch.end(); } }
ããã§ã¯ããã©ããããåããŠãããããªé¯èŠãäœæããŸãããå®éã«ã¯ã«ã¡ã©ãåããŠããã®ã§ããããéããŠèŠãããšãã§ããŸãã ã²ãŒã ã®éå§æã«ãcreateïŒïŒã¡ãœããã¯å座æšïŒé床ïŒã®å¢åVpos [i]ã®å€ãã©ã³ãã ã«éžæããŸãã renderïŒïŒã¡ãœããã§åã·ãŒã³ãåæç»ããããã³ã«ãå€æŽã¹ãããã®å€ã座æšã«è¿œå ãããŸãã 座æšãå€æŽããããã«ç¢ºç«ãããå¢çãè¶ ããå Žåã座æšããããã®å¢çã«æ»ããã«ã¡ã©ãä»ã®æ¹åã«åãå§ããããã«æ°ããé床ãçæããŸãã cam.position.setïŒïŒã¯ãäžèšã®æ³åã«åŸã£ãŠèšç®ãããæ°ãã座æšã«ã«ã¡ã©ãå®éã«èšå®ããcam.updateïŒïŒã¯ã«ã¡ã©ãã©ã¡ãŒã¿ãå€æŽããããã»ã¹ãå®äºããŸãã
ç°ãªãããã€ã¹ã§ã¯ãFPSã®éãããããã£ãŠ1ç§ãããã®renderïŒïŒåŒã³åºãã®æ°ã«ããããã©ãããã®é床ãç°ãªãããšã«æ³šæããŠãã ããã ãã¬ãŒã éã®æéã®åº§æšã®å¢åã®äŸåæ§ãããã«è¿œå ãããšãé床ã¯ã©ãã§ãåãã«ãªããŸãã ãããããããžã§ã¯ããè€éã«ããªãããã«ãããè¡ããŸããã
ããã§ã¯ãã²ãŒã HUDãäœæããŸãããã
public class MyGdxGame extends ApplicationAdapter { ... protected Label label; protected Label crosshair; protected BitmapFont font; protected Stage stage; protected long startTime; protected long hits; @Override public void create() { ... instance.transform.setToRotation(Vector3.Z, 90).translate(-5,0,0); font = new BitmapFont(); label = new Label(" ", new Label.LabelStyle(font, Color.WHITE)); crosshair = new Label("+", new Label.LabelStyle(font, Color.RED)); crosshair.setPosition(Gdx.graphics.getWidth() / 2 - 3, Gdx.graphics.getHeight() / 2 - 9); stage = new Stage(); stage.addActor(label); stage.addActor(crosshair); startTime = System.currentTimeMillis(); } @Override public void render() { ... StringBuilder builder = new StringBuilder(); builder.append(" FPS: ").append(Gdx.graphics.getFramesPerSecond()); long time = System.currentTimeMillis() - startTime; builder.append("| Game time: ").append(time); builder.append("| Hits: ").append(hits); builder.append("| Rating: ").append((float) hits/(float) time); label.setText(builder); stage.draw(); } @Override public void resize(int width, int height) { stage.getViewport().update(width, height, true); } }
ãã©ãããã®å転ããã³ã·ãããã©ã¡ãŒã¿ãŒïŒtranslateïŒxãyãzïŒã¡ãœããïŒã¯ãç»é¢ã®äžå€®ã«ãããã«ã¡ã©ãèŠãŠããã®ãšåãå Žæã«åããããããã«å€æŽãããããšã«æ³šæããŠãã ããã ã€ãŸããã²ãŒã ã®éå§æãç§ãã¡ã¯æµãšåãã³ãŒã¹ã«ããŠãæµããšã³ãžã³ã§çŽæ¥èŠãŸãã
ããã§ã¯ã2ã€ã®ããã¹ãã©ãã«ãäœæããŸãã ã©ãã«ã©ãã«ã¯ãã²ãŒã å æ å ±ïŒFPSãã²ãŒã æéããããçµ±èšïŒã衚瀺ããããã«äœ¿çšãããŸãã ååç·ã®ã©ãã«ã¯èµ€ã§æç»ãããã+ããšãã1æåã®ã¿ãå«ãŸããŠããŸãã ããã«ããããã¬ã€ã€ãŒã¯ç»é¢ã®äžå€®ãã€ãŸãã¹ã³ãŒãã衚瀺ããŸãã ããããã«ã€ããŠãæ°ããã©ãã«ã³ã³ã¹ãã©ã¯ã¿ãŒïŒ<TEXT>ãæ°ããLabel.LabelStyleïŒãã©ã³ãã<COLOR>ïŒïŒã§ãç¢æã®ãã©ã³ããšè²ãå«ãã¹ã¿ã€ã«ãæå®ãããŸãã ã©ãã«ã¯addActorïŒïŒã¡ãœããã«ãã£ãŠStageãªããžã§ã¯ãã«æž¡ãããããã«å¿ããŠãã¹ããŒãžã®æç»æã«èªåçã«æç»ãããŸãã
ããã«ãååç·ã©ãã«ã®å ŽåãsetPositionïŒïŒã¡ãœããã¯äœçœ®ïŒç»é¢ã®äžå€®ïŒãèšå®ããŸãã ããã§ã¯ãç»é¢ãµã€ãºïŒGdx.graphics.getWidthïŒïŒã... getHeightïŒïŒïŒã䜿çšããŠããã©ã¹èšå·ãäžå€®ã«è¡šç€ºãããããã«é 眮ããå Žæãèšç®ããŸãã ãŸã å°ããªæ±ãããã¯ããããŸãïŒsetPositionïŒïŒã¯ãç¢æã®å·Šäžé ã®åº§æšãèšå®ããŸãã ãã©ã¹èšå·ã®äžå¿ãç»é¢ã®äžå¿ã«è¡šç€ºãããããã«ãååŸããå€ããçµéšçã«ïŒã€ãŸãã©ã³ãã ã«ïŒå®æ°3ãš9ãåŒããŸããæ¬æ Œçãªã²ãŒã ã§ã¯ãã®ã¢ãããŒãã䜿çšããªãã§ãã ããã ç»é¢ã®çãäžã«ãããã©ã¹èšå·ã ãã¯æ·±å»ã§ã¯ãããŸããã ååç·ãå¿ èŠãªå Žåã¯ã ã¹ãã©ã€ãã䜿çšã§ããŸãã
æç»ãããã³ã«ãStringBuilderã䜿çšããŠããã¹ããäœæããFPSãã²ãŒã ã®æéããããæ°ãè©äŸ¡ãªã©ã衚瀺ãããã¹ãŠã®ãã®ãç»é¢ã®äžéšã«é 眮ããŸãã setTextïŒïŒã¡ãœããã䜿çšãããšãã©ãã«ããã¹ããèšå®ã§ããŸããããã¯ãrenderïŒïŒã§äœåºŠãè¡ããŸãã
確ãã«ããŸã æ®åœ±ã§ããŸããã ãã®æ¬ é¥ãä¿®æ£ããæãæ¥ãŸããã
public class MyGdxGame extends InputAdapter implements ApplicationListener { ... final float zone = 12f; boolean isUnder = false; long underFire; @Override public void create() { ... Gdx.input.setInputProcessor(new InputMultiplexer(this)); } @Override public void render() { if (Math.abs(pos[1] - startPos[1]) < zone && Math.abs(pos[2] - startPos[2]) < zone) { isUnder = true; crosshair.setColor(Color.RED); } else { isUnder = false; crosshair.setColor(Color.LIME); underFire = 0; } ... } @Override public void pause() {} @Override public void resume() {} @Override public boolean touchDown(int screenX, int screenY, int pointer, int button) { if (isUnder) { underFire = System.currentTimeMillis(); } else { hits /= 2; } return true; } @Override public boolean touchUp(int screenX, int screenY, int pointer, int button) { if (isUnder && underFire != 0) { hits += System.currentTimeMillis() - underFire; underFire = 0; } else { hits /= 2; } return false; } }
MyGdxGameã¯ã©ã¹ã®èª¬æãå€æŽãããŠããããšã«æ³šæããŠãã ããã ããã§ã¯ãInputAdapterããç¶æ¿ããApplicationListenerã€ã³ã¿ãŒãã§ã€ã¹ãå®è£ ããŸãã ãã®ãããªæ§é ã«ãããã³ãŒããå€æŽããã«ä¿åã§ããŸããããŠãŒã¶ãŒå ¥åãåŠçããæ©èœãè¿œå ã§ããŸãã ã¯ã©ã¹ãå ¥åãã³ãã©ãŒãšããŠç»é²ããcreateïŒïŒã¡ãœããã«è¡ãè¿œå ãããŸãã InputAdapterã¯æœè±¡ã§ãããããåã«pauseïŒïŒããã³resumeïŒïŒã¡ãœãããå®è£ ããå¿ èŠããããŸãã
ãã¹ãŠã®æ°åŠãããèšç®ã¯ã¬ã³ããŒïŒïŒã«ãããŸãã ã«ã¡ã©ã®åº§æšããã®ãŸãŒã³ã«ãããã©ããã確èªãã察æŠçžæãåãã³ãŒã¹ã®ç»é¢ã®äžå¿ã«ããããã«ããŸãïŒY座æšãšZ座æšãéå§Â±ãŸãŒã³å ã«ãããã©ããïŒã åãã³ãŒã¹ã«ããå Žåã¯ãå°æã§ããããšãæå³ããŸããisUnder= trueã«èšå®ããã¹ã³ãŒããããæããèµ€ã«ããŸãã ç¹°ãè¿ãã«ãªããŸããããããã決å®ãããã®åçŽãã¯
ã¿ããåŠçã¡ãœããã¯ãtouchDownïŒæãç»é¢ã«è§ŠããïŒããã³touchUpïŒæãç»é¢ããåé€ãããïŒãšåŒã°ããŸãã ãããã®ã¡ãœããã¯ã¿ãã座æšãåãå ¥ããŸãããããã§ã¯äœ¿çšããŸããã å®éããã©ããããçŽæ¥èŠãã«ã¯ãã«ã¡ã©ããã®äœçœ®ã«ãããã©ãããå€æããã ãã§ååã§ãã ãã®å ŽåïŒãŠãŒã¶ãŒãæééãã«ã¯ãªãã¯ããå ŽåïŒãtouchDownã§æµã®ãã©ããããã¬ãŒã¶ãŒã§æããæéã®ã«ãŠã³ããéå§ããŸãã ããã§ãªãå Žåã¯ãååã«åå²ããŠãŠãŒã¶ãŒã®ãã€ã³ããæžãããŸãïŒãã¹ã«å¯Ÿããããã«ãã£ãŒïŒã ãŠãŒã¶ãŒãæãé¢ããšãæãé¢ãã®ãé ããããã©ããã確èªããŸãã é ãããå Žåãæééãã§ããã°ïŒã¬ãŒã¶ãŒããŸã ã¿ãŒã²ãããæããŠããå ŽåïŒããã€ã³ããè¿œå ããŸãã
è¿œå ïŒãã©ãããã§ã¯ãªãæŠéæ©ã®ã¢ãã«
äžè¬çã«ãã²ãŒã ã®æºåã¯ã§ããŠããŸããããã£ãšãŸãšãã«èŠããããã«ããããããã©ãããã¯ããªãéå±ã§ãã ãããã£ãŠãã¬ãã¹ã³ãžã®ãªãã·ã§ã³ã®è¿œå ãšããŠããã©ãããã®ä»£ããã«èªç©ºæ©ã®éåžžã®3Dã¢ãã«ãå®è£ ã§ããŸãã ãã®ã¢ãã«ã䜿çšããŠãã²ãŒã ã«æ¿å ¥ããŠã¿ãŠãã ããã
ã¢ãã«ã«ã¯ãç°ãªã3Dãšãã£ã¿ãŒã®4ã€ã®åœ¢åŒããããŸãã ãã ããlibGDXã¯ãã€ããªã¢ãã«åœ¢åŒã䜿çšãããããã²ãŒã ã§äœ¿çšããã«ã¯å€æããå¿ èŠããããŸãã ãã®ããã«ãç¹å¥ãªãŠãŒãã£ãªãã£fbx-convãæäŸãããŠããŸãã åéãããã€ããªãããŠã³ããŒãããŠãããã€ãã®ãã©ã«ããŒã«è§£åããŸãã WindowsãLinuxãããã³MacOSçšã®ããŒãžã§ã³ããããŸãã WindowsããŒãžã§ã³ã¯äžèŠãªãžã§ã¹ãã£ãŒãªãã§èµ·åããŸããLinuxããã³MacOSã®å Žåã¯ãæåã«ã³ãã³ããå®è¡ããå¿ èŠããããŸã
export LD_LIBRARY_PATH=/folder/where/fbx-conv/extracted/
ãããã£ãŠããŠãŒãã£ãªãã£ã«å ±æã©ã€ãã©ãªlibfbxsdk.soãæ¢ãå Žæã瀺ããŸãã ãŠãŒãã£ãªãã£ãå®è¡ããŸãã
./fbx-conv-lin64 -f space_frigate_6/space_frigate_6.3DS
ãã¡ãããã¢ãã«ãžã®ãã¹ãæå®ããOSã®ãã€ããªã䜿çšããå¿ èŠããããŸãã ãã®çµæããã¡ã€ã«
space_frigate_6.g3db
ãååŸããŸãããã®ãã¡ã€ã«ã¯ããããžã§ã¯ããã©ã«ããŒ
android/assets
ïŒAndroidãã©ãããã©ãŒã ã®ã¢ããªã±ãŒã·ã§ã³ãªãœãŒã¹ãå«ããã©ã«ããŒïŒã«é 眮ããå¿ èŠããããŸãã
ä»ã®ã¢ãã«ã䜿çšããã人ã®ããã®libGDXã®ã¢ãã«å€æã®è€éãã«ã€ããŠ
äžè¬ã«ãlibGDX + fbx-convãã³ãã«ã«ã¯éåžžã«åé¡ããããŸãã ããŸãåäœãããã®ã¢ãã«ãèŠã€ããåã«ã httpïŒ //tf3dm.com/ãšhttp://www.turbosquid.com/ããç¡æã®å®å®è¹ã¢ãã«ã1ããŒã¹ã»ã©è©ŠããŸããã å°é£ã¯éåžžã«ç°ãªããŸãã ã²ãŒã å
ã®ã¢ãã«ããã¯ã¹ãã£ãªãã§å€æããããšãããã°ãæ£åžžã«ããŒããããããšããããŸããã衚瀺ãããªãããšããããŸããã¢ãã«ãããŒããããšãã²ãŒã ã¯OutOfMemoryErrorã§ããããã¢ãŠãããŸãã ãã¡ãããããã¯ã¢ãã€ã«ãã©ãããã©ãŒã ã§ããããšãç解ããŠããŸãã ããããPlayããŒã±ããã®ã²ãŒã ã¯ã¯ããã«è€éãªã°ã©ãã£ãã¯ã¹ã瀺ããŠãããããã«ã¯ååãªã¡ã¢ãªããããŸãã æçµçã«äœ¿çšããã¢ãã«ã§ãããåé¡ãåŒãèµ·ãããŸããã éåžžã¯objããå€æãããŸããã§ãããã3dsããå€æããŸããã ããã«ç
§ãããŠãåœé¢ã®éãã¢ãã«ããµããŒãããlibGDXã¯å°ããã€ããšèšããŸãã æ
éã«ã¢ãã«ãéžæããããlibGDXãšã®äºææ§ãèæ
®ããŠèªåã§ã¢ãã«ãäœæããã°ããã®ãšã³ãžã³ãåçŽãªã²ãŒã ã«äœ¿çšã§ããŸãã ãŸãã¯ã jMonkeyEngineãªã©ã®ããé«åºŠãªãšã³ãžã³ã䜿çšããŸãã
ããŠããããã²ãŒã ã«ãã©ã°ã€ã³ããŸãã
public class MyGdxGame extends InputAdapter implements ApplicationListener { ... public AssetManager assets; public boolean loading; @Override public void create() { ... assets = new AssetManager(); assets.load("space_frigate_6.g3db", Model.class); loading = true; } @Override public void render() { if (loading) if (assets.update()) { model = assets.get("space_frigate_6.g3db", Model.class); instance = new ModelInstance(model); loading = false; } else { return; } ... } @Override public void dispose() { model.dispose(); modelBatch.dispose(); } }
ããã§ãAssetManagerã¯ã©ã¹ã®ã€ã³ã¹ã¿ã³ã¹ãäœæããŸãããã®ã¯ã©ã¹ã¯ãã²ãŒã ãªãœãŒã¹ãããŒãããã¢ãã«ãããŒãããããæ瀺ããŸãã åå³é¢ã§ãAssetManagerãã¢ãã«ïŒbooleanãè¿ãupdateïŒïŒã¡ãœããïŒããŸã ããŒãããŠãããã©ããã確èªããŸãã ãããããŒãããããšãéå±ãããã©ãããã®ä»£ããã«ããããé£è¡æ©ãã€ã³ã¹ã¿ã³ã¹ã«æŒã蟌ã¿ãloading = falseã«èšå®ããŠããã®ã€ã³ã¹ã¿ã³ã¹ã®äœæããã¹ãŠã®ãã¬ãŒã ã§ç¹°ãè¿ãããªãããã«ããŸããããããªããšãã¢ããªã±ãŒã·ã§ã³ã®å®è¡äžã«assets.updateïŒïŒãããã«trueãè¿ããŸã
èµ·åæã«ã
java.io.FileNotFoundException: SPACE_FR.PNG
ãŸãã ãã®ãããã¢ãã«ãã¡ã€ã«ã«ã¯ãã¯ã¹ãã£ãå«ãŸããŠããªããããåå¥ã«ããã·ã¥ããå¿ èŠããããŸãã æ瀺ããã4ã€ã®ãã¯ã¹ãã£ãã
SPACE_FR.PNG
ã®ãã¯ã¹ãã£ã
SPACE_FR.PNG
ãååã
SPACE_FR.PNG
ã«å€æŽãã
SPACE_FR.PNG
ã«å ¥ããŠå®è¡ããŸãã ãã®çµæããªãŒããã³ã°ãã¯ãã£ã«ãããã®ãååŸããŸãã ããŠãããã€-ã²ãŒã ãã¬ã€ã®GIFïŒ
çµè«ïŒéåžžã«ã·ã³ãã«ã§ããã䜿çšããæ段ïŒç §æã移åãHUDãã¿ãããã¢ãã«ïŒã«é¢ããŠã¯ã»ãŒå®å šã«èšè¿°ããããã200è¡ã®ã³ãŒãå ã«åããŸããã ãã¡ãããæ¹åã§ããç¹ã¯ãããããããŸããéåžžã®èŠçãã¹ã«ã€ããã¯ã¹ïŒç©ºãŸãã¯åšå²ã®ç©ºéïŒãã·ã§ãããšé£è¡ã®é³ãã²ãŒã ã¡ãã¥ãŒããããã®éåžžã®å®çŸ©ãªã©ã§ãã libGDXã§ã®ã²ãŒã éçºã®æãéèŠãªãã€ã³ãã ãã®ã¬ãã¹ã³ããåŠçãšHabrã®èŽè¡ã®äž¡æ¹ããAndroidäžã§å€ãã®æ°ããé¢çœãã²ãŒã ã®åºçŸã«è²¢ç®ããããšãé¡ã£ãŠããŸãã
ãœãŒã¹ïŒ
- https://libgdx.badlogicgames.com/nightlies/docs/api/overview-summary.html
- http://www.todroid.com/android-gdx-game-creation-part-i-setting-up-up-android-studio-for-creating-games/
- https://xoppa.github.io/blog/basic-3d-using-libgdx/
- http://stackoverflow.com/questions/19699801/dewitters-game-loop-in-libgdx
- http://stackoverflow.com/questions/21286055/run-libgdx-application-on-android-with-unlimited-fps
- https://xoppa.github.io/blog/interacting-with-3d-objects/
- https://xoppa.github.io/blog/loading-models-using-libgdx/
PSïŒ githubã®ã³ãŒããšã²ãŒã ã®apkãã¡ã€ã«ã§ã ã