Skip to content

Commit 5e0ee41

Browse files
author
Bytekeeper
committed
Added frame skipping to simulator
1 parent 21d4244 commit 5e0ee41

File tree

8 files changed

+129
-81
lines changed

8 files changed

+129
-81
lines changed

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

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,24 +20,26 @@ private AgentUtil() {
2020
// Utility class
2121
}
2222

23-
public static void moveToward(Agent agent, Agent target, float distance) {
24-
if (distance <= agent.speed) {
23+
public static void moveToward(int frames, Agent agent, Agent target, float distance) {
24+
float travelled = frames * agent.speed;
25+
if (distance <= travelled) {
2526
agent.vx = target.x - agent.x;
2627
agent.vy = target.y - agent.y;
2728
} else {
28-
agent.vx = (int) ((target.x - agent.x) * agent.speed / distance);
29-
agent.vy = (int) ((target.y - agent.y) * agent.speed / distance);
29+
agent.vx = (int) ((target.x - agent.x) * travelled / distance);
30+
agent.vy = (int) ((target.y - agent.y) * travelled / distance);
3031
}
3132
}
3233

33-
public static void moveAwayFrom(Agent agent, Agent target, float distance) {
34+
public static void moveAwayFrom(int frames, Agent agent, Agent target, float distance) {
35+
float travelled = frames * agent.speed;
3436
if (distance == 0) {
3537
double a = rnd.nextDouble(Math.PI * 2);
36-
agent.vx = (int) (cos(a) * agent.speed);
37-
agent.vy = (int) (sin(a) * agent.speed);
38+
agent.vx = (int) (cos(a) * travelled);
39+
agent.vy = (int) (sin(a) * travelled);
3840
} else {
39-
agent.vx = (int) ((agent.x - target.x) * agent.speed / distance);
40-
agent.vy = (int) ((agent.y - target.y) * agent.speed / distance);
41+
agent.vx = (int) ((agent.x - target.x) * travelled / distance);
42+
agent.vy = (int) ((agent.y - target.y) * travelled / distance);
4143
}
4244
}
4345

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

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ public class AttackerBehavior implements Behavior {
1111

1212
@Override
1313
public boolean simUnit(
14-
Agent agent, UnorderedCollection<Agent> allies, UnorderedCollection<Agent> enemies) {
14+
int frameSkip, Agent agent, UnorderedCollection<Agent> allies, UnorderedCollection<Agent> enemies) {
1515
if (agent.cooldown > agent.maxCooldown - agent.stopFrames) {
1616
return true;
1717
}
@@ -61,18 +61,18 @@ public boolean simUnit(
6161
agent.attackTarget = selectedEnemy;
6262

6363
if (selectedEnemy == null) {
64-
return !agent.burrowed && simFlee(agent, enemies);
64+
return !agent.burrowed && simFlee(frameSkip, agent, enemies);
6565
}
6666

6767
if (!agent.burrowed) {
68-
simCombatMove(agent, selectedEnemy, selectedDistanceSquared, selectedWeapon);
68+
simCombatMove(frameSkip, agent, selectedEnemy, selectedDistanceSquared, selectedWeapon);
6969
}
7070

7171
if (agent.burrowedAttacker != agent.burrowed) {
7272
return false;
7373
}
7474

75-
if (agent.cooldown == 0
75+
if (agent.cooldown <= 0
7676
&& selectedDistanceSquared
7777
<= Math.max(Simulator.MIN_SIMULATION_RANGE, selectedWeapon.maxRangeSquared)) {
7878
simAttack(agent, allies, enemies, selectedEnemy, selectedWeapon);
@@ -88,7 +88,7 @@ private void simAttack(
8888
Agent selectedEnemy,
8989
Weapon selectedWeapon) {
9090
if (agent.canStim
91-
&& agent.remainingStimFrames == 0
91+
&& agent.remainingStimFrames <= 0
9292
&& agent.healthShifted >= agent.maxHealthShifted / 2) {
9393
AgentUtil.stim(agent);
9494
}
@@ -116,7 +116,7 @@ private void simAttack(
116116
}
117117

118118
private void simCombatMove(
119-
Agent agent, Agent selectedEnemy, int selectedDistanceSquared, Weapon selectedWeapon) {
119+
int frameSkip, Agent agent, Agent selectedEnemy, int selectedDistanceSquared, Weapon selectedWeapon) {
120120
boolean shouldKite =
121121
agent.isKiter
122122
&& agent.cooldown > 0
@@ -125,10 +125,10 @@ private void simCombatMove(
125125
float distance = (float) sqrt(selectedDistanceSquared);
126126
if (shouldKite) {
127127
if (distance + agent.speed < selectedWeapon.maxRange) {
128-
moveAwayFrom(agent, selectedEnemy, distance);
128+
moveAwayFrom(frameSkip, agent, selectedEnemy, distance);
129129
}
130130
} else {
131-
moveToward(agent, selectedEnemy, distance);
131+
moveToward(frameSkip, agent, selectedEnemy, distance);
132132
}
133133
}
134134
}

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

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import org.bk.ass.collection.UnorderedCollection;
44
import org.bk.ass.sim.Simulator.Behavior;
55

6+
import static java.lang.Math.min;
67
import static org.bk.ass.sim.AgentUtil.distanceSquared;
78
import static org.bk.ass.sim.AgentUtil.moveToward;
89

@@ -13,7 +14,7 @@ public class HealerBehavior implements Behavior {
1314

1415
@Override
1516
public boolean simUnit(
16-
Agent agent, UnorderedCollection<Agent> allies, UnorderedCollection<Agent> enemies) {
17+
int frameSkip, Agent agent, UnorderedCollection<Agent> allies, UnorderedCollection<Agent> enemies) {
1718
if (agent.energyShifted < 256) {
1819
return true;
1920
}
@@ -58,16 +59,13 @@ public boolean simUnit(
5859
return false;
5960
}
6061

61-
moveToward(agent, selectedAlly, (float) Math.sqrt(selectedDistanceSquared));
62+
moveToward(frameSkip, agent, selectedAlly, (float) Math.sqrt(selectedDistanceSquared));
6263
if (selectedDistanceSquared > MEDICS_HEAL_RANGE_SQUARED) {
6364
return true;
6465
}
65-
agent.energyShifted -= 256;
66+
agent.energyShifted -= 256 * frameSkip;
6667
selectedAlly.healedThisFrame = true;
67-
selectedAlly.healthShifted += 150;
68-
if (selectedAlly.healthShifted > selectedAlly.maxHealthShifted) {
69-
selectedAlly.healthShifted = selectedAlly.maxHealthShifted;
70-
}
68+
selectedAlly.healthShifted = min(selectedAlly.maxHealthShifted, selectedAlly.healthShifted + 150 * frameSkip);
7169

7270
return true;
7371
}

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

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import org.bk.ass.collection.UnorderedCollection;
44
import org.bk.ass.sim.Simulator.Behavior;
55

6+
import static java.lang.Math.min;
67
import static java.lang.Math.sqrt;
78
import static org.bk.ass.sim.AgentUtil.distanceSquared;
89
import static org.bk.ass.sim.AgentUtil.moveToward;
@@ -14,7 +15,7 @@ public class RepairerBehavior implements Behavior {
1415

1516
@Override
1617
public boolean simUnit(
17-
Agent agent, UnorderedCollection<Agent> allies, UnorderedCollection<Agent> enemies) {
18+
int frameSkip, Agent agent, UnorderedCollection<Agent> allies, UnorderedCollection<Agent> enemies) {
1819
Agent selectedAlly = null;
1920
int selectedDistanceSquared = Integer.MAX_VALUE;
2021

@@ -53,14 +54,11 @@ public boolean simUnit(
5354
return false;
5455
}
5556

56-
moveToward(agent, selectedAlly, (float) sqrt(selectedDistanceSquared));
57+
moveToward(frameSkip, agent, selectedAlly, (float) sqrt(selectedDistanceSquared));
5758
if (selectedDistanceSquared > SCV_REPAIR_RANGE_SQUARED) {
5859
return true;
5960
}
60-
selectedAlly.healthShifted += selectedAlly.hpConstructionRate;
61-
if (selectedAlly.healthShifted > selectedAlly.maxHealthShifted) {
62-
selectedAlly.healthShifted = selectedAlly.maxHealthShifted;
63-
}
61+
selectedAlly.healthShifted = min(selectedAlly.maxHealthShifted, selectedAlly.healthShifted + selectedAlly.hpConstructionRate * frameSkip);
6462

6563
return true;
6664
}

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,11 @@ public class RetreatBehavior implements Behavior {
1111

1212
@Override
1313
public boolean simUnit(
14-
Agent agent, UnorderedCollection<Agent> allies, UnorderedCollection<Agent> enemies) {
15-
return simFlee(agent, enemies);
14+
int frameSkip, Agent agent, UnorderedCollection<Agent> allies, UnorderedCollection<Agent> enemies) {
15+
return simFlee(frameSkip, agent, enemies);
1616
}
1717

18-
static boolean simFlee(Agent agent, UnorderedCollection<Agent> enemies) {
18+
static boolean simFlee(int frames, Agent agent, UnorderedCollection<Agent> enemies) {
1919
if (agent.burrowed || agent.isStasised || agent.isLockeddown) return false;
2020
Agent selectedEnemy = null;
2121
int selectedDistanceSquared = Integer.MAX_VALUE;
@@ -38,7 +38,7 @@ static boolean simFlee(Agent agent, UnorderedCollection<Agent> enemies) {
3838
if (selectedEnemy == null) {
3939
return false;
4040
}
41-
moveAwayFrom(agent, selectedEnemy, (float) sqrt(selectedDistanceSquared));
41+
moveAwayFrom(frames, agent, selectedEnemy, (float) sqrt(selectedDistanceSquared));
4242
return true;
4343
}
4444
}

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

Lines changed: 47 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,11 @@
55

66
import java.util.Collection;
77
import java.util.Collections;
8+
import java.util.Objects;
89
import java.util.function.ToIntFunction;
910

11+
import static java.lang.Math.min;
12+
1013
/**
1114
* Used to simulate 2 groups of agents engaging each other. Either use the default constructor which
1215
* initialized the default behavior or customize the behaviors. Ie. if you want to simulate one
@@ -23,16 +26,12 @@
2326
* Be cautious when modifying {@link Agent}s after they have been added to the simulation.
2427
*/
2528
public class Simulator {
26-
/**
27-
* Use to count health and shields as equal, maybe useful in PvP?
28-
*/
29+
/** Use to count health and shields as equal, maybe useful in PvP? */
2930
public static final ToIntFunction<Agent> HEALTH_AND_SHIELD =
30-
agent -> agent.getHealth() + agent.getShields();
31-
/**
32-
* Use to count shields as half the value of health.
33-
*/
31+
agent -> agent.getHealth() + agent.getShields();
32+
/** Use to count shields as half the value of health. */
3433
public static final ToIntFunction<Agent> HEALTH_AND_HALFED_SHIELD =
35-
agent -> agent.getHealth() + agent.getShields() / 2;
34+
agent -> agent.getHealth() + agent.getShields() / 2;
3635

3736
private static final int MAX_MAP_DIMENSION = 8192;
3837
private static final int TILE_SIZE = 16;
@@ -46,14 +45,28 @@ public class Simulator {
4645
final byte[] collision = new byte[COLLISION_MAP_DIMENSION * COLLISION_MAP_DIMENSION];
4746
private final Behavior playerABehavior;
4847
private final Behavior playerBBehavior;
48+
private final int frameSkip;
4949

5050
public Simulator() {
51-
this(new RoleBasedBehavior(), new RoleBasedBehavior());
51+
this(1);
5252
}
5353

5454
public Simulator(Behavior playerABehavior, Behavior playerBBehavior) {
55+
this(1, playerABehavior, playerBBehavior);
56+
}
57+
58+
public Simulator(int frameSkip) {
59+
this(frameSkip, new RoleBasedBehavior(), new RoleBasedBehavior());
60+
}
61+
62+
public Simulator(int frameSkip, Behavior playerABehavior, Behavior playerBBehavior) {
63+
if (frameSkip < 1) throw new IllegalArgumentException("frameSkip must be >= 1");
64+
Objects.requireNonNull(playerABehavior, "Behavior of player A must be set");
65+
Objects.requireNonNull(playerBBehavior, "Behavior of player B must be set");
66+
5567
this.playerABehavior = playerABehavior;
5668
this.playerBBehavior = playerBBehavior;
69+
this.frameSkip = frameSkip;
5770
}
5871

5972
public Simulator addAgentA(Agent agent) {
@@ -127,7 +140,9 @@ public int simulate() {
127140
* @return the actual number of frames simulated, usually the given number of frames
128141
*/
129142
public int simulate(int frames) {
130-
while (frames-- != 0 && !playerA.isEmpty() && !playerB.isEmpty()) {
143+
if (frames > 0) frames = (frames + frameSkip - 1) / frameSkip;
144+
while (frames != 0 && !playerA.isEmpty() && !playerB.isEmpty()) {
145+
frames -= frameSkip;
131146
if (!step()) {
132147
break;
133148
}
@@ -166,14 +181,14 @@ private boolean step() {
166181
simRunning |=
167182
agent.isLockeddown
168183
|| agent.isStasised
169-
|| playerABehavior.simUnit(agent, playerA, playerB);
184+
|| playerABehavior.simUnit(frameSkip, agent, playerA, playerB);
170185
}
171186
for (int i = playerB.size() - 1; i >= 0; i--) {
172187
Agent agent = playerB.get(i);
173188
simRunning |=
174189
agent.isLockeddown
175190
|| agent.isStasised
176-
|| playerBBehavior.simUnit(agent, playerB, playerA);
191+
|| playerBBehavior.simUnit(frameSkip, agent, playerB, playerA);
177192
}
178193
removeDead(playerA);
179194
removeDead(playerB);
@@ -206,31 +221,14 @@ private void updateStats(UnorderedCollection<Agent> agents) {
206221
agent.vy = 0;
207222
agent.healedThisFrame = false;
208223

209-
if (agent.cooldown > 0) {
210-
agent.cooldown--;
211-
}
212-
if (agent.shieldsShifted < agent.maxShieldsShifted) {
213-
agent.shieldsShifted += 7;
214-
if (agent.shieldsShifted > agent.maxShieldsShifted) {
215-
agent.shieldsShifted = agent.maxShieldsShifted;
216-
}
217-
}
218-
if (agent.plagueDamagePerFrameShifted < agent.healthShifted) {
219-
agent.healthShifted -= agent.plagueDamagePerFrameShifted;
220-
}
221-
if (agent.remainingStimFrames > 0) {
222-
agent.remainingStimFrames--;
223-
}
224-
if (agent.regeneratesHealth && agent.healthShifted < agent.maxHealthShifted) {
225-
agent.healthShifted += 4;
226-
if (agent.healthShifted > agent.maxHealthShifted) {
227-
agent.healthShifted = agent.maxHealthShifted;
228-
}
229-
}
230-
agent.energyShifted += 8;
231-
if (agent.energyShifted > agent.maxEnergyShifted) {
232-
agent.energyShifted = agent.maxEnergyShifted;
233-
}
224+
agent.cooldown = agent.cooldown - frameSkip;
225+
agent.shieldsShifted = min(agent.maxShieldsShifted, agent.shieldsShifted + 7 * frameSkip);
226+
if (agent.plagueDamagePerFrameShifted * frameSkip < agent.healthShifted)
227+
agent.healthShifted -= agent.plagueDamagePerFrameShifted * frameSkip;
228+
agent.remainingStimFrames = agent.remainingStimFrames - frameSkip;
229+
if (agent.regeneratesHealth)
230+
agent.healthShifted = min(agent.maxHealthShifted, agent.healthShifted + 4 * frameSkip);
231+
agent.energyShifted = min(agent.energyShifted + 8 * frameSkip, agent.maxEnergyShifted);
234232
}
235233
}
236234

@@ -290,18 +288,21 @@ public RoleBasedBehavior() {
290288

291289
@Override
292290
public boolean simUnit(
293-
Agent agent, UnorderedCollection<Agent> allies, UnorderedCollection<Agent> enemies) {
291+
int frameSkip,
292+
Agent agent,
293+
UnorderedCollection<Agent> allies,
294+
UnorderedCollection<Agent> enemies) {
294295
if (agent.isSuicider) {
295-
return suiciderSimulator.simUnit(agent, allies, enemies);
296+
return suiciderSimulator.simUnit(frameSkip, agent, allies, enemies);
296297
}
297298
if (agent.isHealer) {
298-
return healerSimulator.simUnit(agent, allies, enemies);
299+
return healerSimulator.simUnit(frameSkip, agent, allies, enemies);
299300
}
300-
if (agent.isRepairer && repairerSimulator.simUnit(agent, allies, enemies)) {
301+
if (agent.isRepairer && repairerSimulator.simUnit(frameSkip, agent, allies, enemies)) {
301302
return true;
302303
// Otherwise FIGHT, you puny SCV!
303304
}
304-
return attackerSimulator.simUnit(agent, allies, enemies);
305+
return attackerSimulator.simUnit(frameSkip, agent, allies, enemies);
305306
}
306307
}
307308

@@ -312,7 +313,10 @@ public boolean simUnit(
312313
public interface Behavior {
313314

314315
boolean simUnit(
315-
Agent agent, UnorderedCollection<Agent> allies, UnorderedCollection<Agent> enemies);
316+
int frameSkip,
317+
Agent agent,
318+
UnorderedCollection<Agent> allies,
319+
UnorderedCollection<Agent> enemies);
316320
}
317321

318322
public static class IntEvaluation {
@@ -333,7 +337,6 @@ public int delta() {
333337
return evalA - evalB;
334338
}
335339

336-
337340
public int dot(IntEvaluation other) {
338341
return evalA * other.evalA - evalB * other.evalB;
339342
}

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

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,13 @@
33
import org.bk.ass.collection.UnorderedCollection;
44
import org.bk.ass.sim.Simulator.Behavior;
55

6-
import static org.bk.ass.sim.AgentUtil.dealDamage;
7-
import static org.bk.ass.sim.AgentUtil.distanceSquared;
6+
import static org.bk.ass.sim.AgentUtil.*;
87

98
public class SuiciderBehavior implements Behavior {
109

1110
@Override
1211
public boolean simUnit(
13-
Agent agent, UnorderedCollection<Agent> allies, UnorderedCollection<Agent> enemies) {
12+
int frameSkip, Agent agent, UnorderedCollection<Agent> allies, UnorderedCollection<Agent> enemies) {
1413
// Don't check for lockdown - I believe there are no suiciders which can be locked down
1514
if (agent.isStasised) return false;
1615
Agent selectedEnemy = null;
@@ -36,6 +35,8 @@ public boolean simUnit(
3635
return false;
3736
}
3837

38+
moveToward(frameSkip, agent, selectedEnemy, (float) Math.sqrt(selectedDistanceSquared));
39+
3940
if (selectedDistanceSquared <= agent.speedSquared) {
4041
dealDamage(agent, agent.weaponVs(selectedEnemy), selectedEnemy);
4142
agent.healthShifted = 0;

0 commit comments

Comments
 (0)