Случайная активность при нажатии кнопки - PullRequest
0 голосов
/ 02 мая 2020

Я хотел бы сделать игру, если я нажму кнопку воспроизведения, откроется случайный уровень (активность). Я получил код для этого: { ссылка } Это работает, но я хотел бы отредактировать, например, все уровни имеют 2 разных ответа, answer1 не пройден, answer2 это пройти уровень, если пользователь проходит level1, и при сбое уровня 2, затем go возвращается к основной активности, и если запустить снова, пропущенные уровни больше не будут отображаться.

Пример: есть 5 уровней, случайный уровень запуска пользователя, пример уровня 3, пройдено , go до следующего случайного уровня, например, level2, пройдено, go до следующего ... level4, не удалось, go назад к основной активности, пользователь запускается снова, но уже пройденные уровни не будут отображаться, только не пройденные ... пример запуска level3 ... если пройдено, то go to level1 ....

Как я могу отредактировать этот код для моего решения? Может кто-нибудь дать мне несколько советов? Потому что в этом случае, если я go вернусь к основной активности и начну снова, то он начнется со всех уровней ... Я пытался редактировать, но я застрял и не работает ...

Плюс я хотел бы чтобы сохранить прогресс, когда пользователь покидает приложение. В общих настройках как я могу сохранить пройденные уровни (arraylist) ....?

MainActivity:

enter code here

Button level1Button = findViewById(R.id.level1Button);
    level1Button.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            // We are creating a list, which will store the activities that haven't been opened yet
            ArrayList<Class> activityList = new ArrayList<>();
            activityList.add(Level1Activity.class);
            activityList.add(Level2Activity.class);
            activityList.add(Level3Activity.class);
            activityList.add(Level4Activity.class);
            activityList.add(Level5Activity.class);

            Random generator = new Random();
            int number = generator.nextInt(5) + 1;

            Class activity = null;

            // Here, we are checking to see what the output of the random was
            switch(number) {
                case 1:
                    activity = Level1Activity.class;
                    // We are adding the number of the activity to the list
                    activityList.remove(Level1Activity.class);
                    break;
                case 2:
                    activity = Level2Activity.class;
                    activityList.remove(Level2Activity.class);
                    break;
                case 3:
                    activity = Level3Activity.class;
                    activityList.remove(Level3Activity.class);
                    break;
                case 4:
                    activity = Level4Activity.class;
                    activityList.remove(Level4Activity.class);
                    break;
                default:
                    activity = Level5Activity.class;
                    activityList.remove(Level5Activity.class);
                    break;
            }
            // We use intents to start activities
            Intent intent = new Intent(getBaseContext(), activity);
            // `intent.putExtra(...)` is used to pass on extra information to the next activity
            intent.putExtra("ACTIVITY_LIST", activityList);
            startActivity(intent);
        }
    });

Level1Activity:

enter code here
failbutton1.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v){
            ArrayList<Class> activityList = new ArrayList<>();
            activityList.add(Level1Activity.class);
            Bundle extras = getIntent().getExtras();
            activityList = (ArrayList<Class>) extras.get("ACTIVITY_LIST");


            //Class activity = null;


            Intent intent = new Intent(Level1Activity.this, Main2Activity.class);
            intent.putExtra("ACTIVITY_LIST", activityList);
            startActivity(intent);
        }
    });

    buttonlevel1.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            ArrayList<Class> activityList = new ArrayList<>();
            Bundle extras = getIntent().getExtras();
            activityList = (ArrayList<Class>) extras.get("ACTIVITY_LIST");

            if(activityList.size() == 0) {
                // Do something when after all activities have been opened
                //startActivity(new Intent(Level1Activity.this, Main2Activity.class));

                //Intent intent = new Intent(Level1Activity.this, Main2Activity.class);
                //intent.putExtra("ACTIVITY_LIST", activityList);
                //startActivity(intent);
            } else {
                // Now, the random number is generated between 1 and however many
                // activities we have remaining
                Random generator = new Random();
                int number = generator.nextInt(activityList.size()) + 1;

                Class activity = null;

                // Here, we are checking to see what the output of the random was
                switch(number) {
                    case 1:
                        // We will open the first remaining activity of the list
                        activity = activityList.get(0);
                        // We will now remove that activity from the list
                        activityList.remove(0);
                        break;
                    case 2:
                        // We will open the second remaining activity of the list
                        activity = activityList.get(1);
                        activityList.remove(1);
                        break;
                    case 3:
                        // We will open the third remaining activity of the list
                        activity = activityList.get(2);
                        activityList.remove(2);
                        break;
                    case 4:
                        // We will open the fourth remaining activity of the list
                        activity = activityList.get(3);
                        activityList.remove(3);
                        break;
                    default:
                        // We will open the fifth remaining activity of the list
                        activity = activityList.get(4);
                        activityList.remove(4);
                        break;
                }

                // Note: in the above, we might not have 3 remaining activities, for example,
                // but it doesn't matter because that case wouldn't be called anyway,
                // as we have already decided that the number would be between 1 and the number of
                // activities left.


                // Starting the activity, and passing on the remaining number of activities
                // to the next one that is opened
                Intent intent = new Intent(getBaseContext(), activity);
                intent.putExtra("ACTIVITY_LIST", activityList);
                startActivity(intent);
            }
        }
    });

level2, level3 .. .. это же просто разные id-ы

1 Ответ

1 голос

Я бы предложил использовать шаблон Singleton для обработки передачи данных между действиями.

Вы можете передать список по назначению putExtra() или SharedPreferences, но с Singleton класс, это выглядит намного лучше и проще манипулировать вашими данными, потому что они инкапсулированы . Тем более в вашей ситуации, когда вы хотите сохранить состояния ваших уровней (например, когда они уже завершены).

Однако, если вы действительно настаиваете на использовании SharedPreferences для сохранения списка, я предлагаю преобразовать его Json с помощью Gson. (Смотрите ниже мой ответ о том, как это реализовать.)

Как я уже сказал, я бы использовал шаблон Singleton, чтобы избежать создания ненужного стандартного кода и инкапсулировать состояния уровней.

LevelManager class (синглтон)

final class LevelManager {

    // constants
    private static final String LEVELS_SHARED_PREFERENCES_NAME = "app_name.LEVELS";

    // variables
    private static LevelManager instance;
    private List<Class> levels;
    private SharedPreferences sharedPreferences;

    private LevelManager(Context context) {
        sharedPreferences =
                context.getSharedPreferences(LEVELS_SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE);
        levels = new ArrayList<>();
        initializeList();
    }

    private void initializeList() {
        // Initialize levels, ie. add levels that are not yet completed/passed
        // Check in SharedPreferences if level has already been completed
        boolean alreadyPassed;

        alreadyPassed = sharedPreferences.getBoolean(Level1Activity.class.getSimpleName(), false);
        if (!alreadyPassed) levels.add(Level1Activity.class);

        alreadyPassed = sharedPreferences.getBoolean(Level2Activity.class.getSimpleName(), false);
        if (!alreadyPassed) levels.add(Level2Activity.class);

        alreadyPassed = sharedPreferences.getBoolean(Level3Activity.class.getSimpleName(), false);
        if (!alreadyPassed) levels.add(Level3Activity.class);

        alreadyPassed = sharedPreferences.getBoolean(Level4Activity.class.getSimpleName(), false);
        if (!alreadyPassed) levels.add(Level4Activity.class);

        alreadyPassed = sharedPreferences.getBoolean(Level5Activity.class.getSimpleName(), false);
        if (!alreadyPassed) levels.add(Level5Activity.class);
    }

    static LevelManager getInstance(Context context) {
        if (instance == null) {
            instance = new LevelManager(context);
        }
        return instance;
    }

    Class getRandomLevel() {
        if (levels.isEmpty()) {
            return null; // Return null if all levels are already completed
        }
        Collections.shuffle(levels);
        return levels.get(0);
    }

    void saveLevelState(Class levelClass, boolean passed) {
        sharedPreferences.edit().putBoolean(levelClass.getSimpleName(), passed).apply();
        if (passed) {
            // Remove level from list if user passed it so that it won't
            // be included in next levels
            levels.remove(levelClass);
        }
    }

    void reset() {
        // Clears all entries in SharedPreferences and re-initialize list
        sharedPreferences.edit().clear().apply();
        initializeList();
    }

}


Внутри onCreate в MainActivity

// Get LevelManager singleton instance
final LevelManager levelManager = LevelManager.getInstance(this);

Button startButton = findViewById(R.id.startButton);
startButton.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        // Get next random level
        Class levelToStart = levelManager.getRandomLevel();

        // If all levels are already completed
        if (levelToStart == null) {
            Toast.makeText(MainActivity.this, "All levels are completed!",
                    Toast.LENGTH_LONG).show();
            return;
        }

        Intent intent = new Intent(MainActivity.this, levelToStart);
        startActivity(intent);
    }
});

// I added a new button to reset all levels
Button resetButton = findViewById(R.id.resetButton);
resetButton.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        // Use the method reset() from LevelManager to restart everything
        levelManager.reset();
        Toast.makeText(MainActivity.this, "All levels have been reset!",
                Toast.LENGTH_LONG).show();
    }
});


Внутри onCreate на каждом уровне деятельности

// Get LevelManager
final LevelManager levelManager = LevelManager.getInstance(this);

// I created two buttons to simulate pass and fail
Button pass = findViewById(R.id.passButton);
Button fail = findViewById(R.id.failButton);

pass.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        // Save state (Don't forget to change 'N' below)
        levelManager.saveLevelState(LevelNActivity.class, true);

        // Get next level
        Class levelToStart = levelManager.getRandomLevel();

        // Check if all are levels already completed
        if (levelToStart == null) {
            Toast.makeText(LevelNActivity.this, "Completed all levels",
                    Toast.LENGTH_LONG).show();
            finish(); // Must implement to avoid going back to previous level (ie. Activity)
            return;
        }

        Intent intent = new Intent(LevelNActivity.this, levelToStart);
        startActivity(intent);
        finish();
    }
});

fail.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        finish();
    }
});


Как вы можете видеть , вы можете просто использовать метод finish(), если пользователь не прошел уровень, тогда как вы используете код ниже, чтобы перейти к следующему уровню:

// Get LevelManager
LevelManager levelManager = LevelManager.getInstance(this);

// Set that the user passed this level (Change 'N' to the current level we are in)
levelManager.saveLevelState(LevelNActivity.class, true);

// Get next level
Class nextLevel = levelManager.getRandomLevel();

// If all levels are completed then 'nextLevel' will be null
if (nextLevel == null) {
    // ...
}

// Start next level and finish current
Intent intent = new Intent(this, nextLevel);
startActivity(intent);
finish();

Примечание: чтобы не вызывать finish() явно при запуске На следующем уровне вы можете поместить android:noHistory="true" в тег активности ваших уровней в файле манифеста.



Как сохранить список в SharedPreferences, преобразовав его Json с использованием Gson

Чтобы на самом деле использовать Gson, вам нужно будет добавить implementation 'com.google.code.gson:gson:2.8.6' в зависимости грейда вашего приложения .

Также существует проблема на Gson при разборе Class объектов на Json: вам необходимо создать свой собственный сериализатор и десериализатор для этих объекты и зарегистрируйте его в GsonBuilder.

ClassAdapter class (здесь мы создаем собственный настраиваемый сериализатор и десериализатор для объектов Class)

public class ClassAdapter implements JsonSerializer<Class>, JsonDeserializer<Class> {

    @Override
    public JsonElement serialize(Class src, Type typeOfSrc, JsonSerializationContext context) {
        // Get our class 'src' name
        return new JsonPrimitive(src.getName());
    }

    @Override
    public Class deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
        try {
            // Get class
            return Class.forName(json.getAsString());
        } catch (ClassNotFoundException e) {
            // If class could not be found or did not exists, handle error here...
            e.printStackTrace();
        }
        return null;
    }

}

Вот пример использования сохранения списка в SharedPreferences с помощью Json с использованием Gson:

// Create new GsonBuilder and register our adapter for Class objects
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.registerTypeAdapter(Class.class, new ClassAdapter());

// Initialize our list of levels (ie. classes)
List<Class> classes = new ArrayList<>();
classes.add(Level1Activity.class);
classes.add(Level2Activity.class);
classes.add(Level3Activity.class);
classes.add(Level4Activity.class);
classes.add(Level5Activity.class);

// Create Gson from GsonBuilder and convert list to json
Gson gson = gsonBuilder.create();
String json = gson.toJson(classes);

// Save json to SharedPreferences
SharedPreferences sharedPreferences = getSharedPreferences("app_name", MODE_PRIVATE);
sharedPreferences.edit().putString("levels", json).apply();

и получения списка обратно:

// Retrieve json from SharedPreferences
SharedPreferences sharedPreferences = getSharedPreferences("app_name", MODE_PRIVATE);
String json = sharedPreferences.getString("levels", null);

// Handle here if json doesn't exist yet
if (json == null) {
    // ...
}

// Create new GsonBuilder and register our adapter for Class objects
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.registerTypeAdapter(Class.class, new ClassAdapter());

// Create Gson from GsonBuilder and specify type of list
Gson gson = gsonBuilder.create();
Type type = new TypeToken<ArrayList<Class>>(){}.getType();

// Convert json to list
List<Class> classes = gson.fromJson(json, type);

Я надеюсь, что вы получили ценные советы для решения этой проблемы! И как всегда, удачного кодирования!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...