javamultithreadingswingjtextfield

Creating a typing-game in java swing, i'm having issues with checking if player input equals the falling words


I have created a game where I summon JTextFields at random X-position at the top of the screen with random words added to the fields.

I don't know how to properly setup a method to check if the input from the user equals the JTextFields words on the board. I'm looking for any ideas to change the "checkWordSpelling" method inside of my "GamePanel" class to make the comparison between the JTextFields word and the users input viable.

Right now I store the object in:

 ArrayList<EnemyTextFields> textFieldsCurrentlyOnBoard = new ArrayList<>(); 

to begin with I thought this would be a good idea because I could track the current object to the String it has but since it's a thread(and I want each JTextField to be a thread) I could not compare them(?).

I've tried replacing my ArrayList with a HashMap which takes the currentThread and String(k,v) but the way i implemented it, neither did that work. I've tried alot of different stuff but I can't name them all.

The game looks like this: Topleft white label is amount of points. Every green rectangle is a JTextField waiting to get eliminated. Bottom white rectangle is the TextArea which the user will input the words to remove them.

I have the "EnemyTextField" private class inside of the "GamePanel" class. This is where each JTextField is a separate Thread:

 
private class EnemyTextField extends Thread {

        private Random rng;
        private int xPlace, yPlace;
        private JTextField txtField;
        private String currWord;
        private int velocityOfTextField;

        public EnemyTextField(String currWord,int velocityOfTextField) {
            this.currWord = currWord;
            this.velocityOfTextField = velocityOfTextField;

            rng = new Random();
            xPlace = rng.nextInt(600);
            txtField = new JTextField(currWord);
        }

        /**
         * Check if the textfield hits the bottom of the screen, and if it does, the application ends
         * @return
         */
        public boolean hitBottomOfScreen() {
            if(yPlace >= height){
                endGame();
                return true;
            }
            return false;
        }

        /**
         * Increments the textfield which belongs to the thread by 10.
         */

        public void updateEnemyTextField() {
            yPlace = yPlace +10;
            txtField.setLocation(xPlace, yPlace);
        }

        /**
         * adding the textfield to the JPanel(UI)
         */
        public void createTextField(){
            txtField.setLocation(xPlace, yPlace);
            txtField.setSize(50+(currWord.length()*2), 50);
            txtField.setBackground(Color.GREEN);
            add(txtField);
        }

        @Override
        public void run() {

            while(!hitBottomOfScreen()) {
                try {
                    //Sleeping for 1 second(1000milliseconds) between each "tick" or "refresh/update".
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                createTextField();
                updateEnemyTextField();

            }
        }
    }
}

Here i have the JPanel code which the JTextFields are created on:

import javax.swing.*;
import java.awt.*;
import java.io.IOException;
import java.util.*;
import java.util.Timer;

public class GamePanel extends JPanel {

    private JTextField guessingTextField;

    private Label pointLabel;
    private Label timeLabel;

    private int width = 800;
    private int height = 600;
    private int currentTime;
    private int points;

    //Here is the Array of all the words from the textfile
    ArrayList<String> listOfWordsFromFile;
    //Here is where i save the k,v for the different JTextFields
    ArrayList<EnemyTextField> textFieldsCurrentlyOnBoard;

    private Timer timer;

    public GamePanel() throws IOException {

        setSize(width, height);
        setLayout(null);
        setBackground(Color.LIGHT_GRAY);

        guessingTextField = new JTextField();
        guessingTextField.setSize(120, 30);
        guessingTextField.setLocation(width / 2 - 60, 530);
        guessingTextField.setForeground(Color.BLACK);
        guessingTextField.setBackground(Color.WHITE);

        pointLabel = new Label();
        pointLabel.setBackground(Color.WHITE);
        pointLabel.setForeground(Color.BLACK);
        pointLabel.setSize(120, 30);
        pointLabel.setLocation(140, 1);

        timeLabel = new Label();
        timeLabel.setBackground(Color.WHITE);
        timeLabel.setForeground(Color.BLACK);
        timeLabel.setSize(30,30);
        timeLabel.setLocation(155,1);
        timeLabel.setText("1");

        add(timeLabel);
        add(pointLabel);
        add(guessingTextField);

        //inserts the ArrayList of words into "words" array.
        listOfWordsFromFile = WordBox.getRandomWord("resources/Random words.txt");
        setVisible(true);

        guessingTextField.addActionListener(e -> {
            //checkWord();
        });
        startTheGameAndResetValues();
        checkWordSpelling();
    }

    /**
     *This is the Method im struggling with.
     */
    public void checkWordSpelling(){

        Thread thread = new Thread(() -> {

            while(true) {
                try {
                    System.out.println(guessingTextField.getText());
                    java.util.Iterator<EnemyTextField> iterator = textFieldsCurrentlyOnBoard.iterator();
                        while(iterator.hasNext()){
                            EnemyTextField currentWord = iterator.next();
                            System.out.println(currentWord);
                            //
                            if(currentWord.equals(guessingTextField.getText())){
                                remove(currentWord.txtField);
                                iterator.remove();
                            }
                        }


                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
        thread.start();
    }

    /*private void removeWord(EnemyTextField entry) {
        java.util.Iterator<EnemyTextField> iterator = textFieldsCurrentlyOnBoard.values().iterator();

        while (iterator.hasNext()){
            EnemyTextField current = iterator.next();
            if (textFieldsCurrentlyOnBoard.containsKey(entry)) {
                remove(current.txtField);
                iterator.remove();

            }
        }
    }*/

    /**
     * gets called when game is over, displays an ending "popup".
     */
    public void endGame() {
        //cancel the while loop and make the game stop
        JOptionPane.showInputDialog(null,"You lost, Game over.");
        timer.cancel();
    }

    /**
     * Method to reset all the values from what the previous round had.
     *
     * Creates a TimerTask which acts as the measurement of difficulty
     * set to 3000milliseconds(3seconds), lower it to have words appear
     * more frequently and higher it if you want the words to appear slower
     */
    public void startTheGameAndResetValues() {
        currentTime = 0;
        points = 0;
        textFieldsCurrentlyOnBoard = new ArrayList<>();

        TimerTask timerTask = new TimerTask() {
            @Override
            public void run() {
                while(true){
                    initNewWord();
                    try {
                        Thread.sleep(3000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        };
        Timer time = new Timer();
        time.schedule(timerTask,3000);
    }

    /**
     * starts the "threading"
     */
    public void initNewWord(){
        String rngWord = randomWord();
        EnemyTextField newWordForTextField = new EnemyTextField(rngWord,2);
        //textFieldsCurrentlyOnBoard.add(newWordForTextField);
        textFieldsCurrentlyOnBoard.add(newWordForTextField);


        newWordForTextField.start();
    }

    /**
     * Picks a random word from the ArrayList words.
     * @return
     */
    public String randomWord() {
        Random rng = new Random();
        System.out.println(listOfWordsFromFile);
        int rngIndex = rng.nextInt(listOfWordsFromFile.size());
        return listOfWordsFromFile.get(rngIndex);
    }

Here is the "WordBox" class which grabs the words from "Random words.txt" in resource directory:

import java.io.*;
import java.util.ArrayList;

public class WordBox {

    static ArrayList<String> listWords = new ArrayList<>();

    /**
     * Grabs all the words and puts each word
     * @param filePath Grabs filepath from GamePanel
     * @return ArrayList of all the words in the textfile.
     * @throws IOException
     */
    public static ArrayList<String> getRandomWord(String filePath) throws IOException {

        try {
            File file = new File(filePath);
            BufferedReader br = new BufferedReader(new FileReader(file));
            listWords = new ArrayList<>();
            String strTemp;

            while((strTemp = br.readLine())!= null) {
                listWords.add(strTemp);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        System.out.println(listWords);
        return listWords;
    }
}

And here is my Main method:

import java.io.IOException;

public class Main {

    public static void main(String[] args) throws IOException {
        new GameFrame();
    }
}

Here are some random words that you can put into the "Random words.txt" file for anyone interested in testing my code:

    flowers
    skillful
    home
    channel
    delirious
    muddled
    aware
    blushing
    unpack
    neck
    animated
    supreme
    snow
    connect
    skin

Besides the problem if anyone finds any way I could improve my code, i'm very open to suggestions and guidelines!


Solution

  • If you are using array-list to store the data then use this method

    ArrayList<String> JtextFiels = new ArrayList<String>();
    JtextFiels.add("flowers");
    JtextFiels.add("skillful");
    JtextFiels.add("home");
    JtextFiels.add("channel");
    
    // I assume that user input is stored in a variable and for this case it is store in " userInput " variable
    

    now here you have your array-list and user input store in a variable

    if(JtextFiels.contains(userInput.trim())//here JtextFiels are your arraylist and userInput has the data stored which was entered by user
    {
      //here you can continue your code ..for example - "show a message that the user entered word is there in the falling words"
    }
    

    Here you can face a problem if the user entered data is in capital or a single letter that is in capital

    So what you can do it

    if(JtextFiels.contains(userInput.trim().toLowerCase())// Or .toUpperCase()
    { 
       // here the user entered text is converted to lower case ...you can change it upper case according to your requirement 
    }
    

    OR

    You can use an array to store the data, I will tell you the difference at the end.

    String[] JtextFiels=new String[100];//here 100 is the size of the array
    JtextFiels[0]="flowers";//index 0
    JtextFiels[1]="skillful";//index 1
    JtextFiels[2]="home";//index 2
    JtextFiels[3]="channel";//index 3
    //arrays start from the index 0
    
    //same as above you have the user entered data with you stored in a variable ..in this case let the variable be userInput
    

    Here you have an array and user entered data

    for(int i=0;i<JtextFiels.length;i++)//here a loop is used to iterate over each index of array
    {
      if(JtextFiels[i]!=null)//checks if the index exists or not 
      {
         if(JtextFiels[i].trim().equalsIgnoreCase(userInput.trim()))
         {
           //here you can continue your code ..for example - "show a message that the user inputed word is there in the falling words"
          }
       }
    }
    

    The difference between the two is:

    ArrayList

    Array

    Many more differences but for now this much is enough.

    What should you choose? Arraylist or array?

    It depends on your data:

    If hope you understood this! If not feel free to ask your questions