我目前正在用 Java 编写游戏,并且在 Jackson 中保存实体数据时遇到问题。我需要使用超类的不同子类对哈希图进行(反)序列化。例如我有一个名为 mob 的类,每个实体(例如玩家)都是 Mob 的子类:
public HashMap<Byte, Mob> mobs = new Hashmap<>(); // Byte is ok here, as I don't have many mobs yet and it can also be changed to whatever I need to
public class Player extends Mob {} // The Player
我想如何序列化地图:
public void loadEntities(String path) {
ObjectMapper om = new ObjectMapper();
try {
runThread.mobs = om.readValue(new File(path + "/entities.json"), HashMap.class);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
但是我需要做什么,才能让 hashmap 正确反序列化 JSON 文件中的生物玩家,然后将其作为玩家序列化回哈希映射中,而不是普通的生物对象?
我的 JSON 是什么样子的:
{
"0" : {
"posX" : 256,
"posY" : 128,
"rotation" : "links"
},
"2" : {
"posX" : 128,
"posY" : 256,
"rotation" : "rechts"
}
}
0 和 2 是实体的 ID,但如果需要,我可以将哈希图更改为列表。
我的暴民的完整示例:
import de.pki.GUI.Welt.Tiles.Tiles;
import java.awt.image.BufferedImage;
public abstract class Mob {
public float posX;
public float posY;
public float screenX;
public float screenY;
// Physik
public float forceX;
public float forceY;
public float gravity = 9.81F;
public float currentGravity = gravity * 2;
public float rotation; // Für Projektile, welche sich in der Luft drehen müssen
public String richtung; // Für normale Mobs, welche nur zwei Richtungen brauchen
public boolean vectorAble; // TODO
public float standardSpeed;
public float sprintSpeed;
public float currentSpeed;
public byte maxSpruenge = 2;
public byte spruengeGenutzt;
public float sprungKraft;
public float aktuelleSprungkraft = -5;
public float lastJump = System.currentTimeMillis();
// Hit box
public short startBoxX;
public short startBoxY;
public short endBoxX;
public short endBoxY;
public float opacity;
// Bilder
public BufferedImage idleLinks;
public BufferedImage idleRechts;
public BufferedImage[] links;
public BufferedImage[] rechts;
public BufferedImage currentImg;
public byte groesse = 1;
public byte imageCount = 0;
public double lastImageAnimation = System.currentTimeMillis();
// Methoden
// Physik
public void updateForces(CollisionChecker collisionChecker, int tickSpeed) {
if (forceX > 0) {
collisionChecker.checkRunning((int) (posX + startBoxX + endBoxX), forceX / tickSpeed, 1, this);
} else if (forceX < 0) {
collisionChecker.checkRunning((int) (posX + startBoxX - 4), (forceX * - 1) / tickSpeed, -1, this);
}
if (forceY > 0) {
collisionChecker.checkFalling((int) (posY + startBoxY + endBoxY), forceY / tickSpeed, 1, this);
} else if (forceY < 0) {
collisionChecker.checkFalling((int) (posY + startBoxY - 2), (forceY * - 1) / tickSpeed, -1, this);
}
}
public void gravity(double tickSpeed) {
forceY += (float) (currentGravity / tickSpeed);
}
public void jump() {
if (lastJump + 500 < System.currentTimeMillis()) {
if (spruengeGenutzt < maxSpruenge) {
forceY = aktuelleSprungkraft;
spruengeGenutzt++;
lastJump = System.currentTimeMillis();
}
}
}
// Für Objekte, welche Vektoren besitzen
public void changeVektor(Mob mob, Tiles tiles, double aufprallWinkel) {
if (mob.vectorAble) {}
// TODO: Noch hinzufügen
}
// Grafische Sachen
public void updateImages() {
switch (richtung) {
case "rechts" -> {
if (System.currentTimeMillis() - lastImageAnimation >= (double) 60 / rechts.length / 1000 + 150) {
if (imageCount + 1 >= rechts.length) {
imageCount = 0;
} else {
imageCount++;
}
currentImg = rechts[imageCount];
lastImageAnimation = System.currentTimeMillis();
}
}
case "links" -> {
if (System.currentTimeMillis() - lastImageAnimation >= (double) 60 / links.length / 1000 + 150) {
if (imageCount + 1 >= links.length) {
imageCount = 0;
} else {
imageCount++;
}
currentImg = links[imageCount];
lastImageAnimation = System.currentTimeMillis();
}
}
}
if (forceX == 0) {
if (richtung.equals("rechts")) {
currentImg = idleRechts;
} else if (richtung.equals("links")) {
currentImg = idleLinks;
}
}
}
}
还有我的玩家:
package de.pki.Entities.Spieler;
import de.pki.Entities.Mob;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
public class Spieler extends Mob {
public Spieler() {
loadVariables();
loadImages();
hitBoxRechts();
}
private void loadImages() {
try {
links = new BufferedImage[2];
rechts = new BufferedImage[2];
idleLinks = ImageIO.read(new FileInputStream("src/Data/Images/Entities/Spieler/Idle/left_idle.png"));
idleRechts = ImageIO.read(new FileInputStream("src/Data/Images/Entities/Spieler/Idle/right_idle.png"));
links[0] = ImageIO.read(new FileInputStream("src/Data/Images/Entities/Spieler/WalkingAnimation/linksLauf1.png"));
links[1] = ImageIO.read(new FileInputStream("src/Data/Images/Entities/Spieler/WalkingAnimation/linksLauf2.png"));
rechts[0] = ImageIO.read(new FileInputStream("src/Data/Images/Entities/Spieler/WalkingAnimation/rechtsLauf1.png"));
rechts[1] = ImageIO.read(new FileInputStream("src/Data/Images/Entities/Spieler/WalkingAnimation/rechtsLauf2.png"));
currentImg = idleRechts;
} catch (IOException e) {
System.out.println(e);
}
}
private void loadVariables() {
sprungKraft = (float) (-9.81 * 1);
aktuelleSprungkraft = sprungKraft;
maxSpruenge = 2;
spruengeGenutzt = 0;
standardSpeed = 3;
sprintSpeed = 4.5F;
currentSpeed = standardSpeed;
richtung = "rechts";
groesse = 2;
hitBoxRechts();
}
public void hitBoxRechts() {
startBoxX = (short) (6 * groesse);
startBoxY = (short) (3 * groesse);
endBoxX = (short) (19 * groesse);
endBoxY = (short) (23 * groesse);
}
}```
(I'm currently in class, so it took me some time to edit the code)
Thanks for the help
参见 https://www.baeldung.com/java-deserialize-generic-type-with-jackson
你可以做
TypeReference typeRef = new TypeReference<Map<Byte, Mob>>() {};
runThread.mobs = om.readValue(new File(path + "/entities.json"), typeRef);
要正确序列化多态实例,您需要使用注释
JsonTypeInfo
和JsonSubTypes
。基本上,JsonTypeInfo
允许在序列化带注释的类的实例时定义额外的属性,而JsonSubTypes
为每个子类定义该额外属性的值。在你的情况下,它看起来像这样:
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "class")
@JsonSubTypes({
@JsonSubTypes.Type(value = Player.class, name = "player")
})
这里还有一篇来自 Baeldung 的有趣文章涵盖了该主题。
此外,由于您希望将
Player
实例存储在通用数据结构中,例如 Map
或 List
,因此您需要使用 TypeReference
子类化您的数据结构,以便 Jackson 知道如何正确反序列化json.
ObjectMapper mapper = new ObjectMapper();
Map<Byte, Mob> map = mapper.readValue(json, new TypeReference<Map<Byte, Mob>>() {});
这里是 OneCompiler 的链接,其中包含代码演示