1 / 63

Android Game Development

Android Game Development. Android Game Engine Basics. Base project. Download our base project and open in NetBeans cg.iit.bme.hu/ gamedev /KIC/11_AndroidDevelopment/11_02_Android_EngineBasics_Base.zip Similar to our OpenGL example Init is called by resize

minowa
Télécharger la présentation

Android Game Development

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Android Game Development Android Game EngineBasics

  2. Base project • Downloadourbase project and openinNetBeans • cg.iit.bme.hu/gamedev/KIC/11_AndroidDevelopment/11_02_Android_EngineBasics_Base.zip • SimilartoourOpenGLexample • Init is called by resize • Changetheandroidsdklocationpath • Per-userproperties (local.properties) • sdk.dir=changepath here • Start an emulator • Build • Run

  3. MainEngine • One instant is createdinMainRenderer • Alleventsareforwardedtothisclass • Windowinited, windowresized, draw a newframe, onTouchevent • New frame: update() • Calculateselapsedtime • Changes „game” state (rotationangles) • Rendersscene (quad)

  4. UEngine.Engine • Createnewpackage: • UEngine.Engine • Reusableclasseswill be created here

  5. Basic classes - Globals • UEngine.Engine.Globals • Wecancreate a classthatwill hold globalvalues • Staticvariables • E.g.: public class Globals { publicstatic float importantThing = 2; } • Easyaccess • Alwaysuseglobalvariablescarefully!

  6. Basic classes • Copyallclasssourcefilesfromtmp_baseclassestosrc\gamedev\android\UEngine\Engine\ • Basic mathutilclasses • Vector • Quaternion • Matrix

  7. Basic Classes – Vectors I. • Vectorclass public class Vector { public float[] d; … • Undefineddimension • Basic operations • addition/substraction • Multiplication/division (elementbyelement) • dotproduct • length • Normalization • add oraddSelf? • Selfwillmodifytheobjectitselfwill (notcreatenewinstance) • Usethiswheneverpossible (efficient)

  8. Basic classes-Vectors II. • Vector3 • Specialization of Vectorto 3 dimension • Definecrossoperation • Defineoftenusedvectors (unit, zero, x dir, y dir etc.) • Vector4 • Specialization of Vectorto 4 dimension • Usedtorepresentvectors of theprojectivespace (homogenouscoordinates) • or RGBA colorvalues • Defineoftenusedvectors (unit, zero, x dir, y dir etc.)

  9. Basic Classes - Quaternion • 4 dimensionalVectorrepresenting a quaternion • Orientationdescribedwith a rotationaxis and angle • Defineinitializationmethodsfromjaw-pitch-roll • Define Vector3 transformation • Defineconcatenation of quaternions (mul/mulSelf) • …

  10. Basic Classes - Matrix • 4x4 matrixclass • Usedtodescribetransformation • Usuallydescribes a rigidtransformationinourcode • Translation • Rotation • Defineinitializationfortranslation and rotation • Defineconcatenation (mul) • Defineinverseifthematrix is a rigidtransform

  11. Resources • Createpackage: UEngine.Engine.Resources • Here weplace: • Textures • Materials • Meshes • Theyareusuallyloadedfrom a file • Theyhave a unique ID • Should be loadedonlyone • Can be sharedbyobjects

  12. AssetManager • Globals.java: import android.content.res.AssetManager; public class Globals { public static AssetManagerassetManager = null; } • MainActivity, onCreate(): gamedev.android.UEngine.Engine.Globals.assetManager = getAssets();

  13. Resource • Createnewclass: Resource package gamedev.android.UEngine.Engine.Resources; public class Resource { String name; public Resource(String name){ this.name = name; } public String getName(){ return this.name; } public void load(){ } public void destroy(){ } }

  14. Resources - Texture • Createnewclass: Texture public class Texture extends Resource { protected int[] id = new int[1]; protected String filename = null; protected float repeatU = 1; protected float repeatV = 1; public Texture(String name) { super(name); id[0] = -1; } public intgetID() { return this.id[0]; } public void setFileName(String filename) { this.filename = filename; } public void setRepeatU(float v){repeatU = v;} public void setRepeatV(float v){repeatV = v;} OpenGLid Howmanytimesweshouldrepeatethetextureoneachdirection (coordinatescaling)

  15. ResourcesTexture II. public void load(){ super.load(); GLES10.glGenTextures(1, this.id, 0); Bitmap bitmap; try{ bitmap = BitmapFactory.decodeStream(Globals.assetManager.open(this.filename == null ? this.name : this.filename)); } catch (IOException e){ e.printStackTrace(); return; } GLES10.glBindTexture(GLES10.GL_TEXTURE_2D, this.id[0]); GLES10.glTexParameterx(GLES10.GL_TEXTURE_2D, GLES10.GL_TEXTURE_MIN_FILTER, GLES10.GL_NEAREST); GLES10.glTexParameterx(GLES10.GL_TEXTURE_2D, GLES10.GL_TEXTURE_MAG_FILTER, GLES10.GL_NEAREST); GLUtils.texImage2D(GLES10.GL_TEXTURE_2D, 0, bitmap, 0); bitmap.recycle(); }

  16. ResourcesTexture III. public void destroy() { super.destroy(); GLES10.glDeleteTextures(1, this.id, 0); } public void enable() { GLES10.glEnable(GLES10.GL_TEXTURE_2D); GLES10.glBindTexture(GLES10.GL_TEXTURE_2D, this.id[0]); GLES10.glMatrixMode(GLES10.GL_TEXTURE); GLES10.glLoadIdentity(); if(repeatU * repeatV != 1){ GLES10.glScalef(repeatU, repeatV, 1.0f); } GLES10.glMatrixMode(GLES10.GL_MODELVIEW); } public static void disable() { GLES10.glBindTexture(GLES10.GL_TEXTURE_2D, 0); GLES10.glDisable(GLES10.GL_TEXTURE_2D); } }

  17. Resources – Material I. public class Material extends Resource{ public static int ALPHA_BLEND_MODE_NONE = 0; public static int ALPHA_BLEND_MODE_BLEND = 1; public static int ALPHA_BLEND_MODE_ADD = 2; protected Texture texture= null; protected boolean lighting = false; protected intalphaBlendMode = ALPHA_BLEND_MODE_NONE; public Material(String name) { super(name); } …

  18. Resources – Material II. public void setTexture(Texture texture) { this.texture = texture; } public Texture getTexture() { return this.texture; } public void setLighting(boolean on) { this.lighting = on; } public booleangetLighting() { return this.lighting; } public intgetAlphaBlendMode() { return alphaBlendMode; } public void setAlhpaBlendMode(int mode){ alphaBlendMode = mode; } …

  19. Resources – Material III. public void load() { } public void destroy(){ } public void set(){ if (this.texture != null) this.texture.enable(); else Texture.disable(); if(alphaBlendMode != ALPHA_BLEND_MODE_NONE){ GLES10.glEnable(GLES10.GL_BLEND); if(alphaBlendMode == ALPHA_BLEND_MODE_ADD) GLES10.glBlendFunc(GLES10.GL_ONE, GLES10.GL_ONE); else GLES10.glBlendFunc(GLES10.GL_SRC_ALPHA, GLES10.GL_ONE_MINUS_SRC_ALPHA); } else{ GLES10.glDisable(GLES10.GL_BLEND); } } }

  20. Resources – Mesh • Createclass: Mesh public class Mesh extends Resource{ protected FloatBuffer VB = null; protected FloatBuffer TB = null; protected FloatBuffer NB = null; protected intvertexcount = 0; public Mesh(String name){ super(name); } public void load(){ super.load(); } public void destroy(){ super.destroy(); this.VB = null; this.TB = null; this.NB = null; }

  21. Resources – Mesh II. publicvoidrender(){ if (this.VB == null) { return; } GLES10.glEnableClientState(GLES10.GL_VERTEX_ARRAY); GLES10.glVertexPointer(3, GLES10.GL_FLOAT, 0, this.VB); if (this.TB != null) { GLES10.glEnableClientState(GLES10.GL_TEXTURE_COORD_ARRAY); GLES10.glTexCoordPointer(2, GLES10.GL_FLOAT, 0, this.TB); } if (this.NB != null) { GLES10.glEnableClientState(GLES10.GL_NORMAL_ARRAY); GLES10.glNormalPointer(GLES10.GL_FLOAT, 0, this.NB); } GLES10.glDrawArrays(GLES10.GL_TRIANGLES, 0, this.vertexcount); GLES10.glDisableClientState(GLES10.GL_VERTEX_ARRAY); GLES10.glDisableClientState(GLES10.GL_TEXTURE_COORD_ARRAY); GLES10.glDisableClientState(GLES10.GL_NORMAL_ARRAY); }

  22. Resources – Quad I. • Createnewclass: Quad publicclassQuadextendsMesh { publicQuad(Stringname){ super(name); this.vertexcount = 6; } publicvoidload(){ float[] VCoords = { -1.0F, -1.0F, 0.0F, 1.0F, -1.0F, 0.0F, 1.0F, 1.0F, 0.0F, //triangle 1 -1.0F, -1.0F, 0.0F, 1.0F, 1.0F, 0.0F, -1.0F, 1.0F, 0.0F }; //triangle 2 float[] TCoords = { 0.0F, 1.0F, 1.0F, 1.0F, 1.0F, 0.0F, //triangle 1 0.0F, 1.0F, 1.0F, 0.0F, 0.0F, 0.0F }; //triangle 2 float[] NCoords = { 0.0F, 0.0F, 1.0F, 0.0F, 0.0F, 1.0F, 0.0F, 0.0F, 1.0F, //triangle 1 0.0F, 0.0F, 1.0F, 0.0F, 0.0F, 1.0F, 0.0F, 0.0F, 1.0F }; //triangle 2 …

  23. Resources – Quad II. ByteBuffervbb = ByteBuffer.allocateDirect(VCoords.length * 4); vbb.order(ByteOrder.nativeOrder()); this.VB = vbb.asFloatBuffer(); this.VB.put(VCoords); this.VB.position(0); ByteBuffernbb = ByteBuffer.allocateDirect(NCoords.length * 4); nbb.order(ByteOrder.nativeOrder()); this.NB = nbb.asFloatBuffer(); this.NB.put(NCoords); this.NB.position(0); ByteBuffertbb = ByteBuffer.allocateDirect(TCoords.length * 4); tbb.order(ByteOrder.nativeOrder()); this.TB = tbb.asFloatBuffer(); this.TB.put(TCoords); this.TB.position(0); } }

  24. Tryourclasses I. • MainEngine: • RemoveprotectedFloatBuffer VB = null; • Add: Material m; Texture t; Mesh mesh; • Init: publicvoidinit() { GLES10.glClearColor(0.5F, 0.5F, 1.0F, 1.0F); t = newTexture("TestTexture"); t.setFileName("brick.jpg"); t.load(); m = newMaterial("TestMaterial"); m.setTexture(t); m.load(); mesh = newQuad("TestQuad"); mesh.load(); }

  25. Tryourclasses II. • MainEngine update: • Remove: GLES10.glColor4f(1, 0, 0, 1); GLES10.glEnableClientState(GLES10.GL_VERTEX_ARRAY); GLES10.glVertexPointer(3, GLES10.GL_FLOAT, 0, this.VB); GLES10.glDrawArrays(GLES10.GL_TRIANGLES, 0, 6); GLES10.glDisableClientState(GLES10.GL_VERTEX_ARRAY); • Add: GLES10.glClearColor(0.5F, 0.5F, 1.0F, 1.0F); m.set(); mesh.render(); }

  26. Compile and Run

  27. ResourceManagers • Resourcesshould be loadedonlyonce • Managerstrackthem, placethemin a map • Eachresourcetypewillhaveitsmanager • Allresourcesshould be registeredtoitsresourcemanager • Allresourcesshould be aquiredthroughtheresourcemanager

  28. ResourceManager I. • CreateclassResourceManagerinResourcespackage publicabstractclassResourceManager<R extends Resource>{ protected HashMap<String, R> resources = new HashMap(); public final R get(String name) { if (this.resources.containsKey(name)) { return this.resources.get(name); } return load(name); } protected abstract R loadImpl(String paramString); protected final R load(String name) { if (this.resources.containsKey(name)) { return this.resources.get(name); } R r = loadImpl(name); if (r != null) { this.resources.put(name, r); } return r; } …

  29. ResourceManager II. public final void destroy(String name){ if (this.resources.containsKey(name)) ((Resource)this.resources.get(name)).destroy(); } public final boolean add(R r){ if (!this.resources.containsKey(r.getName())) { this.resources.put(r.getName(), r); } return false; } public void clear(){ for(Resource r : resources.values()){ r.destroy(); } resources.clear(); } }

  30. TextureManager public class TextureManager extends ResourceManager<Texture> { private static TextureManager instance = new null; public static TextureManagergetSingleton(){ if(instance == null) instance = new TextureManager(); return instance; } public static void clearSingleton(){ if(instance != null) instance.clear(); instance = null; } protected Texture loadImpl(String name){ return null; } }

  31. MaterialManager public class MaterialManager extends ResourceManager<Material>{ private static MaterialManager instance = null; public static MaterialManagergetSingleton(){ if(instance == null) instance = new MaterialManager(); return instance; } public static void clearSingleton(){ if(instance != null) instance.clear(); instance = null; } protected Material loadImpl(String name){ return null; } }

  32. MeshManager public class MeshManager extends ResourceManager<Mesh> { private static MeshManager instance = null; private MeshManager(){ Quad quad = new Quad("UnitQuad"); quad.load(); add(quad); } public static MeshManagergetSingleton() { if(instance == null) instance = new MeshManager(); return instance; } public static void clearSingleton(){ if(instance != null) instance.clear(); instance = null; } protected Mesh loadImpl(String name) { return null; } }

  33. Trythemanagers • MainEngine: remove t, m, meshattributes • Init: Material m; Texture t; Meshmesh; t = newTexture("TestTexture"); t.setFileName("brick.jpg"); t.load(); TextureManager.getSingleton().add(t); m = newMaterial("TestMaterial"); m.setTexture(t); m.load(); MaterialManager.getSingleton().add(m); • update: MaterialManager.getSingleton().get("TestMaterial").set(); MeshManager.getSingleton().get("UnitQuad").render();

  34. Trythemanagers • MainEngine add newmethod: publicvoiddestroy() { MaterialManager.clearSingleton(); TextureManager.clearSingleton(); MeshManager.clearSingleton(); } • MainSurfaceView add method: publicvoidonPause() { super.onPause(); this.mRenderer.engine.destroy(); } • MainActivity add method: publicvoidonPause(){ super.onPause(); mGLView.onPause(); } • Compile and run

  35. Compile and Run

  36. SceneGraph • All actors of the virtual world will be placed in a scene graph • Scene graph: tree hierarchy of transformations • Each scene graph node (scene node) can contain objects of the virtual world (movables) • The concatenated transformation from the root node will be applied for the objects of scene node • Each scene node and movable should have a unique name • They should be registered to the scene graph • Only objects attached to scene nodes will be rendered • Create new package SceneGraph for the classes

  37. SceneManager I. public class SceneManager { public class NameCollisionException extends Exception { public NameCollisionException(String message) { super(message); } } private static SceneManager instance = null; protected intuniqueID = 0; protected intuniqueIDM = 0; protected HashMap<String, SceneNode> nodes = new HashMap(); protected HashMap<String, Movable> movables = new HashMap(); LinkedList<SceneNode> zOrderedNodes = new LinkedList<SceneNode>(); protected SceneNoderootNode; private SceneManager() {} public static SceneManagergetSingleton() { if(instance == null) instance = new SceneManager(); return instance; } public static void clearSingleton(){ if(instance != null) instance.clear(); instance = null; } …

  38. SceneManager II. void registerNode(SceneNode node) throws Exception { if (node.getName() == null) { while (true) { this.uniqueID += 1; node.name = ("SceneNode" + this.uniqueID); try { registerNode(node); break; } catch (NameCollisionExceptionlocalException) { } } } if (this.nodes.containsKey(node.getName())) { throw new NameCollisionException("SceneNode with the same name already exsists: " + node.getName()); } this.nodes.put(node.getName(), node); } …

  39. SceneManager III. void registerMovable(Movable m) throws Exception { if (m.getName() == null) { while (true) { this.uniqueIDM += 1; m.name = ("UnknownMovable" + this.uniqueIDM); try { registerMovable(m); break; } catch (NameCollisionExceptionlocalException) { } } } if (this.movables.containsKey(m.getName())) { throw new NameCollisionException("Movable with the same name already exsists: " + m.getName()); } this.movables.put(m.getName(), m); } …

  40. SceneManager IV. public void zOrderedRender() { if (zOrderedNodes.size() == 0) { class SceneGraphVisitor { public void visit(SceneNode node) { for (SceneNode n : node.children) { insert(n); visit(n); } } protected void insert(SceneNode node) { int location = 0; for (SceneNode n : zOrderedNodes) { if (n.getPosition().z() > node.getPosition().z()) { break; } location++; } zOrderedNodes.add(location, node); } }; new SceneGraphVisitor().visit(rootNode); } for (SceneNode n : zOrderedNodes) { n.render(false); } } …

  41. SceneManager V. public void update(float t, float dt) { this.rootNode.update(t, dt); } public SceneNodegetNode(String name) { return (SceneNode) this.nodes.get(name); } public Movable getMovable(String name) { return (Movable) this.movables.get(name); } public SceneNodegetRootNode() { return this.rootNode; } public void render() { this.rootNode.render(true); } public void clear(){ nodes.clear(); movables.clear(); zOrderedNodes.clear(); rootNode = null; } }

  42. SceneGraph – SceneNode I. public class SceneNode { protected String name = null; protected SceneNode parent = null; protected LinkedList<SceneNode> children = new LinkedList(); protected LinkedList<Movable> movables = new LinkedList(); protected Vector3 position = new Vector3(); protected Quaternion orientation = new Quaternion(); protected Matrix4 transform = new Matrix4(); protected Matrix4 derivedTransform = this.transform; protected Matrix4 transformInv = new Matrix4(); protected Matrix4 derivedTransformInv = this.transformInv; protected booleaninverseDirty = false; …

  43. SceneGraph – SceneNode II. public SceneNode(String name) throws Exception { this.name = name; if (SceneManager.getSingleton() != null) SceneManager.getSingleton().registerNode(this); this.derivedTransform = this.transform; this.derivedTransformInv = this.transformInv; } public SceneNode() { if (SceneManager.getSingleton() != null) try { SceneManager.getSingleton().registerNode(this); } catch (Exception localException) { } this.derivedTransform = this.transform; this.derivedTransformInv = this.transformInv; } …

  44. SceneGraph – SceneNode III. public SceneNode(String name, SceneNode parent) throws Exception { this.name = name; if (SceneManager.getSingleton() != null) SceneManager.getSingleton().registerNode(this); if (parent != null) { this.parent = parent; this.derivedTransform = new Matrix4(parent.derivedTransform); this.derivedTransformInv = new Matrix4(parent.derivedTransformInv); this.inverseDirty = true; } } public SceneNode(SceneNode parent) { if (SceneManager.getSingleton() != null) { try { SceneManager.getSingleton().registerNode(this); } catch (Exception localException){} } if (parent != null) { this.parent = parent; this.derivedTransform = new Matrix4(parent.derivedTransform); this.derivedTransformInv = new Matrix4(parent.derivedTransformInv); this.inverseDirty = true; } } …

  45. SceneGraph – SceneNode IV. private void parentChanged() { refreshDerivedTransform(); } private void refreshDerivedTransform() { if (this.parent != null) { this.derivedTransform = this.transform.mul(this.parent.derivedTransform); } this.inverseDirty = true; for (SceneNode n : this.children) n.refreshDerivedTransform(); } private void refreshInvTransform() { this.transformInv = this.transform.inverseAffine(); if (this.parent != null) { this.derivedTransformInv = this.derivedTransform.inverseAffine(); } this.inverseDirty = false; } …

  46. SceneGraph – SceneNode V. public SceneNodegetParent(){ return parent; } public Matrix4 getInverseTransform() { if (this.inverseDirty) refreshInvTransform(); return this.transformInv; } public Matrix4 getInverseDerivedTransform() { if (this.inverseDirty) refreshInvTransform(); return this.derivedTransformInv; } public String getName() { return this.name; } public Vector3 getPosition() { return this.position; } public void setPosition(Vector3 p) { this.position = p; this.transform.setTranslate(p); refreshDerivedTransform(); this.inverseDirty = true; } …

  47. SceneGraph – SceneNode VI. public void setPosition(float x, float y, float z) { this.position.set(x, y, z); this.transform.setTranslate(this.position); refreshDerivedTransform(); this.inverseDirty = true; } public Quaternion getOrientation() { return this.orientation; } public void setOrientation(Quaternion q) { this.orientation = q; this.transform.setRotate(q); refreshDerivedTransform(); this.inverseDirty = true; } public void setOrientation(float yaw, float pitch, float roll) { this.orientation.set(yaw, pitch, roll); this.transform.setRotate(this.orientation); refreshDerivedTransform(); this.inverseDirty = true; } …

  48. SceneGraph – SceneNode VII. public SceneNodegetChild(int index) { if (this.children.size() <= index) { return null; } return (SceneNode)this.children.get(index); } public SceneNodecreateChild(String name) throws Exception { SceneNode child = new SceneNode(name, this); this.children.add(child); return child; } public SceneNodecreateChild() { SceneNode child = new SceneNode(this); this.children.add(child); return child; } public void addChild(SceneNode node) { if (!this.children.contains(node)) { this.children.add(node); node.parent = this; node.parentChanged(); } } …

  49. SceneGraph – SceneNode VIII. public void removeChild(SceneNode node) { this.children.remove(node); node.parent = null; node.parentChanged(); } public void removeChild(String name) { for (SceneNode n : this.children) if (name.equals(n.getName())) { this.children.remove(n); n.parent = null; n.parentChanged(); return; } } public void attachObject(Movable o) { if (!this.movables.contains(o)) { this.movables.add(o); o.changeParent(this); } } …

  50. SceneGraph – SceneNode IX. public void detachObject(Movable o) { this.movables.remove(o); } public void detachObject(String name) { for (Movable m : this.movables) if (name.equals(m.getName())) { this.movables.remove(m); return; } } …

More Related