fix: improve rasterization and tests
This commit is contained in:
parent
0572450ced
commit
5984e40384
@ -1,17 +0,0 @@
|
||||
package uulm.teamname.marvelous.gamelibrary.gamelogic;
|
||||
|
||||
import uulm.teamname.marvelous.gamelibrary.events.Event;
|
||||
|
||||
import java.util.Observable;
|
||||
|
||||
/** Represents an event emitter for game events fired by a game instance. */
|
||||
class EventEmitter extends Observable {
|
||||
/**
|
||||
* Emits an array of {@link Event}s. This method is necessary because {@link Observable#setChanged} is protected.
|
||||
* @param events The events to emit
|
||||
*/
|
||||
public void update(Event... events) {
|
||||
setChanged();
|
||||
notifyObservers(events);
|
||||
}
|
||||
}
|
@ -1,22 +0,0 @@
|
||||
package uulm.teamname.marvelous.gamelibrary.gamelogic;
|
||||
|
||||
import uulm.teamname.marvelous.gamelibrary.events.Event;
|
||||
|
||||
import java.util.Observable;
|
||||
import java.util.Observer;
|
||||
|
||||
/** Represents an event observer for game events emitted by an {@link EventEmitter}. */
|
||||
public class EventObserver implements Observer {
|
||||
@Override
|
||||
public void update(Observable o, Object arg) {
|
||||
handle((Event[])arg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets called with incoming {@link Event}s. Override this method to handle events.
|
||||
* @param events The events that got emitted
|
||||
*/
|
||||
protected void handle(Event[] events) {
|
||||
|
||||
}
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
package uulm.teamname.marvelous.gamelibrary.gamelogic;
|
||||
|
||||
import uulm.teamname.marvelous.gamelibrary.IntVector2;
|
||||
import uulm.teamname.marvelous.gamelibrary.Tuple;
|
||||
import uulm.teamname.marvelous.gamelibrary.entities.*;
|
||||
import uulm.teamname.marvelous.gamelibrary.entities.Character;
|
||||
import uulm.teamname.marvelous.gamelibrary.events.*;
|
||||
@ -11,7 +12,9 @@ import uulm.teamname.marvelous.gamelibrary.requests.Request;
|
||||
import uulm.teamname.marvelous.gamelibrary.requests.RequestType;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.geom.Area;
|
||||
import java.awt.geom.Line2D;
|
||||
import java.awt.geom.Point2D;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.util.*;
|
||||
|
||||
@ -98,7 +101,7 @@ class GameLogic {
|
||||
}
|
||||
case MindStone -> {
|
||||
EntityType target = data.originEntity.type == EntityType.P1 ? EntityType.P2 : EntityType.P1;
|
||||
for(IntVector2 pos: rasterize(data.originField, data.targetField)) {
|
||||
for(IntVector2 pos: rasterize(data.originField, data.targetField, false, true)) {
|
||||
for(Entity entity: state.entities.findByPosition(pos)) {
|
||||
if(entity.id.isSameType(target)) {
|
||||
result.add(new EventBuilder(EventType.TakenDamageEvent)
|
||||
@ -436,7 +439,7 @@ class GameLogic {
|
||||
* @return Whether or not the light of sight exists
|
||||
*/
|
||||
private static boolean checkLineOfSight(GameState state, IntVector2 start, IntVector2 end) {
|
||||
for(IntVector2 pos: rasterize(start, end)) {
|
||||
for(IntVector2 pos: rasterize(start, end, false, false)) {
|
||||
if(state.entities.blocksVision(pos)) {
|
||||
return false;
|
||||
}
|
||||
@ -949,28 +952,84 @@ class GameLogic {
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes all fields which intersect the line between the center points of the given two fields.
|
||||
* Computes all fields which intersect the line between the center points of the given two fields including the two defining points.
|
||||
* @return The list of intersecting positions
|
||||
*/
|
||||
public static ArrayList<IntVector2> rasterize(IntVector2 a, IntVector2 b) {
|
||||
ArrayList<IntVector2> result = new ArrayList<>();
|
||||
return rasterize(a, b, true, true);
|
||||
}
|
||||
|
||||
//TODO: implement proper line rasterization algorithm in GameLogic.rasterize
|
||||
/**
|
||||
* Computes all fields which intersect the line between the center points of the given two fields.
|
||||
* @param includeA Whether to include point a in the result
|
||||
* @param includeB Whether to include point b in the result
|
||||
* @return The list of intersecting positions
|
||||
*/
|
||||
public static ArrayList<IntVector2> rasterize(IntVector2 a, IntVector2 b, boolean includeA, boolean includeB) {
|
||||
ArrayList<IntVector2> result = new ArrayList<>();
|
||||
|
||||
int x1 = Math.min(a.getX(), b.getX());
|
||||
int x2 = Math.max(a.getX(), b.getX());
|
||||
int y1 = Math.min(a.getY(), b.getY());
|
||||
int y2 = Math.max(a.getY(), b.getY());
|
||||
|
||||
Line2D line = new Line2D.Float(x1 + 0.5f, y1 + 0.5f, x2 + 0.5f, y2 + 0.5f);
|
||||
for(int i = x1; i <= x2; i++) {
|
||||
for(int j = y1; j <= y2; j++) {
|
||||
Rectangle2D cell = new Rectangle.Float(i, j, 1, 1);
|
||||
if(line.intersects(cell)) {
|
||||
HashSet<Point2D.Float> intersections = new HashSet<>();
|
||||
for(Line2D.Float part: getWireframe(new Rectangle.Float(i, j, 1, 1))) {
|
||||
if(part.intersectsLine(line)) {
|
||||
Point2D.Float intersection = calculateInterceptionPoint(line.getP1(), line.getP2(), part.getP1(), part.getP2());
|
||||
intersections.add(intersection);
|
||||
if(intersections.size() > 1) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(intersections.size() > 1) {
|
||||
result.add(new IntVector2(i, j));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(includeA) {
|
||||
result.add(a);
|
||||
}
|
||||
if(includeB) {
|
||||
result.add(b);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
//https://rosettacode.org/wiki/Find_the_intersection_of_two_lines#Java
|
||||
public static Point2D.Float calculateInterceptionPoint(Point2D s1, Point2D s2, Point2D d1, Point2D d2) {
|
||||
double a1 = s2.getY() - s1.getY();
|
||||
double b1 = s1.getX() - s2.getX();
|
||||
double c1 = a1 * s1.getX() + b1 * s1.getY();
|
||||
|
||||
double a2 = d2.getY() - d1.getY();
|
||||
double b2 = d1.getX() - d2.getX();
|
||||
double c2 = a2 * d1.getX() + b2 * d1.getY();
|
||||
|
||||
double delta = a1 * b2 - a2 * b1;
|
||||
return new Point2D.Float((float) ((b2 * c1 - b1 * c2) / delta), (float) ((a1 * c2 - a2 * c1) / delta));
|
||||
}
|
||||
|
||||
/** Computes all wireframe lines for the given rectangle. */
|
||||
public static ArrayList<Line2D.Float> getWireframe(Rectangle.Float rect) {
|
||||
ArrayList<Line2D.Float> result = new ArrayList<>();
|
||||
|
||||
Point2D.Float lt = new Point2D.Float(rect.x, rect.y);
|
||||
Point2D.Float rt = new Point2D.Float(rect.x + rect.width, rect.y);
|
||||
Point2D.Float rb = new Point2D.Float(rect.x + rect.width, rect.y + rect.height);
|
||||
Point2D.Float lb = new Point2D.Float(rect.x, rect.y + rect.height);
|
||||
|
||||
result.add(new Line2D.Float(lt, rt));
|
||||
result.add(new Line2D.Float(rt, rb));
|
||||
result.add(new Line2D.Float(lb, rb));
|
||||
result.add(new Line2D.Float(lt, lb));
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
@ -7,32 +7,27 @@ import uulm.teamname.marvelous.gamelibrary.IntVector2;
|
||||
import uulm.teamname.marvelous.gamelibrary.entities.*;
|
||||
import uulm.teamname.marvelous.gamelibrary.entities.Character;
|
||||
import uulm.teamname.marvelous.gamelibrary.events.Event;
|
||||
import uulm.teamname.marvelous.gamelibrary.events.EventBuilder;
|
||||
import uulm.teamname.marvelous.gamelibrary.events.EventType;
|
||||
import uulm.teamname.marvelous.gamelibrary.json.config.*;
|
||||
import uulm.teamname.marvelous.gamelibrary.requests.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
class GameLogicTest {
|
||||
private static final Iterator<Integer> randomIntegers = ThreadLocalRandom.current().ints().iterator();
|
||||
|
||||
private static PartyConfig partyConfig;
|
||||
private static CharacterConfig characterConfig;
|
||||
private static ScenarioConfig scenarioConfig;
|
||||
private static final PartyConfig partyConfig = new PartyConfig();
|
||||
private static final CharacterConfig characterConfig = new CharacterConfig();
|
||||
private static final ScenarioConfig scenarioConfig = new ScenarioConfig();
|
||||
|
||||
private static ArrayList<Integer> player1Selection = new ArrayList<>();
|
||||
private static ArrayList<Integer> player2Selection = new ArrayList<>();
|
||||
private static final ArrayList<Integer> player1Selection = new ArrayList<>();
|
||||
private static final ArrayList<Integer> player2Selection = new ArrayList<>();
|
||||
|
||||
@BeforeAll
|
||||
static void setUp() {
|
||||
partyConfig = new PartyConfig();
|
||||
partyConfig.maxRounds = 100;
|
||||
partyConfig.mindStoneCD = 2;
|
||||
partyConfig.powerStoneCD = 3;
|
||||
@ -42,13 +37,11 @@ class GameLogicTest {
|
||||
partyConfig.timeStoneCD = 7;
|
||||
partyConfig.mindStoneDMG = 3;
|
||||
|
||||
characterConfig = new CharacterConfig();
|
||||
characterConfig.characters = new CharacterProperties[] {
|
||||
generateCharacter(), generateCharacter(), generateCharacter(), generateCharacter(), generateCharacter(), generateCharacter(),
|
||||
generateCharacter(), generateCharacter(), generateCharacter(), generateCharacter(), generateCharacter(), generateCharacter()
|
||||
};
|
||||
|
||||
scenarioConfig = new ScenarioConfig();
|
||||
scenarioConfig.name = generateName(20);
|
||||
scenarioConfig.author = generateName(20);
|
||||
scenarioConfig.scenario = new FieldType[30][30];
|
||||
@ -179,6 +172,29 @@ class GameLogicTest {
|
||||
assertEquals(EventType.GamestateEvent, actual.type, "First event should be a GameStateEvent");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testRasterize() {
|
||||
ArrayList<IntVector2> result = GameLogic.rasterize(new IntVector2(0, 0), new IntVector2(1, 1), false, false);
|
||||
|
||||
assertEquals(0, result.size(), "Diagonals are not included");
|
||||
|
||||
|
||||
IntVector2[] result2 = GameLogic.rasterize(new IntVector2(0, 0), new IntVector2(4, 0)).toArray(new IntVector2[0]);
|
||||
|
||||
assertEquals(new HashSet<>(Arrays.asList(
|
||||
new IntVector2(0, 0), new IntVector2(1, 0), new IntVector2(2, 0), new IntVector2(3, 0), new IntVector2(4, 0)
|
||||
)), new HashSet<>(Arrays.asList(result2)), "Straight lines work correctly");
|
||||
|
||||
|
||||
IntVector2[] result3 = GameLogic.rasterize(new IntVector2(0, 0), new IntVector2(2, 1)).toArray(new IntVector2[0]);
|
||||
|
||||
assertEquals(new HashSet<>(Arrays.asList(
|
||||
new IntVector2(0, 0), new IntVector2(1, 0), new IntVector2(1, 1), new IntVector2(2, 1))
|
||||
), new HashSet<>(Arrays.asList(result3)), "Tilted lines work correctly");
|
||||
}
|
||||
|
||||
|
||||
// @Provide("gamestate")
|
||||
// Arbitrary<GameState> gamestate() {
|
||||
// var states = Arbitraries.integers()
|
||||
|
Loading…
Reference in New Issue
Block a user