280 likes | 447 Views
Android Game Development. Android Game Engine – Game logic. Base project. Download our base project and open it in NetBeans cg.iit.bme.hu/ gamedev /KIC/11_AndroidDevelopment/11_05_Android_AnimationScripts_Final.zip Change the android sdk location path
E N D
Android Game Development Android Game Engine – Gamelogic
Base project • Downloadourbase project and open it inNetBeans • cg.iit.bme.hu/gamedev/KIC/11_AndroidDevelopment/11_05_Android_AnimationScripts_Final.zip • Changetheandroidsdklocationpath • Per-userproperties (local.properties) • sdk.dir=changepath here • Start an emulator • Build • Run
Character2D I. • Animated character with basic animations • Stand • Walk • Jump • Compound physics shape (box + circle) • Contact check • Is character grounded? -> can jump
Character2D II. • Create Character2D class in PlatformGame package public class Character2D extends GenericGameObject{ protected Fixture footShape; protected Material material; protected boolean grounded = false; protected float characterHeight = 1; protected float characterWidth = 0.75f; protected float speed = 1.0f; protected float maxSpeed = 1.0f; protected float sliding = 0.0f; protected float bouncing = 0.0f; protected float jumpStrength = 1.0f; protected float mass = 0.2f; protected static int STATE_STAND = 0; protected static int STATE_MOVE = 1; protected static int STATE_JUMP = 2; //protected static int STATE_SHOOT = 3; //protected static int STATE_DIE = 4; protected int state = -1;
Character2D III. public Character2D(String name, String materialName, float height, float width){ super(name, null, null); characterHeight = height; characterWidth = width; Vector3 scale = new Vector3(width,height,1.0f); width *= 0.6f; try{ MeshEntity me = new MeshEntity(name + "_MeshEntity", "UnitQuad", scale); me.setMaterial(materialName); material = MaterialManager.getSingleton().get(materialName); BodyDefbd = new BodyDef(); FixtureDeffd = new FixtureDef(); bd.type = BodyType.DYNAMIC; Body body = PhysicsEngine2D.getSingleton().createBody(bd); body.setBullet(true); PolygonShape s = new PolygonShape(); s.setAsBox(width, height - width); fd.density = 1; fd.friction = 0.0f; //this probably has no effect fd.restitution = bouncing; fd.shape = s; body.createFixture(fd); CircleShape s2 = new CircleShape(); s2.m_radius = width; s2.m_p.y = -height + width; fd.shape = s2; footShape = body.createFixture(fd); body.setFixedRotation(true); Physics2DObject po = new Physics2DObject(body); mass = po.getBody().getMass(); reInit(me, po); po.limitVelocity(new Vector3(0.1f * maxSpeed, -1.0f, -1.0f)); po.setUserData(this); } catch(Exception e){ android.util.Log.e("Character2D init",e.toString()); } changeState(STATE_STAND); }
Character2D IV. public void setSpeed(float v){ speed = v; } public void setJumpStrength(float v){ jumpStrength = v; } public void setSpeedLimit(float v){ maxSpeed = v; } public void setBouncing(float v){ for(Fixture f = ((Physics2DObject)physicsO).getBody().getFixtureList(); f != null; f = f.getNext()) { f.setRestitution(bouncing); } bouncing = v; } public void setDensity(float v){ for(Fixture f = ((Physics2DObject)physicsO).getBody().getFixtureList(); f != null; f = f.getNext()){ f.setDensity(v); } ((Physics2DObject)physicsO).getBody().resetMassData(); mass = ((Physics2DObject)physicsO).getBody().getMass(); } public void setSliding(float v){ sliding = v; }
Character2D V. public void update(float t, float dt) { super.update(t,dt); computeGrounded(); if(grounded){ if(state == STATE_JUMP) changeState(STATE_STAND); if(physicsO.getVelocity().length() > 0.01) changeState(STATE_MOVE); else changeState(STATE_STAND); physicsO.setLinearDamping(0); } else{ physicsO.setLinearDamping(0.0f); } } public void move(float amount){ physicsO.addForce(amount * 5 * speed * mass, 0, 0); ((AnimatedTexture)material.getTexture()).lookLeft(amount > 0); }
Character2D VI. private void computeGrounded() { Vector3 prevPos = physicsO.getPosition(); grounded = false; Physics2DObject po = (Physics2DObject) physicsO; Body b = po.getBody(); Contact c = PhysicsEngine2D.getSingleton().getContacts(); while(c != null) { if(c.isTouching() && (c.m_fixtureA == footShape || c.m_fixtureB == footShape)) { WorldManifold manifold = new WorldManifold(); c.getWorldManifold(manifold); boolean below = true; //it should have only one contact point below = (manifold.points[0].y < (prevPos.y() -(characterHeight - characterWidth))); if(below){ grounded = true; break; } } c = c.m_next; } }
Character2D VII. public void jump(float amount){ if(grounded && amount > 0.1f) { Vector3 lastPos = physicsO.getPosition(); physicsO.moveToPos(lastPos.x(), lastPos.y() + 0.05f*characterHeight, lastPos.z()); physicsO.addForce(0, 6 * jumpStrength * mass, 0); changeState(STATE_JUMP); } } protected void changeState(intnewState) { if(newState == state) return; AnimatedTexturetex = (AnimatedTexture) material.getTexture(); if(newState == STATE_STAND){ tex.playAnimation("stand"); } else if(newState == STATE_MOVE){ tex.playAnimation("walk"); } else if(newState == STATE_JUMP){ tex.playAnimation("jump"); } state = newState; } }
GenericGameObject • Add new method public void reInit(MeshEntity entity, PhysicsObjectpo) { if (entity != null) { if (renderO != null) { this.renderNode.detachObject(renderO); } this.renderO = entity; if (this.renderNode == null) { this.renderNode = SceneManager.getSingleton().getRootNode().createChild(); } this.renderNode.attachObject(this.renderO); } if (po != null) { this.physicsO = po; } }
MainCharacter I. • Create MainCharacter class public class MainCharacter extends Character2D implements PhysicsContactEventListener{ protected Quad tmpQuad = new Quad("mytmpquad"); protected int score = 0; protected int life = 3; protected Level level; public intgetScore(){ return score; } public intgetLife(){ return life; } public MainCharacter(Level level){ super("mainCharacter", "g_DarkMan", 0.5f, 0.4f); this.level = level; setType(ObjectType.MainCharacter); PhysicsEngine2D.getSingleton().registerContactListener(this); setBouncing(0.99f); setSliding(0.99f); setSpeed(1.0f); setSpeedLimit(2.0f); setJumpStrength(1.0f); setDensity(30); }
MainCharacter II. public void onContact(PhysicsObject other) { GameObject GO; try{ GO = (GameObject) other.getUserData(); } catch(Exception e) { android.util.Log.d("MainCharacter", "User data of contact physics object is not a GameObject"); return; } switch(GO.getType()) { case Monster:{ life--; level.removeGameObject(GO.getName()); level.removeGameObject(GO.getName() + "_controller"); break; } case Pit:{ life=-1; } case Item:{ score+=20; level.removeGameObject(GO.getName()); } default:{ break; } } } public PhysicsObjectgetObject() { return physicsO; } }
MainEngine I. • New member variables protected MainCharacter character; private float characterMove = 0; private float characterJump = 0; • init() level = LG.generate(); try{ character = new MainCharacter(this.level); character.setPosition(LG.getPlayerStartPos().x, LG.getPlayerStartPos().y, 0); level.addGameObject(character); }catch(Exception e){ android.util.Log.e("MainEngineinit","Unable to create main character", e); }
MainEngine II. public void update() { … character.move(characterMove); characterMove = 0; character.jump(characterJump); characterJump = 0; level.preUpdate(t, dt); PhysicsEngine2D.getSingleton().update(dt); level.update(t, dt); float cX = character.getPosition().x(); camera.getParent().setPosition(cX, 0, 12); //render
MainEngine III. protected float lastX = 0; protected float lastY = 0; public booleanonTouchEvent(MotionEvent e) { if(e.getAction() == MotionEvent.ACTION_MOVE){ float x = e.getX(); float y = e.getY(); float dx = (x - lastX) * 0.01f; float dy = (y - lastY) * -1f; if(Math.abs(dy) < 10) dy = 0; lastY = e.getY(); characterMove = dx; characterJump = dy; }else if(e.getAction() == MotionEvent.ACTION_DOWN){ lastX = e.getX(); lastY = e.getY(); } return true; }
Monster I. public class Monster extends Character2D implements PhysicsContactEventListener{ protected Level level; public Monster(String name, String materialname, Level level){ super(name, materialname, 0.5f, 0.45f); this.level = level; setType(ObjectType.Monster); PhysicsEngine2D.getSingleton().registerContactListener(this); } public void onContact(PhysicsObject other) { GameObject GO; try{ GO = (GameObject) other.getUserData(); } catch(Exception e){ android.util.Log.d("Monster", "User data of contact physics object is not a GameObject"); return; } switch(GO.getType()){ case UsefulThings: { //android.util.Log.e("Monster", "collided with useful thing"); // checkifmonster is hit fromaboveforexample, thenremoveit //level.removeGameObject(name); break; } } } public PhysicsObjectgetObject() { return physicsO; } }
TargetedCharacterController public class TargetedCharacterController extends GameObject{ protected GenericGameObject target; protected Character2D character; protected float range = 3.0f; public TargetedCharacterController(Character2D c, GenericGameObject target, float range){ super(c.getName() + "_controller"); this.target = target; character = c; this.range = range; } public void preUpdate(float t, float dt){ Vector3 tpos = target.getPosition(); Vector3 cpos = character.getPosition(); Vector dir = tpos.sub(cpos); float l = dir.length(); if(l < range) character.move(Math.signum(dir.d[0])); } }
LevelGenerator protected Character2D mainCharacter; public LevelGenerator(Level level, float maxCameraFov, float cameraAspect, float maxCameraDistance, Character2D mainCharacter) { … this.mainCharacter = mainCharacter; } … protected void generateMonster(float x, float y)throws Exception{ try{ Character2D monster = new Monster("monster_" + monsterCount, "Monster", level); monsterCount++; monster.setType(GameObject.ObjectType.Monster); monster.setSpeed(0.6f); monster.setSpeedLimit(1.0f); TargetedCharacterControllermonsterControll = new TargetedCharacterController(monster, mainCharacter, 4); monster.setPosition(x, y, 0); level.addGameObject(monster); level.addGameObject(monsterControll); } catch (Exception ex) { android.util.Log.e("LevelGenerator", "Unable to create monster"); } }
MainEngine • Init() try{ level = new Level(); character = new MainCharacter(level); LevelGenerator LG = new LevelGenerator(level, 0.5f, ratio,12.0f, character); LG.generate(); character.setPosition(LG.getPlayerStartPos().x, LG.getPlayerStartPos().y, 0); level.addGameObject(character); }catch(Exception e){ android.util.Log.e("MainEngineinit","Unable to create main character", e); } • Update //SceneManager.getSingleton().render(); SceneManager.getSingleton().zOrderedRender();
LevelGenerator - items protected void createItem(float x, float y) throws Exception{ CircleShape shape = new CircleShape(); shape.m_radius = 0.2f; BodyDefbd = new BodyDef(); bd.type = BodyType.KINEMATIC; FixtureDeffd = new FixtureDef(); fd.shape = shape; fd.restitution = 0; fd.isSensor = true; Body body = PhysicsEngine2D.getSingleton().createBody(bd); body.createFixture(fd); try{ MeshEntityitemME = new MeshEntity("item_" + itemCount, "UnitQuad"); itemME.setMeshScale(0.2f, 0.2f, 1); itemME.setMaterial("g_Item"); Physics2DObject itemPhy = new Physics2DObject(body); GenericGameObject item = new GenericGameObject("item_" + itemCount, itemME,itemPhy); item.setType(GameObject.ObjectType.Item); item.setPosition(x, y + 0.4f, 0); level.addGameObject(item); } catch(Exception e){ android.util.Log.e("LevelGenerator", "Unable to create item object: " + e.toString()); } itemCount++; }
HUD • Write game relatedinformationtoscreen • Life • Score • Game Over • … • WecanusetheSpriteMap and theStringDrawerclass
MainEngine I. • New membervariable SpriteMapHUDTex; • Init() HUDTex = (SpriteMap) TextureManager.getSingleton().get("g_HUD"); HUDTex.addLiteral("score", 0, 0, 0.65f, 0.187f); //numbers for(inti = 0; i < 10; ++i){ HUDTex.addLiteral(""+i, i*0.1f, 0.187f, (i+1)*0.1f, 0.38f); } HUDTex.addLiteral("Game Over", 0, 0.39f, 1.0f, 0.62f); HUDTex.addLiteral("Life", 0, 0.62f, 0.4f, 0.82f); HUDTex.addLiteral("heart", 0.52f, 0.66f, 0.74f, 0.85f);
MainEngine II. • Update() SceneManager.getSingleton().zOrderedRender(); level.postUpdate(t, dt); floatto = 0; //offset to += HUDTex.draw("score", to, 0.95f, 0.05f, true, true); to += 0.02; StringDrawer.drawString(HUDTex, "" + character.getScore(), to, 0.95f, 0.05f); to = 0.7f; to += HUDTex.draw("Life", to, 0.95f, 0.05f, true, true); for(int i = 0; i < character.getLife(); ++i){ to += HUDTex.draw("heart", to, 0.95f, 0.05f, true, true); } if(character.getLife() < 0){ HUDTex.draw("Game Over", 0.5f, 0.5f, 0.1f, false, false); }