Weapon mount cleanup

This commit is contained in:
Anuken
2020-01-11 17:02:38 -05:00
parent 6f3c771d73
commit f7c4ea3e58
11 changed files with 173 additions and 160 deletions

View File

@@ -1,40 +1,87 @@
package mindustry.entities;
import arc.*;
import arc.graphics.g2d.*;
import arc.math.*;
import arc.util.*;
import mindustry.*;
import mindustry.annotations.Annotations.*;
import mindustry.entities.bullet.*;
import mindustry.entities.traits.*;
import mindustry.entities.type.*;
import mindustry.gen.*;
import mindustry.type.*;
import static mindustry.Vars.net;
public class Weapons{
/** 1 */
private static final int[] one = {1};
/** minimum cursor distance from player, fixes 'cross-eyed' shooting */
private static final float minAimDst = 20f;
/** temporary weapon sequence number */
private static int sequenceNum = 0;
private WeaponMount[] mounts;
private UnitDef lastDef;
/** weapon mount array, never null */
private WeaponMount[] mounts = {};
public void update(Unit unit){
check(unit);
public void init(Unit unit){
mounts = new WeaponMount[unit.type().weapons.size];
for(int i = 0; i < mounts.length; i++){
mounts[i] = new WeaponMount(unit.type().weapons.get(i));
}
}
/** Aim at something. This will make all mounts point at it. */
public void aim(Unit unit, float x, float y){
Tmp.v1.set(x, y).sub(unit.x, unit.y);
if(Tmp.v1.len() < minAimDst) Tmp.v1.setLength(minAimDst);
x = Tmp.v1.x + unit.x;
y = Tmp.v1.y + unit.y;
for(WeaponMount mount : mounts){
Weapon weapon = mount.weapon;
mount.aimX = x;
mount.aimY = y;
}
}
for(int i : (weapon.mirror ? Mathf.signs : one)){
i *= Mathf.sign(weapon.flipped);
/** Update shooting and rotation for this unit. */
public void update(Unit unit){
for(WeaponMount mount : mounts){
Weapon weapon = mount.weapon;
mount.reload -= Time.delta();
float rotation = unit.rotation - 90;
//rotate if applicable
if(weapon.rotate){
float axisXOffset = weapon.mirror ? 0f : weapon.x;
float axisX = unit.x + Angles.trnsx(rotation, axisXOffset, weapon.y),
axisY = unit.y + Angles.trnsy(rotation, axisXOffset, weapon.y);
mount.rotation = Angles.moveToward(mount.rotation, Angles.angle(axisX, axisY, mount.aimX, mount.aimY), weapon.rotateSpeed);
}
//shoot if applicable
//TODO only shoot if angle is reached, don't shoot inaccurately
if(mount.reload <= 0){
for(int i : (weapon.mirror && !weapon.alternate ? Mathf.signs : one)){
i *= Mathf.sign(weapon.flipped) * Mathf.sign(mount.side);
//m a t h
float weaponRotation = rotation + (weapon.rotate ? mount.rotation : 0);
float mountX = unit.x + Angles.trnsx(rotation, weapon.x * i, weapon.y),
mountY = unit.y + Angles.trnsy(rotation, weapon.x * i, weapon.y);
float shootX = mountX + Angles.trnsx(weaponRotation, weapon.shootX * i, weapon.shootY),
shootY = mountY + Angles.trnsy(weaponRotation, weapon.shootX * i, weapon.shootY);
float shootAngle = weapon.rotate ? weaponRotation : Angles.angle(shootX, shootY, mount.aimX, mount.aimY);
shoot(unit, weapon, shootX, shootY, shootAngle);
}
mount.side = !mount.side;
mount.reload = weapon.reload;
}
}
}
/** Draw weapon mounts. */
public void draw(Unit unit){
check(unit);
for(WeaponMount mount : mounts){
Weapon weapon = mount.weapon;
@@ -42,12 +89,12 @@ public class Weapons{
i *= Mathf.sign(weapon.flipped);
float rotation = unit.rotation - 90 + (weapon.rotate ? mount.rotation : 0);
float trY = weapon.length - mount.reload / weapon.reload * weapon.recoil;
float trY = weapon.y - (mount.reload / weapon.reload * weapon.recoil) * (weapon.alternate ? Mathf.num(i == Mathf.sign(mount.side)) : 1);
float width = i > 0 ? -weapon.region.getWidth() : weapon.region.getWidth();
Draw.rect(weapon.region,
unit.x + Angles.trnsx(rotation, weapon.width * i, trY),
unit.y + Angles.trnsy(rotation, weapon.width * i, trY),
unit.x + Angles.trnsx(rotation, weapon.x * i, trY),
unit.y + Angles.trnsy(rotation, weapon.x * i, trY),
width * Draw.scl,
weapon.region.getHeight() * Draw.scl,
rotation - 90);
@@ -55,54 +102,19 @@ public class Weapons{
}
}
//check mount validity
private void check(Unit unit){
if(mounts == null || mounts.length != unit.type().weapons.size || lastDef != unit.type()){
mounts = new WeaponMount[unit.type().weapons.size];
for(int i = 0; i < mounts.length; i++){
mounts[i] = new WeaponMount(unit.type().weapons.get(i));
}
lastDef = unit.type();
}
}
//region weapon code
@Remote(targets = Loc.server, called = Loc.both, unreliable = true)
public static void onPlayerShootWeapon(Player player, float x, float y, float rotation, boolean left){
if(player == null) return;
//clients do not see their own shoot events: they are simulated completely clientside to prevent laggy visuals
//messing with the firerate or any other stats does not affect the server (take that, script kiddies!)
if(net.client() && player == Vars.player){
return;
}
shootDirect(player, x, y, rotation, left);
}
@Remote(targets = Loc.server, called = Loc.both, unreliable = true)
public static void onGenericShootWeapon(ShooterTrait shooter, float x, float y, float rotation, boolean left){
if(shooter == null) return;
shootDirect(shooter, x, y, rotation, left);
}
public static void shootDirect(ShooterTrait shooter, float offsetX, float offsetY, float rotation, boolean left){
float x = shooter.getX() + offsetX;
float y = shooter.getY() + offsetY;
private void shoot(ShooterTrait shooter, Weapon weapon, float x, float y, float rotation){
float baseX = shooter.getX(), baseY = shooter.getY();
Weapon weapon = shooter.getWeapon();
weapon.shootSound.at(x, y, Mathf.random(0.8f, 1.0f));
sequenceNum = 0;
if(weapon.shotDelay > 0.01f){
Angles.shotgun(weapon.shots, weapon.spacing, rotation, f -> {
Time.run(sequenceNum * weapon.shotDelay, () -> weapon.bullet(shooter, x + shooter.getX() - baseX, y + shooter.getY() - baseY, f + Mathf.range(weapon.inaccuracy)));
Time.run(sequenceNum * weapon.shotDelay, () -> bullet(shooter, weapon, x + shooter.getX() - baseX, y + shooter.getY() - baseY, f + Mathf.range(weapon.inaccuracy)));
sequenceNum++;
});
}else{
Angles.shotgun(weapon.shots, weapon.spacing, rotation, f -> weapon.bullet(shooter, x, y, f + Mathf.range(weapon.inaccuracy)));
Angles.shotgun(weapon.shots, weapon.spacing, rotation, f -> bullet(shooter, weapon, x, y, f + Mathf.range(weapon.inaccuracy)));
}
BulletType ammo = weapon.bullet;
@@ -115,64 +127,16 @@ public class Weapons{
boolean parentize = ammo.keepVelocity;
Effects.shake(weapon.shake, weapon.shake, x, y);
Effects.effect(weapon.ejectEffect, x, y, rotation * -Mathf.sign(left));
Effects.effect(weapon.ejectEffect, x, y, rotation);
Effects.effect(ammo.shootEffect, x + Tmp.v1.x, y + Tmp.v1.y, rotation, parentize ? shooter : null);
Effects.effect(ammo.smokeEffect, x + Tmp.v1.x, y + Tmp.v1.y, rotation, parentize ? shooter : null);
//reset timer for remote players
shooter.getTimer().get(shooter.getShootTimer(left), weapon.reload);
}
public void load(){
region = Core.atlas.find(name + "-equip", Core.atlas.find(name, Core.atlas.find("clear")));
}
public void update(ShooterTrait shooter, float pointerX, float pointerY){
for(boolean left : Mathf.booleans){
Tmp.v1.set(pointerX, pointerY).sub(shooter.getX(), shooter.getY());
if(Tmp.v1.len() < minPlayerDist) Tmp.v1.setLength(minPlayerDist);
float cx = Tmp.v1.x + shooter.getX(), cy = Tmp.v1.y + shooter.getY();
float ang = Tmp.v1.angle();
Tmp.v1.trns(ang - 90, width * Mathf.sign(left), length + Mathf.range(lengthRand));
update(shooter, shooter.getX() + Tmp.v1.x, shooter.getY() + Tmp.v1.y, Angles.angle(shooter.getX() + Tmp.v1.x, shooter.getY() + Tmp.v1.y, cx, cy), left);
}
}
public void update(ShooterTrait shooter, float mountX, float mountY, float angle, boolean left){
if(shooter.getTimer().get(shooter.getShootTimer(left), reload)){
if(alternate){
shooter.getTimer().reset(shooter.getShootTimer(!left), reload / 2f);
}
shoot(shooter, mountX - shooter.getX(), mountY - shooter.getY(), angle, left);
}
}
public void shoot(ShooterTrait p, float x, float y, float angle, boolean left){
if(net.client()){
//call it directly, don't invoke on server
shootDirect(p, x, y, angle, left);
}else{
if(p instanceof Player){ //players need special weapon handling logic
Call.onPlayerShootWeapon((Player)p, x, y, angle, left);
}else{
Call.onGenericShootWeapon(p, x, y, angle, left);
}
}
}
void bullet(ShooterTrait owner, float x, float y, float angle){
if(owner == null) return;
private void bullet(ShooterTrait owner, Weapon weapon, float x, float y, float angle){
Tmp.v1.trns(angle, 3f);
Bullet.create(bullet, owner, owner.getTeam(), x + Tmp.v1.x, y + Tmp.v1.y, angle, (1f - velocityRnd) + Mathf.random(velocityRnd));
Bullet.create(weapon.bullet, owner, owner.getTeam(), x + Tmp.v1.x, y + Tmp.v1.y, angle, (1f - weapon.velocityRnd) + Mathf.random(weapon.velocityRnd));
}
//endregion
private static class WeaponMount{
/** reload in frames; 0 means ready to fire */
float reload;
@@ -180,6 +144,10 @@ public class Weapons{
float rotation;
/** weapon associated with this mount */
Weapon weapon;
/** aiming position in world coordinates */
float aimX, aimY;
/** side that's being shot - only valid for mirrors */
boolean side;
public WeaponMount(Weapon weapon){
this.weapon = weapon;

View File

@@ -28,7 +28,7 @@ import java.io.*;
import static mindustry.Vars.*;
public abstract class Unit extends DestructibleEntity implements SaveTrait, TargetTrait, SyncTrait, DrawTrait, TeamTrait{
public abstract class Unit extends DestructibleEntity implements SaveTrait, TargetTrait, SyncTrait, DrawTrait, TeamTrait, ShooterTrait{
/** Total duration of hit flash effect */
public static final float hitDuration = 9f;
/** Percision divisor of velocity, used when writing. For example a value of '2' would mean the percision is 1/2 = 0.5-size chunks. */
@@ -42,12 +42,29 @@ public abstract class Unit extends DestructibleEntity implements SaveTrait, Targ
public float rotation;
protected final Interpolator interpolator = new Interpolator();
/** status effects */
protected final Statuses status = new Statuses();
/** current item held */
protected final ItemStack item = new ItemStack(content.item(0), 0);
/** holds weapon aiming positions and angles */
protected final Weapons weapons = new Weapons();
/** team; can be changed at any time */
protected Team team = Team.sharded;
/** timers for drowning and getting hit */
protected float drownTime, hitTime;
/** this unit's type; do not change internally without calling setType(...) */
protected UnitDef type;
public void setType(UnitDef type){
this.type = type;
clampHealth();
weapons.init(this);
}
public UnitDef type(){
return type;
}
@Override
public boolean collidesGrid(int x, int y){
@@ -59,6 +76,11 @@ public abstract class Unit extends DestructibleEntity implements SaveTrait, Targ
return team;
}
@Override
public Weapons getWeapons(){
return weapons;
}
@Override
public void interpolate(){
interpolator.update();
@@ -137,18 +159,18 @@ public abstract class Unit extends DestructibleEntity implements SaveTrait, Targ
@Override
public void hitbox(Rect rect){
rect.setSize(type().hitsize).setCenter(x, y);
rect.setSize(type.hitsize).setCenter(x, y);
}
@Override
public void hitboxTile(Rect rect){
rect.setSize(type().hitsizeTile).setCenter(x, y);
rect.setSize(type.hitsizeTile).setCenter(x, y);
}
@Override
public float drag(){
return type().drag;
return type.drag;
}
@Override
@@ -181,8 +203,6 @@ public abstract class Unit extends DestructibleEntity implements SaveTrait, Targ
this.rotation = rotation;
}
public abstract UnitDef type();
public void writeSave(DataOutput stream, boolean net) throws IOException{
if(item.item == null) item.item = Items.copper;
@@ -210,7 +230,7 @@ public abstract class Unit extends DestructibleEntity implements SaveTrait, Targ
}
public boolean isImmune(StatusEffect effect){
return type().immunities.contains(effect);
return type.immunities.contains(effect);
}
public boolean isOutOfBounds(){
@@ -411,8 +431,8 @@ public abstract class Unit extends DestructibleEntity implements SaveTrait, Targ
}
public void drawLight(){
if(type().lightRadius > 0){
renderer.lights.add(x, y, type().lightRadius, type().lightColor, 0.6f);
if(type.lightRadius > 0){
renderer.lights.add(x, y, type.lightRadius, type.lightColor, 0.6f);
}
}
@@ -471,15 +491,15 @@ public abstract class Unit extends DestructibleEntity implements SaveTrait, Targ
public abstract TextureRegion getIconRegion();
public final int getItemCapacity(){
return type().itemCapacity;
return type.itemCapacity;
}
@Override
public float mass(){
return type().mass;
return type.mass;
}
public boolean isFlying(){
return type().flying;
return type.flying;
}
}