在libGdx中将我的GameState序列化为JSON不起作用,我该如何修复它



我在将GameState保存到JSON时遇到问题。

最初我将GameState保存为JSON,如下所示:

Json json = new JSON();
String save = json.prettyPrint(state);

我按照如下方式加载:

json.fromJson(GameState.class, save);

然而,State加载不正确,所以我进行了一个小测试。我做了以下事情:

class Car
{
    public int id;
    public Color color;
    public Speed speed;
    public Car(int id, Color color, Speed speed)
    {
        this.color = color;
        this.id = id;
        this.speed = speed;
    }
}
class Speed
{
    enum ASpeed
    {
        FAST, MEDIUM, SLOW;
    }
    ASpeed speed;
    public Speed()
    {
        speed = ASpeed.FAST;
    }
}

并且在create

@Override
public void create()
{
    Json json = new Json();
    Car car = new Car(1, Color.RED, new Speed());
    String carSave = json.prettyPrint(car);
    System.out.println(carSave);
}

我得到的结果是:

{
    id:1
    color:{
        r:1
        a:1
    }
    speed:{}
}

我明白为什么我的游戏没有正确加载;它没有正确序列化。我的GameState基本上是一个包含3个Array数据的类,这些数据需要从一个游戏发展到另一个游戏。我有常规的getter和setter方法,以及几十个访问相关数据的实用方法,如下所示:

//TODO: Possibly add an Array of Event instances to fire for each player when certain circumstances are met as well as a string-based flagging system that can be used in the events.
//TODO: Research threading API in libGdx and see about moving the game logic over to a seperate thread - since this class is used for game logic, consider moving this with it.
public class GameState
{
    private Array<Player> players;
    private Array<Planet> planets;
    private Array<Fleet> fleets;
    public GameState(Array<Player> players, Array<Planet> planets, Array<Fleet> fleets)
    {
        this.players = players;
        this.planets = planets;
        this.fleets = fleets;
    }
    public Fleet getFleet(int id)
    {
        if(id <= fleets.size)
        {
             return fleets.get(id);
        }
        return null;
    }
    public Planet getPlanet(int id)
    {
        if(id <= planets.size)
        {
            return planets.get(id);
        }
        return null;
    }
    public Player getPlayer(int id)
    {
        if(id <= players.size)
        {
            return players.get(id);
        }
        return null;
    }

当然,这不是最好的方法,但我每个字段只有大约100个,不打算添加更多,所以这种方法很好地达到了我的目的。每个播放器都包含一个用于获取相关数据的Integer值数组。一个例子;

public class Player
{
    private final int id;
    //libGdx Color used by ShapeRenderer to display planets in the right political color
    private Color color;
    //Things that the game logic demands be accessible from each Player instance
    //TODO: Move these over to the libGdx IntegerArray when you have the time - this will avoid the boxing/unboxing penalty when accessing members.
    Array<Integer> allies;
    Array<Integer>desiredAllies;
    Array<Integer> enemies:
    Array<Integer> neutrals;
    Array<Integer> planets;
    Array<Integer> fleets;
    public Player(int id, Color color)
    {
        this.id = id;
        this.color = color;
        allies = new Array<Integer>();
        planets = new Array<Integer>();
        fleets = new Array<Integer>();
        neutrals = new Array<Integer>();
        enemies = new Array<Integer>();
    }
    //Getters, Setters, and many, many utility methods.
}

Planet、Player和Fleet类都有类似的结构,甚至实现了相同的接口:

public interface IndexedGameObject extends GameObject
{
    int getID();
}

在系列化之前,我的游戏设计和结构都很好。我学习Json是为了挽救我的比赛,我可能错过了一些东西为什么这个设计在序列化时不起作用?有没有办法让我上班?如果没有,除了编写我自己的保存格式之外,还有什么可能的解决方案?我在XML方面几乎没有经验,这样行吗

注:

我愿意并且能够编写自己的保存格式,但这样做是一致的,人眼可读的方式将增加大量的开销和维护,并将浪费时间(因为这类似于编写一种非常小、不完全功能性的语言,我需要做大量的一般测试来确保它正常工作)和精力,而这些精力将更好地用于开发和维护更直观的用户界面。如果JSON无法达到我的目的,有什么可以做到的吗?

我基本上必须重新制定我的整个时间表(是的,我列出了我需要做的事情,以及我应该在什么时候做,比如:星期二——解决了放学后和家庭作业后几乎不可能重新创建按钮消失的恼人错误)。

理论上,我的JSON应该有这样的结构;

GameState ->
    fleets ->
        fleet ->
            owner: integer id of the player that owns this fleet.
            id: the index of this fleet in the Array
            locationID: integer id of the province this fleet is located in.
            originalTransports: final integer used for reinforcing.
            originalFighters: final integer used for reinforcing.
            originalFrigates: final integer used for reinforcing.
            originalDreadnaughts: final integer used for reinforcing.
            transports: number of troop transports currently in the fleet.
            fighters: the number of fighters currently in fleet.
            frigates: the number of frigates in this fleet.
            dreadnaughts: number of dreadnaughts in the fleet.
    players ->
        player ->
            id: int representing the index of this player in the GameState
            provinces: Integer Array representing the provinces owned by this player.
            allies: Integer Array representing the index of the other Players allied to this one.
            enemies: Integer Array representing the indices of the other players at war with this one.
            neutrals: Integer Array representing the players whom this player is neutral to
            desiredAllies: Integer Array representing the players who this player desires for allies - used mainly by the ai to determine who to send alliance offers to and who to accept them from.
            fleets: Integer Array representing the indices of the fleets of this player
    provinces ->
        province ->
            id: int representing the index of this province
            owner: int id of the owning player in the GameState
            name: String value. Text displayed on the screen when province selected.
            isUnderSiege: boolean. Read the variable name.
            colonies ->
                colony ->
                     name: String value. Displayed in the menu when the city is selected from the province info screen that pops up when the province is selected.
                     controller: The index of the controlling Player in the GameState.
                     population: int number of people who reside here. Used to calculate things such as how many ships this planet provides, or how much tax it gives to the player.
                     fortLevel: double representing the amount of organized military resistance this colony will give an attacker before surrendering.
                     growthRate: the number of births occurring in this colony every 60 ticks.

编辑:

玩家阵列和舰队工作正常。当我到达省份阵列时,事情变得很奇怪;

{
    planets:[
        //There should be 300 provinces. Instead 300 of these
        colonies: [ {},{},{},{},{},{},{} ]
    ]
}

我的课和相关的领域看起来是这样的;

public class Planet implements IndexedGameObject, Modifier
{
    private int id;
    private Array<Colony> colonies;
    public Planet(int id, Array<Colony> colonies)
    {
        this.id = id;
        this.colonies = colonies;
    }
    //Utility methods + Getters/Setters
}
class Colony
{
    private int parentProvinceID;
    private ColonyType type;
    public Colony(int parentProvinceID, ColonyType type)
    {
        this.parentProvinceID = parentProvinceID;
        this.type = type;
    }
    //Some more irrelevant methods
}
enum ColonyType
{
    ADMINISTRATIVE, MILITARY, POPULATION;
}

您的问题是由泛型数组引起的。我认为JSON不可能序列化例如Array<Player>

解决方案是包装通用数组-看看这个线程,或者在可能的情况下使用非通用数组(例如FloatArray而不是Array)。


另一方面,您的逻辑结构似乎类似于关系型——也许使用一些SQL技术会更方便,而不是将其保留在对象中并序列化/反序列化?这里有一些简单的信息

我通过使枚举字段public static并将它们移动到它们的父类中来解决这个问题——正如@Barodapride和@TenFour04所指出的,我忽略了这一点。

public class Planet
{
    private Array<Colony> colonies;
    public static class Colony
    {
        private ColonyType type;
        private int parentProvinceID;
        public static enum ColonyType
        {
            ADMINISTRATIVE, MILITARY, POPULATION;
        }
    }
}

正确序列化。

最新更新