Игра на реакцию (Reaction Game)
Игра на реакцию проверяет, насколько быстро игрок может реагировать на визуальные стимулы (например, подсвеченные плитки). В этой игре предусмотрены два основных режима: Свободный режим и Режим уровня.

Виды игр:
Свободный режим (Free Mode):

Цель: Игроку нужно как можно быстрее нажать на плитку, которая случайным образом подсвечивается на игровом поле.
Прогресс игры:
После нажатия кнопки «Старт» начинается обратный отсчёт.
Плитка подсвечивается случайным образом после завершения обратного отсчёта, и игрок должен нажать на неё как можно быстрее.
Оценка реакции: После каждого нажатия игроку показывается время его реакции, и в зависимости от скорости, игра выдает оценку:
Отличная реакция (≤ 200 мс)
Хорошая реакция (≤ 300 мс)
Средняя реакция (≤ 500 мс)
Можно быстрее (> 500 мс)
Конец игры: Игра завершается после одного раунда, и игрок может начать новый раунд с новыми результатами.
Режим уровня (Level Mode):

Цель: Игрок должен пройти несколько уровней, на каждом из которых его задача — реагировать быстрее установленного времени для данного уровня.
Прогресс уровней:
Игра начинается с первого уровня, и каждый уровень имеет своё целевое время реакции (например, 1000 мс, 900 мс, 800 мс и т.д.).
Если реакция игрока быстрее целевого времени для уровня, он продвигается на следующий уровень.
На более высоких уровнях целевое время реакции сокращается, делая игру всё сложнее.
Завершение уровня: Когда игрок успешно завершает уровень, на экране появляется кнопка «Следующий уровень». Если игрок не успевает уложиться в отведённое время, ему предлагается начать игру с первого уровня или вернуться в главное меню.
Завершение игры: Когда игрок проходит все уровни, игра завершает с победой, предлагая начать заново или вернуться в главное меню.
Дополнительные возможности:
Сохранение результатов: Для каждого режима игры на реакцию сохраняются лучшие результаты игрока.
Плитки разного количества: Игрок может выбрать количество плиток (1, 2, 4 плитки), что влияет на сложность игры.

с игрой на реакцию у меня проблемы почему то в свободном режиме этой игры после прохождения один раз и нажатии на кнопку еще раз когда загорается кнопка нажатия игнорируются вот лог cancle motionEvent because of threeGesture detecting
В режим LevelMode все еще хуже там также игнорируются нажатия на плитку при переходе на следующий уровень но еще и кнопка еще раз накладывается на кнопку следующий уровень когда при успешном прохождении уровня должна быть кнопка следующий уровень только при нажатии на которую должно переносить на следующий уровень и так до конца а при не выполнении условий прохождения уровня должно предлагать перейти на главное меню или начать с начала с первого уровня
посмотри на всю логику этой игры и исправь точно



точно поищи проблемы в логике и в коде игры точно и исправь их



package com.example.memorygameone;

import android.app.Activity;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.os.Handler;
import android.view.View;
import android.widget.Button;
import android.widget.GridLayout;
import android.widget.TextView;
import android.graphics.Color;

import java.util.ArrayList;
import java.util.Random;

import nl.dionsegijn.konfetti.KonfettiView;
import nl.dionsegijn.konfetti.models.Shape;
import nl.dionsegijn.konfetti.models.Size;

public class ReactionGame extends Activity {

    private GridLayout gridLayout;
    private ArrayList<Button> squares;
    private TextView title, reactionTimeText, countdownText;
    private Button startButton, retryButton;
    private Handler handler;
    private Stopwatch stopwatch;
    private int reactionTime;
    private DB dbHelper;
    private SharedPreferences preferences;
    private String playerNickname;
    private int tileCount;
    private boolean gameStarted = false;
    private boolean countdownFinished = false;
    private boolean gameActive = false;
    private Button correctSquare;
    private Runnable showSquareRunnable;
    private String gameMode;
    private int currentLevel = 1;
    private int[] levelTargets = {1000, 900, 800, 700, 600, 550, 500, 450, 400, 350};
    private SoundManager soundManager;
    private KonfettiView konfettiView;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_reaction_game);
        konfettiView = findViewById(R.id.konfettiView);
        gridLayout = findViewById(R.id.gridLayout);

        initializeViews();
        initializeGame();

        gameMode = getIntent().getStringExtra("gameMode");
        if ("level".equals(gameMode)) {
            startLevelMode();
        } else {
            startFreeMode();
        }

        setupListeners();
    }

    private void initializeViews() {
        title = findViewById(R.id.title);
        reactionTimeText = findViewById(R.id.reactionTime);
        countdownText = findViewById(R.id.countdownText);
        startButton = findViewById(R.id.startBtn);
        retryButton = findViewById(R.id.retryBtn);
        gridLayout = findViewById(R.id.gridLayout);
    }

    private void initializeGame() {
        tileCount = getIntent().getIntExtra("tileCount", 1);
        dbHelper = new DB(this);
        preferences = getSharedPreferences("game_prefs", MODE_PRIVATE);
        playerNickname = preferences.getString("nickname", "Player");
        stopwatch = new Stopwatch();
        handler = new Handler();
        soundManager = SoundManager.getInstance(this);

        setupGameGrid();
    }

    private void startLevelMode() {
        updateLevelTitle();
    }

    private void startFreeMode() {
        title.setText("Свободный режим: Проверьте вашу реакцию");
    }

    private void setupListeners() {
        startButton.setOnClickListener(v -> {
            soundManager.playButtonClickSound();
            gameActive = true;
            startCountdown();
            startButton.setVisibility(View.GONE);
        });

        retryButton.setOnClickListener(v -> {
            gameActive = true;
            retryButton.setVisibility(View.GONE);
            startCountdown();
        });

        setAllSquaresClickable(true);
    }

    private void setupGameGrid() {
        squares = new ArrayList<>();
        gridLayout.removeAllViews();

        int columnCount = tileCount == 2 ? 2 : (int) Math.sqrt(tileCount);
        gridLayout.setColumnCount(columnCount);

        int screenWidth = getResources().getDisplayMetrics().widthPixels;
        int tileSize = (screenWidth - 60) / columnCount; // 60 - общий отступ (по 30 с каждой стороны)

        for (int i = 0; i < tileCount; i++) {
            Button button = new Button(this);
            GridLayout.LayoutParams params = new GridLayout.LayoutParams();
            params.width = tileSize;
            params.height = tileSize;
            params.setMargins(5, 5, 5, 5);
            button.setLayoutParams(params);
            button.setBackgroundColor(Color.WHITE);
            button.setOnClickListener(this::checkReaction);
            squares.add(button);
            gridLayout.addView(button);
        }
    }

    private void startCountdown() {
        countdownText.setVisibility(View.VISIBLE);
        gameStarted = false;
        countdownFinished = false;

        handler.postDelayed(() -> countdownText.setText("3"), 0);
        handler.postDelayed(() -> countdownText.setText("2"), 1000);
        handler.postDelayed(() -> countdownText.setText("1"), 2000);

        handler.postDelayed(() -> {
            countdownText.setText("");
            countdownText.setVisibility(View.GONE);
            countdownFinished = true;
            startReactionGame();
        }, 3000);
    }

    private void startReactionGame() {
        title.setText("Ждите...");
        int randomDelay = new Random().nextInt(5000 - 1000) + 1000;

        showSquareRunnable = () -> {
            showRandomSquare();
            stopwatch.start();
            gameStarted = true;
        };

        handler.postDelayed(showSquareRunnable, randomDelay);
    }

    private void showRandomSquare() {
        Random random = new Random();
        int randomIndex = random.nextInt(squares.size());
        correctSquare = squares.get(randomIndex);

        handler.post(() -> {
            correctSquare.setBackgroundColor(Color.GREEN);
            title.setText("Нажмите на зеленую плитку!");
        });
    }

    private void checkReaction(View view) {
        if (!gameActive) {
            return;
        }

        Button clickedButton = (Button) view;

        if (!countdownFinished) {
            title.setText("Подождите окончания отсчета!");
            return;
        }

        if (!gameStarted) {
            title.setText("Слишком рано! Подождите зеленую плитку.");
            resetGame();
            return;
        }

        if (clickedButton != correctSquare) {
            title.setText("Ошибка! Нажата неверная плитка.");
            resetGame();
            return;
        }

        stopwatch.stop();
        reactionTime = (int) stopwatch.getElapsedTimeMillis();
        clickedButton.setBackgroundColor(Color.BLUE);
        reactionTimeText.setText("Время реакции: " + reactionTime + " мс");

        if ("level".equals(gameMode)) {
            checkLevelCompletion(reactionTime);
        } else {
            evaluateReactionTime(reactionTime);
        }

        saveBestTime();
        resetGame();
    }

    private void levelCompleted() {
        soundManager.playLevelUpSound();
        title.setText("Уровень " + currentLevel + " пройден!");
        startButton.setText("Следующий уровень");
        startButton.setVisibility(View.VISIBLE);
        startButton.setOnClickListener(v -> {
            soundManager.playButtonClickSound();
            currentLevel++;
            updateLevelTitle();
            startCountdown();
        });
    }

    private void updateLevelTitle() {
        title.setText("Уровень " + currentLevel + ": Реагируйте быстрее чем " + levelTargets[currentLevel - 1] + " мс");
    }

    private void gameCompleted() {
        soundManager.playVictorySound();
        showConfetti();
        title.setText("Поздравляем! Вы прошли все уровни!");
        startButton.setText("Играть снова");
        startButton.setVisibility(View.VISIBLE);
        startButton.setOnClickListener(v -> {
            soundManager.playButtonClickSound();
            currentLevel = 1;
            startLevelMode();
        });
    }

    private void saveBestTime() {
        boolean newRecord = dbHelper.updateReactionGameStats(playerNickname, reactionTime);
        if (newRecord) {
            soundManager.playNewRecordSound();
            showConfetti();
            title.setText(title.getText() + " Новый рекорд!");
        }
    }

    private void resetGame() {
        handler.removeCallbacks(showSquareRunnable);

        for (Button square : squares) {
            square.setBackgroundColor(Color.WHITE);
        }
        gameStarted = false;
        countdownFinished = false;
        gameActive = false;
        retryButton.setVisibility(View.VISIBLE);

        if (stopwatch.isRunning()) {
            stopwatch.stop();
        }
    }

    private void evaluateReactionTime(int reactionTime) {
        if (reactionTime <= 200) {
            title.setText("Отличная реакция!");
        } else if (reactionTime <= 300) {
            title.setText("Хорошая реакция!");
        } else if (reactionTime <= 500) {
            title.setText("Средняя реакция.");
        } else {
            title.setText("Можно быстрее!");
        }
    }

    private void checkLevelCompletion(int reactionTime) {
        if (reactionTime <= levelTargets[currentLevel - 1]) {
            if (currentLevel >= levelTargets.length) {
                gameCompleted();
            } else {
                levelCompleted();
            }
        } else {
            title.setText("Попробуйте еще раз. Цель: " + levelTargets[currentLevel - 1] + " мс");
        }
    }

    private void setAllSquaresClickable(boolean clickable) {
        for (Button square : squares) {
            square.setClickable(clickable);
            square.setOnClickListener(clickable ? this::checkReaction : null);
        }
    }

    private void showConfetti() {
        konfettiView.build()
                .addColors(Color.YELLOW, Color.GREEN, Color.MAGENTA)
                .setDirection(0.0, 359.0)
                .setSpeed(1f, 5f)
                .setFadeOutEnabled(true)
                .setTimeToLive(2000L)
                .addShapes(Shape.Square.INSTANCE, Shape.Circle.INSTANCE)
                .addSizes(new Size(12, 5f))
                .setPosition(-50f, konfettiView.getWidth() + 50f, -50f, -50f)
                .streamFor(300, 5000L);
    }

}