package com.deftwun.zombiecopter.systems; import com.badlogic.ashley.core.Entity; import com.badlogic.ashley.core.Family; import com.badlogic.ashley.systems.IteratingSystem; import com.badlogic.gdx.graphics.g2d.Sprite; import com.badlogic.gdx.math.Vector2; import com.badlogic.gdx.physics.box2d.Body; import com.badlogic.gdx.physics.box2d.joints.WheelJoint; import com.badlogic.gdx.utils.Logger; import com.deftwun.zombiecopter.ComponentMappers; import com.deftwun.zombiecopter.App; import com.deftwun.zombiecopter.components.CarComponent; import com.deftwun.zombiecopter.components.ControllerComponent; import com.deftwun.zombiecopter.components.HelicopterComponent; import com.deftwun.zombiecopter.components.JumpComponent; import com.deftwun.zombiecopter.components.LedgeHangComponent; import com.deftwun.zombiecopter.components.PhysicsComponent; import com.deftwun.zombiecopter.components.SpriteComponent; import com.deftwun.zombiecopter.components.ThrusterComponent; import com.deftwun.zombiecopter.components.WalkComponent; public class MoveSystem extends IteratingSystem { private int LOG_LEVEL = Logger.INFO; private Logger logger = new Logger("Move System",LOG_LEVEL); private Vector2 velocity = new Vector2(), desiredVel = new Vector2(), accel = new Vector2(), forceToApply = new Vector2(), centerOfMass = new Vector2(); @SuppressWarnings("unchecked") public MoveSystem(){ super(Family.all(PhysicsComponent.class,ControllerComponent.class) .one(WalkComponent.class, JumpComponent.class, LedgeHangComponent.class, ThrusterComponent.class, HelicopterComponent.class, CarComponent.class).get()); logger.debug("initializing"); } private Vector2 calculateForceNeeded(Body body, Vector2 desiredVelocity, float deltaTime){ Vector2 accel = (desiredVelocity.sub(body.getLinearVelocity()).scl(1/deltaTime)); return accel.scl(body.getMass()); } @Override protected void processEntity(Entity entity, float deltaTime) { ComponentMappers mappers = App.engine.mappers; ControllerComponent controller = mappers.controller.get(entity); PhysicsComponent physics = mappers.physics.get(entity); SpriteComponent sprite = mappers.sprite.get(entity); WalkComponent walk = mappers.walk.get(entity); JumpComponent jump = mappers.jump.get(entity); LedgeHangComponent ledge = mappers.ledge.get(entity); ThrusterComponent thrust = mappers.thrust.get(entity); HelicopterComponent copter = mappers.helicopter.get(entity); CarComponent car = mappers.car.get(entity); //Physics variables Body body = physics.getPrimaryBody(); velocity.set(body.getLinearVelocity()); centerOfMass.set(body.getWorldCenter()); PhysicsSystem physicsSystem = App.engine.systems.physics; //TODO: Raycasts better? boolean isBlockedBottom = physicsSystem.getContactCount(physics.getFixture("bottomSensor")) > 0; boolean isBlockedLeft = physicsSystem.getContactCount(physics.getFixture("leftSensor")) > 0; boolean isBlockedRight = physicsSystem.getContactCount(physics.getFixture("rightSensor")) > 0; boolean isBlockedTopLeft = physicsSystem.getContactCount(physics.getFixture("topLeftSensor")) > 0; boolean isBlockedTopRight = physicsSystem.getContactCount(physics.getFixture("topRightSensor")) > 0; boolean isBlockedBottomLeft = physicsSystem.getContactCount(physics.getFixture("bottomLeftSensor")) > 0; boolean isBlockedBottomRight = physicsSystem.getContactCount(physics.getFixture("bottomRightSensor")) > 0; boolean isOnTheGround = isBlockedBottom; //flip sprite Sprite s = sprite.spriteMap.get(physics.getPrimaryBodyName()); if (s != null){ //if (physics != null && sprite != null && controller.moveVector.x != 0) { //for (Sprite s : sprite.spriteMap.values()){ Vector2 v = physics.getLinearVelocity(); if (controller.moveVector.x < 0 && v.x < 0) s.setFlip(true, s.isFlipY()); if (controller.moveVector.x > 0 && v.x > 0) s.setFlip(false, s.isFlipY()); //} } //==== WALKING ==== if (walk != null){ desiredVel.set(0,velocity.y); if (controller.moveVector.x < 0 && !isBlockedTopLeft) desiredVel.x = -walk.topSpeed; if (controller.moveVector.x > 0 && !isBlockedTopRight) desiredVel.x = walk.topSpeed; forceToApply.set(calculateForceNeeded(body,desiredVel,deltaTime)); if (isOnTheGround == false) forceToApply.scl(.5f); body.applyForce(forceToApply,centerOfMass, true); } //==== HELICOPTER ==== if (copter != null){ //TODO: Change this so helicopter rotates smoothly and not so artificially velocity.set(physics.getLinearVelocity()); accel.set(controller.moveVector).nor(); if (isOnTheGround) accel.x = 0; accel.x *= copter.lateralPower * deltaTime; accel.y *= copter.verticalPower * deltaTime; //Copter angle float angle = 0; if (accel.x < 0) { if (velocity.x > copter.topSpeed * -.3f ) angle = 15; else if (velocity.x > copter.topSpeed * -.6f) angle = 30; else angle = 45; } else if (accel.x > 0) { if (velocity.x < copter.topSpeed * .3f ) angle = 345; else if (velocity.x < copter.topSpeed * .6f) angle = 330; else angle = 315; } physics.setRotation(angle); //Cant thrust downward && below maxAltitude if (accel.y < 0 || physics.getPosition().y > copter.maxAltitude) accel.y = 0; //Limit acceleration //TODO Possible bug. Gravity force is limited when moving left/right if (accel.len() > 0){ desiredVel.set(velocity).add(accel.scl(deltaTime)); forceToApply.set(calculateForceNeeded(body,desiredVel.limit(copter.topSpeed),deltaTime)); body.applyForce(forceToApply,centerOfMass, true); } } //==== JUMPING ==== if (jump != null){ jump.timeSinceJump += deltaTime; //apply jump force if (isOnTheGround && controller.moveVector.y > 0 && jump.timeSinceJump > jump.coolDown){ desiredVel.set(velocity.x,jump.power); forceToApply.set(calculateForceNeeded(body,desiredVel,deltaTime)); body.applyForce(forceToApply, centerOfMass, true); jump.timeSinceJump = 0; } } //==== LEDGE HANGING ==== if (ledge != null){ int facing = 0; if (isBlockedRight && isBlockedBottomRight && !isBlockedTopRight && !isOnTheGround){ facing = 1; ledge.hanging = true; } else if (isBlockedLeft && isBlockedBottomLeft && !isBlockedTopLeft && !isOnTheGround){ facing = -1; ledge.hanging = true; } else ledge.hanging = false; if (ledge.hanging){ if (jump != null) jump.timeSinceJump = jump.coolDown * .5f; desiredVel.set(facing * .5f,0); if (ledge.climbing){ desiredVel.set(ledge.climbSpeed * facing,ledge.climbSpeed); } forceToApply.set(calculateForceNeeded(body,desiredVel,deltaTime)); body.applyForce(forceToApply,centerOfMass, true); } } //==== THRUSTER ==== //TODO: (Depracated?) if (thrust != null){ //Reset thruster timer when we land if (isOnTheGround){ thrust.timeThrusting = 0; thrust.timeOffGround = 0; } //Apply thrusters force else { accel.set(thrust.vector).nor().scl(thrust.power * deltaTime); if (accel.len() > 0 && thrust.timeOffGround >= thrust.delay){ thrust.timeOffGround += deltaTime; if (thrust.timeThrusting < thrust.duration){ thrust.timeThrusting += deltaTime; desiredVel.set(velocity).add(accel.scl(deltaTime)); forceToApply.set(calculateForceNeeded(body,desiredVel.limit(thrust.topSpeed),deltaTime)); body.applyForce(forceToApply,centerOfMass, true); } } } } // ==== CAR ==== if (car != null){ WheelJoint leftWheelJoint = (WheelJoint) physics.getJoint("leftWheelJoint"), rightWheelJoint = (WheelJoint) physics.getJoint("rightWheelJoint"); if (leftWheelJoint == null || rightWheelJoint == null) { logger.error("Car is missing wheel joints"); return; } if(controller.moveVector.x != 0) { Body b = physics.getPrimaryBody(); b.applyForce(new Vector2(0,-car.downForce * deltaTime), b.getWorldCenter(), true); } if (controller.moveVector.x > 0 ){ rightWheelJoint.setMotorSpeed(-car.speed); leftWheelJoint.setMotorSpeed(-car.speed); if (car.frontWheelDrive) leftWheelJoint.enableMotor(true); else leftWheelJoint.enableMotor(false); if (car.rearWheelDrive) rightWheelJoint.enableMotor(true); else rightWheelJoint.enableMotor(false); } else if (controller.moveVector.x < 0) { rightWheelJoint.setMotorSpeed(car.speed); leftWheelJoint.setMotorSpeed(car.speed); if (car.frontWheelDrive) rightWheelJoint.enableMotor(true); else rightWheelJoint.enableMotor(false); if (car.rearWheelDrive) leftWheelJoint.enableMotor(true); else leftWheelJoint.enableMotor(false); } else { leftWheelJoint.enableMotor(false); rightWheelJoint.enableMotor(false); } } } }