-1

I cannot get through one function I recently added to my Tetris game. Basically I am working on the key settings allowing user to change the controls for example to WASD instead of arrows etc. I think I have everything set up but my config is not saving the settings once I close the game and open it fresh again. Config file resets itself to default every time I open the game.

May you please give me a helping hand and skimm through the codes if you find something that might be causing this issue?

Thank you very much in advance!

MainClass:

package mypackage;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.ArrayList;
import java.util.Collections;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;

public class RiskTetris extends JPanel {
    /**
     *
     */
    private static final long serialVersionUID = 1L;

    public static void main(String[] args) {
        final JFrame f = new JFrame("Tetrisoid");
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        //f.setLocationRelativeTo(null);                
        // setting up frame in the middle
        //for Keys configuration.
        KeyGetter.LoadKeys();
        try {
            Config.loadConfig();
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

//menubar from here
        JMenuBar mb= new JMenuBar();
        JMenu file = new JMenu("Menu");
        mb.add(file);

        JMenuItem NewGame=new JMenuItem("New Game");
//file.add(NewGame);
        NewGame.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                System.out.println("Starting New Game...");
            }
        });

        JMenuItem HighScore=new JMenuItem("High Score");
//file.add(HighScore);
        HighScore.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                //System.out.println("High Score...");
                long score=0;   //replace with high score code later
                final JFrame alert=new JFrame("High Score");

                alert.setSize(300, 200);

                alert.setLayout(null);
                alert.setLocationRelativeTo(null);
                //alert.setAlwaysOnTop(true); 

                JLabel highscore=new JLabel("The highscore is: " + score);
                highscore.setBounds(85,0, 200,50);

                alert.setResizable(false);
                alert.setVisible(true);

                JButton okayButton=new JButton ("Okay");

                alert.add(highscore);
                alert.add(okayButton);
                okayButton.setBounds(90, 120, 100, 30);
                alert.setLocationRelativeTo(null);
                okayButton.addActionListener(new ActionListener() {
                    public void actionPerformed(ActionEvent e) {
                        //alert.add(okayButton);
                        alert.dispose();
                    }
                });
            }
        });
        JMenuItem options = new JMenuItem("Options");
//file.add(options);
        options.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                System.out.println("Options...");
                Config.openConfig(f);
            }
        });

        JMenuItem exit = new JMenuItem ("Exit");
//file.add(exit);
        exit.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                System.out.println("Exit...");
                System.exit(0);
            }
        });

        f.setJMenuBar(mb);

        f.setSize(12*26+10, 26*23+25);
        f.setVisible(true);
        f.setSize(12*26+11, 26*24+26);      //Corrected so that the frame shows from the beginening, not only with sizing.
        f.setVisible(true);

        final RiskTetris game = new RiskTetris();

        file.add(NewGame);
        file.add(HighScore);
        file.add(options);
        file.add(exit);

        game.init();
        f.add(game);

        f.addKeyListener(new KeyListener() {
            public void keyTyped(KeyEvent e) {
            }
            public void keyPressed(KeyEvent e) {
                switch (e.getKeyCode()) {
                    case KeyEvent.VK_UP:
                        game.rotate(-1);
                        break;
                    case KeyEvent.VK_DOWN:
                        game.rotate(+1);
                        break;
                    case KeyEvent.VK_LEFT:
                        game.move(-1);
                        break;
                    case KeyEvent.VK_RIGHT:
                        game.move(+1);
                        break;
                    case KeyEvent.VK_SPACE:
                        game.dropDown();
    //game.score += 1;
                        break;
                }
            }

            public void keyReleased(KeyEvent e) {
            }
        });
        new Thread() {
            @Override public void run() {
                while (true) {
                    try {
                        Thread.sleep(1000);
                        game.dropDown();
                    } catch ( InterruptedException e ) {}
                }
            }
        }.start();
    }

    private final Point[][][] MyShapes = {
    // I-Piece
            {
                    { new Point(0, 1), new Point(1, 1), new Point(2, 1), new Point(3, 1) },
                    { new Point(1, 0), new Point(1, 1), new Point(1, 2), new Point(1, 3) },
                    { new Point(0, 1), new Point(1, 1), new Point(2, 1), new Point(3, 1) },
                    { new Point(1, 0), new Point(1, 1), new Point(1, 2), new Point(1, 3) }
            },

// J-Piece
            {
                    { new Point(0, 1), new Point(1, 1), new Point(2, 1), new Point(2, 0) },
                    { new Point(1, 0), new Point(1, 1), new Point(1, 2), new Point(2, 2) },
                    { new Point(0, 1), new Point(1, 1), new Point(2, 1), new Point(0, 2) },
                    { new Point(1, 0), new Point(1, 1), new Point(1, 2), new Point(0, 0) }
            },

// L-Piece
            {
                    { new Point(0, 1), new Point(1, 1), new Point(2, 1), new Point(2, 2) },
                    { new Point(1, 0), new Point(1, 1), new Point(1, 2), new Point(0, 2) },
                    { new Point(0, 1), new Point(1, 1), new Point(2, 1), new Point(0, 0) },
                    { new Point(1, 0), new Point(1, 1), new Point(1, 2), new Point(2, 0) }
            },

// O-Piece
            {
                    { new Point(0, 0), new Point(0, 1), new Point(1, 0), new Point(1, 1) },
                    { new Point(0, 0), new Point(0, 1), new Point(1, 0), new Point(1, 1) },
                    { new Point(0, 0), new Point(0, 1), new Point(1, 0), new Point(1, 1) },
                    { new Point(0, 0), new Point(0, 1), new Point(1, 0), new Point(1, 1) }
            }
    };

    private final Color[] MyColors = {
            Color.cyan, Color.MAGENTA, Color.orange, Color.yellow, Color.black, Color.pink,
            Color.red };

    private Point pt;
    private int currentPiece;
    private int rotation;
    private ArrayList<Integer> nextPieces = new ArrayList<Integer>();

    public long score;
    private Color[][] well;

    private void init() {
        well = new Color[12][24];
        for (int i = 0; i < 12; i++) {
            for (int j = 0; j < 23; j++) {
                if (i == 0 || i == 11 || j == 22) {
                    well[i][j] = Color.darkGray;
                } else {
                    well[i][j] = Color.black;
                }
            }
        }
        newPiece();
    }
    public void newPiece() {
        pt = new Point(5, 2);
        rotation = 0;
        if (nextPieces.isEmpty()) {
            Collections.addAll(nextPieces, 0, 1, 2, 3);
            Collections.shuffle(nextPieces);
        }
        currentPiece = nextPieces.get(0);
        nextPieces.remove(0);
    }

    private boolean collidesAt(int x, int y, int rotation) {
        for (Point p : MyShapes[currentPiece][rotation]) {
            if (well[p.x + x][p.y + y] != Color.black) {
                return true;
            }
        }
        return false;
    }

    public void rotate(int i) {
        int newRotation = (rotation + i) % 4;
        if (newRotation < 0) {
            newRotation = 3;
        }
        if (!collidesAt(pt.x, pt.y, newRotation)) {
            rotation = newRotation;
        }
        repaint();
    }

    public void move(int i) {
        if (!collidesAt(pt.x + i, pt.y, rotation)) {
            pt.x += i;
        }
        repaint();
    }

    public void dropDown() {
        if (!collidesAt(pt.x, pt.y + 1, rotation)) {
            pt.y += 1;
        } else {
            fixToWell();
        }
        repaint();
    }
    public void fixToWell() {
        for (Point p : MyShapes[currentPiece][rotation]) {
            well[pt.x + p.x][pt.y + p.y] = MyColors[currentPiece];
        }
        clearRows();
        newPiece();
    }

    public void deleteRow(int row) {
        for (int j = row-1; j > 0; j--) {
            for (int i = 1; i < 11; i++) {
                well[i][j+1] = well[i][j];
            }
        }
    }

    public void clearRows() {
        boolean gap;
        int numClears = 0;
        for (int j = 21; j > 0; j--) {
            gap = false;
            for (int i = 1; i < 11; i++) {
                if (well[i][j] == Color.black) {
                    gap = true;
                    break;
                }
            }
            if (!gap) {
                deleteRow(j);
                j += 1;
                numClears += 1;
            }
        }
        switch (numClears) {
            case 1: score += 100;break;
            case 2: score += 300;break;
            case 3: score += 500;break;
            case 4: score += 800;break;
        }
    }
    private void drawPiece(Graphics g) {
        g.setColor(MyColors[currentPiece]);
        for (Point p : MyShapes[currentPiece][rotation]) {
            g.fillRect((p.x + pt.x) * 26,
                    (p.y + pt.y) * 26,
                    25, 25);
        }
    }

    @Override
    public void paintComponent(Graphics g)
    {
        g.fillRect(0, 0, 26*12, 26*23);
        for (int i = 0; i < 12; i++) {
            for (int j = 0; j < 23; j++) {
                g.setColor(well[i][j]);
                g.fillRect(26*i, 26*j, 25, 25);
            }
        }
        g.setColor(Color.GREEN);
        g.drawString("Score : " + score, 19*12, 25);

        drawPiece(g);
    }
}

KeyGetter class:

package mypackage;

import java.awt.event.KeyEvent;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.HashMap;

//import com.sun.java.util.jar.pack.Package.Class.Field;

//<>()*//\\()}}}}}{    [ ]

public class KeyGetter {
    public static HashMap<String, Integer> keys;
    public static ArrayList<String> keyNames;

    public static void LoadKeys() {
        keys= new HashMap<String, Integer>();
        keyNames=new ArrayList<String>();

        java.lang.reflect.Field[] fields = KeyEvent.class.getFields();
        for(java.lang.reflect.Field f: fields) {
            if(Modifier.isStatic(f.getModifiers())) {
                if(f.getName().startsWith("VK")) {
                    try {
                        int num=f.getInt(null);
                        String name= KeyEvent.getKeyText(num);

                        keys.put(name, num);
                        keyNames.add(name);
                    }
                    catch(Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
}

Config class:

package mypackage;

import java.awt.Choice;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Scanner;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;

public class Config {

    public static String rotate = "Up", left = "Left", right = "Right", down = "Down", pause = "P";
    private static ArrayList<Choice> choices;

    //<>()*//\\()}}}}}{    [ ]

    public static void openConfig(JFrame frame) {
        choices = new ArrayList<Choice>();
        final JFrame options = new JFrame("Options");
        options.setSize(400, 300);
        options.setResizable(true);
        options.setLocationRelativeTo(null); //???
        options.setLayout(null);

        Choice left = addChoice("Left", options, 30, 30);
        left.select(Config.left);

        Choice right = addChoice("Right", options, 150, 30);
        right.select(Config.right);

        Choice down = addChoice("Down", options, 30, 80);
        down.select(Config.down);

        Choice rotate = addChoice("Rotate", options, 150, 80);
        rotate.select(Config.rotate);

        Choice pause = addChoice("Pause", options, 30, 130);
        pause.select(Config.pause);

        JButton done = new JButton("Done");
        done.setBounds(150, 220, 100, 30);
        done.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                options.dispose();
                saveChanges();
            }
        });
        options.add(done);
        options.setVisible(true);
    }

    public static void saveChanges() {
        Choice left = choices.get(0);
        Choice right = choices.get(1);
        Choice down = choices.get(2);
        Choice rotate = choices.get(3);
        Choice pause = choices.get(4);
        Config.left = left.getSelectedItem();
        Config.right = right.getSelectedItem();
        Config.down = down.getSelectedItem();
        Config.rotate = rotate.getSelectedItem();
        Config.pause = pause.getSelectedItem();

        try {
            saveConfig();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static Choice addChoice(String name, JFrame options, int x, int y) {
        JLabel label = new JLabel(name);
        label.setBounds(x, y - 20, 100, 20);
        Choice key = new Choice();
        for (String s : getKeyNames()) {
            key.add(s);
        }
        key.setBounds(x, y, 100, 20);
        options.add(key);
        options.add(label);
        choices.add(key);
        return key;
    }

    public static ArrayList<String> getKeyNames() {
        ArrayList<String> result = new ArrayList<String>();

        for (String s : KeyGetter.keyNames) {
            result.add(s);
            if (s.equalsIgnoreCase("F24")) {
                break;
            }
        }
        return result;
    }

    public static void loadConfig() throws Exception {
        File directory = new File(getDefaultDirectory(), "/Tetris");
        if (!directory.exists()) {
            directory.mkdirs();
        }

        File config = new File(directory, "/Tetris");
        if (!config.exists()) {
            config.createNewFile();
            System.out.println("File not found, saving defaults");

            saveConfig();
            return;
        }

        //@SuppressWarnings("resource")
        Scanner s = new Scanner(config);
        HashMap<String, String> values = new HashMap<String, String>();
        while (s.hasNextLine()) {
            String[] entry = s.nextLine().split(":");         //BUde souviset s tim ze je to v configu napsane na PICU

            if (entry.length >= 2) {
                String key = entry[0];         // COrrect error here
                String value = entry[1];
                values.put(key, value);
                s.close();   //pridano mnou
            }
        }
        if (values.size() != 5) {
            System.out.println("Config is unuasable, saving defaults.");
            saveConfig();
            return;
        }

        if (!values.containsKey("left") || !values.containsKey("right") || !values.containsKey("rotate") || !values.containsKey("down") || !values.containsKey("pause")) {
            System.out.println("Invalid names in config, saving defauls");
            saveConfig();
            return;
        }
        String left = values.get("left");
        String right = values.get("right");
        String rotate = values.get("rotate");
        String down = values.get("down");
        String pause = values.get("pause");

        if (!(getKeyNames().contains(left) && getKeyNames().contains(right) && getKeyNames().contains(rotate) && getKeyNames().contains(down) && getKeyNames().contains(pause))) {
            System.out.println("Invalid key in config, saving defaults");
            ;
        }
        Config.left = left;
        Config.right = right;
        Config.rotate = rotate;
        Config.down = down;
        Config.pause = pause;
    }

    public static void saveConfig() throws Exception {
        File directory = new File(getDefaultDirectory(), "/Tetris");
        if (!directory.exists()) {
            directory.mkdirs();
        }

        File config = new File(directory, "/config.text");

        PrintWriter pw = new PrintWriter(config);

        pw.println("right:" + right);
        pw.println("left:" + left);
        pw.println("rotate:" + rotate);
        pw.println("down:" + down);
        pw.println("pause:" + pause);
        pw.close();
    }

    public static String getDefaultDirectory() {
        String OS = System.getProperty("os.name").toUpperCase();
        if (OS.contains("WIN")) {
            return System.getenv("APPDATA");
        }
        if (OS.contains("MAC")) {
            return System.getProperty("user.home") + "Library/Application Support";
        }
        return System.getProperty("user.home");
    }
}

1 Answers1

0

For saving the config file you use the path "/Tetris/config.text", but for reading the config file you use the path "/Tetris/Tetris". It should be the same filename as the one for saving the config file, otherwise you are reading and writing different files.

In fact, you should save the directory path and config file name in a static field like:

public static final String START_DIRECTORY = "Tetris";
public static final String CONFIG_FILENAME = "config.text";

and use these constants in your code. That way all the different places (reading the config file, saving the config file, ...) uses the exact same name and you don't run in the same problem twice, that the name is different in different locations. The code will look like this:

...
File config=new File(directory, CONFIG_FILENAME);
if(!config.exists()) {
    ...
Progman
  • 16,827
  • 6
  • 33
  • 48
  • Hello and thank you very much for such fast response! I changed the codes accordingly on all the needed places and I am having a new error: `java.lang.IllegalStateException: Scanner closed at java.base/java.util.Scanner.ensureOpen(Scanner.java:1150) at java.base/java.util.Scanner.findWithinHorizon(Scanner.java:1781) at java.base/java.util.Scanner.hasNextLine(Scanner.java:1610) at mypackage.Config.loadConfig(Config.java:161) at mypackage.RiskTetris.main(RiskTetris.java:37)` ----------------------------------------------- `Saving of the config settings doesnt work either. :/ – Marek Ševela Oct 31 '19 at 18:51
  • 1
    @MarekŠevela You might want to check https://stackoverflow.com/questions/28052519/java-lang-illegalstateexception-scanner-closed. Keep in mind that this is a different problem, unrelated to this question. You can ask a new question, but please take the [tour] to learn how Stack Overflow works and read [ask] on how to improve the quality of your questions. You should also read [mcve] for asking questions without any unrelated information you can delete. – Progman Oct 31 '19 at 18:56