com.tnf.ptm.handler.input.AiPilot.java Source code

Java tutorial

Introduction

Here is the source code for com.tnf.ptm.handler.input.AiPilot.java

Source

/*
 * Copyright 2017 TheNightForum
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.tnf.ptm.handler.input;

import com.badlogic.gdx.math.Vector2;
import com.tnf.ptm.common.PtmMath;
import com.tnf.ptm.common.PtmGame;
import com.tnf.ptm.entities.item.Engine;
import com.tnf.ptm.entities.planet.Planet;
import com.tnf.ptm.entities.planet.PlanetBind;
import com.tnf.ptm.entities.ship.FarShip;
import com.tnf.ptm.entities.ship.PtmShip;
import com.tnf.ptm.entities.ship.hulls.HullConfig;
import com.tnf.ptm.entities.Faction;
import com.tnf.ptm.entities.item.Gun;

public class AiPilot implements Pilot {

    public static final float MIN_IDLE_DIST = .8f;
    public static final float MAX_GROUND_BATTLE_SPD = .7f;
    public static final float MAX_BATTLE_SPD_BIG = 1f;
    public static final float MAX_BATTLE_SPD = 2f;
    public static final float MAX_BIND_AWAIT = .25f;
    public static final float MAX_RE_EQUIP_AWAIT = 3f;

    private final MoveDestProvider myDestProvider;
    private final boolean myCollectsItems;
    private final Mover myMover;
    private final Shooter myShooter;
    private final Faction myFaction;
    private final boolean myShootAtObstacles;
    private final String myMapHint;
    private final BattleDestProvider myBattleDestProvider;
    private final float myDetectionDist;
    private final AbilityUpdater myAbilityUpdater;

    private float myBindAwait;
    private PlanetBind myPlanetBind;
    private float myReEquipAwait;

    public AiPilot(MoveDestProvider destProvider, boolean collectsItems, Faction faction, boolean shootAtObstacles,
            String mapHint, float detectionDist) {
        myDestProvider = destProvider;
        myDetectionDist = detectionDist;
        myMover = new Mover();
        myShooter = new Shooter();
        myBattleDestProvider = new BattleDestProvider();
        myCollectsItems = collectsItems;
        myFaction = faction;
        myShootAtObstacles = shootAtObstacles;
        myMapHint = mapHint;
        myAbilityUpdater = new AbilityUpdater();
    }

    @Override
    public void update(PtmGame game, PtmShip ship, PtmShip nearestEnemy) {
        myAbilityUpdater.update(ship, nearestEnemy);
        myPlanetBind = null;
        Vector2 shipPos = ship.getPosition();
        HullConfig hullConfig = ship.getHull().config;
        float maxIdleDist = getMaxIdleDist(hullConfig);
        myDestProvider.update(game, shipPos, maxIdleDist, hullConfig, nearestEnemy);

        Boolean canShoot = canShoot0(ship);
        boolean canShootUnfixed = canShoot == null;
        if (canShootUnfixed) {
            canShoot = true;
        }
        Planet np = game.getPlanetMan().getNearestPlanet();
        boolean nearGround = np.isNearGround(shipPos);

        Vector2 dest = null;
        Vector2 destSpd = null;
        boolean shouldStopNearDest = false;
        boolean avoidBigObjs = false;
        float desiredSpdLen = myDestProvider.getDesiredSpdLen();
        boolean hasEngine = ship.getHull().getEngine() != null;
        if (hasEngine) {
            Boolean battle = null;
            if (nearestEnemy != null) {
                battle = myDestProvider.shouldManeuver(canShoot, nearestEnemy, nearGround);
            }
            if (battle != null) {
                dest = myBattleDestProvider.getDest(ship, nearestEnemy, np, battle, game.getTimeStep(),
                        canShootUnfixed, nearGround);
                shouldStopNearDest = myBattleDestProvider.shouldStopNearDest();
                destSpd = nearestEnemy.getSpd();
                boolean big = hullConfig.getType() == HullConfig.Type.BIG;
                float maxBattleSpd = nearGround ? MAX_GROUND_BATTLE_SPD : big ? MAX_BATTLE_SPD_BIG : MAX_BATTLE_SPD;
                if (maxBattleSpd < desiredSpdLen) {
                    desiredSpdLen = maxBattleSpd;
                }
                if (!big) {
                    desiredSpdLen += destSpd.len();
                }
            } else {
                dest = myDestProvider.getDest();
                destSpd = myDestProvider.getDestSpd();
                shouldStopNearDest = myDestProvider.shouldStopNearDest();
                avoidBigObjs = myDestProvider.shouldAvoidBigObjs();
            }
        }

        myMover.update(game, ship, dest, np, maxIdleDist, hasEngine, avoidBigObjs, desiredSpdLen,
                shouldStopNearDest, destSpd);
        boolean moverActive = myMover.isActive();

        Vector2 enemyPos = nearestEnemy == null ? null : nearestEnemy.getPosition();
        Vector2 enemySpd = nearestEnemy == null ? null : nearestEnemy.getSpd();
        float enemyApproxRad = nearestEnemy == null ? 0 : nearestEnemy.getHull().config.getApproxRadius();
        myShooter.update(ship, enemyPos, moverActive, canShoot, enemySpd, enemyApproxRad);
        if (hasEngine && !moverActive && !isShooterRotated()) {
            myMover.rotateOnIdle(ship, np, dest, shouldStopNearDest, maxIdleDist);
        }

        if (myReEquipAwait <= 0) {
            myReEquipAwait = MAX_RE_EQUIP_AWAIT;
        } else {
            myReEquipAwait -= game.getTimeStep();
        }
    }

    private float getMaxIdleDist(HullConfig hullConfig) {
        float maxIdleDist = hullConfig.getApproxRadius();
        if (maxIdleDist < MIN_IDLE_DIST) {
            maxIdleDist = MIN_IDLE_DIST;
        }
        return maxIdleDist;
    }

    private Boolean canShoot0(PtmShip ship) {
        Gun g1 = ship.getHull().getGun(false);
        if (g1 != null && g1.canShoot()) {
            return !g1.config.fixed ? null : true;
        }
        Gun g2 = ship.getHull().getGun(true);
        if (g2 != null && (g2.canShoot())) {
            return !g2.config.fixed ? null : true;
        }
        return false;
    }

    private boolean isShooterRotated() {
        return myShooter.isLeft() || myShooter.isRight();
    }

    @Override
    public boolean isUp() {
        return myMover.isUp();
    }

    @Override
    public boolean isLeft() {
        return myMover.isLeft() || myShooter.isLeft();
    }

    @Override
    public boolean isRight() {
        return myMover.isRight() || myShooter.isRight();
    }

    @Override
    public boolean isShoot() {
        return myShooter.isShoot();
    }

    @Override
    public boolean isShoot2() {
        return myShooter.isShoot2();
    }

    @Override
    public boolean collectsItems() {
        return myCollectsItems;
    }

    @Override
    public boolean isAbility() {
        return myAbilityUpdater.isAbility();
    }

    @Override
    public Faction getFaction() {
        return myFaction;
    }

    @Override
    public boolean shootsAtObstacles() {
        return myShootAtObstacles;
    }

    @Override
    public float getDetectionDist() {
        return myDetectionDist;
    }

    @Override
    public String getMapHint() {
        return myMapHint;
    }

    @Override
    public void updateFar(PtmGame game, FarShip farShip) {
        Vector2 shipPos = farShip.getPos();
        HullConfig hullConfig = farShip.getHullConfig();
        float maxIdleDist = getMaxIdleDist(hullConfig);
        myDestProvider.update(game, shipPos, maxIdleDist, hullConfig, null);
        Vector2 dest = myDestProvider.getDest();

        Vector2 spd = farShip.getSpd();
        float angle = farShip.getAngle();
        Engine engine = farShip.getEngine();
        float ts = game.getTimeStep();
        if (dest == null || engine == null) {
            if (myPlanetBind == null) {
                if (myBindAwait > 0) {
                    myBindAwait -= ts;
                } else {
                    myPlanetBind = PlanetBind.tryBind(game, shipPos, angle);
                    myBindAwait = MAX_BIND_AWAIT;
                }
            }
            if (myPlanetBind != null) {
                myPlanetBind.setDiff(spd, shipPos, false);
                spd.scl(1 / ts);
                angle = myPlanetBind.getDesiredAngle();
            }
        } else {
            float toDestLen = shipPos.dst(dest);
            float desiredAngle;
            float maxIdleDistHack = .05f; // to avoid StillGuards from getting stuck inside ground
            if (myDestProvider.shouldStopNearDest() && toDestLen < maxIdleDistHack) {
                spd.set(myDestProvider.getDestSpd());
                desiredAngle = angle; // can be improved
            } else {
                desiredAngle = PtmMath.angle(shipPos, dest);
                if (myDestProvider.shouldAvoidBigObjs()) {
                    desiredAngle = myMover.getBigObjAvoider().avoid(game, shipPos, dest, desiredAngle);
                }
                float desiredSpdLen = myDestProvider.getDesiredSpdLen();
                float spdLenDiff = engine.getAcc() * ts;
                float spdLen = PtmMath.approach(spd.len(), desiredSpdLen, spdLenDiff);
                if (toDestLen < spdLen) {
                    spdLen = toDestLen;
                }
                PtmMath.fromAl(spd, desiredAngle, spdLen);
            }
            angle = PtmMath.approachAngle(angle, desiredAngle, engine.getMaxRotSpd() * ts);
        }

        farShip.setSpd(spd);
        farShip.setAngle(angle);

        Vector2 newPos = PtmMath.getVec(spd);
        newPos.scl(ts);
        newPos.add(shipPos);
        farShip.setPos(newPos);
        PtmMath.free(newPos);
    }

    @Override
    public String toDebugString() {
        return "moverActive: " + myMover.isActive();
    }

    @Override
    public boolean isPlayer() {
        return myDestProvider instanceof BeaconDestProvider;
    }

}