1

Edit: Solved by Mark Rotteveel! During my save, I was using oos.writeObject(this);rather than oos.writeObject(GamePlay.this);

so I am having a lot of trouble getting my load function to work. When I applied this logic to simple programs I never had a problem, and this is the first time I make something that involves serializing and Threads. So I have a hunch the problem is due to Threads.

So the way I made this is I have a Gameplay class that saves itself using this. Saving this file gets no errors and it successfully appears in my folder.:

                try {

                FileOutputStream fos = new FileOutputStream("C:\\temp\\gameplay.dat");
                try (ObjectOutputStream oos = new ObjectOutputStream(fos)) {
                    oos.writeObject(this);
                }
                System.out.println("Gameplay Saved");
            } catch (IOException e) {
                System.out.println("Error Saving");
            }

When I am playing the game, the console tells me it saved successfully. However when I restart the game and try to load it, I get the ClassCastException. Here is the load game code

  public void actionPerformed(ActionEvent arg0) {
            try {
                FileInputStream fi = new FileInputStream("C:\\temp\\gameplay.dat");
                ObjectInputStream oi = new ObjectInputStream(fi);
                try {
                    Gameplay game = new Gameplay();
                    try {
                        game = (Gameplay) oi.readObject();
                    } catch (ClassCastException e) {
                        System.out.println("ClassCastException ");
                    }
                    oi.close();
                    fi.close();
                    game.addKeyBindings(panelCont);
                    frame.add(game);
                    Thread t1 = new Thread(game);
                    t1.start();
                } catch (ClassNotFoundException ex) {
                    Logger.getLogger(SpaceRaiders.class.getName()).log(Level.SEVERE, null, ex);
                }

            } catch (FileNotFoundException e) {
                System.out.println("File not found");
            } catch (IOException e) {
                System.out.println("Error initializing stream");

            }

I really want to understand what is going on, and I appreciate any help if someone could simply point me in the right direction!

Note if you need to look at the Gameplay class, I don't mind posting it, but it is quite long and I don't want to overwhelm.

Here is the Gameplay class

public class Gameplay extends JPanel implements ActionListener, Runnable, Serializable {

private Ship player = new Ship(new Point(200, 555));
private Timer t = new Timer(5, this);
private int score;

//Laser and shot variables ----------
private ArrayList<Laser> lasers = new ArrayList<Laser>();
private boolean readytofire;
private boolean shot = false;

//Invader variables -----------
private ArrayList<Invader> invaders = new ArrayList<Invader>();

public Gameplay() {
    super();
    t.start();
    setFocusable(true);
    requestFocus();
    setFocusTraversalKeysEnabled(false);

    for (int j = 0; j < 80; j += 20) {
        for (int i = 0; i < 20; i++) {
            invaders.add(new Invader(5 + i * 30, j));
        }
    }
}

public boolean addLaser(Laser a) {
    lasers.add(a);
    return true;
}

public boolean addPlayer(Ship p) {

    this.player = p;

    return true;
}

// Les évenements claviers --------------------
@Override
public void actionPerformed(ActionEvent ae) {
    repaint();
}

public void addKeyBindings(JComponent jc) {
    jc.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0, false), "moveRight");
    jc.getActionMap().put("moveRight", new AbstractAction() {
        @Override
        public void actionPerformed(ActionEvent ae) {
            moveRight();
        }
    });

    jc.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0, false), "moveLeft");
    jc.getActionMap().put("moveLeft", new AbstractAction() {
        @Override
        public void actionPerformed(ActionEvent ae) {
            moveLeft();
        }
    });
    jc.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0, false), "shoot");
    jc.getActionMap().put("shoot", new AbstractAction() {
        @Override
        public void actionPerformed(ActionEvent ae) {
            shoot();
        }
    });

    // FONCTIONS DE SAUVEGARDE------------------------
    jc.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_S, 0, false), "save");
    jc.getActionMap().put("save", new AbstractAction() {
        @Override
        public void actionPerformed(ActionEvent ae) {
            try {

                FileOutputStream fos = new FileOutputStream("C:\\temp\\gameplay.dat");
                try (ObjectOutputStream oos = new ObjectOutputStream(fos)) {
                    oos.writeObject(this);
                }
                System.out.println("Gameplay Saved");
            } catch (IOException e) {
                System.out.println("Error Saving");
            }

        }
    });
}

// Le mouvement du Ship --------------------
public void moveRight() {
    if (player.getCentre().getX() >= 580) {
        player.setX(580);
    } else {
        double movement = player.getCentre().getX();
        movement += 10;
        player.setX(movement);
    }
    this.repaint();
}

public void moveLeft() {
    if (player.getCentre().getX() <= 20) {
        player.setX(20);
    } else {
        double movement = player.getCentre().getX();
        movement -= 10;
        player.setX(movement);
    }
    this.repaint();
}

// Création du laser --------------------
public void shoot() {

    shot = true;
    if (readytofire) {
        Point top = new Point(player.getTopX(), player.getTopY());
        Laser laser = new Laser(top);
        addLaser(laser);

    }
}

// Mouvement du laser --------------------    
public void moveShot() {
    if (shot) {
        for (Laser l : lasers) {
            l.setY(l.getTopLeft().getY() - 2);

        }
    }
}

// Collision Detection
public boolean checkCollision(Invader i, Laser l) {
    double x = i.getlocX();
    double y = i.getlocY();
    if (l.getX() > x && l.getX() < x + 15 && l.getY() > y && l.getY() < y + 15) {
        return true;
    } else {
        return false;
    }
}

public boolean outBounds(Laser l) {

    if (l.getY() == 0) {
        return true;
    } else {
        return false;
    }
}

// Dessiner les graphiques --------------------
@Override
public void paint(Graphics g) {
    setBackground(Color.black);
    super.paint(g);
    player.draw(g);
    try {
        for (Laser l : lasers) {
            l.draw(g);
        }
        for (Invader i : invaders) {
            i.draw(g);
        }

    } catch (Exception e) {

    }
    g.drawString("Score: " + score, 0, 10);

}

// public void paintComponent (Graphics g){
// Controle Thread
public void run() {

    while (true) {
        moveShot();

        //Verifie Collision-------------------------------------------------
        List<Invader> invaderRemove = new ArrayList<Invader>();
        List<Laser> laserRemove = new ArrayList<Laser>();
        for (Invader i : invaders) {
            for (Laser l : lasers) {

                if (checkCollision(i, l) == true) {

                    laserRemove.add(l);
                    invaderRemove.add(i);
                    score += 1;
                }
            }
        }

        lasers.removeAll(laserRemove);
        invaders.removeAll(invaderRemove);

        //Enleve les lasers si ils arrivent a la fin du frame---------------
        for (Laser l : lasers) {
            if (outBounds(l) == true) {
                laserRemove.add(l);

            }

        }
        lasers.removeAll(laserRemove);

        //Mouvement des invaders
        for (Invader i : invaders) {
            i.moveAndUpdate();

        }

        try {
            Thread.sleep(10);
            readytofire = true;

        } catch (InterruptedException ex) {
            Logger.getLogger(Gameplay.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

}

}

And the stacktrace

java.lang.ClassCastException: spaceraiders.vue.Gameplay$4 cannot be cast to spaceraiders.vue.Gameplay
at spaceraiders.Controlleur.SpaceRaiders$2.actionPerformed(SpaceRaiders.java:106)
at javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:2022)
at javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2348)
at javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:402)
at javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:259)
at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(BasicButtonListener.java:252)
at java.awt.Component.processMouseEvent(Component.java:6533)
at javax.swing.JComponent.processMouseEvent(JComponent.java:3324)
at java.awt.Component.processEvent(Component.java:6298)
at java.awt.Container.processEvent(Container.java:2236)
at java.awt.Component.dispatchEventImpl(Component.java:4889)
at java.awt.Container.dispatchEventImpl(Container.java:2294)
at java.awt.Component.dispatchEvent(Component.java:4711)
at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4888)
at java.awt.LightweightDispatcher.processMouseEvent(Container.java:4525)
at java.awt.LightweightDispatcher.dispatchEvent(Container.java:4466)
at java.awt.Container.dispatchEventImpl(Container.java:2280)
at java.awt.Window.dispatchEventImpl(Window.java:2746)
at java.awt.Component.dispatchEvent(Component.java:4711)
at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:758)
at java.awt.EventQueue.access$500(EventQueue.java:97)
at java.awt.EventQueue$3.run(EventQueue.java:709)
at java.awt.EventQueue$3.run(EventQueue.java:703)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:76)
at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:86)
at java.awt.EventQueue$4.run(EventQueue.java:731)
at java.awt.EventQueue$4.run(EventQueue.java:729)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:76)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:728)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:201)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:116)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:105)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:93)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:82)
SatoNaka55
  • 13
  • 4
  • Is it possible that multiple threads are trying to save the game simultaneously? – Lev Leontev Jan 30 '19 at 19:19
  • I set it so it saves when you press the "S" key through a key binding. I only get one "Game Succesfully Saved" console output when I save, so I don't think so. – SatoNaka55 Jan 30 '19 at 19:22
  • Perhaps you can post the entire code of your class Gameplay ? Also, in the code you posted, change the code in the "catch" blocks to print the stack trace, as in "e.printStackTrace()" – Abra Jan 30 '19 at 19:25
  • @Abra Alright I edited in the Gameplay class. I apologize for the size, I am still a beginner. – SatoNaka55 Jan 30 '19 at 19:37
  • Please post the full exception stacktrace. And consider reducing your code to a [mcve] – Mark Rotteveel Jan 30 '19 at 19:41
  • @MarkRotteveel Done I edited in the stack trace. I thought of cutting some things out from the Gameplay class as well to minimalize it to make my question more readable, but as a beginner I have no idea what part of the code could be doing this. – SatoNaka55 Jan 30 '19 at 19:45

1 Answers1

0

This is your code:

jc.getActionMap().put("save", new AbstractAction() {
    @Override
    public void actionPerformed(ActionEvent ae) {
        try {
            FileOutputStream fos = new FileOutputStream("C:\\temp\\gameplay.dat");
            try (ObjectOutputStream oos = new ObjectOutputStream(fos)) {
                oos.writeObject(this);
            }
            System.out.println("Gameplay Saved");
        } catch (IOException e) {
            System.out.println("Error Saving");
        }
    }
});

This creates an anonymous class, and the this in oos.writeObject(this) refers to this anonymous class. It does not refer to your GamePlay instance. So you are serializing that Action, and when deserializing and casting to GamePlay, the cast fails.

You either need to make the action call a method in the GamePlay class that contains the actual serialization code, or you need to reference the enclosing class using GamePlay.this. See for details: Getting hold of the outer class object from the inner class object

Mark Rotteveel
  • 100,966
  • 191
  • 140
  • 197
  • Thank you so much. I appreciate the answer as well as the suggestions to make my next posts better. I learned something today! – SatoNaka55 Jan 30 '19 at 19:55