Skip to content

Commit 0e0d1a0

Browse files
author
Bytekeeper
committed
Fix invalid collision map behavior; Improved collision map performance, no "fill" anymore; Fixed DT range < TILE_SIZE of collision map problem
1 parent 22d32a7 commit 0e0d1a0

File tree

9 files changed

+85
-54
lines changed

9 files changed

+85
-54
lines changed

src/jmh/java/org/bk/ass/SimulatorBenchmark.java

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,7 @@
22

33
import org.openbw.bwapi4j.test.BWDataProvider;
44
import org.openbw.bwapi4j.type.UnitType;
5-
import org.openjdk.jmh.annotations.Benchmark;
6-
import org.openjdk.jmh.annotations.Fork;
7-
import org.openjdk.jmh.annotations.Level;
8-
import org.openjdk.jmh.annotations.Measurement;
9-
import org.openjdk.jmh.annotations.Scope;
10-
import org.openjdk.jmh.annotations.Setup;
11-
import org.openjdk.jmh.annotations.State;
5+
import org.openjdk.jmh.annotations.*;
126

137
@Measurement(iterations = 5, time = 5)
148
@Fork(3)
@@ -24,10 +18,10 @@ public static class MyState {
2418
public void setup() {
2519
simulator = new Simulator();
2620

27-
for (int i = 0; i < 7; i++) {
21+
for (int i = 0; i < 30; i++) {
2822
simulator.addAgentA(factory.of(UnitType.Zerg_Mutalisk));
2923
}
30-
for (int i = 0; i < 8; i++) {
24+
for (int i = 0; i < 30; i++) {
3125
simulator.addAgentB(factory.of(UnitType.Zerg_Hydralisk));
3226
}
3327
}
@@ -45,4 +39,10 @@ public void setup() {
4539
public int _7MutasVs8Hydras(MyState state) {
4640
return state.simulator.simulate(-1);
4741
}
42+
43+
@Benchmark
44+
public int clearCollisionMaps(MyState state) {
45+
state.simulator.reset();
46+
return state.simulator.getAgentsA().size() + state.simulator.getAgentsB().size();
47+
}
4848
}

src/main/java/org/bk/ass/AgentUtil.java

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ private AgentUtil() {
1616

1717
public static void moveToward(Agent agent, Agent target, int distanceSquared) {
1818
if (distanceSquared <= agent.speedSquared) {
19-
agent.x = target.x;
20-
agent.y = target.y;
19+
agent.vx = target.x - agent.x;
20+
agent.vy = target.y - agent.y;
2121
} else {
2222
float distance = (float) sqrt(distanceSquared);
2323
agent.vx = (int) ((target.x - agent.x) * agent.speed / distance);
@@ -49,11 +49,11 @@ public static void dealRadialSplashDamage(
4949
Agent mainTarget,
5050
UnorderedCollection<Agent> allies,
5151
UnorderedCollection<Agent> enemies) {
52-
for (int i = 0; i < allies.size(); i++) {
52+
for (int i = allies.size() - 1; i >= 0; i--) {
5353
Agent ally = allies.get(i);
5454
applySplashDamage(weapon, mainTarget, ally);
5555
}
56-
for (int i = 0; i < enemies.size(); i++) {
56+
for (int i = enemies.size() - 1; i >= 0; i--) {
5757
Agent enemy = enemies.get(i);
5858
applySplashDamage(weapon, mainTarget, enemy);
5959
}
@@ -85,7 +85,7 @@ private static void applySplashDamage(Weapon weapon, Agent mainTarget, Agent spl
8585
*/
8686
public static void dealRadialSplashDamage(
8787
Weapon weapon, Agent mainTarget, UnorderedCollection<Agent> enemies) {
88-
for (int i = 0; i < enemies.size(); i++) {
88+
for (int i = enemies.size() - 1; i >= 0; i--) {
8989
Agent enemy = enemies.get(i);
9090
applySplashDamage(weapon, mainTarget, enemy);
9191
}
@@ -104,7 +104,7 @@ public static void dealLineSplashDamage(
104104
weapon.maxRangeSquared
105105
+ 2 * weapon.maxRange * weapon.innerSplashRadius
106106
+ weapon.innerSplashRadiusSquared;
107-
for (int i = 0; i < enemies.size(); i++) {
107+
for (int i = enemies.size() - 1; i >= 0; i--) {
108108
Agent enemy = enemies.get(i);
109109
if (enemy == mainTarget || enemy.burrowed || enemy.isFlyer != mainTarget.isFlyer) {
110110
continue;
@@ -128,7 +128,7 @@ public static void dealBounceDamage(
128128
Weapon weapon, Agent lastTarget, UnorderedCollection<Agent> enemies) {
129129
int remainingBounces = 2;
130130
int damage = weapon.damageShifted / 3;
131-
for (int i = 0; i < enemies.size() && remainingBounces > 0; i++) {
131+
for (int i = enemies.size() - 1; i >= 0 && remainingBounces > 0; i--) {
132132
Agent enemy = enemies.get(i);
133133
if (enemy == lastTarget) {
134134
continue;

src/main/java/org/bk/ass/AttackerBehavior.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ public boolean simUnit(
3434
}
3535

3636
if (selectedEnemy == null) {
37-
for (int i = 0; i < enemies.size(); i++) {
37+
for (int i = enemies.size() - 1; i >= 0; i--) {
3838
Agent enemy = enemies.get(i);
3939
Weapon wpn = agent.weaponVs(enemy);
4040
if (enemy.healthShifted >= 1 && wpn.damageShifted != 0 && enemy.detected) {
@@ -66,7 +66,9 @@ public boolean simUnit(
6666
return false;
6767
}
6868

69-
if (agent.cooldown == 0 && selectedDistanceSquared <= selectedWeapon.maxRangeSquared) {
69+
if (agent.cooldown == 0
70+
&& selectedDistanceSquared
71+
<= Math.max(Simulator.MIN_SIMULATION_RANGE, selectedWeapon.maxRangeSquared)) {
7072
simAttack(agent, allies, enemies, selectedEnemy, selectedWeapon);
7173
}
7274

src/main/java/org/bk/ass/HealerBehavior.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ public boolean simUnit(
3131
}
3232

3333
if (selectedAlly == null) {
34-
for (int i = 0; i < allies.size(); i++) {
34+
for (int i = allies.size() - 1; i >= 0; i--) {
3535
Agent ally = allies.get(i);
3636
if (ally.isOrganic
3737
&& ally.healthShifted < ally.maxHealthShifted

src/main/java/org/bk/ass/RepairerBehavior.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ public boolean simUnit(
2626
}
2727

2828
if (selectedAlly == null) {
29-
for (int i = 0; i < allies.size(); i++) {
29+
for (int i = allies.size() - 1; i >= 0; i--) {
3030
Agent ally = allies.get(i);
3131
if (ally.isMechanic && ally.healthShifted < ally.maxHealthShifted && ally != agent) {
3232

src/main/java/org/bk/ass/RetreatBehavior.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ public boolean simUnit(
1717
static boolean simFlee(Agent agent, UnorderedCollection<Agent> enemies) {
1818
Agent selectedEnemy = null;
1919
int selectedDistanceSquared = Integer.MAX_VALUE;
20-
for (int i = 0; i < enemies.size(); i++) {
20+
for (int i = enemies.size() - 1; i >= 0; i--) {
2121
Agent enemy = enemies.get(i);
2222
Weapon wpn = enemy.weaponVs(agent);
2323
if (wpn.damageShifted != 0) {

src/main/java/org/bk/ass/Simulator.java

Lines changed: 29 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,20 @@
1717
* <li>On each frame, call <code>reset()</code> <em>once</em>
1818
* <li>Before each simulation call <code>resetUnits()</code> before adding units
1919
* </ol>
20+
*
21+
* Do <b>not</b> modify {@link Agent}s, after adding them to the simulation.
2022
*/
2123
public class Simulator {
2224

2325
private static final int MAX_MAP_DIMENSION = 8192;
2426
private static final int TILE_SIZE = 16;
27+
public static final int MIN_SIMULATION_RANGE =
28+
(TILE_SIZE + TILE_SIZE / 2) * (TILE_SIZE + TILE_SIZE / 2);
2529
private static final int COLLISION_MAP_DIMENSION = MAX_MAP_DIMENSION / TILE_SIZE;
2630
private final UnorderedCollection<Agent> playerA = new UnorderedCollection<>();
2731
private final UnorderedCollection<Agent> playerB = new UnorderedCollection<>();
2832

29-
private final byte[] collision = new byte[COLLISION_MAP_DIMENSION * COLLISION_MAP_DIMENSION];
33+
final byte[] collision = new byte[COLLISION_MAP_DIMENSION * COLLISION_MAP_DIMENSION];
3034
private final Behavior playerABehavior;
3135
private final Behavior playerBBehavior;
3236

@@ -95,30 +99,33 @@ public int simulate(int frames) {
9599
}
96100

97101
public void reset() {
102+
for (int i = playerA.size() - 1; i >= 0; i--) {
103+
Agent agent = playerA.get(i);
104+
if (!agent.isFlyer) collision[colindex(agent.x, agent.y)]--;
105+
}
106+
for (int i = playerB.size() - 1; i >= 0; i--) {
107+
Agent agent = playerB.get(i);
108+
if (!agent.isFlyer) collision[colindex(agent.x, agent.y)]--;
109+
}
98110
resetUnits();
99-
resetCollisionMap();
100111
}
101112

102-
public void resetUnits() {
113+
private void resetUnits() {
103114
playerA.clear();
104115
playerB.clear();
105116
}
106117

107-
public void resetCollisionMap() {
108-
FastArrayFill.fillArray(collision, (byte) 0);
109-
}
110-
111118
/**
112119
* Simulate one frame.
113120
*
114121
* @return false, if nothing happened in this step and the sim can be aborted.
115122
*/
116123
private boolean step() {
117124
boolean simRunning = false;
118-
for (int i = 0; i < playerA.size(); i++) {
125+
for (int i = playerA.size() - 1; i >= 0; i--) {
119126
simRunning |= playerABehavior.simUnit(playerA.get(i), playerA, playerB);
120127
}
121-
for (int i = 0; i < playerB.size(); i++) {
128+
for (int i = playerB.size() - 1; i >= 0; i--) {
122129
simRunning |= playerBBehavior.simUnit(playerB.get(i), playerB, playerA);
123130
}
124131
removeDead(playerA);
@@ -133,7 +140,7 @@ private void removeDead(UnorderedCollection<Agent> agents) {
133140
while (i < agents.size()) {
134141
if (agents.get(i).healthShifted < 1) {
135142
Agent agent = agents.removeAt(i);
136-
collision[colindex(agent.x, agent.y)]--;
143+
if (!agent.isFlyer) collision[colindex(agent.x, agent.y)]--;
137144
agent.onDeathReplacer.accept(agents);
138145
} else {
139146
i++;
@@ -142,9 +149,11 @@ private void removeDead(UnorderedCollection<Agent> agents) {
142149
}
143150

144151
private void updateStats(UnorderedCollection<Agent> agents) {
145-
for (int i = 0; i < agents.size(); i++) {
152+
for (int i = agents.size() - 1; i >= 0; i--) {
146153
Agent agent = agents.get(i);
147154

155+
assert agent.healthShifted >= 0;
156+
148157
updatePosition(agent);
149158
agent.vx = 0;
150159
agent.vy = 0;
@@ -182,13 +191,16 @@ private void updatePosition(Agent agent) {
182191
return;
183192
}
184193

185-
if (!agent.isFlyer
186-
&& (agent.x / TILE_SIZE != tx / TILE_SIZE || agent.y / TILE_SIZE != ty / TILE_SIZE)) {
187-
if (collision[colindex(tx, ty)] > TILE_SIZE / 8 - 1) {
188-
return;
194+
if (!agent.isFlyer) {
195+
int oldCI = colindex(agent.x, agent.y);
196+
int newCI = colindex(tx, ty);
197+
if (oldCI != newCI) {
198+
if (collision[newCI] > TILE_SIZE / 8 - 1) {
199+
return;
200+
}
201+
collision[oldCI]--;
202+
collision[newCI]++;
189203
}
190-
collision[colindex(agent.x, agent.y)]--;
191-
collision[colindex(tx, ty)]++;
192204
}
193205

194206
agent.x = tx;

src/main/java/org/bk/ass/SuiciderBehavior.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ public boolean simUnit(
1313
Agent agent, UnorderedCollection<Agent> allies, UnorderedCollection<Agent> enemies) {
1414
Agent selectedEnemy = null;
1515
int selectedDistanceSquared = Integer.MAX_VALUE;
16-
for (int i = 0; i < enemies.size(); i++) {
16+
for (int i = enemies.size() - 1; i >= 0; i--) {
1717
Agent enemy = enemies.get(i);
1818
Weapon wpn = agent.weaponVs(enemy);
1919
if (enemy.healthShifted >= 1 && wpn.damageShifted != 0 && enemy.detected) {

src/test/java/org/bk/ass/SimulatorTest.java

Lines changed: 32 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
package org.bk.ass;
22

3-
import static org.assertj.core.api.Assertions.assertThat;
4-
import static org.junit.jupiter.api.Assertions.assertThrows;
5-
63
import org.bk.ass.Simulator.RoleBasedBehavior;
74
import org.junit.jupiter.api.BeforeAll;
85
import org.junit.jupiter.api.Test;
96
import org.openbw.bwapi4j.test.BWDataProvider;
107
import org.openbw.bwapi4j.type.UnitType;
118

9+
import static org.assertj.core.api.Assertions.assertThat;
10+
import static org.junit.jupiter.api.Assertions.assertThrows;
11+
1212
class SimulatorTest {
1313

1414
private Simulator simulator = new Simulator();
@@ -346,8 +346,8 @@ void _2LurkersVs10Marines() {
346346
void _2LurkersVs12Marines() {
347347
// GIVEN
348348
simulator
349-
.addAgentA(factory.of(UnitType.Zerg_Lurker).setBurrowed(true))
350-
.addAgentA(factory.of(UnitType.Zerg_Lurker).setBurrowed(true));
349+
.addAgentA(factory.of(UnitType.Zerg_Lurker).setBurrowed(true).setX(130).setY(30))
350+
.addAgentA(factory.of(UnitType.Zerg_Lurker).setBurrowed(true).setX(150).setY(50));
351351

352352
for (int i = 0; i < 12; i++) {
353353
simulator.addAgentB(factory.of(UnitType.Terran_Marine).setX(10 * i).setY(20));
@@ -379,9 +379,9 @@ void _7MutaVs1BunkerAndSCV() {
379379
}
380380

381381
@Test
382-
void _7MutaVs1BunkerAnd4SCVs() {
382+
void _6MutaVs1BunkerAnd4SCVs() {
383383
// GIVEN
384-
for (int i = 0; i < 7; i++) {
384+
for (int i = 0; i < 6; i++) {
385385
simulator.addAgentA(factory.of(UnitType.Zerg_Mutalisk));
386386
}
387387
simulator.addAgentB(factory.of(UnitType.Terran_Bunker));
@@ -414,12 +414,12 @@ void _5MutaVs1Bunker() {
414414
}
415415

416416
@Test
417-
void _7MutasVs9Hydras() {
417+
void _7MutasVs8Hydras() {
418418
// GIVEN
419419
for (int i = 0; i < 7; i++) {
420420
simulator.addAgentA(factory.of(UnitType.Zerg_Mutalisk));
421421
}
422-
for (int i = 0; i < 9; i++) {
422+
for (int i = 0; i < 8; i++) {
423423
simulator.addAgentB(factory.of(UnitType.Zerg_Hydralisk));
424424
}
425425

@@ -454,13 +454,14 @@ void _8DragoonsVs6Hydras() {
454454
}
455455

456456
@Test
457-
void _13DragoonsVs10UpgradedHydras() {
457+
void _12DragoonsVs10UpgradedHydras() {
458458
// GIVEN
459-
for (int i = 0; i < 13; i++) {
460-
simulator.addAgentA(factory.of(UnitType.Protoss_Dragoon).setX(400).setY(400));
459+
for (int i = 0; i < 12; i++) {
460+
simulator.addAgentA(factory.of(UnitType.Protoss_Dragoon).setX(400 + i * 8).setY(400));
461461
}
462462
for (int i = 0; i < 10; i++) {
463-
simulator.addAgentB(factory.of(UnitType.Zerg_Hydralisk, 0, 0, 32, 32, true, false).setX(200));
463+
simulator.addAgentB(
464+
factory.of(UnitType.Zerg_Hydralisk, 0, 0, 32, 32, true, false).setX(200 + i * 8));
464465
}
465466

466467
// WHEN
@@ -472,9 +473,9 @@ void _13DragoonsVs10UpgradedHydras() {
472473
}
473474

474475
@Test
475-
void _13MarinesVs10Hydras() {
476+
void _12MarinesVs10Hydras() {
476477
// GIVEN
477-
for (int i = 0; i < 13; i++) {
478+
for (int i = 0; i < 12; i++) {
478479
simulator.addAgentA(factory.of(UnitType.Terran_Marine).setX(200 + i * 8).setY(400));
479480
}
480481
for (int i = 0; i < 10; i++) {
@@ -614,4 +615,20 @@ void addAgentBAtInvalidPositionShouldThrowException() {
614615
PositionOutOfBoundsException.class,
615616
() -> simulator.addAgentB(factory.of(UnitType.Protoss_Scout).setY(9000)));
616617
}
618+
619+
@Test
620+
void shouldResetCollisions() {
621+
// GIVEN
622+
for (int i = 0; i < 1000; i++)
623+
simulator.addAgentA(factory.of(UnitType.Protoss_Dragoon).setX(i * 8).setY(i * 8));
624+
for (int i = 0; i < 1000; i++)
625+
simulator.addAgentB(factory.of(UnitType.Protoss_Scout).setX(8191 - i * 8).setY(i * 8));
626+
simulator.simulate();
627+
628+
// WHEN
629+
simulator.reset();
630+
631+
// THEN
632+
assertThat(simulator.collision).containsOnly(0);
633+
}
617634
}

0 commit comments

Comments
 (0)