package fr.wisper.screens.gamescreen; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.assets.AssetManager; import com.badlogic.gdx.graphics.GL20; import com.badlogic.gdx.graphics.g2d.SpriteBatch; import com.badlogic.gdx.maps.tiled.TiledMap; import com.badlogic.gdx.maps.tiled.TmxMapLoader; import com.badlogic.gdx.maps.tiled.renderers.OrthogonalTiledMapRenderer; import com.badlogic.gdx.math.Vector2; import com.badlogic.gdx.physics.box2d.*; import com.badlogic.gdx.physics.box2d.joints.MouseJoint; import com.badlogic.gdx.physics.box2d.joints.MouseJointDef; import com.badlogic.gdx.scenes.scene2d.InputEvent; import com.badlogic.gdx.scenes.scene2d.utils.ClickListener; import com.badlogic.gdx.utils.Array; import com.badlogic.gdx.utils.Scaling; import com.badlogic.gdx.utils.Timer; import com.badlogic.gdx.utils.viewport.ScalingViewport; import fr.wisper.Game.WisperGame; import fr.wisper.assets.GameScreenAssets; import fr.wisper.entities.AbstractBox2dWrapper; import fr.wisper.entities.BulletBox2d; import fr.wisper.entities.Wisper; import fr.wisper.entities.WisperBox2d; import fr.wisper.screens.loading.LoadingScreen; import fr.wisper.utils.Config; import fr.wisper.utils.Debug; import fr.wisper.utils.ExtendedStage; import net.dermetfan.utils.libgdx.box2d.Box2DMapObjectParser; import java.util.ArrayList; import java.util.List; public class GameScreen implements FadingScreen { // Global stuff long lastClickTime = 0; boolean isDashUp = true; boolean isMoveUp = true; private Timer timer; private Timer.Task timerTask; private static final float TIME_STEP = 1 / 60f; private static final int VELOCITY_ITERATIONS = 8; private static final int POSITION_ITERATIONS = 3; // Stage private ExtendedStage<GameScreen> stage; // Box2d private World world; private Box2DDebugRenderer debugRenderer; private OrthogonalTiledMapRenderer mapRenderer; Box2DMapObjectParser box2dParser; WisperBox2d wisper; private MouseJointDef jointDef; private MouseJoint joint; private List<AbstractBox2dWrapper> removedWrappers = new ArrayList<AbstractBox2dWrapper>(); private List<Body> inactiveBodies = new ArrayList<Body>(); // Batch private SpriteBatch batch; private Array<Body> bodies = new Array<Body>(); private int chosenWisper = Wisper.BLACK_WISPER; public GameScreen(int chosenWisper) { this.chosenWisper = chosenWisper; } @Override public void render(float delta) { Gdx.gl.glClearColor(0.95f, 0.95f, 0.95f, 1); Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); // Manage camera WisperGame.Camera.update(); // Stage stage.act(delta); stage.draw(); // Clear world clearWorld(); // Box2D world.step(TIME_STEP, VELOCITY_ITERATIONS, POSITION_ITERATIONS); mapRenderer.setView(WisperGame.Camera); mapRenderer.getSpriteBatch().setProjectionMatrix(WisperGame.Camera.combined); mapRenderer.render(); //debugRenderer.render(world, WisperGame.Camera.combined); // Batch batch.setProjectionMatrix(WisperGame.Camera.combined); world.getBodies(bodies); batch.begin(); for (Body body : bodies) { if (body.getUserData() != null && body.getUserData() instanceof AbstractBox2dWrapper) { if (((AbstractBox2dWrapper) body.getUserData()).isComplete()) { removedWrappers.add(((WisperBox2d) body.getUserData())); } else { ((AbstractBox2dWrapper) body.getUserData()).draw(batch, delta); } } } batch.end(); } public void clearWorld() { for (AbstractBox2dWrapper entity : removedWrappers) { world.destroyBody(entity.getBody()); entity.dispose(); } removedWrappers.clear(); for (Body body : inactiveBodies) { body.setActive(false); } inactiveBodies.clear(); } @Override public void resize(int width, int height) { WisperGame.Camera.zoom = Config.GAME_RATIO; WisperGame.Camera.updateViewport(); ScalingViewport stageViewport = new ScalingViewport( Scaling.fit, WisperGame.VirtualViewport.getVirtualWidth(), WisperGame.VirtualViewport.getVirtualHeight(), WisperGame.Camera); stage.setViewport(stageViewport); stage.getViewport().update(width, height, true); } @Override public void show() { // Stage stage = new ExtendedStage(this, new WisperChooseMenu()); initInputListener(); Gdx.input.setInputProcessor(stage); Gdx.input.setCatchBackKey(true); // Box2d world = new World(new Vector2(0, -9.81f), true); // newton -9.81f debugRenderer = new Box2DDebugRenderer(); initContactListener(); // Wisper & Batch timer = new Timer(); batch = new SpriteBatch(); wisper = new WisperBox2d(chosenWisper, world); // Temps new WisperBox2d(Wisper.BLACK_WISPER, world).setPosition( Config.APP_WIDTH / 2 - 10, Config.APP_HEIGHT / 2 - 10); new WisperBox2d(Wisper.BLUE_WISPER, world).setPosition( Config.APP_WIDTH / 2 + 10, Config.APP_HEIGHT / 2 + 10); // Tiled map TiledMap map = new TmxMapLoader().load("tiledmap/tiledmap.tmx"); mapRenderer = new OrthogonalTiledMapRenderer(map, Config.GAME_RATIO); box2dParser = new Box2DMapObjectParser(Config.GAME_RATIO); box2dParser.load(world, map); // Joint jointDef = new MouseJointDef(); jointDef.bodyA = box2dParser.getBodies().values().next(); jointDef.collideConnected = true; jointDef.bodyB = wisper.getBody(); } private void moveWisperTo(float x, float y, float maxForce, float dampingRation) { if (isMoveUp) { jointDef.maxForce = maxForce; // 500 jointDef.dampingRatio = dampingRation; // 15 if (joint != null) { world.destroyJoint(joint); joint = null; } jointDef.target.set(wisper.getPosition()); joint = (MouseJoint) world.createJoint(jointDef); joint.setTarget(new Vector2(x, y)); } else { Debug.Log("Wait until dash is over to move !"); } } private void dashWisperTo(float x, float y) { if (isDashUp && isMoveUp) { Vector2 particlePos = wisper.getPosition(); Vector2 requestedPos = new Vector2(x, y); double distance = Math.max( Math.sqrt(Math.pow(particlePos.x - requestedPos.x, 2) + Math.pow(particlePos.y - requestedPos.y, 2)), 1) / Config.GAME_RATIO; double dashDistance = Math.min(distance, Config.WISPER_DASH_DISTANCE); float alpha = (float)dashDistance / (float)distance; Vector2 AB = new Vector2(requestedPos.x - particlePos.x, requestedPos.y - particlePos.y); Vector2 ABPrim = new Vector2(alpha * AB.x, alpha * AB.y); Vector2 BPrim = new Vector2(ABPrim.x + particlePos.x, ABPrim.y + particlePos.y); moveWisperTo(BPrim.x, BPrim.y, Config.BOX2D_WISPER_DASH_FORCE, Config.BOX2D_WISPER_DASH_DAMPING); timerTask = new Timer.Task() { @Override public void run() { isDashUp = true; } }; isDashUp = false; timer.scheduleTask(timerTask, Config.WISPER_DASH_TIMEOUT); isMoveUp = false; timer.scheduleTask(new Timer.Task() { @Override public void run() { isMoveUp = true; } }, Config.BOX2D_WISPER_DASH_TIME); } else { moveWisperTo(x, y, Config.BOX2D_WISPER_MOVE_FORCE, Config.BOX2D_WISPER_MOVE_DAMPING); Debug.Log("Dash not ready yet, " + (timerTask.getExecuteTimeMillis() - System.nanoTime() / 1000000) + "ms remaining"); } } private void wisperShotWithDirection(float x, float y) { BulletBox2d bullet = new BulletBox2d(wisper.getType(), world); float forceFactor = 75; float xForce = (x - wisper.getPosition().x) * forceFactor; float yForce = (y - wisper.getPosition().y) * forceFactor; float xOffset = xForce < 0 ? -1 : 1; float yOffset = yForce < 0 ? -1 : 1; bullet.setPosition(wisper.getPosition().x + xOffset, wisper.getPosition().y + yOffset); bullet.getBody().applyLinearImpulse( new Vector2(xForce, yForce), bullet.getPosition(), true); } private void initInputListener() { stage.addListener(new ClickListener() { private int dragCount = 0; private void resetDrag() { dragCount = 0; } @Override public boolean touchDown(InputEvent event, final float x, final float y, int pointer, int button) { return super.touchDown(event, x, y, pointer, button); } @Override public void touchUp(InputEvent event, float x, float y, int pointer, int button) { if (dragCount > 5) { wisperShotWithDirection(x, y); resetDrag(); } else { long currentTime = System.currentTimeMillis(); if (currentTime - lastClickTime < Config.DOUBLE_TAP_INTERVAL) { dashWisperTo(x, y); } else { moveWisperTo(x, y, Config.BOX2D_WISPER_MOVE_FORCE, Config.BOX2D_WISPER_MOVE_DAMPING); } lastClickTime = currentTime; } super.touchUp(event, x, y, pointer, button); } @Override public void touchDragged(InputEvent event, float x, float y, int pointer) { ++dragCount; super.touchDragged(event, x, y, pointer); } }); } private void initContactListener() { world.setContactListener(new ContactListener() { private void collideWisperBullet(Body wisperBody, Body bulletBody) { removedWrappers.add(((BulletBox2d) bulletBody.getUserData())); ((WisperBox2d) wisperBody.getUserData()).explode(); inactiveBodies.add(wisperBody); } @Override public void beginContact(Contact contact) { Body bodyA = contact.getFixtureA().getBody(); Body bodyB = contact.getFixtureB().getBody(); // Collision Bullet / Wisper if (bodyA.getUserData() != null && bodyA.getUserData() instanceof WisperBox2d && bodyA.getUserData() != wisper && bodyB.isBullet()) { collideWisperBullet(bodyA, bodyB); } else if (bodyB.getUserData() != null && bodyB.getUserData() instanceof WisperBox2d && bodyB.getUserData() != wisper && bodyA.isBullet()) { collideWisperBullet(bodyB, bodyA); } // Collision Bullet / Other else if (bodyA.isBullet() && bodyB.getUserData() == null) { removedWrappers.add((BulletBox2d) bodyA.getUserData()); } else if (bodyB.isBullet() && bodyA.getUserData() == null) { removedWrappers.add((BulletBox2d) bodyB.getUserData()); } } @Override public void endContact(Contact contact) { } @Override public void preSolve(Contact contact, Manifold oldManifold) { } @Override public void postSolve(Contact contact, ContactImpulse impulse) { } }); } public void fadeTo(final FadingScreen screen) { LoadingScreen loader = ((WisperGame) Gdx.app.getApplicationListener()).getLoader(); loader.setNextScreen(screen); } @Override public AssetManager getAssetManager() { return GameScreenAssets.manager; } @Override public void load() { GameScreenAssets.load(); } @Override public void hide() { dispose(); } @Override public void pause() { } @Override public void resume() { } @Override public void dispose() { batch.dispose(); wisper.dispose(); stage.dispose(); world.dispose(); debugRenderer.dispose(); mapRenderer.dispose(); } }