当我尝试为 Space Invaders 克隆加载游戏时出现 ClassCastException

ClassCastException when I try to load gameplay for Space Invaders clone

编辑:由 Mark Rotteveel 解决!在保存期间,我使用的是 oos.writeObject(this); 而不是 oos.writeObject(GamePlay.this);

所以我在加载函数工作时遇到了很多麻烦。当我将此逻辑应用于简单程序时,我从未遇到过问题,这是我第一次制作涉及序列化和线程的东西。所以我有预感问题是由于线程引起的。

所以我做这个的方法是我有一个游戏 class 可以使用它来保存自己。保存此文件没有错误,它成功出现在我的文件夹中。:

                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");
            }

当我玩游戏的时候,控制台提示我保存成功。但是,当我重新启动游戏并尝试加载它时,我得到了 ClassCastException。这是加载游戏代码

  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");

            }

我真的很想了解发生了什么,如果有人能简单地指出我正确的方向,我将不胜感激!

请注意,如果您需要查看游戏玩法class,我不介意发布它,但它很长,我不想让人不知所措。

这是游戏玩法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);
        }
    }

}

}

和堆栈跟踪

java.lang.ClassCastException: spaceraiders.vue.Gameplay cannot be cast to spaceraiders.vue.Gameplay
at spaceraiders.Controlleur.SpaceRaiders.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.access0(EventQueue.java:97)
at java.awt.EventQueue.run(EventQueue.java:709)
at java.awt.EventQueue.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.run(EventQueue.java:731)
at java.awt.EventQueue.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)

这是您的代码:

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");
        }
    }
});

这将创建一个匿名 class,oos.writeObject(this) 中的 this 引用此匿名 class。它不涉及您的 GamePlay 实例。因此,您正在序列化 Action,当反序列化并强制转换为 GamePlay 时,强制转换失败。

您需要使操作调用 GamePlay class 中包含实际序列化代码的方法,或者您需要使用 [=17] 引用封闭的 class =].详情见:Getting hold of the outer class object from the inner class object