Hitscan fix 2 (#8175)

* Revert "Reverting #8037"

Re-implement #8037

* Properly count collisions

Fix #8170
This commit is contained in:
MEEPofFaith
2023-01-14 07:05:30 -08:00
committed by GitHub
parent 3159ce6707
commit 5e324e71d4

View File

@@ -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<Unit> units = new Seq<>();
private static final IntSet collidedBlocks = new IntSet();
private static final IntFloatMap damages = new IntFloatMap();
private static final Seq<Collided> collided = new Seq<>();
private static final Pool<Collided> collidePool = Pools.get(Collided.class, Collided::new);
private static final Seq<Building> 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<Unit> 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);
}
}
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;
}
}
}