Rimscape Combat AI Here


      /**
       * @param ship The ship to move
       * @return returns a double representing how many radians away from the desired angle the ship is.  
       * This is to be used for considering when to fire when the destination is a Ship
       */
      public static double[] moveShipInCombat(Ship ship) {
            
            double destX = ship.getTarget().getX();
            double destY = ship.getTarget().getY();

            double directTheta = Math.atan2(
                        destY - ship.getY(),
                        destX - ship.getX());
            
            double distanceSqrd = Point2D.distanceSq(destX, destY, ship.getX(), ship.getY());
            if (Rimscape.DEBUG && Rimscape.gameInProgress && MainScreen.isScreenTarget(ship))
                  System.out.println("moving in combat, distance = " + Math.sqrt(distanceSqrd));
            
            //FIXME: I don't like how this works
            //if (distanceSqrd < Ship.RANGE_SQRD)
            //      directTheta += (chanceRand.nextDouble()*2 - 1)*((double)(Constants.DIFFICULTY_MAX - Rimscape.difficulty)/Constants.DIFFICULTY_DEFAULT);
                        
            double dx = ship.getDx(), dy = ship.getDy();
            double velocityTheta = Math.atan2(dy, dx);
            double offset = circleMod(velocityTheta - directTheta);
      
            if (distanceSqrd < Ship.RANGE_SQRD/9) {
                  ship.accel();
            }
            else if (distanceSqrd < Ship.RANGE_SQRD/6) {
                  ship.reverse();
            }
            else if (distanceSqrd < Ship.RANGE_SQRD/4) {
                //coast
            }
            else if (distanceSqrd < Ship.RANGE_SQRD/2) {
                  ship.decel();
            }
            else {
                  double accel = ship.getStatMax(Ship.STAT_ACCELERATION);
                  double vSqrd = dx*dx + dy*dy;
                  double stuffUnderRadical = 0; //calculated when it's first checked to avoid an unnecessary sqrt
                  
                  //stuffUnderRadical < 0 means that Math.sqrt() check will return NaN
                  // this is because the equation checks for when the velocity will equal 0 if the brakes are hit now (Quadratic regression)
                  // therefore an imaginary root means you never reached 0 and thus didn't reach your destination
                  // it also means that if we stop now we'll stop waaay short of our destination so go further
                  
                  //Math.abs(offset) < THETA_TOLERANCE means don't hit the gas if you're not facing the right direction
                  //however if vSqrd < accel, then this check ^^^ probably doesn't make sense because the velocity
                  //used to create the offset is so small that deriving an angle from it isn't practical
                  
                  if (Math.abs(offset) < THETA_TOLERANCE/2 && (stuffUnderRadical = vSqrd - 2*accel*Math.sqrt(distanceSqrd)) < 0
                                                             //If other checks pass, check finalV < accel
                              || (vSqrd < accel || (2*Math.sqrt(vSqrd) - Math.sqrt(stuffUnderRadical)) < accel*accel)) {
                  
                        if (Rimscape.DEBUG && Rimscape.gameInProgress && MainScreen.isScreenTarget(ship))
                              System.out.println("speeding up to target");
                        
                        if (vSqrd < REALLY_FAST*REALLY_FAST*2) //TODO: new change...test it
                            ship.accel();
                  }
                  else {
                        if (Rimscape.DEBUG && Rimscape.gameInProgress && MainScreen.isScreenTarget(ship))
                              System.out.println("slowing down");
                        ship.decel();
                  }
            }
            
            double desiredTheta;
            if (distanceSqrd < Ship.RANGE_SQRD)
                  desiredTheta = directTheta;
            else
                  desiredTheta = directTheta - (Math.abs(offset) < THETA_TOLERANCE ? offset : 0);
            
            double thetaToGo = circleMod(desiredTheta - ship.getTheta());
            
      
            if (thetaToGo < -ship.getStat(Ship.STAT_ROTATION))
                  ship.turnLeft();
            else if (thetaToGo > ship.getStat(Ship.STAT_ROTATION))
                  ship.turnRight();
            else
                ship.setTheta(desiredTheta);
            
            //return new double[] {thetaToGo, distanceSqrd};
            return new double[] {circleMod(directTheta - ship.getTheta()), distanceSqrd};
      }

There she is :slight_smile: Hopefully the comments help to illustrate what’s going on. I felt this might be appropriate for the Shared Code forum, but since I’m interested in feedback and suggestions and it’s also directly related to AI, I felt this forum was better.

Let me know what you guys think! If you wanna see it in action, start up Rimscape and piss someone off :wink:

man it’d be really cool if I could teach my ships to avoid shooting innocent bystanders :slight_smile: