I want to load and render multiple objects to a gameworld using data from a class with a save/load functionality using (de)serialization, but i cant figure out how to properly reintroduce them to the program since they contain transient objects that are nessesary to render/display them.
The first time i run my program, it tries to load data from a txt file called 'Data.txt' that doesnt exist. The program creates a new Data.txt file, adds a Campfire object called 'campfire'to it and saves it. As long as the program runs it will be rendered to the screen (this part works fine). After closing the program and restarting it its supposed to check for the file, find it and load the ArrayList 'data' with the previously saved/serialized campfire object from it. Then it adds another Object of the same type to it and renders both of them. This part throws a NullPointerException in the render method of my Campfire class.
This is the Main class:
public class MainClass extends ApplicationAdapter{
public static SpriteBatch batch;
private Data data;
private Campfire campfire;
@Override
public void create () {
batch = new SpriteBatch();
data = new Data();
data.load();
campfire = new Campfire();
data.addCampfire(campfire);
System.out.println(data.getSize());
data.save();
}
@Override
public void render () {
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
batch.begin();
data.render(batch);
batch.end();
}
The class that loads all the files:
public class Data {
private String filename;
private ArrayList<Campfire> data;
public Data() {
data = new ArrayList<Campfire>();
filename = "Data.txt";
}
public void save(){
try {
FileOutputStream file = new FileOutputStream (filename);
ObjectOutputStream out = new ObjectOutputStream (file);
out.writeObject(data);
out.close();
file.close();
}catch (IOException e) {e.printStackTrace();}
}
public void load() {
try {
FileInputStream file = new FileInputStream (filename);
ObjectInputStream in = new ObjectInputStream(file);
data = (ArrayList<Campfire>)in.readObject();
in.close();
file.close();
}
catch (IOException io) {System.out.println("File not found.");}
catch (ClassNotFoundException ex) {System.out.println("Cant load from file.");}
}
public void addCampfire(Campfire object) {
data.add(object);
}
public void render(SpriteBatch batch) {
for(int i = 0;i < data.size(); i++) {
Campfire camp = data.get(i);
camp.render(batch);
//data.get(i).render(batch);
}
}
public Campfire get(int index) {
return data.get(index);
}
public void set(int index, Campfire object) {
data.set(index, object);
}
public int getSize() {
return data.size();
}
And this is the class that throws the NullPointerException in render():
public class Campfire implements Serializable{
private transient Texture img;
private int id;
public Campfire() {
img = new Texture("campfire.png");
}
public void render(SpriteBatch batch) {
batch.draw(img, 200,200, 2000,2000);
}
The reason for this is that the Texture 'img' is nonexistent since i need to use the transient keyword with it and therefore it will not be saved/loaded to/from the data file.
i need a different way to create objects based on the array list i am loading from. I cant work with the objects in the arrayList because they cant be rendered (the transient keyword has to be assigned to the Texture() object - its not serializable). I have watched plenty of tutorials and read a good amount on articles about this topic, but i cant find one that mentions how i can reintroduce the object so i can make use of its functions that rely on not (de)serializable parts of it.
So heres my question: Is there a better way than my attempt (creating the object again and then assigning the deserialized values to it? I have no clue how to properly load and work with the 'data' ArrayList after the deserialization process and i am thankful for every advice on how to reintroduce them to the program.
Thanks in advance, M
I would recommend not using java serialization for this. It can have advantages in terms of the size of its serialized format, but in my experience it is a little bit of a pain to work with. You have encountered this pain, because you cannot serialize that Texture
object because it is not Serializable
. You avoided the issue by marking it as transient, which is a mistake. There are probably workarounds for working with objects that you do not own - registering some handler, but tbh I do not know the details because I avoid it.
Instead, go for a nice friendly format like json. This will mean that your serialized data file will be a bit bigger, but, you can open it up and read it and see what you have saved.
And... libgdx comes with some tools for it. See their wiki page on usage here
There are alternatives - like googles gson library as well, but why not just stick with libgdx's tools - I have found them to be pretty solid.
Just an extra warning - if you are using some sort of code obfuscation/minimization tool in Android, you will need to configure that to not rename any object that you serialize, because it does rely on the package and object names for deserialization. It is also something to be aware of if you save a game state - then change the names/packages of your objects and then try to load that game state.