package com.example.flappybirdgame;

import android.content.Context;
import android.content.SharedPreferences;

public class Achievement {

    private String name;           // Name of the achievement
    private String description;    // Description of the achievement
    private boolean unlocked;      // Unlock status
    private String key;            // Unique key for saving to SharedPreferences

    public Achievement(String name, String description, String key) {
        this.name = name;
        this.description = description;
        this.key = key;
        this.unlocked = false;
    }

    // Load the unlock status from SharedPreferences
    public void load(Context context) {
        SharedPreferences prefs = context.getSharedPreferences("achievements", Context.MODE_PRIVATE);
        unlocked = prefs.getBoolean(key, false);
    }

    // Save the unlock status to SharedPreferences
    public void save(Context context) {
        SharedPreferences prefs = context.getSharedPreferences("achievements", Context.MODE_PRIVATE);
        SharedPreferences.Editor editor = prefs.edit();
        editor.putBoolean(key, unlocked);
        editor.apply();
    }

    // Unlock the achievement
    public void unlock(Context context) {
        if (!unlocked) {
            unlocked = true;
            save(context); // Save the new status
        }
    }

    // Getters
    public String getName() {
        return name;
    }

    public String getDescription() {
        return description;
    }

    public boolean isUnlocked() {
        return unlocked;
    }

    public String getKey() {
        return key;
    }

    // Setters
    public void setUnlocked(boolean unlocked) {
        this.unlocked = unlocked;
    }
}package com.example.flappybirdgame;

import android.content.Context;
import android.content.SharedPreferences;
import android.widget.Toast;

import java.util.ArrayList;

public class AchievementManager {

    private ArrayList<Achievement> achievements = new ArrayList<>();
    private Context context;

    public AchievementManager(Context context) {
        this.context = context;

        // Define achievements
        achievements.add(new Achievement(context.getString(R.string.flap_1_time),
                context.getString(R.string.flap_1_time_desc), "achievement_first_flap"));
        achievements.add(new Achievement(context.getString(R.string.flap_500_times),
                context.getString(R.string.flap_500_times_desc), "achievement_500_flaps"));
        achievements.add(new Achievement(context.getString(R.string.score_100_points),
                context.getString(R.string.score_100_points_desc), "achievement_high_scorer"));

        // Load unlocked achievements
        loadAchievements();
    }

    private void loadAchievements() {
        SharedPreferences prefs = context.getSharedPreferences("achievements", Context.MODE_PRIVATE);
        for (Achievement achievement : achievements) {
            achievement.setUnlocked(prefs.getBoolean(achievement.getKey(), false));
        }
    }

    public void checkAchievements(int flapCount, int score) {
        for (Achievement achievement : achievements) {
            if (!achievement.isUnlocked()) {
                if (achievement.getKey().equals("achievement_first_flap") && flapCount >= 1) {
                    achievement.unlock(context);
                    notifyPlayer(achievement);
                } else if (achievement.getKey().equals("achievement_500_flaps") && flapCount >= 500) {
                    achievement.unlock(context);
                    notifyPlayer(achievement);
                } else if (achievement.getKey().equals("achievement_high_scorer") && score >= 100) {
                    achievement.unlock(context);
                    notifyPlayer(achievement);
                }
            }
        }
    }

    private void notifyPlayer(Achievement achievement) {
        // Notify the player about the unlocked achievement
        String message = String.format(context.getString(R.string.achievement_unlocked),
                achievement.getName());
        Toast.makeText(context, message, Toast.LENGTH_SHORT).show();
    }

    // Add this method to get the list of achievements
    public ArrayList<Achievement> getAchievements() {
        return achievements;
    }
}package com.example.flappybirdgame;

import android.os.Bundle;
import android.widget.ArrayAdapter;
import android.widget.ListView;

import androidx.appcompat.app.AppCompatActivity;

import java.util.ArrayList;

public class AchievementsActivity extends AppCompatActivity {
    private ListView achievementsListView;
    private ArrayAdapter<String> adapter;
    private ArrayList<String> achievementsList = new ArrayList<>();
    private AchievementManager achievementManager;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_achievements);

        achievementManager = new AchievementManager(this);
        achievementsListView = findViewById(R.id.achievementsListView);

        // Load achievements and populate the list
        achievementsList.clear();
        for (Achievement achievement : achievementManager.getAchievements()) {
            String status = achievement.isUnlocked() ? getString(R.string.unlocked) : getString(R.string.locked);
            achievementsList.add(achievement.getName() + " - " + status);
        }

        adapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, achievementsList);
        achievementsListView.setAdapter(adapter);
    }
}package com.example.flappybirdgame;

import android.content.Context;
import android.content.SharedPreferences;
import android.media.AudioAttributes;
import android.media.SoundPool;
import android.util.DisplayMetrics;

import java.util.ArrayList;

public class AppConstants {

    // Screen dimensions and ratios
    public static int SCREEN_WIDTH;
    public static int SCREEN_HEIGHT;
    public static float SCREEN_RATIO_X;
    public static float SCREEN_RATIO_Y;

    // Game speeds
    public static int BACKGROUND_SPEED = 10;
    public static int PIPE_SPEED = 10;

    // Sound management
    public static SoundPool soundPool;
    public static int soundWing, soundHit, soundPoint;
    public static boolean SOUND_ENABLED = true;

    // Game context
    public static Context gameActivityContext;

    // Ground position
    public static int GROUND_Y;

    // Difficulty and settings
    public static int DIFFICULTY = 1;
    public static boolean INVERTED_CONTROLS = false;
    public static int SENSITIVITY = 5;

    // Themes and birds
    public static Theme currentTheme;
    public static ArrayList<Theme> availableThemes;

    // Localization
    public static String LANGUAGE = "en";

    // Initialize constants
    public static void initialization(Context context) {
        gameActivityContext = context;

        // Initialize screen dimensions
        DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
        SCREEN_WIDTH = displayMetrics.widthPixels;
        SCREEN_HEIGHT = displayMetrics.heightPixels;

        SCREEN_RATIO_X = SCREEN_WIDTH / 1080f;
        SCREEN_RATIO_Y = SCREEN_HEIGHT / 1920f;

        // Initialize SoundPool
        AudioAttributes audioAttributes = new AudioAttributes.Builder()
                .setUsage(AudioAttributes.USAGE_GAME)
                .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
                .build();

        soundPool = new SoundPool.Builder()
                .setAudioAttributes(audioAttributes)
                .setMaxStreams(5)
                .build();

        // Load sounds
        soundWing = soundPool.load(context, R.raw.wing, 1);
        soundHit = soundPool.load(context, R.raw.hit, 1);
        soundPoint = soundPool.load(context, R.raw.point, 1);

        // Initialize themes
        availableThemes = new ArrayList<>();

        // Add default theme
        availableThemes.add(new Theme(
                R.drawable.background,     // Background
                R.drawable.pipe_top,       // Pipe Top
                R.drawable.pipe_bottom     // Pipe Bottom
        ));

        // Load settings from SharedPreferences
        SharedPreferences prefs = context.getSharedPreferences("game", Context.MODE_PRIVATE);
        SOUND_ENABLED = prefs.getBoolean("soundEnabled", true);
        DIFFICULTY = prefs.getInt("difficulty", 1);
        INVERTED_CONTROLS = prefs.getBoolean("invertedControls", false);
        SENSITIVITY = prefs.getInt("sensitivity", 5);
        LANGUAGE = prefs.getString("language", "en");

        // Load current theme index
        int themeIndex = prefs.getInt("currentTheme", 0);
        if (themeIndex < 0 || themeIndex >= availableThemes.size()) {
            themeIndex = 0; // Default to first theme
        }
        currentTheme = availableThemes.get(themeIndex);

        // Initialize BirdManager
        BirdManager.initialize(context);
    }

    // Method to save settings
    public static void saveSettings(Context context) {
        SharedPreferences prefs = context.getSharedPreferences("game", Context.MODE_PRIVATE);
        SharedPreferences.Editor editor = prefs.edit();
        editor.putBoolean("soundEnabled", SOUND_ENABLED);
        editor.putInt("difficulty", DIFFICULTY);
        editor.putBoolean("invertedControls", INVERTED_CONTROLS);
        editor.putInt("sensitivity", SENSITIVITY);
        editor.putString("language", LANGUAGE);
        editor.apply();
    }

    // Method to set the current theme
    public static void setCurrentTheme(int index, Context context) {
        if (index >= 0 && index < availableThemes.size()) {
            currentTheme = availableThemes.get(index);
            SharedPreferences prefs = context.getSharedPreferences("game", Context.MODE_PRIVATE);
            SharedPreferences.Editor editor = prefs.edit();
            editor.putInt("currentTheme", index);
            editor.apply();
        }
    }
}package com.example.flappybirdgame;

import android.graphics.Bitmap;
import android.graphics.Canvas;

public class Background {
    public int x = 0, y = 0;
    private Bitmap background;

    public Background() {
        // Fetch the preloaded and scaled background bitmap
        background = ResourceManager.getInstance(AppConstants.gameActivityContext).getBitmap(R.drawable.background);
    }

    public void update() {
        x -= AppConstants.BACKGROUND_SPEED;
        if (x + background.getWidth() < 0) {
            x = background.getWidth();
        }
    }

    public void draw(Canvas canvas) {
        canvas.drawBitmap(background, x, y, null);
    }

    public Bitmap getBitmap() {
        return background;
    }
}package com.example.flappybirdgame;

import android.graphics.Bitmap;
import android.graphics.Rect;

public class Bird {
    private float x, y;              // Position as float
    private float velocity = 0;      // Current velocity
    private float gravity = 1;       // Gravity
    private float flapForce = -15;   // Flap force
    private int width, height;       // Dimensions
    private Bitmap[] birdFrames;     // Animation frames
    private int frameIndex = 0;      // Current frame index
    private int frameCount = 3;      // Number of frames
    private int frameDelay = 5;      // Delay for animation speed
    private int frameTicker = 0;     // Frame ticker
    private Rect collisionRect;      // Collision rectangle
    private boolean isInvincible = false;   // Invincibility state
    private boolean isMagnetActive = false; // Magnet power-up state
    private int originalWidth, originalHeight; // Original dimensions
    private boolean isShrunk = false;       // Shrink power-up state

    public Bird(int screenY) {
        // Fetch preloaded and scaled bird frames
        birdFrames = new Bitmap[frameCount];
        birdFrames[0] = ResourceManager.getInstance(AppConstants.gameActivityContext).getBitmap(R.drawable.bird_frame_1);
        birdFrames[1] = ResourceManager.getInstance(AppConstants.gameActivityContext).getBitmap(R.drawable.bird_frame_2);
        birdFrames[2] = ResourceManager.getInstance(AppConstants.gameActivityContext).getBitmap(R.drawable.bird_frame_3);

        // Get dimensions from the first frame
        width = birdFrames[0].getWidth();
        height = birdFrames[0].getHeight();

        // Store original dimensions
        originalWidth = width;
        originalHeight = height;

        // Initialize position as float
        x = AppConstants.SCREEN_WIDTH * 0.1f;
        y = screenY / 2f - height / 2f;

        collisionRect = new Rect();
    }

    // Get the current frame for animation
    public Bitmap getCurrentFrame() {
        return birdFrames[frameIndex];
    }

    // Update bird's state
    public void update() {
        velocity += gravity;
        y += velocity;

        // Prevent bird from going off the screen
        if (y + height > AppConstants.GROUND_Y) {
            y = AppConstants.GROUND_Y - height;
            velocity = 0;
        }

        if (y < 0) {
            y = 0;
            velocity = 0;
        }

        // Update the collision rectangle with integer values
        collisionRect.set((int) x, (int) y, (int) x + width, (int) y + height);

        // Update animation frame
        frameTicker++;
        if (frameTicker >= frameDelay) {
            frameTicker = 0;
            frameIndex++;
            if (frameIndex >= frameCount) {
                frameIndex = 0;
            }
        }
    }

    public void flap(int sensitivity) {
        float adjustedFlapForce = flapForce * (sensitivity / 5.0f);
        if (AppConstants.INVERTED_CONTROLS) {
            velocity = -adjustedFlapForce;
        } else {
            velocity = adjustedFlapForce;
        }
    }

    public void dive(int sensitivity) {
        float adjustedDiveForce = -flapForce * (sensitivity / 5.0f);
        velocity = adjustedDiveForce;
    }

    // Shrink the bird for the shrink power-up
    public void shrink() {
        if (!isShrunk) {
            isShrunk = true;
            width /= 2;
            height /= 2;
            x += width / 2; // Adjust position to center
            y += height / 2;

            for (int i = 0; i < birdFrames.length; i++) {
                birdFrames[i] = Bitmap.createScaledBitmap(birdFrames[i], width, height, false);
            }
        }
    }

    // Reset bird's size after shrink power-up ends
    public void resetSize() {
        if (isShrunk) {
            x -= width / 2; // Adjust position back
            y -= height / 2;
            width = originalWidth;
            height = originalHeight;

            for (int i = 0; i < birdFrames.length; i++) {
                birdFrames[i] = ResourceManager.getInstance(AppConstants.gameActivityContext).getBitmap(
                        i == 0 ? R.drawable.bird_frame_1 : (i == 1 ? R.drawable.bird_frame_2 : R.drawable.bird_frame_3));
            }
            isShrunk = false;
        }
    }

    // Get the collision rectangle for collision detection
    public Rect getCollisionShape() {
        return collisionRect;
    }

    // Set invincibility state
    public void setInvincible(boolean invincible) {
        isInvincible = invincible;
    }

    // Check if the bird is invincible
    public boolean isInvincible() {
        return isInvincible;
    }

    // Set magnet power-up state
    public void setMagnetActive(boolean magnetActive) {
        isMagnetActive = magnetActive;
    }

    // Check if magnet power-up is active
    public boolean isMagnetActive() {
        return isMagnetActive;
    }

    // Getters for position and dimensions
    public int getX() { return (int) x; }
    public int getY() { return (int) y; }
    public int getHeight() { return height; }
    public int getWidth() { return width; }
}package com.example.flappybirdgame;

import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.GridView;
import android.widget.ImageView;

import java.util.ArrayList;

public class BirdAdapter extends BaseAdapter {
    private Context context;
    private ArrayList<Integer> birdList;

    public BirdAdapter(Context context, ArrayList<Integer> birdList) {
        this.context = context;
        this.birdList = birdList;
    }

    @Override
    public int getCount() {
        return birdList.size();
    }

    @Override
    public Object getItem(int position) {
        return birdList.get(position);
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ImageView birdImageView;
        if (convertView == null) {
            birdImageView = new ImageView(context);
            birdImageView.setLayoutParams(new GridView.LayoutParams(200, 200));
            birdImageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
        } else {
            birdImageView = (ImageView) convertView;
        }

        birdImageView.setImageResource(birdList.get(position));
        return birdImageView;
    }
}package com.example.flappybirdgame;

import android.content.Context;
import android.content.SharedPreferences;

import java.util.ArrayList;

public class BirdManager {
    private static ArrayList<Integer> availableBirds = new ArrayList<>();
    private static int currentBirdIndex = 0;

    public static void initialize(Context context) {
        SharedPreferences prefs = context.getSharedPreferences("game", Context.MODE_PRIVATE);

        // Load available birds
        availableBirds.add(R.drawable.bird_frame_1); // Default bird frames

        if (prefs.getBoolean("bird_unlocked_cool_bird", false)) {
            availableBirds.add(R.drawable.bird_frame_2); // Assuming bird_frame_2 is the cool bird
            availableBirds.add(R.drawable.bird_frame_3); // Additional frames if needed
        }

        currentBirdIndex = prefs.getInt("currentBirdIndex", 0);
    }

    public static int getCurrentBirdResourceId() {
        return availableBirds.get(currentBirdIndex);
    }

    public static void setCurrentBird(int index, Context context) {
        if (index >= 0 && index < availableBirds.size()) {
            currentBirdIndex = index;
            SharedPreferences prefs = context.getSharedPreferences("game", Context.MODE_PRIVATE);
            SharedPreferences.Editor editor = prefs.edit();
            editor.putInt("currentBirdIndex", index);
            editor.apply();
        }
    }

    public static void unlockBird(int resourceId, String key, Context context) {
        if (!availableBirds.contains(resourceId)) {
            availableBirds.add(resourceId);
            SharedPreferences prefs = context.getSharedPreferences("game", Context.MODE_PRIVATE);
            SharedPreferences.Editor editor = prefs.edit();
            editor.putBoolean(key, true);
            editor.apply();
        }
    }

    public static boolean isBirdUnlocked(String key, Context context) {
        SharedPreferences prefs = context.getSharedPreferences("game", Context.MODE_PRIVATE);
        return prefs.getBoolean(key, false);
    }

    public static ArrayList<Integer> getAvailableBirds() {
        return availableBirds;
    }
}package com.example.flappybirdgame;

import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Rect;

public class BossPipe extends Pipe {
    private int verticalSpeed = 4; // Speed at which the boss pipe moves vertically
    private boolean movingDown = true; // Direction flag for vertical movement

    public BossPipe() {
        super();

        // Customize the gap size for increased difficulty during boss levels
        gap = (int) (AppConstants.SCREEN_HEIGHT * 0.2f); // Smaller gap for boss pipes
        setGapSize(gap);

        // Initialize position
        y = getRandomYPosition();
    }

    @Override
    public void update() {
        // Move horizontally
        x -= pipeSpeed;

        // Vertical movement logic
        if (movingDown) {
            y += verticalSpeed;
            // Check lower boundary
            if (y + height + gap + height >= AppConstants.GROUND_Y - 50) {
                movingDown = false; // Reverse direction
            }
        } else {
            y -= verticalSpeed;
            // Check upper boundary
            if (y <= -height + 50) {
                movingDown = true; // Reverse direction
            }
        }

        // Reset 'scored' status when off-screen
        if (isOffScreen()) {
            resetPosition();
        }
    }

    @Override
    public void draw(Canvas canvas) {
        super.draw(canvas);
        // Additional boss-specific visuals can be added here
    }
}package com.example.flappybirdgame;

import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.GridView;
import android.widget.Toast;

import androidx.appcompat.app.AppCompatActivity;

public class CharacterSelectionActivity extends AppCompatActivity {

    private GridView birdGridView;
    private BirdAdapter birdAdapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_character_selection);

        birdGridView = findViewById(R.id.birdGridView);
        birdAdapter = new BirdAdapter(this, BirdManager.getAvailableBirds());
        birdGridView.setAdapter(birdAdapter);

        birdGridView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                BirdManager.setCurrentBird(position, CharacterSelectionActivity.this);
                Toast.makeText(CharacterSelectionActivity.this, getString(R.string.bird_selected), Toast.LENGTH_SHORT).show();
                finish();
            }
        });
    }
}package com.example.flappybirdgame;

import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Rect;

public class Collectible {
    private int x, y, width, height;
    private Bitmap bitmap;
    private Rect collisionRect;
    private int speed = AppConstants.PIPE_SPEED; // Move at the same speed as pipes

    public Collectible() {
        // Fetch the preloaded and scaled collectible bitmap (e.g., coin)
        bitmap = ResourceManager.getInstance(AppConstants.gameActivityContext).getBitmap(R.drawable.coin);

        // Set dimensions based on preloaded bitmap
        width = bitmap.getWidth();
        height = bitmap.getHeight();

        x = AppConstants.SCREEN_WIDTH;
        y = getRandomYPosition();
        collisionRect = new Rect(x, y, x + width, y + height);
    }

    private int getRandomYPosition() {
        int minY = 0;
        int maxY = AppConstants.GROUND_Y - height;
        return minY + (int) (Math.random() * ((maxY - minY) + 1));
    }

    public void update() {
        x -= speed;
        collisionRect.set(x, y, x + width, y + height);
    }

    public void draw(Canvas canvas) {
        canvas.drawBitmap(bitmap, x, y, null);
    }

    public Rect getCollisionRect() {
        return collisionRect;
    }

    public boolean isOffScreen() {
        return x + width < 0;
    }

    // Getters and Setters for Position
    public int getX() {
        return x;
    }

    public int getY() {
        return y;
    }

    public void setX(int x) {
        this.x = x;
        collisionRect.left = x;
        collisionRect.right = x + width;
    }

    public void setY(int y) {
        this.y = y;
        collisionRect.top = y;
        collisionRect.bottom = y + height;
    }
}package com.example.flappybirdgame;

import android.os.Bundle;
import android.view.WindowManager;

import androidx.appcompat.app.AppCompatActivity;

public class GameActivity extends AppCompatActivity {

    private GameView gameView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // Make the game full-screen
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
                WindowManager.LayoutParams.FLAG_FULLSCREEN);

        // Initialize AppConstants
        AppConstants.initialization(this.getApplicationContext());

        // Initialize GameView and set it as the content view
        gameView = new GameView(this);
        setContentView(gameView);
    }

    @Override
    protected void onPause() {
        super.onPause();
        gameView.pause();
    }

    @Override
    protected void onResume() {
        super.onResume();
        gameView.resume();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (AppConstants.soundPool != null) {
            AppConstants.soundPool.release();
            AppConstants.soundPool = null;
        }
        if (gameView != null) {
            gameView.cleanup();
            gameView = null;
        }
    }
}package com.example.flappybirdgame;

import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.os.Handler;
import android.os.Looper;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.widget.Toast;

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

/**
 * The main game view where all game elements are drawn and updated.
 */
public class GameView extends SurfaceView implements Runnable {

    private Thread thread;
    private boolean isPlaying;
    private Background background1, background2;
    private Bird bird;
    private PipeManager pipeManager;
    private int screenX, screenY;
    private Paint paint;
    private GameActivity activity;
    private boolean isGameOver = false;
    private int score = 0;
    private Handler mainHandler = new Handler(Looper.getMainLooper());
    private Runnable restartRunnable;
    private Ground ground1, ground2;
    private int nextDifficultyScore = 10; // Increase difficulty every 10 points
    private boolean isPaused = false;
    private Rect pauseButtonRect;
    private Bitmap pauseButtonBitmap; // Ensure you have this drawable
    private ArrayList<PowerUp> powerUps = new ArrayList<>();
    private ArrayList<Collectible> collectibles = new ArrayList<>();
    private int totalCoinsCollected = 0;
    private Random random = new Random();
    private LevelManager levelManager;
    private int flapCount = 0;
    private AchievementManager achievementManager;

    public GameView(GameActivity activity) {
        super(activity);

        this.activity = activity;

        // Initialize settings context
        AppConstants.gameActivityContext = activity.getApplicationContext();

        // Initialize ResourceManager
        ResourceManager.getInstance(AppConstants.gameActivityContext);

        // Initialize game variables, bitmaps, etc.
        screenX = AppConstants.SCREEN_WIDTH;
        screenY = AppConstants.SCREEN_HEIGHT;

        background1 = new Background();
        background2 = new Background();
        ground1 = new Ground();
        ground2 = new Ground();

        background2.x = screenX;
        ground2.x = screenX;

        bird = new Bird(screenY);
        levelManager = new LevelManager();
        pipeManager = new PipeManager(levelManager);

        paint = new Paint();
        paint.setTextSize(64);
        paint.setColor(Color.WHITE);
        paint.setAntiAlias(true);

        // Initialize pause button rectangle and bitmap
        int btnSize = (int) (AppConstants.SCREEN_WIDTH * 0.1);
        int btnX = AppConstants.SCREEN_WIDTH - btnSize - 20;
        int btnY = 20;
        pauseButtonRect = new Rect(btnX, btnY, btnX + btnSize, btnY + btnSize);

        // Load pause button image
        pauseButtonBitmap = ResourceManager.getInstance(AppConstants.gameActivityContext).getBitmap(R.drawable.play_button_image);
        pauseButtonBitmap = Bitmap.createScaledBitmap(pauseButtonBitmap, btnSize, btnSize, false);

        applyLevelSettings();

        // Initialize achievement manager
        achievementManager = new AchievementManager(activity);
    }

    @Override
    public void run() {
        while (isPlaying) {
            if (!isPaused) {
                update();
            }
            draw();
            sleep();
        }
    }

    private void update() {
        // Update ground positions
        ground1.update();
        ground2.update();

        // Update background positions
        background1.update();
        background2.update();

        // Update bird
        bird.update();

        // Update pipes
        pipeManager.update();

        // Check for collisions
        if (pipeManager.checkCollision(bird) || bird.getY() <= 0 || bird.getY() + bird.getHeight() >= AppConstants.SCREEN_HEIGHT) {
            if (!bird.isInvincible()) {
                isPlaying = false;
                isGameOver = true;
                if (AppConstants.SOUND_ENABLED) {
                    AppConstants.soundPool.play(AppConstants.soundHit, 1, 1, 0, 0, 1);
                }
                achievementManager.checkAchievements(flapCount, score); // Update achievements on game over
            }
        }

        // Increase score if bird passes a pipe
        if (pipeManager.checkForScore(bird)) {
            score++;
            checkForLevelAdvance();
            checkForBirdUnlock();
            achievementManager.checkAchievements(flapCount, score);
            if (AppConstants.SOUND_ENABLED) {
                AppConstants.soundPool.play(AppConstants.soundPoint, 1, 1, 0, 0, 1);
            }
        }

        // Check for increasing difficulty
        if (score >= nextDifficultyScore) {
            nextDifficultyScore += 10; // Set next score milestone

            // Increase pipe speed
            AppConstants.PIPE_SPEED += 2; // Adjust as needed

            // Decrease gap between pipes
            pipeManager.decreaseGap(20); // Reduce gap by 20 pixels

            // Optionally increase background speed
            AppConstants.BACKGROUND_SPEED += 1;

            // Apply new speeds to existing pipes
            pipeManager.applySpeed();
        }

        // Spawn power-ups at random intervals
        if (random.nextInt(1000) < 5) { // Adjust the probability as needed
            spawnPowerUp();
        }

        // Update power-ups
        Iterator<PowerUp> powerUpIterator = powerUps.iterator();
        while (powerUpIterator.hasNext()) {
            PowerUp powerUp = powerUpIterator.next();
            powerUp.update();

            // Remove if off-screen
            if (powerUp.isOffScreen()) {
                powerUpIterator.remove();
                continue;
            }

            // Check collision with bird
            if (Rect.intersects(bird.getCollisionShape(), powerUp.getCollisionRect())) {
                activatePowerUp(powerUp.getType());
                powerUpIterator.remove();
            }
        }

        // Spawn collectibles at random intervals
        if (random.nextInt(1000) < 5) {
            collectibles.add(new Collectible());
        }

        // Update collectibles
        Iterator<Collectible> collectibleIterator = collectibles.iterator();
        while (collectibleIterator.hasNext()) {
            Collectible collectible = collectibleIterator.next();
            collectible.update();

            // Magnet effect
            if (bird.isMagnetActive()) {
                int deltaX = bird.getX() - collectible.getX();
                int deltaY = bird.getY() - collectible.getY();
                double distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
                if (distance < 300 * AppConstants.SCREEN_RATIO_X) {
                    collectible.setX(collectible.getX() + (int) (deltaX * 0.1));
                    collectible.setY(collectible.getY() + (int) (deltaY * 0.1));
                }
            }

            // Check if collectible is off-screen
            if (collectible.isOffScreen()) {
                collectibleIterator.remove();
                continue;
            }

            // Check collision with bird
            if (Rect.intersects(bird.getCollisionShape(), collectible.getCollisionRect())) {
                totalCoinsCollected++;
                collectibleIterator.remove();
                // Optionally play a sound or update UI
                if (AppConstants.SOUND_ENABLED) {
                    AppConstants.soundPool.play(AppConstants.soundPoint, 1, 1, 0, 0, 1);
                }
            }
        }
    }

    private void draw() {
        if (getHolder().getSurface().isValid()) {

            Canvas canvas = getHolder().lockCanvas();

            // Draw background
            background1.draw(canvas);
            background2.draw(canvas);

            // Draw pipes
            pipeManager.draw(canvas);

            // Draw ground
            ground1.draw(canvas);
            ground2.draw(canvas);

            // Draw bird
            canvas.drawBitmap(bird.getCurrentFrame(), (int) bird.getX(), (int) bird.getY(), null);

            // Draw power-ups
            for (PowerUp powerUp : powerUps) {
                powerUp.draw(canvas);
            }

            // Draw collectibles
            for (Collectible collectible : collectibles) {
                collectible.draw(canvas);
            }

            // Draw score and coins
            paint.setTextSize(64);
            paint.setColor(Color.WHITE);
            canvas.drawText(activity.getString(R.string.score, score), 50, 100, paint);
            canvas.drawText(activity.getString(R.string.coins, totalCoinsCollected), 50, 170, paint);

            // Draw Pause Button
            canvas.drawBitmap(pauseButtonBitmap, pauseButtonRect.left, pauseButtonRect.top, null);

            if (isGameOver) {
                // Save high score
                saveHighScore();

                // Draw Game Over text
                paint.setTextSize(150);
                paint.setColor(Color.RED);
                paint.setTextAlign(Paint.Align.CENTER);
                canvas.drawText(activity.getString(R.string.game_over), screenX / 2f, screenY / 2f, paint);

                // Reset paint settings
                paint.setTextAlign(Paint.Align.LEFT);
                paint.setTextSize(64);
                paint.setColor(Color.WHITE);

                // Ensure we only schedule the restart once
                if (restartRunnable == null) {
                    // Restart game after a delay
                    restartRunnable = new Runnable() {
                        @Override
                        public void run() {
                            activity.startActivity(new Intent(activity, MainActivity.class));
                            activity.finish();
                        }
                    };
                    mainHandler.postDelayed(restartRunnable, 2000); // Delay of 2000 milliseconds (2 seconds)
                }
            }

            getHolder().unlockCanvasAndPost(canvas);
        }
    }

    private void saveHighScore() {
        SharedPreferences prefs = activity.getSharedPreferences("game", Context.MODE_PRIVATE);
        int highScore = prefs.getInt("highScore", 0);
        if (score > highScore) {
            SharedPreferences.Editor editor = prefs.edit();
            editor.putInt("highScore", score);
            editor.apply();
        }
    }

    private void sleep() {
        try {
            Thread.sleep(17); // Approximately 60 FPS
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public void resume() {
        isPlaying = true;
        isPaused = false;
        thread = new Thread(this);
        thread.start();
    }

    public void pause() {
        isPlaying = false;
        isPaused = true;
        try {
            thread.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (event.getAction() == MotionEvent.ACTION_DOWN) {

            if (!isGameOver) {
                float touchX = event.getX();
                float touchY = event.getY();

                // Check if pause button is tapped
                if (pauseButtonRect.contains((int) touchX, (int) touchY)) {
                    if (isPaused) {
                        resume(); // Resume the game
                        mainHandler.post(() -> Toast.makeText(activity, "Game Resumed", Toast.LENGTH_SHORT).show());
                    } else {
                        pause(); // Pause the game
                        mainHandler.post(() -> Toast.makeText(activity, "Game Paused", Toast.LENGTH_SHORT).show());
                    }
                } else {
                    // Handle flap based on inverted controls
                    bird.flap(AppConstants.SENSITIVITY);
                    flapCount++;
                    achievementManager.checkAchievements(flapCount, score);

                    if (AppConstants.SOUND_ENABLED) {
                        AppConstants.soundPool.play(AppConstants.soundWing, 1, 1, 0, 0, 1);
                    }
                }
            }
        }
        return true;
    }

    private void applyLevelSettings() {
        Level currentLevel = levelManager.getCurrentLevel();
        AppConstants.PIPE_SPEED = currentLevel.getPipeSpeed();
        pipeManager.setGapSize(currentLevel.getGapSize());
        // Adjust other parameters as needed
    }

    private void checkForLevelAdvance() {
        Level currentLevel = levelManager.getCurrentLevel();
        if (score >= currentLevel.getTargetScore()) {
            levelManager.advanceToNextLevel();
            applyLevelSettings();
            pipeManager.onLevelChange(); // Notify PipeManager of level change

            mainHandler.post(() -> {
                String message;
                if (levelManager.isLastLevel()) {
                    message = activity.getString(R.string.boss_level);
                } else {
                    // Assuming @string/level is defined as "Level %2$d!"
                    message = String.format(activity.getString(R.string.level), "", currentLevel.getLevelNumber());
                }
                Toast.makeText(activity, message, Toast.LENGTH_SHORT).show();
            });
        }
    }

    private void spawnPowerUp() {
        PowerUpType[] types = PowerUpType.values();
        PowerUpType randomType = types[random.nextInt(types.length)];
        PowerUp powerUp = new PowerUp(randomType);
        powerUps.add(powerUp);
    }

    private void activatePowerUp(PowerUpType type) {
        switch (type) {
            case INVINCIBILITY:
                bird.setInvincible(true);
                mainHandler.post(() -> Toast.makeText(activity, "Invincibility Activated!", Toast.LENGTH_SHORT).show());
                mainHandler.postDelayed(() -> bird.setInvincible(false), 5000); // Active for 5 seconds
                break;
            case SLOW_MOTION:
                AppConstants.PIPE_SPEED /= 2; // Reduce pipe speed
                AppConstants.BACKGROUND_SPEED /= 2;
                mainHandler.post(() -> Toast.makeText(activity, "Slow Motion Activated!", Toast.LENGTH_SHORT).show());
                mainHandler.postDelayed(() -> {
                    AppConstants.PIPE_SPEED *= 2;
                    AppConstants.BACKGROUND_SPEED *= 2;
                }, 5000); // Revert after 5 seconds
                break;
            case SHRINK:
                bird.shrink();
                mainHandler.post(() -> Toast.makeText(activity, "Shrunk!", Toast.LENGTH_SHORT).show());
                mainHandler.postDelayed(() -> bird.resetSize(), 5000); // Revert after 5 seconds
                break;
            case MAGNET:
                bird.setMagnetActive(true);
                mainHandler.post(() -> Toast.makeText(activity, "Magnet Activated!", Toast.LENGTH_SHORT).show());
                mainHandler.postDelayed(() -> bird.setMagnetActive(false), 5000); // Active for 5 seconds
                break;
        }
    }

    private void checkForBirdUnlock() {
        // Example: Unlock a new bird when score reaches 50
        if (score >= 50 && !BirdManager.isBirdUnlocked("bird_unlocked_cool_bird", activity)) {
            BirdManager.unlockBird(R.drawable.bird_frame_2, "bird_unlocked_cool_bird", activity);
            mainHandler.post(() -> Toast.makeText(activity, activity.getString(R.string.new_bird_unlocked), Toast.LENGTH_SHORT).show());
        }
    }

    /**
     * Cleanup resources to prevent memory leaks.
     */
    public void cleanup() {
        // Recycle pause button bitmap
        if (pauseButtonBitmap != null && !pauseButtonBitmap.isRecycled()) {
            pauseButtonBitmap.recycle();
            pauseButtonBitmap = null;
        }
    }
}package com.example.flappybirdgame;

import android.graphics.Bitmap;
import android.graphics.Canvas;

public class Ground {
    public int x = 0, y;
    private Bitmap ground;

    public Ground() {
        // Fetch the preloaded and scaled ground bitmap
        ground = ResourceManager.getInstance(AppConstants.gameActivityContext).getBitmap(R.drawable.ground);
        y = AppConstants.SCREEN_HEIGHT - ground.getHeight();
    }

    public void update() {
        x -= AppConstants.BACKGROUND_SPEED * 2;
        if (x + ground.getWidth() < 0) {
            x = ground.getWidth();
        }
    }

    public void draw(Canvas canvas) {
        canvas.drawBitmap(ground, x, y, null);
    }

    public Bitmap getBitmap() {
        return ground;
    }
}package com.example.flappybirdgame;

import android.os.Bundle;
import android.view.View;
import android.widget.ImageButton;

import androidx.appcompat.app.AppCompatActivity;

public class HelpActivity extends AppCompatActivity {

    private ImageButton backButton;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_help);

        // Initialize back button
        backButton = findViewById(R.id.backButton);

        // Set up back button click listener
        backButton.setOnClickListener(view -> finish());
    }
}package com.example.flappybirdgame;

public class Level {
    private int levelNumber;
    private int pipeSpeed;
    private int gapSize;
    private int targetScore;

    public Level(int levelNumber, int pipeSpeed, int gapSize, int targetScore) {
        this.levelNumber = levelNumber;
        this.pipeSpeed = pipeSpeed;
        this.gapSize = gapSize;
        this.targetScore = targetScore;
    }

    // Getters
    public int getLevelNumber() { return levelNumber; }
    public int getPipeSpeed() { return pipeSpeed; }
    public int getGapSize() { return gapSize; }
    public int getTargetScore() { return targetScore; }
}package com.example.flappybirdgame;
import java.util.ArrayList;

public class LevelManager {
    private ArrayList<Level> levels = new ArrayList<>();
    private int currentLevelIndex = 0;

    public LevelManager() {
        // Define levels
        levels.add(new Level(1, 10, 500, 10));
        levels.add(new Level(2, 12, 450, 20));
        levels.add(new Level(3, 14, 400, 30));
        levels.add(new Level(4, 16, 350, 40));

        // Boss level
        levels.add(new Level(5, 18, 300, 50));
    }

    public Level getCurrentLevel() {
        return levels.get(currentLevelIndex);
    }

    public void advanceToNextLevel() {
        if (currentLevelIndex < levels.size() - 1) {
            currentLevelIndex++;
        }
    }

    public boolean isLastLevel() {
        return currentLevelIndex == levels.size() - 1;
    }
}package com.example.flappybirdgame;

import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

import androidx.appcompat.app.AppCompatActivity;

import java.util.Calendar;

public class MainActivity extends AppCompatActivity {

    private Button playButton;
    private TextView highScoreText;
    private Button settingsButton, helpButton, achievementsButton, characterSelectionButton;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main); // Set the layout resource

        checkDailyReward();

        // Initialize UI elements using findViewById
        playButton = findViewById(R.id.playButton);
        highScoreText = findViewById(R.id.highScoreText);
        settingsButton = findViewById(R.id.settingsButton);
        helpButton = findViewById(R.id.helpButton);
        achievementsButton = findViewById(R.id.achievementsButton);
        characterSelectionButton = findViewById(R.id.characterSelectionButton);

        // Display high score
        SharedPreferences prefs = getSharedPreferences("game", MODE_PRIVATE);
        int highScore = prefs.getInt("highScore", 0);
        highScoreText.setText(getString(R.string.high_score, highScore));

        // Set up the Play button click listener
        playButton.setOnClickListener(view -> {
            Intent intent = new Intent(MainActivity.this, GameActivity.class);
            startActivity(intent);
            // No need to call finish() to allow the user to return to main menu
        });

        // Set up the Settings button click listener
        settingsButton.setOnClickListener(view -> {
            Intent intent = new Intent(MainActivity.this, SettingsActivity.class);
            startActivity(intent);
        });

        // Set up the Help button click listener
        helpButton.setOnClickListener(view -> {
            Intent intent = new Intent(MainActivity.this, HelpActivity.class);
            startActivity(intent);
        });

        // Set up the Achievements button click listener
        achievementsButton.setOnClickListener(view -> {
            Intent intent = new Intent(MainActivity.this, AchievementsActivity.class);
            startActivity(intent);
        });

        // Set up the Character Selection button click listener
        characterSelectionButton.setOnClickListener(view -> {
            Intent intent = new Intent(MainActivity.this, CharacterSelectionActivity.class);
            startActivity(intent);
        });
    }

    private void checkDailyReward() {
        SharedPreferences prefs = getSharedPreferences("game", MODE_PRIVATE);
        long lastLoginTime = prefs.getLong("lastLoginTime", 0);
        int loginStreak = prefs.getInt("loginStreak", 0);
        long currentTime = System.currentTimeMillis();

        if (!isSameDay(lastLoginTime, currentTime)) {
            // Reset or update login streak
            loginStreak = (currentTime - lastLoginTime) <= 24 * 60 * 60 * 1000 ? loginStreak + 1 : 1;
            SharedPreferences.Editor editor = prefs.edit();
            editor.putInt("loginStreak", loginStreak);
            editor.putLong("lastLoginTime", currentTime);
            editor.apply();

            // Reward player (e.g., unlock themes or give other rewards)
            Toast.makeText(this, "Daily Reward! Login Streak: " + loginStreak, Toast.LENGTH_SHORT).show();
        }
    }

    private boolean isSameDay(long time1, long time2) {
        Calendar cal1 = Calendar.getInstance();
        Calendar cal2 = Calendar.getInstance();
        cal1.setTimeInMillis(time1);
        cal2.setTimeInMillis(time2);
        return cal1.get(Calendar.YEAR) == cal2.get(Calendar.YEAR) &&
                cal1.get(Calendar.DAY_OF_YEAR) == cal2.get(Calendar.DAY_OF_YEAR);
    }
}package com.example.flappybirdgame;

import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Rect;

public class Pipe {
    protected int x, y, width, height;
    protected Bitmap pipeTop, pipeBottom;
    protected int gap;
    protected int pipeSpeed = AppConstants.PIPE_SPEED;
    protected boolean scored = false;
    protected int minGap;

    public Pipe() {
        // Fetch preloaded and scaled pipe bitmaps
        pipeTop = ResourceManager.getInstance(AppConstants.gameActivityContext).getBitmap(R.drawable.pipe_top);
        pipeBottom = ResourceManager.getInstance(AppConstants.gameActivityContext).getBitmap(R.drawable.pipe_bottom);

        // Calculate gap based on current level settings
        gap = AppConstants.currentGapSize;
        minGap = (int) (AppConstants.SCREEN_HEIGHT * 0.15); // Set minimum gap
        setGapSize(gap);

        x = AppConstants.SCREEN_WIDTH;
        y = getRandomYPosition();
    }

    protected int getRandomYPosition() {
        int minY = (int) (AppConstants.SCREEN_HEIGHT * 0.1f) - height;
        int maxY = AppConstants.GROUND_Y - gap - height - (int) (AppConstants.SCREEN_HEIGHT * 0.1f);

        if (maxY <= minY) {
            maxY = minY + 1;
        }

        return minY + (int) (Math.random() * (maxY - minY + 1));
    }

    /**
     * Sets the gap size between the top and bottom pipes.
     *
     * @param gapSize The new gap size in pixels.
     */
    public void setGapSize(int gapSize) {
        this.gap = gapSize;
        // Calculate y position based on new gap
        y = getRandomYPosition();
    }

    /**
     * Decreases the gap size by a specified amount.
     *
     * @param amount The amount to decrease the gap size by.
     */
    public void decreaseGap(int amount) {
        setGapSize(this.gap - amount);
    }

    public void update() {
        x -= pipeSpeed;
    }

    public void draw(Canvas canvas) {
        canvas.drawBitmap(pipeTop, x, y, null);
        canvas.drawBitmap(pipeBottom, x, y + height + gap, null);
    }

    public int getWidth() {
        return width;
    }

    public Rect getTopPipeRect() {
        return new Rect(x, y, x + width, y + height);
    }

    public Rect getBottomPipeRect() {
        return new Rect(x, y + height + gap, x + width, y + 2 * height + gap);
    }

    public boolean isOffScreen() {
        return x + width < 0;
    }

    public boolean isScored() {
        return scored;
    }

    public void setScored(boolean scored) {
        this.scored = scored;
    }

    public void resetPosition() {
        x = AppConstants.SCREEN_WIDTH;
        y = getRandomYPosition();
        scored = false;
    }
}package com.example.flappybirdgame;

import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.Rect;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/**
 * Manages the creation, updating, and rendering of pipes within the game.
 */
public class PipeManager {

    private ArrayList<Pipe> pipes;          // List of pipes
    private int pipeSpacing;                // Spacing between pipes in pixels
    private int numberOfPipes;              // Number of initial pipes
    private Resources res;                  // Resources for loading bitmaps
    private LevelManager levelManager;      // Reference to LevelManager
    private boolean isBossLevel = false;    // Flag to indicate boss level
    private int currentGapSize;             // Current gap size between pipes in pixels

    /**
     * Constructor for PipeManager.
     *
     * @param res          The Resources object for loading bitmaps.
     * @param levelManager The LevelManager instance to manage level-related attributes.
     */
    public PipeManager(Resources res, LevelManager levelManager) {
        this.res = res;
        this.levelManager = levelManager;
        this.pipes = new ArrayList<>();
        this.numberOfPipes = 2; // Default number of pipes displayed simultaneously
        this.pipeSpacing = AppConstants.SCREEN_WIDTH / 2; // Default spacing between pipes

        // Determine if it's a boss level based on the current level
        this.isBossLevel = levelManager.isLastLevel();

        // Initialize pipes
        initializePipes();
    }

    /**
     * Initializes or resets the pipe list based on the current level.
     */
    private void initializePipes() {
        pipes.clear();

        Level currentLevel = levelManager.getCurrentLevel();
        currentGapSize = currentLevel.getGapSize();
        AppConstants.PIPE_SPEED = currentLevel.getPipeSpeed();

        // Update boss level flag in case of level change
        isBossLevel = levelManager.isLastLevel();

        for (int i = 0; i < numberOfPipes; i++) {
            Pipe pipe;
            if (isBossLevel) {
                // For boss levels, create special pipes or obstacles
                pipe = new BossPipe(AppConstants.SCREEN_HEIGHT, res);
            } else {
                pipe = new Pipe(AppConstants.SCREEN_HEIGHT, res);
            }
            pipe.setGapSize(currentGapSize); // Set the gap size for the pipe
            pipe.setX(AppConstants.SCREEN_WIDTH + i * pipeSpacing); // Position pipes off-screen to the right
            pipes.add(pipe);
        }
    }

    /**
     * Updates the positions of all pipes and handles the creation of new pipes when old ones go off-screen.
     */
    public void update() {
        List<Pipe> pipesToAdd = new ArrayList<>(); // Temporary list to hold new pipes

        Iterator<Pipe> iterator = pipes.iterator();
        while (iterator.hasNext()) {
            Pipe pipe = iterator.next();
            pipe.update();

            if (pipe.isOffScreen()) {
                iterator.remove(); // Remove the off-screen pipe

                // Create a new pipe based on the current level
                Pipe newPipe;
                if (isBossLevel) {
                    newPipe = new BossPipe(AppConstants.SCREEN_HEIGHT, res);
                } else {
                    newPipe = new Pipe(AppConstants.SCREEN_HEIGHT, res);
                }
                newPipe.setGapSize(currentGapSize); // Set the gap size for the new pipe
                newPipe.setX(getLastPipeX() + pipeSpacing); // Position new pipe based on spacing
                pipesToAdd.add(newPipe); // Add to temporary list
            }
        }

        // Add all new pipes after the iteration to avoid ConcurrentModificationException
        pipes.addAll(pipesToAdd);
    }

    /**
     * Draws all the pipes onto the provided canvas.
     *
     * @param canvas The Canvas object where pipes will be drawn.
     */
    public void draw(Canvas canvas) {
        for (Pipe pipe : pipes) {
            pipe.draw(canvas);
        }
    }

    /**
     * Checks for collisions between the bird and any pipe.
     *
     * @param bird The Bird object to check collisions against.
     * @return True if a collision is detected, false otherwise.
     */
    public boolean checkCollision(Bird bird) {
        if (bird.isInvincible()) {
            return false; // Bird is invincible; no collision
        }

        for (Pipe pipe : pipes) {
            // Retrieve the collision rectangles
            Rect birdRect = bird.getCollisionShape();
            Rect topPipeRect = pipe.getTopPipeRect();
            Rect bottomPipeRect = pipe.getBottomPipeRect();

            // Check for intersection between bird and pipes
            if (Rect.intersects(birdRect, topPipeRect) || Rect.intersects(birdRect, bottomPipeRect)) {
                return true; // Collision detected
            }
        }
        return false;
    }

    /**
     * Checks if the bird has successfully passed any pipe, incrementing the score accordingly.
     *
     * @param bird The Bird object to check against.
     * @return True if the bird has passed a pipe and the score should be incremented, false otherwise.
     */
    public boolean checkForScore(Bird bird) {
        for (Pipe pipe : pipes) {
            if (!pipe.isScored() && pipe.getX() + pipe.getWidth() < bird.getX()) {
                pipe.setScored(true); // Mark the pipe as scored
                return true; // Successful pass
            }
        }
        return false;
    }

    /**
     * Decreases the gap size between the top and bottom pipes by a specified amount.
     *
     * @param amount The amount in pixels to decrease the gap size by.
     */
    public void decreaseGap(int amount) {
        currentGapSize -= amount;
        if (currentGapSize < AppConstants.SCREEN_HEIGHT * 0.15) {
            currentGapSize = (int) (AppConstants.SCREEN_HEIGHT * 0.15); // Minimum gap size
        }
        for (Pipe pipe : pipes) {
            pipe.setGapSize(currentGapSize); // Update gap size for all existing pipes
        }
    }

    /**
     * Sets the gap size between pipes, used when changing levels.
     *
     * @param gapSize The new gap size in pixels.
     */
    public void setGapSize(int gapSize) {
        currentGapSize = gapSize;
        for (Pipe pipe : pipes) {
            pipe.setGapSize(gapSize); // Update gap size for all existing pipes
        }
    }

    /**
     * Retrieves the X-coordinate of the last pipe in the list.
     *
     * @return The X-coordinate of the last pipe, or the screen width if no pipes exist.
     */
    private int getLastPipeX() {
        if (pipes.size() > 0) {
            return pipes.get(pipes.size() - 1).getX();
        } else {
            return AppConstants.SCREEN_WIDTH;
        }
    }

    /**
     * Updates the pipe settings when advancing to the next level.
     */
    public void onLevelChange() {
        // Update the boss level flag based on the new current level
        isBossLevel = levelManager.isLastLevel();
        initializePipes(); // Re-initialize pipes with new settings
    }
}package com.example.flappybirdgame;

import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Rect;

public class PowerUp {
    private int x, y, width, height;
    private Bitmap bitmap;
    private PowerUpType type;
    private Rect collisionRect;
    private int speed = AppConstants.PIPE_SPEED; // Move at the same speed as pipes
    private boolean isActive = false;

    public PowerUp(PowerUpType type) {
        this.type = type;

        // Fetch the appropriate bitmap based on the power-up type
        switch (type) {
            case INVINCIBILITY:
                bitmap = ResourceManager.getInstance(AppConstants.gameActivityContext).getBitmap(R.drawable.powerup_invincibility);
                break;
            case SLOW_MOTION:
                bitmap = ResourceManager.getInstance(AppConstants.gameActivityContext).getBitmap(R.drawable.powerup_slow_motion);
                break;
            case SHRINK:
                bitmap = ResourceManager.getInstance(AppConstants.gameActivityContext).getBitmap(R.drawable.powerup_shrink);
                break;
            case MAGNET:
                bitmap = ResourceManager.getInstance(AppConstants.gameActivityContext).getBitmap(R.drawable.powerup_magnet);
                break;
        }

        // Set dimensions based on preloaded bitmap
        width = bitmap.getWidth();
        height = bitmap.getHeight();

        x = AppConstants.SCREEN_WIDTH;
        y = getRandomYPosition();
        collisionRect = new Rect(x, y, x + width, y + height);
    }

    private int getRandomYPosition() {
        int minY = 0;
        int maxY = AppConstants.GROUND_Y - height;
        return minY + (int) (Math.random() * ((maxY - minY) + 1));
    }

    public void update() {
        x -= speed;
        collisionRect.set(x, y, x + width, y + height);
    }

    public void draw(Canvas canvas) {
        canvas.drawBitmap(bitmap, x, y, null);
    }

    public Rect getCollisionRect() {
        return collisionRect;
    }

    public PowerUpType getType() {
        return type;
    }

    public boolean isOffScreen() {
        return x + width < 0;
    }

    // Getters and Setters for Position
    public int getX() {
        return x;
    }

    public int getY() {
        return y;
    }

    public void setX(int x) {
        this.x = x;
        collisionRect.left = x;
        collisionRect.right = x + width;
    }

    public void setY(int y) {
        this.y = y;
        collisionRect.top = y;
        collisionRect.bottom = y + height;
    }
}package com.example.flappybirdgame;

public enum PowerUpType {
    INVINCIBILITY,
    SLOW_MOTION,
    SHRINK,
    MAGNET
}package com.example.flappybirdgame;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.util.SparseArray;

public class ResourceManager {
    private static ResourceManager instance;
    private SparseArray<Bitmap> bitmapCache;
    private Context context;

    private ResourceManager(Context context) {
        this.context = context.getApplicationContext();
        bitmapCache = new SparseArray<>();
        loadBitmaps();
    }

    public static synchronized ResourceManager getInstance(Context context) {
        if (instance == null) {
            instance = new ResourceManager(context);
        }
        return instance;
    }

    private void loadBitmaps() {
        // Load all necessary bitmaps here and add to cache
        // Example:
        bitmapCache.put(R.drawable.background, decodeAndScale(R.drawable.background, AppConstants.SCREEN_WIDTH, AppConstants.SCREEN_HEIGHT));
        bitmapCache.put(R.drawable.ground, decodeAndScale(R.drawable.ground, AppConstants.SCREEN_WIDTH, (int) (AppConstants.SCREEN_HEIGHT * 0.2f)));

        // Load pipe bitmaps for default theme
        bitmapCache.put(R.drawable.pipe_top, decodeAndScale(R.drawable.pipe_top, (int) (AppConstants.SCREEN_WIDTH * 0.15f),
                (int) ((AppConstants.SCREEN_WIDTH * 0.15f) * ((float) BitmapFactory.decodeResource(context.getResources(), R.drawable.pipe_top).getHeight() /
                        BitmapFactory.decodeResource(context.getResources(), R.drawable.pipe_top).getWidth()))));

        bitmapCache.put(R.drawable.pipe_bottom, decodeAndScale(R.drawable.pipe_bottom, (int) (AppConstants.SCREEN_WIDTH * 0.15f),
                (int) ((AppConstants.SCREEN_WIDTH * 0.15f) * ((float) BitmapFactory.decodeResource(context.getResources(), R.drawable.pipe_bottom).getHeight() /
                        BitmapFactory.decodeResource(context.getResources(), R.drawable.pipe_bottom).getWidth()))));

        // Load bird frames
        bitmapCache.put(R.drawable.bird_frame_1, decodeAndScale(R.drawable.bird_frame_1,
                (int) (AppConstants.SCREEN_WIDTH * 0.1f),
                (int) ((AppConstants.SCREEN_WIDTH * 0.1f) * ((float) BitmapFactory.decodeResource(context.getResources(), R.drawable.bird_frame_1).getHeight() /
                        BitmapFactory.decodeResource(context.getResources(), R.drawable.bird_frame_1).getWidth()))));
        bitmapCache.put(R.drawable.bird_frame_2, decodeAndScale(R.drawable.bird_frame_2,
                (int) (AppConstants.SCREEN_WIDTH * 0.1f),
                (int) ((AppConstants.SCREEN_WIDTH * 0.1f) * ((float) BitmapFactory.decodeResource(context.getResources(), R.drawable.bird_frame_2).getHeight() /
                        BitmapFactory.decodeResource(context.getResources(), R.drawable.bird_frame_2).getWidth()))));
        bitmapCache.put(R.drawable.bird_frame_3, decodeAndScale(R.drawable.bird_frame_3,
                (int) (AppConstants.SCREEN_WIDTH * 0.1f),
                (int) ((AppConstants.SCREEN_WIDTH * 0.1f) * ((float) BitmapFactory.decodeResource(context.getResources(), R.drawable.bird_frame_3).getHeight() /
                        BitmapFactory.decodeResource(context.getResources(), R.drawable.bird_frame_3).getWidth()))));

        // Load power-up bitmaps
        bitmapCache.put(R.drawable.powerup_invincibility, decodeAndScale(R.drawable.powerup_invincibility,
                (int) (AppConstants.SCREEN_WIDTH * 0.05f),
                (int) ((AppConstants.SCREEN_WIDTH * 0.05f) * ((float) BitmapFactory.decodeResource(context.getResources(), R.drawable.powerup_invincibility).getHeight() /
                        BitmapFactory.decodeResource(context.getResources(), R.drawable.powerup_invincibility).getWidth()))));
        bitmapCache.put(R.drawable.powerup_slow_motion, decodeAndScale(R.drawable.powerup_slow_motion,
                (int) (AppConstants.SCREEN_WIDTH * 0.05f),
                (int) ((AppConstants.SCREEN_WIDTH * 0.05f) * ((float) BitmapFactory.decodeResource(context.getResources(), R.drawable.powerup_slow_motion).getHeight() /
                        BitmapFactory.decodeResource(context.getResources(), R.drawable.powerup_slow_motion).getWidth()))));
        bitmapCache.put(R.drawable.powerup_shrink, decodeAndScale(R.drawable.powerup_shrink,
                (int) (AppConstants.SCREEN_WIDTH * 0.05f),
                (int) ((AppConstants.SCREEN_WIDTH * 0.05f) * ((float) BitmapFactory.decodeResource(context.getResources(), R.drawable.powerup_shrink).getHeight() /
                        BitmapFactory.decodeResource(context.getResources(), R.drawable.powerup_shrink).getWidth()))));
        bitmapCache.put(R.drawable.powerup_magnet, decodeAndScale(R.drawable.powerup_magnet,
                (int) (AppConstants.SCREEN_WIDTH * 0.05f),
                (int) ((AppConstants.SCREEN_WIDTH * 0.05f) * ((float) BitmapFactory.decodeResource(context.getResources(), R.drawable.powerup_magnet).getHeight() /
                        BitmapFactory.decodeResource(context.getResources(), R.drawable.powerup_magnet).getWidth()))));

        // Load additional bitmaps as needed
        // ...
    }

    private Bitmap decodeAndScale(int resourceId, int width, int height) {
        Bitmap original = BitmapFactory.decodeResource(context.getResources(), resourceId);
        return Bitmap.createScaledBitmap(original, width, height, false);
    }

    public Bitmap getBitmap(int resourceId) {
        return bitmapCache.get(resourceId);
    }

    public void recycleBitmaps() {
        for(int i = 0; i < bitmapCache.size(); i++) {
            Bitmap bmp = bitmapCache.valueAt(i);
            if (bmp != null && !bmp.isRecycled()) {
                bmp.recycle();
            }
        }
        bitmapCache.clear();
    }
}package com.example.flappybirdgame;

import android.content.Intent;
import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.net.Uri;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.SeekBar;
import android.widget.Spinner;
import android.widget.Switch;
import android.widget.Toast;

import androidx.appcompat.app.AppCompatActivity;

import com.google.android.material.slider.Slider;

import java.util.Locale;

/**
 * Activity to handle game settings like sound, difficulty, sensitivity, controls, and language.
 */
public class SettingsActivity extends AppCompatActivity {

    private Switch soundSwitch;
    private Slider difficultySlider;
    private SeekBar sensitivitySeekBar;
    private Switch invertedControlsSwitch;
    private Spinner languageSpinner;
    private Button privacyPolicyButton;

    // Flag to prevent OnItemSelected from triggering on initial setup
    private boolean isSpinnerInitialized = false;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_settings);

        // Initialize UI elements using findViewById
        soundSwitch = findViewById(R.id.soundSwitch);
        difficultySlider = findViewById(R.id.difficultySlider);
        sensitivitySeekBar = findViewById(R.id.sensitivitySeekBar);
        invertedControlsSwitch = findViewById(R.id.invertedControlsSwitch);
        languageSpinner = findViewById(R.id.languageSpinner);
        privacyPolicyButton = findViewById(R.id.privacyPolicyButton);

        // Load settings
        SharedPreferences prefs = getSharedPreferences("game", MODE_PRIVATE);
        boolean soundEnabled = prefs.getBoolean("soundEnabled", true);
        int difficulty = prefs.getInt("difficulty", 1);
        int sensitivity = prefs.getInt("sensitivity", 5);
        boolean invertedControls = prefs.getBoolean("invertedControls", false);
        String language = prefs.getString("language", "en");

        soundSwitch.setChecked(soundEnabled);
        difficultySlider.setValue(difficulty);
        sensitivitySeekBar.setProgress(sensitivity);
        invertedControlsSwitch.setChecked(invertedControls);

        // Set up language spinner
        String[] languages = {getString(R.string.english), getString(R.string.persian)}; // English, Persian
        ArrayAdapter<String> adapter = new ArrayAdapter<>(this, android.R.layout.simple_spinner_dropdown_item, languages);
        languageSpinner.setAdapter(adapter);

        // Determine spinner position based on saved language
        int spinnerPosition = language.equals("en") ? 0 : 1;
        languageSpinner.setSelection(spinnerPosition);
        isSpinnerInitialized = true; // Spinner is now initialized

        // Handle changes to the sound switch
        soundSwitch.setOnCheckedChangeListener((buttonView, isChecked) -> {
            SharedPreferences.Editor editor = prefs.edit();
            editor.putBoolean("soundEnabled", isChecked);
            editor.apply();
            AppConstants.SOUND_ENABLED = isChecked;
            Toast.makeText(this, isChecked ? "Sound Enabled" : "Sound Disabled", Toast.LENGTH_SHORT).show();
        });

        // Handle changes to the difficulty slider
        difficultySlider.addOnChangeListener((Slider slider, float value, boolean fromUser) -> {
            if (fromUser) { // Only respond to user-initiated changes
                int difficultyLevel = (int) value;
                SharedPreferences.Editor editor = prefs.edit();
                editor.putInt("difficulty", difficultyLevel);
                editor.apply();
                AppConstants.DIFFICULTY = difficultyLevel;
                Toast.makeText(this, "Difficulty set to " + difficultyLevel, Toast.LENGTH_SHORT).show();
            }
        });

        // Handle changes to the sensitivity seekbar
        sensitivitySeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
            @Override
            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
                if (fromUser) { // Only respond to user-initiated changes
                    SharedPreferences.Editor editor = prefs.edit();
                    editor.putInt("sensitivity", progress);
                    editor.apply();
                    AppConstants.SENSITIVITY = progress;
                    Toast.makeText(SettingsActivity.this, "Sensitivity set to " + progress, Toast.LENGTH_SHORT).show();
                }
            }

            @Override
            public void onStartTrackingTouch(SeekBar seekBar) {
                // Not needed
            }

            @Override
            public void onStopTrackingTouch(SeekBar seekBar) {
                // Not needed
            }
        });

        // Handle changes to the inverted controls switch
        invertedControlsSwitch.setOnCheckedChangeListener((buttonView, isChecked) -> {
            SharedPreferences.Editor editor = prefs.edit();
            editor.putBoolean("invertedControls", isChecked);
            editor.apply();
            AppConstants.INVERTED_CONTROLS = isChecked;
            Toast.makeText(this, isChecked ? "Controls Inverted" : "Controls Normal", Toast.LENGTH_SHORT).show();
        });

        // Handle language selection
        languageSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
            @Override
            public void onItemSelected(AdapterView<?> adapterView, View view, int position, long id) {
                if (!isSpinnerInitialized) return; // Ignore initial selection

                String selectedLanguage = position == 0 ? "en" : "fa"; // "en" for English, "fa" for Persian
                if (!AppConstants.LANGUAGE.equals(selectedLanguage)) {
                    setLocale(selectedLanguage);

                    // Save language preference
                    SharedPreferences.Editor editor = prefs.edit();
                    editor.putString("language", selectedLanguage);
                    editor.apply();
                    AppConstants.LANGUAGE = selectedLanguage;

                    Toast.makeText(SettingsActivity.this, "Language set to " + languages[position], Toast.LENGTH_SHORT).show();
                }
            }

            @Override
            public void onNothingSelected(AdapterView<?> adapterView) {
                // Not needed
            }
        });

        // Handle privacy policy button click
        privacyPolicyButton.setOnClickListener(v -> {
            Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("https://your_privacy_policy_url.com"));
            startActivity(browserIntent);
        });
    }

    /**
     * Sets the application's locale and restarts the activity to apply changes.
     *
     * @param lang The language code (e.g., "en" for English, "fa" for Persian).
     */
    private void setLocale(String lang) {
        Locale locale = new Locale(lang);
        Locale.setDefault(locale);

        Resources resources = getResources();
        Configuration config = resources.getConfiguration();
        config.setLocale(locale);

        resources.updateConfiguration(config, resources.getDisplayMetrics());

        // Restart the activity to apply changes
        Intent intent = getIntent();
        finish();
        startActivity(intent);
    }
}package com.example.flappybirdgame;

public class Theme {
    public int birdResourceId; // We'll handle different birds separately
    public int backgroundResourceId;
    public int pipeTopResourceId;
    public int pipeBottomResourceId;

    public Theme(int backgroundResourceId, int pipeTopResourceId, int pipeBottomResourceId) {
        this.backgroundResourceId = backgroundResourceId;
        this.pipeTopResourceId = pipeTopResourceId;
        this.pipeBottomResourceId = pipeBottomResourceId;
    }
}<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <!-- Achievements Title -->
    <TextView
        android:id="@+id/achievementsTitle"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/achievements"
        android:textSize="32sp"
        android:textColor="@color/colorPrimaryDark"
        android:textStyle="bold"
        android:fontFamily="@font/poppins_bold"
        android:layout_marginTop="16dp"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"/>

    <!-- Achievements List -->
    <ListView
        android:id="@+id/achievementsListView"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:divider="@android:color/darker_gray"
        android:dividerHeight="1dp"
        app:layout_constraintTop_toBottomOf="@id/achievementsTitle"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"/>

</androidx.constraintlayout.widget.ConstraintLayout><?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <!-- Character Selection Title -->
    <TextView
        android:id="@+id/characterSelectionTitle"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/character_selection"
        android:textSize="32sp"
        android:textColor="@color/colorPrimaryDark"
        android:textStyle="bold"
        android:fontFamily="@font/poppins_bold"
        android:layout_gravity="center_horizontal"
        android:layout_marginTop="16dp"/>

    <!-- Bird GridView -->
    <GridView
        android:id="@+id/birdGridView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:numColumns="3"
        android:verticalSpacing="16dp"
        android:horizontalSpacing="16dp"
        android:padding="16dp"
        android:stretchMode="columnWidth"
        android:gravity="center"/>

</LinearLayout><?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <!-- Back Button -->
    <ImageButton
        android:id="@+id/backButton"
        android:layout_width="36dp"
        android:layout_height="36dp"
        android:src="@android:drawable/ic_delete"
        android:contentDescription="Back"
        android:background="?attr/selectableItemBackgroundBorderless"
        app:tint="@color/colorPrimaryDark"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        android:layout_marginTop="16dp"
        android:layout_marginStart="16dp"/>

    <!-- Help Title -->
    <TextView
        android:id="@+id/helpTitle"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="How to Play"
        android:textSize="32sp"
        android:textColor="@color/colorPrimaryDark"
        android:textStyle="bold"
        android:fontFamily="@font/poppins_bold"
        android:layout_marginTop="16dp"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintStart_toEndOf="@id/backButton"
        app:layout_constraintEnd_toEndOf="parent"/>

    <!-- Help Content -->
    <ScrollView
        android:id="@+id/helpScrollView"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_constraintTop_toBottomOf="@id/helpTitle"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        android:layout_marginTop="16dp"
        android:layout_marginStart="16dp"
        android:layout_marginEnd="16dp"
        app:layout_constraintBottom_toBottomOf="parent"
        android:layout_marginBottom="16dp">

        <TextView
            android:id="@+id/helpContent"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@string/help_text"
            android:textColor="@android:color/black"
            android:textSize="16sp"
            android:fontFamily="@font/poppins_regular"/>

    </ScrollView>

</androidx.constraintlayout.widget.ConstraintLayout><?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <!-- Background Image -->
    <ImageView
        android:id="@+id/backgroundImage"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:src="@drawable/background"
    android:scaleType="centerCrop"
    app:layout_constraintTop_toTopOf="parent"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintEnd_toEndOf="parent" />

    <!-- Game Title -->
    <TextView
        android:id="@+id/gameTitle"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/app_name"
        android:textSize="48sp"
        android:textColor="@android:color/white"
        android:textStyle="bold"
        android:fontFamily="sans-serif-medium"
        android:elevation="5dp"
        android:layout_marginTop="32dp"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"/>

    <!-- High Score Text -->
    <TextView
        android:id="@+id/highScoreText"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/high_score"
        android:textSize="20sp"
        android:textColor="@android:color/white"
        android:fontFamily="sans-serif"
        android:layout_marginTop="8dp"
        app:layout_constraintTop_toBottomOf="@id/gameTitle"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"/>

    <!-- Play Button -->
    <com.google.android.material.button.MaterialButton
        android:id="@+id/playButton"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:text="@string/play"
        android:textSize="18sp"
        android:textColor="@android:color/white"
        android:fontFamily="sans-serif-medium"
        android:backgroundTint="@color/colorPrimary"
    app:cornerRadius="12dp"
    app:icon="@drawable/ic_play_arrow"
    app:iconTint="@android:color/white"
    app:iconPadding="8dp"
    app:iconGravity="textStart"
    android:layout_marginTop="24dp"
    app:layout_constraintTop_toBottomOf="@id/highScoreText"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintWidth_percent="0.8"/>

    <!-- Settings Button -->
    <com.google.android.material.button.MaterialButton
        android:id="@+id/settingsButton"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:text="@string/settings"
        android:textSize="18sp"
        android:textColor="@android:color/white"
        android:fontFamily="sans-serif-medium"
        android:backgroundTint="@color/colorPrimaryDark"
    app:cornerRadius="12dp"
    app:icon="@android:drawable/ic_menu_manage"
    app:iconTint="@android:color/white"
    app:iconPadding="8dp"
    app:iconGravity="textStart"
    android:layout_marginTop="16dp"
    app:layout_constraintTop_toBottomOf="@id/playButton"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintWidth_percent="0.8"/>

    <!-- Help Button -->
    <com.google.android.material.button.MaterialButton
        android:id="@+id/helpButton"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:text="@string/help"
        android:textSize="18sp"
        android:textColor="@android:color/white"
        android:fontFamily="sans-serif-medium"
        android:backgroundTint="@color/colorAccent"
    app:cornerRadius="12dp"
    app:icon="@android:drawable/ic_menu_help"
    app:iconTint="@android:color/white"
    app:iconPadding="8dp"
    app:iconGravity="textStart"
    android:layout_marginTop="16dp"
    app:layout_constraintTop_toBottomOf="@id/settingsButton"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintWidth_percent="0.8"/>

    <!-- Achievements Button -->
    <com.google.android.material.button.MaterialButton
        android:id="@+id/achievementsButton"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:text="@string/achievements"
        android:textSize="18sp"
        android:textColor="@android:color/white"
        android:fontFamily="sans-serif-medium"
        android:backgroundTint="@color/colorPrimaryVariant"
    app:cornerRadius="12dp"
    app:icon="@drawable/ic_trophy"
    app:iconTint="@android:color/white"
    app:iconPadding="8dp"
    app:iconGravity="textStart"
    android:layout_marginTop="16dp"
    app:layout_constraintTop_toBottomOf="@id/helpButton"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintWidth_percent="0.8"/>

    <!-- Character Selection Button -->
    <com.google.android.material.button.MaterialButton
        android:id="@+id/characterSelectionButton"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:text="@string/character_selection"
        android:textSize="18sp"
        android:textColor="@android:color/white"
        android:fontFamily="sans-serif-medium"
        android:backgroundTint="@color/colorSecondary"
    app:cornerRadius="12dp"
    app:icon="@drawable/ic_person1"
    app:iconTint="@android:color/white"
    app:iconPadding="8dp"
    app:iconGravity="textStart"
    android:layout_marginTop="16dp"
    app:layout_constraintTop_toBottomOf="@id/achievementsButton"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintWidth_percent="0.8"/>

</androidx.constraintlayout.widget.ConstraintLayout><?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:fillViewport="true">

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:padding="16dp">

        <!-- Settings Title -->
        <TextView
            android:id="@+id/settingsTitle"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/settings"
            android:textSize="32sp"
            android:textColor="@color/colorPrimaryDark"
            android:textStyle="bold"
            android:fontFamily="@font/poppins_bold"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintStart_toStartOf="parent"/>

        <!-- Sound Setting -->
        <TextView
            android:id="@+id/soundLabel"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/sound"
            android:textSize="18sp"
            android:textColor="@android:color/black"
            android:fontFamily="@font/poppins_medium"
            android:layout_marginTop="32dp"
            app:layout_constraintTop_toBottomOf="@id/settingsTitle"
            app:layout_constraintStart_toStartOf="parent"/>

        <Switch
            android:id="@+id/soundSwitch"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:checked="true"
            app:layout_constraintTop_toTopOf="@id/soundLabel"
            app:layout_constraintBottom_toBottomOf="@id/soundLabel"
            app:layout_constraintEnd_toEndOf="parent"/>

        <!-- Difficulty Setting -->
        <TextView
            android:id="@+id/difficultyLabel"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/difficulty"
            android:textSize="18sp"
            android:textColor="@android:color/black"
            android:fontFamily="@font/poppins_medium"
            android:layout_marginTop="32dp"
            app:layout_constraintTop_toBottomOf="@id/soundLabel"
            app:layout_constraintStart_toStartOf="parent"/>

        <com.google.android.material.slider.Slider
            android:id="@+id/difficultySlider"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:value="1"
            android:valueFrom="1"
            android:valueTo="3"
            android:stepSize="1"
            android:theme="@style/Widget.MaterialComponents.Slider"
            app:layout_constraintTop_toBottomOf="@id/difficultyLabel"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintEnd_toEndOf="parent"/>

        <TextView
            android:id="@+id/difficultyDescription"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/difficulty_description"
            android:textSize="14sp"
            android:textColor="@android:color/darker_gray"
            android:fontFamily="@font/poppins_regular"
            android:layout_marginTop="8dp"
            app:layout_constraintTop_toBottomOf="@id/difficultySlider"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintEnd_toEndOf="parent"/>

        <!-- Sensitivity Setting -->
        <TextView
            android:id="@+id/sensitivityLabel"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/sensitivity"
            android:textSize="18sp"
            android:textColor="@android:color/black"
            android:fontFamily="@font/poppins_medium"
            android:layout_marginTop="32dp"
            app:layout_constraintTop_toBottomOf="@id/difficultyDescription"
            app:layout_constraintStart_toStartOf="parent"/>

        <SeekBar
            android:id="@+id/sensitivitySeekBar"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:max="10"
            android:progress="5"
            app:layout_constraintTop_toBottomOf="@id/sensitivityLabel"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintEnd_toEndOf="parent"/>

        <!-- Inverted Controls Setting -->
        <TextView
            android:id="@+id/invertedControlsLabel"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/invert_controls"
            android:textSize="18sp"
            android:textColor="@android:color/black"
            android:fontFamily="@font/poppins_medium"
            android:layout_marginTop="32dp"
            app:layout_constraintTop_toBottomOf="@id/sensitivitySeekBar"
            app:layout_constraintStart_toStartOf="parent"/>

        <Switch
            android:id="@+id/invertedControlsSwitch"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            app:layout_constraintTop_toTopOf="@id/invertedControlsLabel"
            app:layout_constraintBottom_toBottomOf="@id/invertedControlsLabel"
            app:layout_constraintEnd_toEndOf="parent"/>

        <!-- Language Setting -->
        <TextView
            android:id="@+id/languageLabel"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/language"
            android:textSize="18sp"
            android:textColor="@android:color/black"
            android:fontFamily="@font/poppins_medium"
            android:layout_marginTop="32dp"
            app:layout_constraintTop_toBottomOf="@id/invertedControlsLabel"
            app:layout_constraintStart_toStartOf="parent"/>

        <Spinner
            android:id="@+id/languageSpinner"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            app:layout_constraintTop_toTopOf="@id/languageLabel"
            app:layout_constraintBottom_toBottomOf="@id/languageLabel"
            app:layout_constraintEnd_toEndOf="parent"/>

        <!-- Privacy Policy Button -->
        <Button
            android:id="@+id/privacyPolicyButton"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/privacy_policy"
            android:layout_marginTop="32dp"
            app:layout_constraintTop_toBottomOf="@id/languageLabel"
            app:layout_constraintStart_toStartOf="parent"/>

    </androidx.constraintlayout.widget.ConstraintLayout>

</ScrollView><?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.flappybirdgame">

    <!-- Specify minimum and target SDK versions -->
    <uses-sdk
        android:minSdkVersion="21"
        android:targetSdkVersion="33" />

    <!-- Permissions -->
    <uses-permission android:name="android.permission.INTERNET" /> <!-- If you have internet features -->

    <application
        android:allowBackup="true"
        android:dataExtractionRules="@xml/data_extraction_rules"
        android:fullBackupContent="@xml/backup_rules"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.FlappyBirdGame">

        <!-- Main Activity - Launcher -->
        <activity
            android:name=".MainActivity"
            android:exported="true"
            android:screenOrientation="portrait"
            android:theme="@style/Theme.FlappyBirdGame.NoActionBar">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <!-- Game Activity -->
        <activity
            android:name=".GameActivity"
            android:exported="false"
            android:screenOrientation="portrait"
            android:theme="@style/Theme.FlappyBirdGame">
        </activity>

        <!-- Help Activity -->
        <activity
            android:name=".HelpActivity"
            android:exported="false"
            android:screenOrientation="portrait"
            android:theme="@style/Theme.FlappyBirdGame.NoActionBar">
        </activity>

        <!-- Settings Activity -->
        <activity
            android:name=".SettingsActivity"
            android:exported="false"
            android:screenOrientation="portrait"
            android:theme="@style/Theme.FlappyBirdGame.NoActionBar">
        </activity>

        <!-- Achievements Activity -->
        <activity
            android:name=".AchievementsActivity"
            android:exported="false"
            android:screenOrientation="portrait"
            android:theme="@style/Theme.FlappyBirdGame.NoActionBar">
        </activity>

        <!-- Character Selection Activity -->
        <activity
            android:name=".CharacterSelectionActivity"
            android:exported="false"
            android:screenOrientation="portrait"
            android:theme="@style/Theme.FlappyBirdGame.NoActionBar">
        </activity>

    </application>

</manifest>