Java tutorial
/* * Copyright 2015 MovingBlocks * * 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 org.destinationsol.game.input; import com.badlogic.gdx.math.Vector2; import org.destinationsol.common.SolMath; import org.destinationsol.game.gun.GunItem; import org.destinationsol.game.gun.GunMount; import org.destinationsol.game.projectile.ProjectileConfig; import org.destinationsol.game.ship.SolShip; public class Shooter { public static final float E_SPD_PERC = .6f; // 0 means that target speed is not considered, 1 means that it's fully considered public static final float MIN_SHOOT_AAD = 2f; private boolean myShoot; private boolean myShoot2; private boolean myRight; private boolean myLeft; public Shooter() { } public void update(SolShip ship, Vector2 enemyPos, boolean dontRotate, boolean canShoot, Vector2 enemySpd, float enemyApproxRad) { myLeft = false; myRight = false; myShoot = false; myShoot2 = false; Vector2 shipPos = ship.getPosition(); if (enemyPos == null || !canShoot) return; float toEnemyDst = enemyPos.dst(shipPos); GunItem g1 = processGun(ship, false); GunItem g2 = processGun(ship, true); if (g1 == null && g2 == null) return; float projSpd = 0; GunItem g = null; if (g1 != null) { ProjectileConfig projConfig = g1.config.clipConf.projConfig; projSpd = projConfig.spdLen + projConfig.acc; // for simplicity g = g1; } if (g2 != null) { ProjectileConfig projConfig = g2.config.clipConf.projConfig; float g2PS = projConfig.spdLen + projConfig.acc; // for simplicity if (projSpd < g2PS) { projSpd = g2PS; g = g2; } } Vector2 gunRelPos = ship.getHull().getGunMount(g == g2).getRelPos(); Vector2 gunPos = SolMath.toWorld(gunRelPos, ship.getAngle(), shipPos); float shootAngle = calcShootAngle(gunPos, ship.getSpd(), enemyPos, enemySpd, projSpd, false); SolMath.free(gunPos); if (shootAngle != shootAngle) return; { // ok this is a hack float toShip = SolMath.angle(enemyPos, shipPos); float toGun = SolMath.angle(enemyPos, gunPos); shootAngle += toGun - toShip; } float shipAngle = ship.getAngle(); float maxAngleDiff = SolMath.angularWidthOfSphere(enemyApproxRad, toEnemyDst) + 10f; ProjectileConfig projConfig = g.config.clipConf.projConfig; if (projSpd > 0 && projConfig.guideRotSpd > 0) maxAngleDiff += projConfig.guideRotSpd * toEnemyDst / projSpd; if (SolMath.angleDiff(shootAngle, shipAngle) < maxAngleDiff) { myShoot = true; myShoot2 = true; return; } if (dontRotate) return; Boolean ntt = Mover.needsToTurn(shipAngle, shootAngle, ship.getRotSpd(), ship.getRotAcc(), MIN_SHOOT_AAD); if (ntt != null) { if (ntt) myRight = true; else myLeft = true; } } // returns gun if it's fixed & can shoot private GunItem processGun(SolShip ship, boolean second) { GunMount mount = ship.getHull().getGunMount(second); if (mount == null) return null; GunItem g = mount.getGun(); if (g == null || g.ammo <= 0) return null; if (g.config.clipConf.projConfig.zeroAbsSpd || g.config.clipConf.projConfig.guideRotSpd > 0) { if (second) myShoot2 = true; else myShoot = true; return null; } if (g.config.fixed) return g; if (mount.isDetected()) { if (second) myShoot2 = true; else myShoot = true; } return null; } public boolean isShoot() { return myShoot; } public boolean isShoot2() { return myShoot2; } public boolean isLeft() { return myLeft; } public boolean isRight() { return myRight; } public static float calcShootAngle(Vector2 gunPos, Vector2 gunSpd, Vector2 ePos, Vector2 eSpd, float projSpd, boolean sharp) { Vector2 eSpdShortened = SolMath.getVec(eSpd); if (!sharp) eSpdShortened.scl(E_SPD_PERC); Vector2 relESpd = SolMath.distVec(gunSpd, eSpdShortened); SolMath.free(eSpdShortened); float rotAngle = SolMath.angle(relESpd); float v = relESpd.len(); float v2 = projSpd; SolMath.free(relESpd); Vector2 toE = SolMath.distVec(gunPos, ePos); SolMath.rotate(toE, -rotAngle); float x = toE.x; float y = toE.y; float a = v * v - v2 * v2; float b = 2 * x * v; float c = x * x + y * y; float t = SolMath.genQuad(a, b, c); float res; if (t != t) { res = Float.NaN; } else { toE.x += t * v; res = SolMath.angle(toE) + rotAngle; } SolMath.free(toE); return res; } }