package manakeri.Zombicalypse; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.Input.Keys; import com.badlogic.gdx.InputProcessor; import com.badlogic.gdx.Screen; import com.badlogic.gdx.graphics.GL10; import com.badlogic.gdx.graphics.GL20; import com.badlogic.gdx.graphics.Mesh; import com.badlogic.gdx.graphics.PerspectiveCamera; import com.badlogic.gdx.graphics.VertexAttribute; import com.badlogic.gdx.graphics.VertexAttributes.Usage; import com.badlogic.gdx.graphics.g2d.SpriteBatch; import com.badlogic.gdx.math.Intersector; import com.badlogic.gdx.math.Plane; import com.badlogic.gdx.math.Vector2; import com.badlogic.gdx.math.Vector3; /** * @author manakeri */ public class GameLoop implements Screen, InputProcessor { private static int WIDTH = 21; private static int HEIGHT = 22; private static final int THRESHOLD = 250; private static final int TARGET_TIME = 5500; private static final int Z_START = 50; private PerspectiveCamera cam; private City city; private final GameLoopUI UI; private final SpriteBatch batch; private GL20 gl; private long counter_start = System.currentTimeMillis(); private long target_start = System.currentTimeMillis(); private long start_time; private long ct; private boolean targeting = false; private final static Plane xzPlane = new Plane(new Vector3(0, 1, 0), 0); private final Vector3 intersection = new Vector3(); private final Vector3 curr = new Vector3(); private final Vector3 last = new Vector3(-1, -1, -1); private final Vector3 delta = new Vector3(); private final Vector2 target = new Vector2(); private Boolean running = true; //FPSLogger fps = new FPSLogger(); private Zombies zombies; private final float[] x = new float[360]; private final float[] z = new float[360]; private final float[] vertices = new float[360 * 3]; private final Mesh points = new Mesh(false, 360 * 3, 0, new VertexAttribute(Usage.Position, 3, "a_position")); private float explosion_delta; private boolean exploding = false; private String s_start_time; private String s_target_start; public GameLoop() { UI = new GameLoopUI(); batch = new SpriteBatch(); for (int i = 0; i < 360; i++) { x[i] = (float) Math.sin(i * 0.01745f) * 2.5f; z[i] = (float) Math.cos(i * 0.01745f) * 2.5f; } } private void checkTargeting(float delta2) { if (targeting && ct - target_start >= TARGET_TIME) { explosion_delta = 0; exploding = true; if (TGame.prefs.getBoolean("effects")) { int expsnd = TGame.rand.nextInt(4); if (TGame.DEBUG) { Gdx.app.log(TGame.TAG, "expsnd #: " + expsnd); } TGame.snd_explosion[expsnd] .play(TGame.prefs.getFloat("volume")); Gdx.input.vibrate(250); } if (TGame.DEBUG) { Gdx.app.log(TGame.TAG, "shot at: " + target); } targeting = false; } if (exploding) { int vi = 0; explosion_delta += delta2; for (int i = 0; i < 360; i++) { vertices[i] = 0; } // Gdx.app.log(TGame.TAG, "total_delta: " + explosion_delta); if (explosion_delta < 0.75f) { for (int i = 0; i < 360; i += 2) { float ox = target.x + 0.5f + explosion_delta * x[i]; float oz = target.y + 0.5f + explosion_delta * z[i]; if (city.isRoad(ox / city.getWidth(), oz / city.getHeight())) { zombies.checkHit(city, (int) ox, (int) oz); vertices[vi++] = ox; vertices[vi++] = 0.1f; vertices[vi++] = oz; } else { vertices[vi++] = 0; vertices[vi++] = 0; vertices[vi++] = 0; } } points.setVertices(vertices); } else { exploding = false; } } }; @Override public void dispose() { if (TGame.DEBUG) { Gdx.app.log(TGame.TAG, "gameloop.dispose()"); } batch.dispose(); UI.dispose(); }; private void drawUI(float delta2) { s_start_time = String.format("%1$TM:%1$TS", ct - start_time); s_target_start = "0"; if (targeting) { s_target_start = Long .toString((TARGET_TIME - (ct - target_start)) / 1000); } UI.draw(gl, delta2, zombies.amount(), s_start_time, s_target_start); } @Override public void hide() { if (TGame.DEBUG) { Gdx.app.log(TGame.TAG, "gameloop.hide()"); } } private void init_city() { city = new City(WIDTH, HEIGHT); zombies = new Zombies(city, Z_START); zombies.init(cam); } @Override public boolean keyDown(int keycode) { switch (keycode) { case Keys.P: running = !running; break; case Keys.BACK: case Keys.ESCAPE: TGame.game.setScreen(TGame.mainmenu); break; case Keys.F1: if (TGame.DEBUG) { Gdx.app.log( TGame.TAG, "fov: " + cam.fieldOfView + ", x: " + cam.position.x + ", y: " + cam.position.y + ", z: " + cam.position.z + ", fps: " + Gdx.graphics.getFramesPerSecond()); } break; case Keys.O: case Keys.MENU: /* * if (TGame.DEBUG) { WIDTH++; HEIGHT++; init_city(); } else { */ TGame.previous_screen = TGame.gameloop; TGame.game.setScreen(TGame.options); // } break; } return true; } @Override public boolean keyTyped(char character) { return false; } @Override public boolean keyUp(int keycode) { return false; } @Override public boolean mouseMoved(int x, int y) { return false; } @Override public void pause() { if (TGame.DEBUG) { Gdx.app.log(TGame.TAG, "gameloop.pause()"); } TGame.prefs.flush(); running = false; } @Override public void render(float delta) { // fps.log(); if (running) { gl.glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT); cam.update(); city.draw(cam); zombies.draw(cam, delta); ct = System.currentTimeMillis(); checkTargeting(delta); if (exploding) { TGame.colshader.begin(); TGame.colshader.setUniformMatrix("u_worldView", cam.combined); Gdx.gl.glEnable(GL20.GL_DEPTH_TEST); points.render(TGame.colshader, GL20.GL_POINTS); Gdx.gl.glDisable(GL20.GL_DEPTH_TEST); TGame.colshader.end(); } drawUI(delta); if (TGame.prefs.getBoolean("effects") && ((ct - start_time) / 1000) % 25 == 0 && TGame.rand.nextInt(20) == 10 - 1) { TGame.snd_zombie[TGame.rand.nextInt(4)].play(TGame.prefs .getFloat("volume") * 0.25f); } } else { // TODO: DRAW "PAUSED" } } @Override public void resize(int width, int height) { if (TGame.DEBUG) { Gdx.app.log(TGame.TAG, "gameloop.resize()"); } gl.glViewport(0, 0, width, height); float unitsOnX = (float) Math.sqrt(2) * width / (width * 0.15f); float pixelsOnX = width / unitsOnX; float unitsOnY = height / pixelsOnX; if (TGame.DEBUG) { Gdx.app.log(TGame.TAG, unitsOnX + ", " + unitsOnY); } cam = new PerspectiveCamera(45, unitsOnX, unitsOnY); cam.position.set(0, 15, 0); cam.near = 1; cam.far = 100; cam.lookAt(WIDTH / 2, 0, HEIGHT / 2); cam.update(); UI.resize(width, height); // if (!_initialized) { init_city(); // } start_time = System.currentTimeMillis(); } @Override public void resume() { if (TGame.DEBUG) { Gdx.app.log(TGame.TAG, "gameloop.resume()"); } running = true; } @Override public boolean scrolled(int amount) { return false; } @Override public void show() { if (TGame.DEBUG) { Gdx.app.log(TGame.TAG, "gameloop.show()"); } gl = Gdx.graphics.getGL20(); Gdx.input.setInputProcessor(this); gl.glClearDepthf(1.0f); gl.glDepthFunc(GL10.GL_LEQUAL); switch ((int) TGame.prefs.getFloat("quality")) { case 1: gl.glDisable(GL10.GL_DITHER); // gl.glHint(GL20.GL_POLYGON_SMOOTH_HINT, GL10.GL_FASTEST); // gl.glHint(GL20.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_FASTEST); // gl.glShadeModel(GL10.GL_FLAT); break; case 5: // gl.glHint(GL20.GL_POLYGON_SMOOTH_HINT, GL10.GL_NICEST); // gl.glHint(GL20.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_NICEST); // gl.glShadeModel(GL10.GL_SMOOTH); // gl.glEnable(GL10.GL_LIGHTING); // gl.glEnable(GL10.GL_LIGHT0); // gl.glEnable(GL10.GL_COLOR_MATERIAL); break; } } @Override public boolean touchDown(int x, int y, int pointer, int button) { counter_start = System.currentTimeMillis(); return false; } @Override public boolean touchDragged(int x, int y, int pointer) { Intersector.intersectRayPlane(cam.getPickRay(x, y), xzPlane, curr); if (!(last.x == -1 && last.y == -1 && last.z == -1)) { Intersector.intersectRayPlane(cam.getPickRay(last.x, last.y), xzPlane, delta); delta.sub(curr); cam.position.add(delta.x, 0, delta.z); cam.lookAt(WIDTH / 2, 0, HEIGHT / 2); } if (cam.position.x < -8.5f) { cam.position.x = -8.5f; } if (cam.position.z < -8.5f) { cam.position.z = -8.5f; } if (cam.position.x > 30) { cam.position.x = 30; } if (cam.position.z > 30) { cam.position.z = 30; } cam.update(); last.set(x, y, 0); return true; } @Override public boolean touchUp(int x, int y, int pointer, int button) { last.set(-1, -1, -1); if (System.currentTimeMillis() - counter_start < THRESHOLD) { Intersector.intersectRayPlane( cam.getPickRay(Gdx.input.getX(), Gdx.input.getY()), xzPlane, intersection); int ix = (int) intersection.x; int iy = (int) intersection.y; int iz = (int) intersection.z; if (ix >= 0 && ix < WIDTH && iz >= 0 && iz < HEIGHT && iy == 0 && !exploding && !targeting && city.getTile(ix, iz) >= 128) { target_start = System.currentTimeMillis(); targeting = true; target.x = ix; target.y = iz; if (TGame.DEBUG) { Gdx.app.log(TGame.TAG, "target set at x: " + ix + ", z: " + iz); } } } counter_start = System.currentTimeMillis(); return true; } }