diff --git a/core/src/mindustry/entities/Damage.java b/core/src/mindustry/entities/Damage.java index 04b87492fb..e7323d395b 100644 --- a/core/src/mindustry/entities/Damage.java +++ b/core/src/mindustry/entities/Damage.java @@ -6,6 +6,7 @@ import arc.math.*; import arc.math.geom.*; import arc.struct.*; import arc.util.*; +import arc.util.pooling.*; import mindustry.content.*; import mindustry.core.*; import mindustry.game.EventType.*; @@ -26,6 +27,8 @@ public class Damage{ private static final Seq units = new Seq<>(); private static final IntSet collidedBlocks = new IntSet(); private static final IntFloatMap damages = new IntFloatMap(); + private static final Seq collided = new Seq<>(); + private static final Pool collidePool = Pools.get(Collided.class, Collided::new); private static final Seq builds = new Seq<>(); private static final FloatSeq distances = new FloatSeq(); @@ -184,7 +187,7 @@ public class Damage{ return Math.min(distances.size < pierceCap || pierceCap < 0 ? length : Math.max(6f, distances.get(pierceCap - 1)), maxDst); } - /** TODO Collides a bullet with blocks in a laser, taking into account absorption blocks. Resulting length is stored in the bullet's fdata. */ + /** Collides a bullet with blocks in a laser, taking into account absorption blocks. Resulting length is stored in the bullet's fdata. */ public static float collideLaser(Bullet b, float length, boolean large, boolean laser, int pierceCap){ float resultLength = findPierceLength(b, pierceCap, length); @@ -226,40 +229,27 @@ public class Damage{ length = findPierceLength(hitter, pierceCap, length); } - //TODO pierceCount ++ should happen in blocks AND units! - collidedBlocks.clear(); vec.trnsExact(angle, length); - Intc2 collider = (cx, cy) -> { - Building tile = world.build(cx, cy); - boolean collide = tile != null && hitter.checkUnderBuild(tile, cx * tilesize, cy * tilesize) && collidedBlocks.add(tile.pos()); - - if(hitter.damage > 0){ - float health = !collide ? 0 : tile.health; - - if(collide && tile.team != team && tile.collide(hitter)){ - tile.collision(hitter); - hitter.type.hit(hitter, cx * tilesize, cy * tilesize); - } - - //try to heal the tile - if(collide && hitter.type.testCollision(hitter, tile)){ - hitter.type.hitTile(hitter, tile, cx * tilesize, cy * tilesize, health, false); - } - } - }; - if(hitter.type.collidesGround){ seg1.set(x, y); seg2.set(seg1).add(vec); World.raycastEachWorld(x, y, seg2.x, seg2.y, (cx, cy) -> { - collider.get(cx, cy); + Building tile = world.build(cx, cy); + boolean collide = tile != null && hitter.checkUnderBuild(tile, cx * tilesize, cy * tilesize) + && ((tile.team != team && tile.collide(hitter)) || hitter.type.testCollision(hitter, tile)) && collidedBlocks.add(tile.pos()); + if(collide){ + collided.add(collidePool.obtain().set(cx * tilesize, cy * tilesize, tile)); - for(Point2 p : Geometry.d4){ - Tile other = world.tile(p.x + cx, p.y + cy); - if(other != null && (large || Intersector.intersectSegmentRectangle(seg1, seg2, other.getBounds(Tmp.r1)))){ - collider.get(cx + p.x, cy + p.y); + for(Point2 p : Geometry.d4){ + Tile other = world.tile(p.x + cx, p.y + cy); + if(other != null && (large || Intersector.intersectSegmentRectangle(seg1, seg2, other.getBounds(Tmp.r1)))){ + Building build = other.build; + if(build != null && hitter.checkUnderBuild(build, cx * tilesize, cy * tilesize) && collidedBlocks.add(build.pos())){ + collided.add(collidePool.obtain().set((p.x + cx * tilesize), (p.y + cy) * tilesize, build)); + } + } } } return false; @@ -271,32 +261,46 @@ public class Damage{ rect.setPosition(x, y).setSize(vec.x, vec.y).normalize().grow(expand * 2f); float x2 = vec.x + x, y2 = vec.y + y; - Cons cons = e -> { - if(!e.hittable()) return; - //the peirce cap works for units, but really terribly, I'm just disabling it for now. - //if(pierceCap > 0 && pierceCount > pierceCap) return; - - e.hitbox(hitrect); - - Vec2 vec = Geometry.raycastRect(x, y, x2, y2, hitrect.grow(expand * 2)); - - if(vec != null && hitter.damage > 0){ - effect.at(vec.x, vec.y); - e.collision(hitter, vec.x, vec.y); - hitter.collision(e, vec.x, vec.y); - } - }; - - units.clear(); - Units.nearbyEnemies(team, rect, u -> { - if(u.checkTarget(hitter.type.collidesAir, hitter.type.collidesGround)){ - units.add(u); + if(u.checkTarget(hitter.type.collidesAir, hitter.type.collidesGround) && u.hittable()){ + u.hitbox(hitrect); + + Vec2 vec = Geometry.raycastRect(x, y, x2, y2, hitrect.grow(expand * 2)); + + if(vec != null){ + collided.add(collidePool.obtain().set(vec.x, vec.y, u)); + } } }); - units.sort(u -> u.dst2(hitter)); - units.each(cons); + int[] collideCount = {0}; + collided.sort(c -> hitter.dst2(c.x, c.y)); + collided.each(c -> { + if(hitter.damage > 0 && (pierceCap <= 0 || collideCount[0] < pierceCap)){ + if(c.target instanceof Unit u){ + effect.at(c.x, c.y); + u.collision(hitter, c.x, c.y); + hitter.collision(u, c.x, c.y); + collideCount[0]++; + }else if(c.target instanceof Building tile){ + float health = tile.health; + + if(tile.team != team && tile.collide(hitter)){ + tile.collision(hitter); + hitter.type.hit(hitter, c.x, c.y); + collideCount[0]++; + } + + //try to heal the tile + if(hitter.type.testCollision(hitter, tile)){ + hitter.type.hitTile(hitter, tile, c.x, c.y, health, false); + } + } + } + }); + + collidePool.freeAll(collided); + collided.clear(); } /** @@ -338,7 +342,7 @@ public class Damage{ */ public static Healthc linecast(Bullet hitter, float x, float y, float angle, float length){ vec.trns(angle, length); - + tmpBuilding = null; if(hitter.type.collidesGround){ @@ -613,4 +617,16 @@ public class Damage{ public static float applyArmor(float damage, float armor){ return Math.max(damage - armor, minArmorDamage * damage); } -} \ No newline at end of file + + public static class Collided{ + public float x, y; + public Teamc target; + + public Collided set(float x, float y, Teamc target){ + this.x = x; + this.y = y; + this.target = target; + return this; + } + } +}