1

I'm trying to write a dungeon master game and the hero would go through different rooms and fights monster and get items. I want to save the hero every time they get to a new level but I get an IOException even though I have implemented Serializable on the hero and everything the hero uses. Some help would be very appreciated. Thank you.

The panel that has the save method:

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.*;
import java.io.*;
import java.awt.image.BufferedImage;
import javax.imageio.ImageIO;
/**
 * The panel where the game happens.
 */
public class Panel extends JPanel implements Runnable, KeyListener {
  private Thread t;
  private Hero hero;
  private File f;
  ...
  public Panel(String n, int g) {
    f = new File("save.dat");
    ...
  }
public void save() {
    try {
      JOptionPane.showMessageDialog(null, "Saving...");
      ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(f));
      out.writeObject(hero);
      out.close();
    } catch (IOException e) {
      JOptionPane.showMessageDialog(null, "Error saving file.");
    }
  }

The Hero class:

import java.awt.Point;
import java.io.Serializable;
import java.util.ArrayList;
import javax.swing.*;
import java.awt.*;
/**
 * Our awesome hero.
 */
public class Hero extends Character implements Serializable {
  /** Array list of items of hero */
  private ArrayList<Item> items;
  /** Character's location */
  private Point location;
  private int dx, dy, tempX, tempY;
  /**
   * Constructor
   * 
   * @param n
   *            Hero's name.
   * @param q
   *            Hero's catch phrase.
   * @param start
   *            Hero's starting point.
   */
  public Hero(String n, String q, Point start) {
    super(n, q, 15, 1, 0);
    location = start;
    items = new ArrayList<Item>();
    tempX = (int) location.getX();
    tempY = (int) location.getY();
  }
  /**
   * Drawing the hero.
   * 
   * @param g The graphics
   */
  public void drawHero(Graphics g) {
    g.setColor(Color.BLUE);
    g.fillRect((int) location.getX(), (int) location.getY(), 50, 50);
    move();
  }
  /**
   * Moving the hero.
   */
  public void move() {
    setX(getX() + dx);
    setY(getY() + dy);
  }
  /**
   * Stopping the hero.
   */
  public void stop() {
    dx = 0;
    dy = 0;
  }
  /**
   * Attacking the enemy.
   * 
   * @param C The enemy that will be attacked.
   */
  public void attack(Character C) {
    int h = (int) (Math.random() * 3) + 1;
    h += getLevel();
    C.takeDamage(h);
  }
  /**
   * Get the items.
   * 
   * @return The item arraylist.
   */
  public ArrayList<Item> getItems() {
    return items;
  }
  /**
   * Picking up the item and check if 
   * inventory is full.
   */
  public boolean pickUpItem(Item i) {
    if (items.size() == 5)
      return false;
    else {
      items.add(i);
      return true;
    }
  }
  /**
   * Check what room is the hero in.
   */
  public char checkRoom(Level l) { 
    int x = (int) location.getX();
    int y = (int) location.getY();
    if ((x < 400 && y < 400 && x >= 0 && y >= 0)) {
      return l.getRoom(location);
    } else
      return 'n';
  }
  /**
   * Remove item by its name.
   * 
   * @param i The item to be removed.
   */
  public void removeItem(Item i) {
    int item = items.indexOf(i);
    items.remove(item);
  }

  /**
   * Remove item by its index.
   * 
   * @param index The index of the item to be removed.
   */
  public void removeItem(int index) {
    index -= 1;
    Item i = items.get(index);
    int gold = i.getValue();
    collectGold(gold);
    items.remove(index);
  }
  /**
   * Getting hero's location.
   * 
   * @return The hero's location.
   */
  public Point getLocation() {
    return location;
  }
  /**
   * Setting the hero's location.
   * 
   * @param p The location that will be set to.
   */
  public void setLocation(Point p) {
    int x = (int) p.getX();
    int y = (int) p.getY();
    location.setLocation(x, y);
  }
  /** 
   * Checking to see if hero is out of bounds.
   */
  public void checkBounds() {
    if ( getX() <= 0 || getX()+50 >= 400 || getY() <= 0 || getY()+50 >= 400 ) {
      dx = 0;
      dy = 0;
    }
    tempX = getX();
    tempY = getY();
  }
  /**
   * Stopping the hero.
   */
  public void staph() {
    dx = 0;
    dy = 0;
    setX(tempX);
    setY(tempY);
  }
  /**
   * Going north.
   */
  public void goNorth() {
    if ( getY() > 0 ) {
      dx = 0;
      dy = -2;
    }
  }
  /**
   * Going south.
   */
  public void goSouth() {
    if ( getY()+50 < 400 ) {
      dx = 0;
      dy = 2;
    }
  }
  /**
   * Going east.
   */
  public void goEast() {
    if ( getX()+50 < 400 ) {
      dx = 2;
      dy = 0;
    }
  }
  /**
   * Going west.
   */
  public void goWest() {
    if ( getX() > 0 ) {
      dx = -2;
      dy = 0;
    }
  }
  /**
   * Running north.
   */
  public void runNorth() {
    setY(getY() - 100);
  }
  /**
   * Running north.
   */
  public void runSouth() {
    setY(getY() + 100);
  }
  /**
   * Running north.
   */
  public void runEast() {
    setX(getX() + 100);
  }
  /**
   * Running north.
   */
  public void runWest() {
    setX(getX() - 100);
  }
  /**
   * Getting x location of hero.
   * 
   * @return Hero's x location.
   */
  public int getX() {
    return (int) location.getX();
  }
  /**
   * Getting y location of hero.
   * 
   * @return Hero's y location.
   */
  public int getY() {
    return (int) location.getY();
  }
  /**
   * Setting x location of hero.
   */
  public void setX(double x) {
    location.setLocation(x, getY());
  }
  /**
   * Setting y location of hero.
   */
  public void setY(double y) {
    location.setLocation(getX(), y);
  }
  /**
   * Check if hero is active.
   */
  public boolean isActive() {
    return getHP() > 0;
  }
}

Item class:

import java.io.Serializable;
import java.awt.image.BufferedImage;
import javax.imageio.ImageIO;
/**
 * The item that the hero will have.
 */
public class Item implements Serializable {
  /** Item's level */
  private String name;
  /** Item's gold value */
  private int goldValue;
  private BufferedImage img;
  /**
   * Constructor
   * 
   * @param n
   *            Item's name.
   * @param v
   *            Item's gold value.
   */
  public Item(String n, int v, BufferedImage i) {
    name = n;
    goldValue = v;
    img = i;
  }

  /**
   * Get the name of the item.
   * 
   * @return the name of the item.
   */
  public String getName() {
    return name;
  }

  /**
   * Get the value of the item.
   * 
   * @return The gold value of the item.
   */
  public int getValue() {
    return goldValue;
  }

  public BufferedImage getImage() {
    return img;
  }
}
Ccyan
  • 1,057
  • 12
  • 32
  • 1
    What are symptoms? (Provide stacktrace and point on which line exception is thrown) – Alex Salauyou May 06 '15 at 20:35
  • The IOException is thrown in the save method on the line `ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(f));`. It would display `Saving...` then `Error saving file` – Ccyan May 06 '15 at 20:39
  • Seems that provided file cannot be accessed, because exception is thrown before you start writing. Add `e.printStackTrace()` to discover actual reason. – Alex Salauyou May 06 '15 at 20:41
  • Can you print out the actual error? If you read it, it might be trying to tell you something ;) – Peter Lawrey May 06 '15 at 20:42
  • Oh thanks @Sasha Salauyou, I added `e.printStackTrace()` and found out the problem is that the `BufferedImage` is not Serializable. Is there a way I can make it serializable? – Ccyan May 06 '15 at 20:53
  • See http://stackoverflow.com/questions/3988788/what-is-a-stack-trace-and-how-can-i-use-it-to-debug-my-application-errors – isnot2bad May 06 '15 at 20:54
  • @Ccyan Do you really want to serialize the images too? – isnot2bad May 06 '15 at 20:55
  • @Ccyan add `transient` left to `private BufferedImage img;` to skip its serialization. – Alex Salauyou May 06 '15 at 20:56
  • Thank you for the comments. I have figured it out. I added a `writeObject` and `readobject` methods to the item and it now works correctly. Thank you everyone! – Ccyan May 06 '15 at 21:02

1 Answers1

0

You need to change the variable img to be transient

private transient BufferedImage img;

This will prevent the exception. Allthough, you won't save the image as transients means, don't write this field. I would say, you need to serialize the bytes of the BufferedImage, either as bytes[] or a similar veriable type.

The transient keyword is here explained. It says

4) Transient variable in java is not persisted or saved when an object gets serialized.

Read more: http://javarevisited.blogspot.com/2011/09/transient-keyword-variable-in-java.html#ixzz3ZeGZZQHd

remipod
  • 11,269
  • 1
  • 22
  • 25