Добавить общую систему весовых объектов

This commit is contained in:
2026-08-19 07:40:11 +03:00
parent 19bb64edfb
commit 259fcd316b
32 changed files with 1017 additions and 34 deletions
@@ -72,6 +72,10 @@ public final class LevelContentTool {
for (int i = 0; i < level.platforms.size(); i++) {
rect(value, "platform", i, level.platforms.get(i).box, "#64748b");
}
for (int i = 0; i < level.objects.size(); i++) {
LevelDefinition.PhysicalObject item = level.objects.get(i);
rect(value, "object-" + item.type, i, item.box, "#f59e0b");
}
for (int i = 0; i < level.hazards.size(); i++) {
rect(value, "hazard-" + level.hazards.get(i).type, i,
level.hazards.get(i).box, "#ef4444");
@@ -108,6 +112,11 @@ public final class LevelContentTool {
row(value, level.number, "platform", i, item.isMoving() ? "MOVING" : "STATIC",
item.box, item.travelX, item.travelY, item.controlId);
}
for (int i = 0; i < level.objects.size(); i++) {
LevelDefinition.PhysicalObject item = level.objects.get(i);
row(value, level.number, "object", i, item.type.name(), item.box,
0f, 0f, "mass=" + item.mass);
}
for (int i = 0; i < level.hazards.size(); i++) {
LevelDefinition.Hazard item = level.hazards.get(i);
row(value, level.number, "hazard", i, item.type.name(), item.box,
@@ -10,6 +10,7 @@ public final class LevelDefinition {
SPIKES, SAW, FREEZER, ELECTRIC, PIT, CRUSHER, FIRE, PROJECTILE, EXPLOSION
}
public enum SwitchType { PRESSURE, TOGGLE, TIMED }
public enum PhysicalObjectType { BOX, ROCK, BALL, ICE_BLOCK, COUNTERWEIGHT }
public static final class Box {
public final float x;
@@ -115,6 +116,18 @@ public final class LevelDefinition {
}
}
public static final class PhysicalObject {
public final PhysicalObjectType type;
public final Box box;
public final int mass;
public PhysicalObject(PhysicalObjectType type, Box box, int mass) {
this.type = type;
this.box = box;
this.mass = mass;
}
}
public final int number;
public final int formatVersion;
public final int physicsVersion;
@@ -129,6 +142,7 @@ public final class LevelDefinition {
public final Box goal;
public final int targetDeaths;
public final int targetSeconds;
public final List<PhysicalObject> objects;
public final List<Platform> platforms;
public final List<Hazard> hazards;
public final List<Switch> switches;
@@ -151,7 +165,7 @@ public final class LevelDefinition {
) {
this(1, 1, number, title, hint, title, hint, worldWidth, 1080f,
spawnX, spawnY, goal, targetDeaths, targetSeconds,
platforms, hazards, switches, doors);
Collections.emptyList(), platforms, hazards, switches, doors);
}
public LevelDefinition(
@@ -173,6 +187,32 @@ public final class LevelDefinition {
List<Hazard> hazards,
List<Switch> switches,
List<Door> doors
) {
this(formatVersion, physicsVersion, number, title, hint, titleRu, hintRu,
worldWidth, worldHeight, spawnX, spawnY, goal, targetDeaths,
targetSeconds, Collections.emptyList(), platforms, hazards, switches, doors);
}
public LevelDefinition(
int formatVersion,
int physicsVersion,
int number,
String title,
String hint,
String titleRu,
String hintRu,
float worldWidth,
float worldHeight,
float spawnX,
float spawnY,
Box goal,
int targetDeaths,
int targetSeconds,
List<PhysicalObject> objects,
List<Platform> platforms,
List<Hazard> hazards,
List<Switch> switches,
List<Door> doors
) {
this.formatVersion = formatVersion;
this.physicsVersion = physicsVersion;
@@ -188,6 +228,7 @@ public final class LevelDefinition {
this.goal = goal;
this.targetDeaths = targetDeaths;
this.targetSeconds = targetSeconds;
this.objects = Collections.unmodifiableList(objects);
this.platforms = Collections.unmodifiableList(platforms);
this.hazards = Collections.unmodifiableList(hazards);
this.switches = Collections.unmodifiableList(switches);
@@ -37,6 +37,7 @@ public final class LevelJsonLoader {
optionalText(value, "controlId", path)));
}
List<LevelDefinition.PhysicalObject> objects = physicalObjects(root, source);
List<LevelDefinition.Hazard> hazards = hazards(root, source);
List<LevelDefinition.Switch> switches = switches(root, source);
List<LevelDefinition.Door> doors = doors(root, source);
@@ -56,12 +57,29 @@ public final class LevelJsonLoader {
box(required(root, "goal", source), source + ".goal"),
integer(targets, "deaths", source + ".targets"),
integer(targets, "seconds", source + ".targets"),
objects,
platforms,
hazards,
switches,
doors), source);
}
private static List<LevelDefinition.PhysicalObject> physicalObjects(
Map<String, Object> root, String source) {
if (!root.containsKey("objects")) return Collections.emptyList();
List<Object> values = array(root.get("objects"), source + ".objects");
List<LevelDefinition.PhysicalObject> result = new ArrayList<>();
for (int i = 0; i < values.size(); i++) {
String path = source + ".objects[" + i + "]";
Map<String, Object> value = object(values.get(i), path);
result.add(new LevelDefinition.PhysicalObject(
physicalObjectType(text(value, "type", path), path + ".type"),
box(required(value, "box", path), path + ".box"),
integer(value, "mass", path)));
}
return result;
}
static List<String> loadIndex(Reader reader, String sourceName) {
String source = sourceName == null ? "<levels-index>" : sourceName;
Map<String, Object> root = object(new JsonValueParser(reader, source).parse(), source);
@@ -171,6 +189,15 @@ public final class LevelJsonLoader {
}
}
private static LevelDefinition.PhysicalObjectType physicalObjectType(
String value, String path) {
try {
return LevelDefinition.PhysicalObjectType.valueOf(value);
} catch (IllegalArgumentException error) {
throw invalid(path, "has unknown physical object type '" + value + "'");
}
}
private static void requireEmptyArray(Map<String, Object> parent, String key, String path) {
List<Object> values = array(required(parent, key, path), path + "." + key);
if (!values.isEmpty()) {
@@ -25,6 +25,13 @@ public final class LevelValidator {
if (level.platforms.isEmpty()) {
throw invalid(source + ".platforms", "must contain at least one platform");
}
for (int i = 0; i < level.objects.size(); i++) {
LevelDefinition.PhysicalObject object = level.objects.get(i);
String path = source + ".objects[" + i + "]";
if (object.type == null) throw invalid(path + ".type", "must be known");
box(object.box, level, path + ".box");
if (object.mass <= 0) throw invalid(path + ".mass", "must be positive");
}
for (int i = 0; i < level.platforms.size(); i++) {
LevelDefinition.Platform platform = level.platforms.get(i);
String path = source + ".platforms[" + i + "]";