Coverage Summary for Class: NPCShip (com.mygdx.game.Entitys)

Class Class, % Method, % Line, %
NPCShip 100% (1/1) 100% (12/12) 89.9% (71/79)


1 package com.mygdx.game.Entitys; 2  3 import com.badlogic.gdx.ai.fsm.DefaultStateMachine; 4 import com.badlogic.gdx.ai.fsm.StateMachine; 5 import com.badlogic.gdx.ai.steer.behaviors.Arrive; 6 import com.badlogic.gdx.math.Vector2; 7 import com.badlogic.gdx.utils.JsonValue; 8 import com.badlogic.gdx.utils.TimeUtils; 9 import com.mygdx.game.AI.EnemyState; 10 import com.mygdx.game.Components.*; 11 import com.mygdx.game.Managers.GameManager; 12 import com.mygdx.game.Physics.CollisionCallBack; 13 import com.mygdx.game.Physics.CollisionInfo; 14 import com.mygdx.utils.QueueFIFO; 15 import com.mygdx.utils.Utilities; 16  17 import java.util.Objects; 18  19 /** 20  * NPC ship entity class. 21  */ 22 public class NPCShip extends Ship implements CollisionCallBack { 23  public StateMachine<NPCShip, EnemyState> stateMachine; 24  private static JsonValue AISettings; 25  private long lastShootTime; //Added for Assessment 2, stores the time when the ship last attacked 26  27  /** 28  * Creates an initial state machine 29  * Changed for Assessment 2: 30  * - Added lastShootTime to store the time when the ship last attacked 31  */ 32  public NPCShip() { 33  super(); 34  //QueueFIFO<Vector2> path = new QueueFIFO<>(); 35  36  if (AISettings == null) { 37  AISettings = GameManager.getSettings().get("AI"); 38  } 39  40  stateMachine = new DefaultStateMachine<>(this, EnemyState.WANDER); 41  42  setName("NPC"); 43  AINavigation nav = new AINavigation(); 44  45  addComponent(nav); 46  47  48  RigidBody rb = getComponent(RigidBody.class); 49  // rb.setCallback(this); 50  51  JsonValue starting = GameManager.getSettings().get("starting"); 52  53  // aggro trigger 54  rb.addTrigger(Utilities.tilesToDistance(starting.getFloat("argoRange_tiles")), "aggro"); 55  getComponent(Pirate.class).setInfiniteAmmo(true); 56  57  lastShootTime = TimeUtils.millis() / 1000; 58  } 59  60  /** 61  * gets the top of targets from pirate component 62  * 63  * @return the top target 64  */ 65  private Ship getTarget() { 66  return getComponent(Pirate.class).getTarget(); 67  } 68  69  /** 70  * Amended for Assessment 2: Added check for life and kills stateMachine and ship in case of death 71  * updates the state machine 72  */ 73  @Override 74  public void update() { 75  if(!isAlive()) { 76  kill(); 77  stateMachine = null; 78  }else{ 79  super.update(); 80  stateMachine.update(); 81  } 82  } 83  84  /** 85  * Added for Assessment 2 86  * Removes the ship from play 87  */ 88  private void kill() { 89  getComponent(Renderable.class).hide(); 90  Transform t = getComponent(Transform.class); 91  t.setPosition(20000, 20000); 92  93  RigidBody rb = getComponent(RigidBody.class); 94  rb.setPosition(t.getPosition()); 95  rb.setVelocity(0, 0); 96  97  dispose(); 98  } 99  100  /** 101  * creates a new steering behaviour that will make the NPC beeline for the target (doesn't factor in obstacles) 102  */ 103  public void followTarget() { 104  if (getTarget() == null) { 105  stopMovement(); 106  return; 107  } 108  AINavigation nav = getComponent(AINavigation.class); 109  110  Arrive<Vector2> arrives = new Arrive<>(nav, 111  getTarget().getComponent(Transform.class)) 112  .setTimeToTarget(AISettings.getFloat("accelerationTime")) 113  .setArrivalTolerance(AISettings.getFloat("arrivalTolerance")) 114  .setDecelerationRadius(AISettings.getFloat("slowRadius")); 115  116  nav.setBehavior(arrives); 117  } 118  119  /** 120  * Added for Assessment 2 121  * Creates a new steering behaviour that will make the NPC circle the college it is attached to (doesn't factor in obstacles) 122  */ 123  public void circleOrigin() { 124  College origin = GameManager.getCollege(getFaction().id); 125  Vector2 dirToOrigin = new Vector2( (origin.getPosition().x - getPosition().x),(origin.getPosition().y - getPosition().y) ); 126  double currentAngle = Utilities.vectorToAngle(dirToOrigin); 127  128  double theta; 129  if (dirToOrigin.x > 0){ 130  theta = currentAngle - (Math.PI)/12; 131  }else{ 132  theta = currentAngle + (Math.PI)/12; 133  } 134  135  Transform target = new Transform(); 136  float radius = Utilities.tilesToDistance(30); 137  float xPos = (float) (origin.getPosition().x + (radius * Math.cos(theta))); 138  float yPos = (float) (origin.getPosition().y + (radius * Math.sin(theta))); 139  target.setPosition(xPos,yPos); 140  141  AINavigation nav = getComponent(AINavigation.class); 142  143  Arrive<Vector2> arrives = new Arrive<>(nav,target) 144  .setTimeToTarget(AISettings.getFloat("accelerationTime")) 145  .setArrivalTolerance(AISettings.getFloat("arrivalTolerance")) 146  .setDecelerationRadius(AISettings.getFloat("slowRadius")); 147  148  nav.setBehavior(arrives); 149  } 150  151  /** 152  * stops all movement and sets the behaviour to null 153  */ 154  public void stopMovement() { 155  AINavigation nav = getComponent(AINavigation.class); 156  nav.setBehavior(null); 157  nav.stop(); 158  } 159  160  /** 161  * Added for Assessment 2, calculates the direction an Enemy Ship is in 162  */ 163  public Vector2 directionToShip(Ship ship) { 164  Vector2 shipLocale = ship.getPosition(); 165  Vector2 thisPosition = getPosition(); 166  167  float xDiff = shipLocale.x-thisPosition.x; 168  float yDiff = shipLocale.y-thisPosition.y; 169  170  return new Vector2(xDiff,yDiff); 171  } 172  173  /** 174  * Added for Assessment 2, shoots a cannonball towards the player ship 175  */ 176  public void attackShip(Ship ship) { 177  long current = TimeUtils.millis() / 1000; 178  if (current > lastShootTime) { 179  Vector2 direction = directionToShip(ship); 180  shoot(direction); 181  } 182  lastShootTime = current; 183  } 184  185  /** 186  * @return the current state the NPCShip is in 187  */ 188  public EnemyState getCurrentState() { 189  return stateMachine.getCurrentState(); 190  } 191  192  /** 193  * if the aggro fixture hit a ship set it as the target 194  * @param info the collision info 195  */ 196  @Override 197  public void EnterTrigger(CollisionInfo info) { 198  super.EnterTrigger(info); 199  if (info.a instanceof Ship) { 200  Ship other = (Ship) info.a; 201  if (Objects.equals(other.getComponent(Pirate.class).getFaction(), getComponent(Pirate.class).getFaction())) { 202  // is the same faction 203  return; 204  } 205  // add the new collision as a new target 206  Pirate pirate = getComponent(Pirate.class); 207  pirate.addTarget(other); 208  } 209  } 210  211  /** 212  * if a target has left remove it from the potential targets Queue 213  * @param info collision info 214  */ 215  @Override 216  public void ExitTrigger(CollisionInfo info) { 217  if (!(info.a instanceof Ship)) { 218  return; 219  } 220  Pirate pirate = getComponent(Pirate.class); 221  Ship o = (Ship) info.a; 222  // remove the object from the targets list 223  for (Ship targ : pirate.getTargets()) { 224  if (targ == o) { 225  pirate.getTargets().remove(targ); 226  break; 227  } 228  } 229  } 230 }