القائمة الرئيسية

الصفحات

كيفية برمجة لعبة إطلاق نار من الأعلى إلى الأسفل باستخدام AIDE

تطوير ألعاب Android، ألعاب Android، LibGDX، AIDE، لعبة إطلاق نار، لعبة ثنائية الأبعاد، برمجة ألعاب، دروس ألعاب، إعدادات اللعبة، نشر تطبيقات Android، واجهة مستخدم UI، رسومات ألعاب، تحكم باللمس، حركة اللاعب، حركة العدو، إطلاق نار، اصطدامات، تجميع نقاط، حفظ البيانات، شاشة الإعدادات، شاشة حول اللعبة، قائمة رئيسية، شاشة النهاية، توقيع APK، كيفية تطوير لعبة Android باستخدام AIDE و LibGDX، دليل شامل لإنشاء لعبة Top-Down Shooter على Android، إضافة شاشة إعدادات إلى لعبة Android باستخدام LibGDX، إنشاء واجهة مستخدم قابلة للتخصيص في LibGDX باستخدام Skin، حفظ واستعادة إعدادات اللعبة في Android، برمجة حركة اللاعب والأعداء في لعبة ثنائية الأبعاد، تنفيذ نظام إطلاق نار باللمس في ألعاب Android، معالجة الاصطدامات بين العناصر في ألعاب LibGDX، إضافة نظام تجميع نقاط إلى لعبة Android، خطوات نشر تطبيق Android تم تطويره باستخدام AIDE، إنشاء شاشة "حول اللعبة" لعرض معلومات التطبيق، الانتقال بين شاشات اللعبة المختلفة في LibGDX، استخدام Stage و Skin لإنشاء واجهات مستخدم في LibGDX، توقيع تطبيق Android قبل نشره على متجر Google Play، تطوير ألعاب Android، AIDE، LibGDX، ألعاب ثنائية الأبعاد، Top-Down Shooter، حركة اللاعب، إطلاق النار، الاصطدامات، تجميع النقاط، حفظ البيانات، نشر التطبيق، برمجة الألعاب، تصميم الألعاب، AIDE Android، تطوير ألعاب Android، ألعاب ثنائية الأبعاد، Top-Down Shooter، إطلاق نار من الأعلى، LibGDX، Java، واجهة المستخدم، التحكم باللمس، حركة اللاعب، حركة العدو، إطلاق النار، الاصطدامات، تجميع النقاط، حفظ البيانات، SharedPreferences، نشر التطبيق، باستخدام AIDE على نظام Android، برنامج صنع الألعاب 3d على الاندرويد، إطلاق النار من الأعلى إلى الأسفل (Top-Down Shooter) باستخدام AIDE على نظام Android، AIDE على نظام Android، إنشاء لعبة إطلاق نار من الأعلى إلى الأسفل باستخدام AIDE على نظام Android،How to create a top-down shooter game on Android using AIDE and LibGDX، كيفية برمجة لعبة إطلاق نار من الأعلى إلى الأسفل على باستخدام AIDE، كيفية إنشاء لعبة إطلاق نار من الأعلى إلى الأسفل على Android باستخدام AIDE و LibGDX، How to code a top-down shooter game on Android using AIDE and LibGDX، كيفية برمجة لعبة إطلاق نار من الأعلى إلى الأسفل على باستخدام AIDE، How to code top-down shooter game in AIDE، LibGDX، كيفية برمجة لعبة إطلاق نار من الأعلى إلى الأسفل على باستخدام AIDE، ألعاب ثنائية الأبعاد، Top-Down Shooter، كيفية تطوير لعبة Android باستخدام AIDE و LibGDX،



كيفية برمجة لعبة إطلاق نار من الأعلى إلى الأسفل باستخدام AIDE



انطلق في مغامرة تطوير ألعاب Android مثيرة لإنشاء لعبة ثنائية الأبعاد حركية من نوع
 Top-Down Shooter مباشرة على جهازك باستخدام بيئة التطوير المتكاملة AIDE Android.
 يمثل هذا الدليل المفصل نقطة انطلاق لاستكشاف عالم إنشاء الألعاب،
 حيث سنستخدم مكتبة LibGDX القوية لتسهيل عملية الرسم، وإدارة المدخلات، وتشغيل الصوت. 
بينما يتطلب بناء لعبة إطلاق نار من الأعلى كاملة الميزات رحلة برمجية معمقة تتجاوز
 حدود هذا المقال الواحد، سنسلط الضوء على الخطوات الأساسية ونقدم أكوادًا
 جوهرية لتوجيهك خلال مراحل إنشاء واجهة المستخدم، وتنفيذ التحكم باللمس السلس،
 وبرمجة حركة اللاعب الديناميكية، وإضافة حركة العدو الذكية، وتنفيذ آلية إطلاق النار، 
واكتشاف الاصطدامات، وتنفيذ نظام تجميع النقاط، وآليات حفظ البيانات باستخدام 
SharedPreferences، وصولًا إلى الخطوات الأولية نحو نشر التطبيق. 
استعد للانغماس في عالم Java و LibGDX لإنشاء لعبتك الخاصة!
* ملاحظة هامة: سنستخدم مكتبة LibGDX لتسهيل إنشاء الرسومات والمدخلات
 والصوت في اللعبة. تأكد من إضافة تبعيات LibGDX إلى مشروع AIDE
 (عادةً عبر Gradle إذا كان AIDE يدعم ذلك، أو يدويًا بإضافة ملفات JAR).


خطوات برمجة لعبة إطلاق نار باستخدام AIDE على الاندرويد 



الخطوات الأساسية:

1. تهيئة مشروع AIDE وإعداد LibGDX:

- إنشاء مشروع جديد في AIDE: اختر مشروع Java أو LibGDX إذا كان متاحًا كخيار.
- إضافة LibGDX: إذا لم يكن LibGDX مدمجًا، ستحتاج إلى إضافة مكتبات 
LibGDX JAR إلى مشروعك. يمكنك تنزيلها من موقع LibGDX الرسمي 
وإضافتها كملفات JAR خارجية في AIDE.

2. إنشاء واجهة المستخدم الأساسية (شاشة اللعبة):

* كود (GameScreen.java - نقطة الدخول الرئيسية):
Java




package com.example.topdownshooter.screens;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Screen;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.math.MathUtils;
import com.badlogic.gdx.math.Rectangle;
import com.badlogic.gdx.utils.ScreenUtils;
import com.example.topdownshooter.Bullet;
import com.example.topdownshooter.Enemy;
import com.example.topdownshooter.MainGame;
import com.example.topdownshooter.Player;

public class GameScreen implements Screen {
    final MainGame game;
    SpriteBatch batch;
    Player player;
    Enemy enemy;
    int score = 0;
    BitmapFont font;

    public GameScreen(final MainGame game) {
        this.game = game;
        batch = game.batch; // استخدم نفس SpriteBatch الموجود في MainGame
        player = new Player("player.png", 100, 100, 200, game); // مرر كائن MainGame
        enemy = new Enemy("enemy.png", 300, 300, 100);
        font = game.font; // استخدم نفس BitmapFont الموجود في MainGame
    }

    @Override
    public void show() {
        // سيتم تنفيذه عند تعيين هذه الشاشة كالشاشة الحالية
    }

    @Override
    public void render(float delta) {
        ScreenUtils.clear(0, 0, 0, 1);

        player.update(delta);
        enemy.update(delta);

        // معالجة اصطدام الرصاص بالعدو
        for (int i = player.bullets.size - 1; i >= 0; i--) {
            Bullet bullet = player.bullets.get(i);
            Rectangle bulletRect = new Rectangle(bullet.getPosition().x, bullet.getPosition().y,
                    bullet.getWidth(), bullet.getHeight());
            Rectangle enemyRect = new Rectangle(enemy.getPosition().x, enemy.getPosition().y,
                    enemy.getWidth(), enemy.getHeight());

            if (bulletRect.overlaps(enemyRect)) {
                player.bullets.removeIndex(i);
                enemy.dispose(); // تخلص من العدو
                enemy = new Enemy("enemy.png", MathUtils.random(0, Gdx.graphics.getWidth() - 50),
                        MathUtils.random(0, Gdx.graphics.getHeight() - 50), 100); // إنشاء عدو جديد
                score += 10; // زيادة النقاط
                game.highScore = Math.max(score, game.highScore); // تحديث أعلى نتيجة في MainGame
                break; // الخروج من حلقة الرصاص بعد الاصطدام
            }
        }

        batch.begin();
        player.render(batch);
        enemy.render(batch);

        // عرض النقاط
        font.draw(batch, "Score: " + score, 10, Gdx.graphics.getHeight() - 10);
        font.draw(batch, "High Score: " + game.highScore, 10, Gdx.graphics.getHeight() - 40);

        batch.end();

        // حفظ أعلى نتيجة بشكل دوري أو عند شروط معينة
        if (MathUtils.random(0f, 1f) < 0.01f) { // مثال على حفظ عشوائي
            game.saveSettings();
        }
    }

    @Override
    public void resize(int width, int height) {
        // يتم استدعاؤه عند تغيير حجم الشاشة
    }

    @Override
    public void pause() {
        game.saveSettings(); // حفظ عند إيقاف اللعبة مؤقتًا
    }

    @Override
    public void resume() {
        // يتم استدعاؤه عند استئناف اللعبة
    }

    @Override
    public void hide() {
        // يتم استدعاؤه عند إخفاء هذه الشاشة
    }

    @Override
    public void dispose() {
        // سيتم التخلص من الكائنات الأخرى في الكلاسات الخاصة بها أو في MainGame
    }
}



--


* كود (MainGame.java - نقطة الدخول الرئيسية وإدارة الشاشات):
Java




package com.example.topdownshooter;

import com.badlogic.gdx.Game;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Preferences;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.example.topdownshooter.screens.GameScreen;
import com.example.topdownshooter.screens.MainMenuScreen;
import com.example.topdownshooter.screens.SettingsScreen;

public class MainGame extends Game {
    public SpriteBatch batch;
    public BitmapFont font;
    public Preferences prefs;

    // مفاتيح الإعدادات
    public static final String DIFFICULTY_KEY = "gameDifficulty";
    public static final String HINTS_KEY = "showHints";
    public static final String LANGUAGE_KEY = "gameLanguage";
    public static final String VOLUME_KEY = "gameVolume";
    public static final String SCORE_KEY = "highScore";

    // قيم الإعدادات الافتراضية
    public String gameDifficulty = "Normal";
    public boolean showHints = true;
    public String gameLanguage = "English";
    public float gameVolume = 1.0f;
    public int highScore = 0;

    @Override
    public void create() {
        batch = new SpriteBatch();
        font = new BitmapFont();
        font.getData().setScale(2);
        prefs = Gdx.app.getPreferences("TopDownShooterSettings");
        loadSettings();
        setScreen(new MainMenuScreen(this)); // ابدأ بشاشة القائمة الرئيسية
    }

    public void loadSettings() {
        gameDifficulty = prefs.getString(DIFFICULTY_KEY, "Normal");
        showHints = prefs.getBoolean(HINTS_KEY, true);
        gameLanguage = prefs.getString(LANGUAGE_KEY, "English");
        gameVolume = prefs.getFloat(VOLUME_KEY, 1.0f);
        highScore = prefs.getInteger(SCORE_KEY, 0);
    }

    public void saveSettings() {
        prefs.putString(DIFFICULTY_KEY, gameDifficulty);
        prefs.putBoolean(HINTS_KEY, showHints);
        prefs.putString(LANGUAGE_KEY, gameLanguage);
        prefs.putFloat(VOLUME_KEY, gameVolume);
        prefs.putInteger(SCORE_KEY, highScore);
        prefs.flush();
    }

    @Override
    public void render() {
        super.render(); // يقوم باستدعاء متód render للشاشة الحالية
    }

    @Override
    public void dispose() {
        batch.dispose();
        font.dispose();
        getScreen().dispose();
    }

    public void changeScreen(ScreenType type) {
        switch (type) {
            case MAIN_MENU:
                this.setScreen(new MainMenuScreen(this));
                break;
            case GAME:
                this.setScreen(new GameScreen(this));
                break;
            case SETTINGS:
                this.setScreen(new SettingsScreen(this));
                break;
            default:
                break;
        }
    }

    public enum ScreenType {
        MAIN_MENU,
        GAME,
        SETTINGS
    }
}


--

3. التحكم في حركة اللاعب:

* كود (Player.java):
Java




package com.example.topdownshooter;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.utils.Array;

public class Player {
    Texture texture;
    Vector2 position;
    float speed;
    Array<Bullet> bullets;
    float fireRate = 0.5f;
    float fireTimer = 0;
    Texture bulletTexture;
    final MainGame game; // احتفظ بمرجع لكائن MainGame

    public Player(String texturePath, float x, float y, float speed, final MainGame game) {
        texture = new Texture(texturePath);
        position = new Vector2(x, y);
        this.speed = speed;
        this.game = game;
        bullets = new Array<>();
        bulletTexture = new Texture("bullet.png");
    }

    public void update(float deltaTime) {
        // حركة اللاعب
        if (Gdx.input.isKeyPressed(Input.Keys.W)) {
            position.y += speed * deltaTime;
        }
        if (Gdx.input.isKeyPressed(Input.Keys.S)) {
            position.y -= speed * deltaTime;
        }
        if (Gdx.input.isKeyPressed(Input.Keys.A)) {
            position.x -= speed * deltaTime;
        }
        if (Gdx.input.isKeyPressed(Input.Keys.D)) {
            position.x += speed * deltaTime;
        }

        // حدود الشاشة (اختياري)
        if (position.x < 0) position.x = 0;
        if (position.y < 0) position.y = 0;
        if (position.x > Gdx.graphics.getWidth() - texture.getWidth())
            position.x = Gdx.graphics.getWidth() - texture.getWidth();
        if (position.y > Gdx.graphics.getHeight() - texture.getHeight())
            position.y = Gdx.graphics.getHeight() - texture.getHeight();

        fireTimer += deltaTime;
        if (Gdx.input.isTouched() && fireTimer > fireRate) {
            fireTimer = 0;
            // حساب زاوية الإطلاق باتجاه اللمس
            Vector2 touchPos = new Vector2(Gdx.input.getX(), Gdx.graphics.getHeight() - Gdx.input.getY());
            float angle = (float) Math.toDegrees(Math.atan2(touchPos.y - (position.y + getHeight() / 2),
                    touchPos.x - (position.x + getWidth() / 2)));
            bullets.add(new Bullet("bullet.png", position.x + getWidth() / 2, position.y + getHeight() / 2, angle, 400));
        }

        for (Bullet bullet : bullets) {
            bullet.update(deltaTime);
        }
        bullets.removeAll(bullet -> bullet.position.x < 0 || bullet.position.x > Gdx.graphics.getWidth() ||
                        bullet.position.y < 0 || bullet.position.y > Gdx.graphics.getHeight(), null);
    }

    public void render(SpriteBatch batch) {
        batch.draw(texture, position.x, position.y);
        for (Bullet bullet : bullets) {
            bullet.render(batch);
        }
    }

    public void dispose() {
        texture.dispose();
        bulletTexture.dispose();
        for (Bullet bullet : bullets) {
            bullet.dispose();
        }
    }

    public Vector2 getPosition() {
        return position;
    }

    public float getWidth() {
        return texture.getWidth();
    }

    public float getHeight() {
        return texture.getHeight();
    }
}


   

--


4. إضافة الأعداء وحركتهم:

* كود (Enemy.java - مثال بسيط لحركة عشوائية):
Java




package com.example.topdownshooter;

import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.math.MathUtils;
import com.badlogic.gdx.math.Vector2;

public class Enemy {
    Texture texture;
    Vector2 position;
    float speed;

    public Enemy(String texturePath, float x, float y, float speed) {
        texture = new Texture(texturePath);
        position = new Vector2(x, y);
        this.speed = speed;
    }

    public void update(float deltaTime) {
        // حركة عشوائية بسيطة
        position.x += MathUtils.random(-speed, speed) * deltaTime;
        position.y += MathUtils.random(-speed, speed) * deltaTime;

        // حدود الشاشة (اختياري)
        if (position.x < 0) position.x = 0;
        if (position.y < 0) position.y = 0;
        if (position.x > Gdx.graphics.getWidth() - texture.getWidth())
            position.x = Gdx.graphics.getWidth() - texture.getWidth();
        if (position.y > Gdx.graphics.getHeight() - texture.getHeight())
            position.y = Gdx.graphics.getHeight() - texture.getHeight();
    }

    public void render(SpriteBatch batch) {
        batch.draw(texture, position.x, position.y);
    }

    public void dispose() {
        texture.dispose();
    }

    public Vector2 getPosition() {
        return position;
    }

    public float getWidth() {
        return texture.getWidth();
    }

    public float getHeight() {
        return texture.getHeight();
    }
}



--

5. تنفيذ إطلاق النار:

* كود (Bullet.java):
Java




package com.example.topdownshooter;

import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic

.badlogic.gdx.math.Vector2;

public class Bullet {
    Texture texture;
    Vector2 position;
    Vector2 velocity;
    float speed;

    public Bullet(String texturePath, float x, float y, float angle, float speed) {
        texture = new Texture(texturePath);
        position = new Vector2(x, y);
        this.speed = speed;
        velocity = new Vector2(Math.cos(Math.toRadians(angle)), Math.sin(Math.toRadians(angle))).nor().scl(speed);
    }

    public void update(float deltaTime) {
        position.add(velocity.x * deltaTime, velocity.y * deltaTime);
    }

    public void render(SpriteBatch batch) {
        batch.draw(texture, position.x, position.y);
    }

    public void dispose() {
        texture.dispose();
    }

    public Vector2 getPosition() {
        return position;
    }

    public float getWidth() {
        return texture.getWidth();
    }

    public float getHeight() {
        return texture.getHeight();
    }
}



--





6. معالجة الاصطدامات وتجميع النقاط:

* كود (إضافة منطق الاصطدام في MainGame.java):
Java




package com.example.topdownshooter;

import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.math.Rectangle;
import com.badlogic.gdx.utils.ScreenUtils;

public class MainGame extends ApplicationAdapter {
    SpriteBatch batch;
    Player player;
    Enemy enemy;
    int score = 0;
    BitmapFont font;

    @Override
    public void create() {
        batch = new SpriteBatch();
        player = new Player("player.png", 100, 100, 200);
        enemy = new Enemy("enemy.png", 300, 300, 100);
        font = new BitmapFont(); // خط افتراضي
        font.getData().setScale(2);
    }

    @Override
    public void render() {
        float deltaTime = Gdx.graphics.getDeltaTime();
        player.update(deltaTime);
        enemy.update(deltaTime);

// معالجة اصطدام الرصاص بالعدو
        for (int i = player.bullets.size - 1; i >= 0; i--) {
            Bullet bullet = player.bullets.get(i);
            Rectangle bulletRect = new Rectangle(bullet.getPosition().x, bullet.getPosition().y,
                    bullet.getWidth(), bullet.getHeight());
            Rectangle enemyRect = new Rectangle(enemy.getPosition().x, enemy.getPosition().y,
                    enemy.getWidth(), enemy.getHeight());

            if (bulletRect.overlaps(enemyRect)) {
                player.bullets.removeIndex(i);
                enemy.dispose(); // تخلص من العدو
                enemy = new Enemy("enemy.png", MathUtils.random(0, Gdx.graphics.getWidth() - 50),
                        MathUtils.random(0, Gdx.graphics.getHeight() - 50), 100); // إنشاء عدو جديد
                score += 10; // زيادة النقاط
                break; // الخروج من حلقة الرصاص بعد الاصطدام
            }
        }

        ScreenUtils.clear(0, 0, 0, 1);
        batch.begin();
        player.render(batch);
        enemy.render(batch);

        // عرض النقاط
        font.draw(batch, "Score: " + score, 10, Gdx.graphics.getHeight() - 10);

        batch.end();
    }

    @Override
    public void dispose() {
        batch.dispose();
        player.dispose();
        enemy.dispose();
        font.dispose();
    }
}


--

* الشرح:
- قمنا بإنشاء كائن Rectangle لكل من الرصاصة والعدو لتمثيل حدودهما.
- استخدمنا overlaps للتحقق من حدوث تصادم.
- عند الاصطدام، نقوم بإزالة الرصاصة، التخلص من العدو القديم وإنشاء
 عدو جديد في موقع عشوائي، وزيادة النقاط.
- قمنا بإضافة كائن BitmapFont لعرض قيمة النقاط على الشاشة.

7. حفظ النقاط (باستخدام SharedPreferences):

* كود (إضافة وظائف حفظ وتحميل النقاط في MainGame.java):
Java




package com.example.topdownshooter;

import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Preferences;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.math.MathUtils;
import com.badlogic.gdx.math.Rectangle;
import com.badlogic.gdx.utils.ScreenUtils;

public class MainGame extends ApplicationAdapter {
    SpriteBatch batch;
    Player player;
    Enemy enemy;
    int score = 0;
    BitmapFont font;
    Preferences prefs;
    final String SCORE_KEY = "highScore";
    int highScore = 0;

    @Override
    public void create() {
        batch = new SpriteBatch();
        player = new Player("player.png", 100, 100, 200);
        enemy = new Enemy("enemy.png", 300, 300, 100);
        font = new BitmapFont();
        font.getData().setScale(2);
        prefs = Gdx.app.getPreferences("TopDownShooterPrefs");
        loadHighScore();
    }

    private void loadHighScore() {
        highScore = prefs.getInteger(SCORE_KEY, 0);
    }

    private void saveHighScore() {
        if (score > highScore) {
            highScore = score;
            prefs.putInteger(SCORE_KEY, highScore);
            prefs.flush();
        }
    }

    @Override
    public void render() {
        float deltaTime = Gdx.graphics.getDeltaTime();
        player.update(deltaTime);
        enemy.update(deltaTime);

        for (int i = player.bullets.size - 1; i >= 0; i--) {
            Bullet bullet = player.bullets.get(i);
            Rectangle bulletRect = new Rectangle(bullet.getPosition().x, bullet.getPosition().y,
                    bullet.getWidth(), bullet.getHeight());
            Rectangle enemyRect = new Rectangle(enemy.getPosition().x, enemy.getPosition().y,
                    enemy.getWidth(), enemy.getHeight());

            if (bulletRect.overlaps(enemyRect)) {
                player.bullets.removeIndex(i);
                enemy.dispose();
                enemy = new Enemy("enemy.png", MathUtils.random(0, Gdx.graphics.getWidth() - 50),
                        MathUtils.random(0, Gdx.graphics.getHeight() - 50), 100);
                score += 10;
                break;
            }
        }

        ScreenUtils.clear(0, 0, 0, 1);
        batch.begin();
        player.render(batch);
        enemy.render(batch);

        font.draw(batch, "Score: " + score, 10, Gdx.graphics.getHeight() - 10);
        font.draw(batch, "High Score: " + highScore, 10, Gdx.graphics.getHeight() - 40);

        batch.end();

        // حفظ النقاط عند انتهاء اللعبة (يمكن تعديل هذا الشرط)
        if (enemy == null) { // مثال بسيط لانتهاء اللعبة
            saveHighScore();
        }
    }

    @Override
    public void dispose() {
        batch.dispose();
        player.dispose();
        enemy.dispose();
        font.dispose();
    }
}


--

- استخدمنا كلاس Preferences من LibGDX لتخزين البيانات البسيطة.
- loadHighScore(): يقوم بتحميل أعلى نتيجة محفوظة عند بدء تشغيل اللعبة.
- saveHighScore(): يقوم بحفظ النتيجة الحالية إذا كانت أعلى من النتيجة المحفوظة.
- يتم استدعاء loadHighScore() في create() و saveHighScore() 
عند انتهاء اللعبة (يمكن تعديل شرط النهاية).
يتم عرض أعلى نتيجة على الشاشة.

8. إنشاء شاشة الإعدادات :

 الأكواد الأساسية لتنفيذ إنشاء واجهة مستخدم بسيطة للإعدادات (مثل التحكم في مستوى الصوت):

كود (SettingsScreen.java - شاشة الإعدادات):
Java

 



package com.example.topdownshooter.screens;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Screen;
import com.badlogic.gdx.Preferences;
import com.badlogic.gdx.scenes.scene2d.Actor;
import com.badlogic.gdx.scenes.scene2d.Stage;
import com.badlogic.gdx.scenes.scene2d.ui.CheckBox;
import com.badlogic.gdx.scenes.scene2d.ui.Label;
import com.badlogic.gdx.scenes.scene2d.ui.SelectBox;
import com.badlogic.gdx.scenes.scene2d.ui.Skin;
import com.badlogic.gdx.scenes.scene2d.ui.Slider;
import com.badlogic.gdx.scenes.scene2d.ui.Table;
import com.badlogic.gdx.scenes.scene2d.ui.TextButton;
import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.ScreenUtils;
import com.example.topdownshooter.MainGame;

public class SettingsScreen implements Screen {

    final MainGame game;
    Stage stage;
    Skin skin;
    Preferences prefs;

    // مفاتيح حفظ الإعدادات
    final String VOLUME_KEY = "gameVolume";
    final String DIFFICULTY_KEY = "gameDifficulty";
    final String HINTS_KEY = "showHints";
    final String LANGUAGE_KEY = "gameLanguage";

    // قيم الإعدادات الافتراضية
    float gameVolume = 1.0f;
    String gameDifficulty = "Normal";
    boolean showHints = true;
    String gameLanguage = "English";

    public SettingsScreen(final MainGame game) {
        this.game = game;
        prefs = Gdx.app.getPreferences("TopDownShooterSettings");
        loadSettings();

        stage = new Stage();
        Gdx.input.setInputProcessor(stage);

        skin = new Skin(Gdx.files.internal("uiskin.json")); // تحتاج إلى ملف uiskin.json في مجلد الأصول

        // عنصر التحكم في مستوى الصوت
        Label volumeLabel = new Label("Volume:", skin);
        final Slider volumeSlider = new Slider(0f, 1f, 0.1f, false, skin);
        volumeSlider.setValue(gameVolume);

        // خيارات مستوى الصعوبة
        Label difficultyLabel = new Label("Difficulty:", skin);
        Array<String> difficulties = new Array<>(new String[]{"Easy", "Normal", "Hard"});
        final SelectBox<String> difficultySelectBox = new SelectBox<>(skin);
        difficultySelectBox.setItems(difficulties);
        difficultySelectBox.setSelected(gameDifficulty);

        // خيار تفعيل/إيقاف التلميحات
        Label hintsLabel = new Label("Show Hints:", skin);
        final CheckBox hintsCheckBox = new CheckBox("", skin);
        hintsCheckBox.setChecked(showHints);

        // خيار اللغة
        Label languageLabel = new Label("Language:", skin);
        Array<String> languages = new Array<>(new String[]{"English", "Arabic" /* أضف المزيد من اللغات */});
        final SelectBox<String> languageSelectBox = new SelectBox<>(skin);
        languageSelectBox.setItems(languages);
        languageSelectBox.setSelected(gameLanguage);

        // زر حول اللعبة
        TextButton aboutButton = new TextButton("About Game", skin);
        aboutButton.addListener(new ChangeListener() {
            @Override
            public void changed(ChangeEvent event, Actor actor) {
                game.setScreen(new AboutScreen(game));
                dispose();
            }
        });

        // زر الرجوع
        TextButton backButton = new TextButton("Back", skin);
        backButton.addListener(new ChangeListener() {
            @Override
            public void changed(ChangeEvent event, Actor actor) {
                saveSettings();
                game.setScreen(new GameScreen(game));
                dispose();
            }
        });

        // تنسيق العناصر باستخدام Table
        Table settingsTable = new Table();
        settingsTable.setFillParent(true);
        settingsTable.center();

        settingsTable.add(volumeLabel).left().padRight(20);
        settingsTable.add(volumeSlider).width(200).left().row();

        settingsTable.add(difficultyLabel).left().padRight(20).padTop(20);
        settingsTable.add(difficultySelectBox).left().row();

        settingsTable.add(hintsLabel).left().padRight(20).padTop(20);
        settingsTable.add(hintsCheckBox).left().row();

        settingsTable.add(languageLabel).left().padRight(20).padTop(20);
        settingsTable.add(languageSelectBox).left().row();

        settingsTable.add(aboutButton).fillX().padTop(40).row();
        settingsTable.add(backButton).fillX().padTop(20);

        stage.addActor(settingsTable);

        // إضافة مستمعين لتغيير القيم
        volumeSlider.addListener(new ChangeListener() {
            @Override
            public void changed(ChangeEvent event, Actor actor) {
                gameVolume = volumeSlider.getValue();
                // يمكنك هنا تطبيق تغيير مستوى الصوت الفعلي في اللعبة
                System.out.println("Volume changed to: " + gameVolume);
            }
        });

        difficultySelectBox.addListener(new ChangeListener() {
            @Override
            public void changed(ChangeEvent event, Actor actor) {
                gameDifficulty = difficultySelectBox.getSelected();
                System.out.println("Difficulty selected: " + gameDifficulty);
                // يمكنك هنا تطبيق تغيير مستوى الصعوبة في اللعبة
            }
        });

        hintsCheckBox.addListener(new ChangeListener() {
            @Override
            public void changed(ChangeEvent event, Actor actor) {
                showHints = hintsCheckBox.isChecked();
                System.out.println("Show Hints: " + showHints);
                // يمكنك هنا تفعيل/إيقاف ظهور التلميحات في اللعبة
            }
        });

        languageSelectBox.addListener(new ChangeListener() {
            @Override
            public void changed(ChangeEvent event, Actor actor) {
                gameLanguage = languageSelectBox.getSelected();
                System.out.println("Language selected: " + gameLanguage);
                // يمكنك هنا تغيير لغة اللعبة
            }
        });
    }

    private void loadSettings() {
        gameVolume = prefs.getFloat(VOLUME_KEY, game.gameVolume);
        gameDifficulty = prefs.getString(DIFFICULTY_KEY, game.gameDifficulty);
        showHints = prefs.getBoolean(HINTS_KEY, game.showHints);
        gameLanguage = prefs.getString(LANGUAGE_KEY, game.gameLanguage);
    }

    private void saveSettings() {
        prefs.putFloat(VOLUME_KEY, gameVolume);
        prefs.putString(DIFFICULTY_KEY, gameDifficulty);
        prefs.putBoolean(HINTS_KEY, showHints);
        prefs.putString(LANGUAGE_KEY, gameLanguage);
        prefs.flush();
        game.loadSettings(); // تحديث الإعدادات في MainGame
    }

    @Override
    public void show() {
        Gdx.input.setInputProcessor(stage);
    }

    @Override
    public void render(float delta) {
        ScreenUtils.clear(0.2f, 0.2f, 0.2f, 1);
        stage.act(Math.min(Gdx.graphics.getDeltaTime(), 1 / 30f));
        stage.draw();
    }

    @Override
    public void resize(int width, int height) {
        stage.getViewport().update(width, height, true);
    }

    @Override
    public void pause() {
        saveSettings();
    }

    @Override
    public void resume() {
        loadSettings();
        Gdx.input.setInputProcessor(stage);
    }

    @Override
    public void hide() {
        Gdx.input.setInputProcessor(null);
    }

    @Override
    public void dispose() {
        stage.dispose();
        skin.dispose();
    }
}


--

شرح الكود:
- SettingsScreen: كلاس يمثل شاشة الإعدادات في اللعبة. يجب أن تنفذ واجهة Screen من LibGDX.
- Stage: حاوية لعناصر واجهة المستخدم (Actors).
- Skin: يحتوي على معلومات حول مظهر عناصر واجهة المستخدم (الخطوط، الألوان، الصور). 
هنا نفترض وجود ملف uiskin.json الذي يأتي مع LibGDX أو يمكنك إنشاؤه/تخصيصه.
- Label: لعرض نص "Volume:".
- Slider: شريط تمرير للتحكم في مستوى الصوت (من 0 إلى 1 بقيم متزايدة قدرها 0.1).
- TextButton: زر "Back" للعودة إلى شاشة اللعبة.
- Table: لتنظيم العناصر بشكل مرئي في وسط الشاشة.
-  setFillParent(true) يجعل الجدول يملأ الشاشة، و center() يضع محتوياته في المنتصف.
-  padRight() و padTop() لإضافة مسافات بين العناصر، و colspan() لجعل الزر يمتد على عمودين.
- ChangeListener: مستمع يتم تفعيله عند تغيير قيمة شريط التمرير أو النقر على الزر.
- loadSettings() و saveSettings(): وظائف لتحميل وحفظ قيمة مستوى الصوت باستخدام Preferences.
في render()، يتم تحديث وعرض المرحلة.
- في show()، يتم تعيين معالج الإدخال على المرحلة لجعل عناصر واجهة المستخدم قابلة للتفاعل.
في dispose()، يتم التخلص من الموارد المستخدمة.
- difficultySelectBox (SelectBox): قائمة منسدلة تتيح للمستخدم اختيار مستوى الصعوبة ("Easy"، "Normal"، "Hard").
- hintsCheckBox (CheckBox): مربع اختيار (زر تبديل) لتفعيل أو إيقاف ظهور التلميحات في اللعبة.
- languageSelectBox (SelectBox): قائمة منسدلة لاختيار لغة اللعبة 
("English"، "Arabic" كمثال). يمكنك إضافة المزيد من اللغات إلى المصفوفة.
- aboutButton (TextButton): زر عند النقر عليه يقوم بتنفيذ إجراء ما
 (في هذا المثال، يطبع رسالة في وحدة التحكم. يمكنك استبدال هذا بفتح شاشة "حول اللعبة").




لتضمين هذه الشاشة في لعبتك:
إنشاء ملف uiskin.json: إذا لم يكن لديك بالفعل، قم بإنشاء أو تنزيل ملف
 uiskin.json وضعه في مجلد assets الخاص بمشروعك. يمكنك العثور على مثال
 لهذا الملف في توزيعة LibGDX أو عبر الإنترنت.
تعديل MainGame.java: قم بإضافة شاشة الإعدادات إلى كلاس MainGame
 وإمكانية الانتقال إليها من شاشة اللعبة (أو من قائمة رئيسية إذا كانت لديك).
Java




package com.example.topdownshooter;

import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.Game;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input;
import com.badlogic.gdx.Preferences;
import com.badlogic.gdx.Screen;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.math.MathUtils;
import com.badlogic.gdx.math.Rectangle;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.scenes.scene2d.Actor;
import com.badlogic.gdx.scenes.scene2d.Stage;
import com.badlogic.gdx.scenes.scene2d.ui.CheckBox;
import com.badlogic.gdx.scenes.scene2d.ui.Label;
import com.badlogic.gdx.scenes.scene2d.ui.SelectBox;
import com.badlogic.gdx.scenes.scene2d.ui.Skin;
import com.badlogic.gdx.scenes.scene2d.ui.Table;
import com.badlogic.gdx.scenes.scene2d.ui.TextButton;
import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.ScreenUtils;

public class MainGame extends Game {

    public SpriteBatch batch;
    public BitmapFont font;
    public Preferences prefs;

    // مفاتيح الإعدادات
    public static final String DIFFICULTY_KEY = "gameDifficulty";
    public static final String HINTS_KEY = "showHints";
    public static final String LANGUAGE_KEY = "gameLanguage";
    public static final String VOLUME_KEY = "gameVolume";
    public static final String SCORE_KEY = "highScore";

    // قيم الإعدادات الافتراضية
    public String gameDifficulty = "Normal";
    public boolean showHints = true;
    public String gameLanguage = "English";
    public float gameVolume = 1.0f;
    public int highScore = 0;

    @Override
    public void create() {
        batch = new SpriteBatch();
        font = new BitmapFont();
        font.getData().setScale(2);
        prefs = Gdx.app.getPreferences("TopDownShooterSettings");
        loadSettings();
        setScreen(new GameScreen(this)); // ابدأ بشاشة اللعبة
    }

    public void loadSettings() {
        gameDifficulty = prefs.getString(DIFFICULTY_KEY, "Normal");
        showHints = prefs.getBoolean(HINTS_KEY, true);
        gameLanguage = prefs.getString(LANGUAGE_KEY, "English");
        gameVolume = prefs.getFloat(VOLUME_KEY, 1.0f);
        highScore = prefs.getInteger(SCORE_KEY, 0);
    }

    public void saveSettings() {
        prefs.putString(DIFFICULTY_KEY, gameDifficulty);
        prefs.putBoolean(HINTS_KEY, showHints);
        prefs.putString(LANGUAGE_KEY, gameLanguage);
        prefs.putFloat(VOLUME_KEY, gameVolume);
        prefs.putInteger(SCORE_KEY, highScore);
        prefs.flush();
    }

    @Override
    public void render() {
        super.render(); // يقوم باستدعاء متód render للشاشة الحالية
    }

    @Override
    public void dispose() {
        batch.dispose();
        font.dispose();
        getScreen().dispose();
    }
}

// كلاس اللاعب
class Player {
    Texture texture;
    Vector2 position;
    float speed;
    Array<Bullet> bullets;
    float fireRate = 0.5f;
    float fireTimer = 0;
    Texture bulletTexture;
    MainGame game;

    public Player(String texturePath, float x, float y, float speed, MainGame game) {
        texture = new Texture(texturePath);
        position = new Vector2(x, y);
        this.speed = speed;
        this.game = game;
        bullets = new Array<>();
        bulletTexture = new Texture("bullet.png");
    }

    public void update(float deltaTime) {
        // حركة اللاعب
        if (Gdx.input.isKeyPressed(Input.Keys.W)) {
            position.y += speed * deltaTime;
        }
        if (Gdx.input.isKeyPressed(Input.Keys.S)) {
            position.y -= speed * deltaTime;
        }
        if (Gdx.input.isKeyPressed(Input.Keys.A)) {
            position.x -= speed * deltaTime;
        }
        if (Gdx.input.isKeyPressed(Input.Keys.D)) {
            position.x += speed * deltaTime;
        }

        // حدود الشاشة
        if (position.x < 0) position.x = 0;
        if (position.y < 0) position.y = 0;
        if (position.x > Gdx.graphics.getWidth() - texture.getWidth())
            position.x = Gdx.graphics.getWidth() - texture.getWidth();
        if (position.y > Gdx.graphics.getHeight() - texture.getHeight())
            position.y = Gdx.graphics.getHeight() - texture.getHeight();

        // إطلاق النار
        fireTimer += deltaTime;
        if (Gdx.input.isTouched() && fireTimer > fireRate) {
            fireTimer = 0;
            Vector2 touchPos = new Vector2(Gdx.input.getX(), Gdx.graphics.getHeight() - Gdx.input.getY());
            float angle = (float) Math.toDegrees(Math.atan2(touchPos.y - (position.y + getHeight() / 2),
                    touchPos.x - (position.x + getWidth() / 2)));
            bullets.add(new Bullet("bullet.png", position.x + getWidth() / 2, position.y + getHeight() / 2, angle, 400));
        }

        // تحديث الرصاص
        for (Bullet bullet : bullets) {
            bullet.update(deltaTime);
        }
        bullets.removeAll(bullet -> bullet.position.x < 0 || bullet.position.x > Gdx.graphics.getWidth() ||
                bullet.position.y < 0 || bullet.position.y > Gdx.graphics.getHeight(), null);
    }

    public void render(SpriteBatch batch) {
        batch.draw(texture, position.x, position.y);
        for (Bullet bullet : bullets) {
            bullet.render(batch);
        }
    }

    public void dispose() {
        texture.dispose();
        bulletTexture.dispose();
        for (Bullet bullet : bullets) {
            bullet.dispose();
        }
    }

    public Vector2 getPosition() {
        return position;
    }

    public float getWidth() {
        return texture.getWidth();
    }

    public float getHeight() {
        return texture.getHeight();
    }
}

// كلاس العدو
class Enemy {
    Texture texture;
    Vector2 position;
    float speed;
    int health;
    float aiTimer = 0;
    float aiInterval = 2;
    MainGame game;

    public Enemy(String texturePath, float x, float y, float speed, MainGame game) {
        texture = new Texture(texturePath);
        position = new Vector2(x, y);
        this.speed = speed;
        this.health = 3;
        this.game = game;
    }

    public void update(float deltaTime, Player player) {
        // حركة العدو الأساسية: اتبع اللاعب
        if (position.x < player.getPosition().x) {
            position.x += speed * deltaTime;
        } else if (position.x > player.getPosition().x) {
            position.x -= speed * deltaTime;
        }
        if (position.y < player.getPosition().y) {
            position.y += speed * deltaTime;
        } else if (position.y > player.getPosition().y) {
            position.y -= speed * deltaTime;
        }

        // حركة عشوائية إضافية
        aiTimer += deltaTime;
        if (aiTimer > aiInterval) {
            aiTimer = 0;
            position.x += MathUtils.random(-speed * 0.5f, speed * 0.5f) * deltaTime;
            position.y += MathUtils.random(-speed * 0.5f, speed * 0.5f) * deltaTime;
            aiInterval = MathUtils.random(1, 3);
        }

        // حدود الشاشة
        if (position.x < 0) position.x = 0;
        if (position.y < 0) position.y = 0;
        if (position.x > Gdx.graphics.getWidth() - texture.getWidth())
            position.x = Gdx.graphics.getWidth() - texture.getWidth();
        if (position.y > Gdx.graphics.getHeight() - texture.getHeight())
            position.y = Gdx.graphics.getHeight() - texture.getHeight();
    }

    public void render(SpriteBatch batch) {
        batch.draw(texture, position.x, position.y);
    }

    public void dispose() {
        texture.dispose();
    }

    public Vector2 getPosition() {
        return position;
    }

    public float getWidth() {
        return texture.getWidth();
    }

    public float getHeight() {
        return texture.getHeight();
    }

    public void takeDamage(int damage) {
        health -= damage;
    }

    public int getHealth() {
        return health;
    }
}

// كلاس الرصاصة
class Bullet {
    Texture texture;
    Vector2 position;
    Vector2 velocity;
    float speed;

    public Bullet(String texturePath, float x, float y, float angle, float speed) {
        texture = new Texture(texturePath);
        position = new Vector2(x, y);
        this.speed = speed;
        velocity = new Vector2(Math.cos(Math.toRadians(angle)), Math.sin(Math.toRadians(angle))).nor().scl(speed);
    }

    public void update(float deltaTime) {
        position.add(velocity.x * deltaTime, velocity.y * deltaTime);
    }

    public void render(SpriteBatch batch) {
        batch.draw(texture, position.x, position.y);
    }

    public void dispose() {
        texture.dispose();
    }

    public Vector2 getPosition() {
        return position;
    }

    public float getWidth() {
        return texture.getWidth();
    }

    public float getHeight() {
        return texture.getHeight();
    }
}

// شاشة اللعبة
class GameScreen implements Screen {

    final MainGame game;
    Player player;
    Array<Enemy> enemies;
    SpriteBatch batch;
    int score = 0;
    BitmapFont font;
    Texture background;
    float spawnTimer = 0;
    float spawnInterval = 2;

    public GameScreen(final MainGame game) {
        this.game = game;
        batch = game.batch;
        font = game.font;
        player = new Player("player.png", 100, 100, 200, game);
        enemies = new Array<>();
        enemies.add(new Enemy("enemy.png", 300, 300, 50, game));
        background = new Texture("background.png");
    }

    @Override
    public void show() {
        Gdx.input.setInputProcessor(null);
    }

    @Override
    public void render(float delta) {
        ScreenUtils.clear(0, 0, 0, 1);

        // رسم الخلفية
        batch.begin();
        batch.draw(background, 0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());

        player.update(delta);

        // تحديث الأعداء
        for (int i = enemies.size - 1; i >= 0; i--) {
            Enemy enemy = enemies.get(i);
            enemy.update(delta, player);

            // معالجة اصطدام الرصاص بالعدو
            for (int j = player.bullets.size - 1; j >= 0; j--) {
                Bullet bullet = player.bullets.get(j);
                Rectangle bulletRect = new Rectangle(bullet.getPosition().x, bullet.getPosition().y,
                        bullet.getWidth(), bullet.getHeight());
                Rectangle enemyRect = new Rectangle(enemy.getPosition().x, enemy.getPosition().y,
                        enemy.getWidth(), enemy.getHeight());

                if (bulletRect.overlaps(enemyRect)) {
                    player.bullets.removeIndex(j);
                    enemy.takeDamage(1);
                    if (enemy.getHealth() <= 0) {
                        enemies.removeIndex(i);
                        enemy.dispose();
                        score += 10;
                        break;
                    }
                    break;
                }
            }
        }

        // رسم اللاعب والأعداء والرصاص
        player.render(batch);
        for (Enemy enemy : enemies) {
            enemy.render(batch);
        }

        // رسم النقاط
        font.draw(batch, "Score: " + score, 10, Gdx.graphics.getHeight() - 10);
        font.draw(batch, "High Score: " + game.highScore, 10, Gdx.graphics.getHeight() - 40);


        batch.end();

        // إضافة أعداء جدد
        spawnTimer += delta;
        if (spawnTimer > spawnInterval) {
            spawnTimer = 0;
            enemies.add(new Enemy("enemy.png", MathUtils.random(0, Gdx.graphics.getWidth() - 50),
                    MathUtils.random(0, Gdx.graphics.getHeight() - 50), 50, game));
            spawnInterval = MathUtils.random(1, 3);
        }

        // Game Over
        if (enemies.size == 0) { // مثال بسيط: تنتهي اللعبة عندما لا يتبقى أعداء
            gameOver();
        }
    }

    void gameOver() {
        game.saveSettings();
        game.setScreen(new GameOverScreen(game, score));
        dispose();
    }

    @Override
    public void resize(int width, int height) {
    }

    @Override
    public void pause() {
    }

    @Override
    public void resume() {
    }

    @Override
    public void hide() {
    }

    @Override
    public void dispose() {
        player.dispose();
        for (Enemy enemy : enemies) {
            enemy.dispose();
        }
        background.dispose();
    }
}

// شاشة النهاية
class GameOverScreen implements Screen {
    final MainGame game;
    int score;
    Stage stage;
    Skin skin;

    public GameOverScreen(final MainGame game, int score) {
        this.game = game;
        this.score = score;
        this.stage = new Stage();
        Gdx.input.setInputProcessor(stage);
        this.skin = new Skin(Gdx.files.internal("uiskin.json"));

        Label gameOverLabel = new Label("Game Over", skin);
        gameOverLabel.setFontScale(3);

        Label scoreLabel = new Label("Your Score: " + score, skin);
        Label highScoreLabel = new Label("High Score: " + game.highScore, skin);

        TextButton playAgainButton = new TextButton("Play Again", skin);
        playAgainButton.addListener(new ChangeListener() {
            @Override
            public void changed(ChangeEvent event, Actor actor) {
                game.setScreen(new GameScreen(game));
                dispose();
            }
        });

        TextButton settingsButton = new TextButton("Settings", skin);
        settingsButton.addListener(new ChangeListener() {
            @Override
            public void changed(ChangeEvent event, Actor actor) {
                game.setScreen(new SettingsScreen(game));
                dispose();
            }
        });

        TextButton exitButton = new TextButton("Exit", skin);
        exitButton.addListener(new ChangeListener() {
            @Override
            public void changed(ChangeEvent event, Actor actor) {
                Gdx.app.exit();
            }
        });

        Table table = new Table();
        table.setFillParent(true);
        table.center();
        table.add(gameOverLabel).row();
        table.add(scoreLabel).padTop(20).row();
        table.add(highScoreLabel).padTop(20).row();
        table.add(playAgainButton).padTop(50).fillX().row();
        table.add(settingsButton).padTop(20).fillX().row();
        table.add(exitButton).padTop(20).fillX().row();

        stage.addActor(table);
    }

    @Override
    public void show() {
        Gdx.input.setInputProcessor(stage);
    }

    @Override
    public void render(float delta) {
        ScreenUtils.clear(0.2f, 0.2f, 0.2f, 1);
        stage.act(Math.min(Gdx.graphics.getDeltaTime(), 1 / 30f));
        stage.draw();
        game.batch.begin();
        game.font.draw(game.batch, "Game Over", Gdx.graphics.getWidth() / 2 - 100, Gdx.graphics.getHeight() / 2 + 50);
        game.batch.end();
    }

    @Override
    public void resize(int width, int height) {
        stage.getViewport().update(width, height, true);
    }

    @Override
    public void pause() {
    }

    @Override
    public void resume() {
        Gdx.input.setInputProcessor(stage);
    }

    @Override
    public void hide() {
        Gdx.input.setInputProcessor(null);
    }

    @Override
    public void dispose() {
        stage.dispose();
        skin.dispose();
    }
}

// شاشة الإعدادات
class SettingsScreen implements Screen {

    final MainGame game;
    Stage stage;
    Skin skin;
    Preferences prefs;

    public SettingsScreen(final MainGame game) {
        this.game = game;
        this.prefs = game.prefs;

        stage = new Stage();
        Gdx.input.setInputProcessor(stage);

        skin = new Skin(Gdx.files.internal("uiskin.json"));

        // خيارات اللعبة

        // مستوى الصعوبة
        Label difficultyLabel = new Label("مستوى الصعوبة:", skin);
        Array<String> difficulties = new Array<>(new String[]{"سهل", "عادي", "صعب"});
        final SelectBox<String> difficultySelectBox = new SelectBox<>(skin);
        difficultySelectBox.setItems(difficulties);
        difficultySelectBox.setSelected(game.gameDifficulty);

        // تفعيل/إيقاف التلميحات
        Label hintsLabel = new Label("إظهار التلميحات:", skin);
        final CheckBox hintsCheckBox = new CheckBox("", skin);
        hintsCheckBox.setChecked(game.showHints);

        // خيارات أخرى

        // اللغة
        Label languageLabel = new Label("اللغة:", skin);
        Array<String> languages = new Array<>(new String[]{"English", "العربية"});
        final SelectBox<String> languageSelectBox = new SelectBox<>(skin);
        languageSelectBox.setItems(languages);
        languageSelectBox.setSelected(game.gameLanguage);

        // مستوى الصوت
        Label volumeLabel = new Label("مستوى الصوت:", skin);
        final Slider volumeSlider = new Slider(0f, 1f, 0.1f, false, skin);
        volumeSlider.setValue(game.gameVolume);


        // زر حول اللعبة
        TextButton aboutButton = new TextButton("حول اللعبة", skin);
        aboutButton.addListener(new ChangeListener() {
            @Override
            public void changed(ChangeEvent event, Actor actor) {
                game.setScreen(new AboutScreen(game));
                dispose();
            }
        });

        // زر الرجوع
        TextButton backButton = new TextButton("رجوع", skin);
        backButton.addListener(new ChangeListener() {
            @Override
            public void changed(ChangeEvent event, Actor actor) {
                saveSettings();
                game.setScreen(new GameScreen(game));
                dispose();
            }
        });

        // تنسيق العناصر باستخدام Table
        Table settingsTable = new Table();
        settingsTable.setFillParent(true);
        settingsTable.center();

        settingsTable.add(difficultyLabel).left().padRight(20);
        settingsTable.add(difficultySelectBox).left().row();

        settingsTable.add(hintsLabel).left().padRight(20).padTop(20);
        settingsTable.add(hintsCheckBox).left().padTop(20).row();

        settingsTable.add(languageLabel).left().padRight(20).padTop(20);
        settingsTable.add(languageSelectBox).left().padTop(20).row();

        settingsTable.add(volumeLabel).left().padRight(20).padTop(20);
        settingsTable.add(volumeSlider).left().padTop(20).width(200).row();

        settingsTable.add(aboutButton).fillX().padTop(40).row();
        settingsTable.add(backButton).fillX().padTop(20);

        stage.addActor(settingsTable);

        // إضافة مستمعين لتغيير القيم
        difficultySelectBox.addListener(new ChangeListener() {
            @Override
            public void changed(ChangeEvent event, Actor actor) {
                game.gameDifficulty = difficultySelectBox.getSelected();
                System.out.println("Difficulty selected: " + game.gameDifficulty);
                // قم بتطبيق تغيير مستوى الصعوبة في اللعبة هنا
            }
        });

        hintsCheckBox.addListener(new ChangeListener() {
            @Override
            public void changed(ChangeEvent event, Actor actor) {
                game.showHints = hintsCheckBox.isChecked();
                System.out.println("Show Hints: " + game.showHints);
                // قم بتفعيل/إيقاف ظهور التلميحات في اللعبة هنا
            }
        });

        languageSelectBox.addListener(new ChangeListener() {
            @Override
            public void changed(ChangeEvent event, Actor actor) {
                game.gameLanguage = languageSelectBox.getSelected();
                System.out.println("Language selected: " + game.gameLanguage);
                // قم بتغيير لغة اللعبة هنا
            }
        });

        volumeSlider.addListener(new ChangeListener() {
            @Override
            public void changed(ChangeEvent event, Actor actor) {
                game.gameVolume = volumeSlider.getValue();
                System.out.println("Volume changed to: " + game.gameVolume);
            }
        });
    }

    private void loadSettings() {
        game.gameDifficulty = game.prefs.getString(DIFFICULTY_KEY, "Normal");
        game.showHints = game.prefs.getBoolean(HINTS_KEY, true);
        game.gameLanguage = game.prefs.getString(LANGUAGE_KEY, "English");
        game.gameVolume = game.prefs.getFloat(VOLUME_KEY, 1.0f);
    }

    private void saveSettings() {
        game.prefs.putString(DIFFICULTY_KEY, game.gameDifficulty);
        game.prefs.putBoolean(HINTS_KEY, game.showHints);
        game.prefs.putString(LANGUAGE_KEY, game.gameLanguage);
        game.prefs.putFloat(VOLUME_KEY, game.gameVolume);
        game.prefs.flush();
    }

    @Override
    public void show() {
        Gdx.input.setInputProcessor(stage);
    }

    @Override
    public void render(float delta) {
        ScreenUtils.clear(0.2f, 0.2f, 0.2f, 1);
        stage.act(Math.min(Gdx.graphics.getDeltaTime(), 1 / 30f));
        stage.draw();
    }

    @Override
    public void resize(int width, int height) {
        stage.getViewport().update(width, height, true);
    }

    @Override
    public void pause() {
        saveSettings();
    }

    @Override
    public void resume() {
        loadSettings();
        Gdx.input.setInputProcessor(stage);
    }

    @Override
    public void hide() {
        Gdx.input.setInputProcessor(null);
    }

    @Override
    public void dispose() {
        stage.dispose();
        skin.dispose();
    }
}

// شاشة حول اللعبة
class AboutScreen implements Screen {
    final MainGame game;
    Stage stage;
    Skin skin;

    public AboutScreen(final MainGame game) {
        this.game = game;
        this.stage = new Stage();
        Gdx.input.setInputProcessor(stage);
        this.skin = new Skin(Gdx.files.internal("uiskin.json"));

        Label titleLabel = new Label("حول اللعبة", skin);
        titleLabel.setFontScale(2);


String aboutText = "Top Down Shooter\n\n" +
                           "تم التطوير بواسطة: Your Name\n" +
                           "باستخدام LibGDX\n\n" +
                           "نسخة اللعبة: 1.0\n" +
                           "تاريخ الإصدار: 2025";

        Label aboutLabel = new Label(aboutText, skin);
        aboutLabel.setWrap(true);
        aboutLabel.setAlignment(Align.top);

        TextButton backButton = new TextButton("رجوع", skin);
        backButton.addListener(new ChangeListener() {
            @Override
            public void changed(ChangeEvent event, Actor actor) {
                game.setScreen(new MainMenuScreen(game));
                dispose();
            }
        });

        Table table = new Table();
        table.setFillParent(true);
        table.pad(20);
        table.add(titleLabel).expandX().center().padBottom(20).row();
        table.add(aboutLabel).width(400).height(200).padBottom(30).row();
        table.add(backButton).width(200).height(50).center();

        stage.addActor(table);
    }

    @Override
    public void show() {}

    @Override
    public void render(float delta) {
        Gdx.gl.glClearColor(0, 0, 0.2f, 1);
        Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);

        stage.act(Gdx.graphics.getDeltaTime());
        stage.draw();
    }

    @Override
    public void resize(int width, int height) {
        stage.getViewport().update(width, height, true);
    }

    @Override
    public void pause() {}

    @Override
    public void resume() {}

    @Override
    public void hide() {}

    @Override
    public void dispose() {
        stage.dispose();
        skin.dispose();
    }
}

    @Override
    public void dispose() {
        batch.dispose();
        this.getScreen().dispose();
    }

    // يمكنك إضافة متód هنا لتغيير الشاشة من أي مكان في اللعبة
    public void changeScreen(ScreenType type) {
        switch (type) {
            case MAIN_MENU:
                this.setScreen(new MainMenuScreen(this));
                break;
            case GAME:
                this.setScreen(new GameScreen(this));
                break;
            case SETTINGS:
                this.setScreen(new SettingsScreen(this));
                break;
            default:
                break;
        }
    }

    // نوع تعداد (enum) لتحديد الشاشات المختلفة في اللعبة
    public enum ScreenType {
        MAIN_MENU,
        GAME,
        SETTINGS
    }
}




--


* شرح التغييرات والإضافات:

- استيراد MainMenuScreen: تم استيراد كلاس MainMenuScreen. 
تحتاج إلى إنشاء هذا الكلاس في ملف منفصل (MainMenuScreen.java) ليحتوي على
 منطق شاشة القائمة الرئيسية (مثل أزرار "ابدأ اللعبة"، "الإعدادات"، "خروج").
- بدء التشغيل بشاشة القائمة الرئيسية: في متغير  create(), تم تغيير 
السطر ليبدأ اللعبة بشاشة القائمة الرئيسية:
this.setScreen(new MainMenuScreen(this));
هذا هو المكان المنطقي لبدء تشغيل اللعبة، حيث يمكن للمستخدم اختيار بدء اللعب أو الذهاب إلى الإعدادات.
- ód changeScreen(): تم إضافة متغير جديد باسم changeScreen() لتسهيل
 الانتقال بين الشاشات المختلفة للعبة من أي مكان في الكود. يأخذ هذا قيمة من نوع
 ScreenType (الذي تم تعريفه أدناه) لتحديد الشاشة المراد الانتقال إليها.
- نوع تعداد ScreenType: تم تعريف نوع تعداد (enum) باسم ScreenType 
لتحديد الشاشات المختلفة في اللعبة بشكل منظم وسهل القراءة. يمكنك إضافة المزيد 
من أنواع الشاشات هنا حسب حاجتك (مثل GAME_OVER, PAUSE, إلخ.).

لكي يعمل هذا الكود بشكل كامل، تحتاج إلى:

- إنشاء كلاس MainMenuScreen: قم بإنشاء ملف جديد باس
 MainMenuScreen.java في الحزمة الصحيحة 
(com.example.topdownshooter.screens) وقم بتضمين منطق
 القائمة الرئيسية فيه (مثل إنشاء أزرار باستخدام Stage و Skin، وإضافة مستمعين
 للأزرار للانتقال إلى شاشة اللعبة أو الإعدادات باستخدام ((MainGame) Gdx.app.getApplicationListener()).changeScreen(MainGame.ScreenType.GAME); أو ((MainGame) Gdx.app.getApplicationListener()).changeScreen(MainGame.ScreenType.SETTINGS);).
- التأكد من وجود GameScreen و SettingsScreen: يجب أن 
تكون ملفات GameScreen.java و SettingsScreen.java موجودة في الحزمة
 الصحيحة وتحتوي على منطق شاشة اللعبة وشاشة الإعدادات على التوالي.
- باستخدام هذا الهيكل، يمكنك الآن إدارة تدفق اللعبة والانتقال بين الشاشات المختلفة بسهولة أكبر. 
تذكر أن هذا هو الكود الأساسي لـ MainGame، وستحتاج إلى إضافة المزيد 
من المنطق إلى الشاشات الأخرى لجعل اللعبة تعمل بشكل كامل.

9. إنشاء شاشة "حول اللعبة" (تتضمن كود AboutScreen.java)

كود (AboutScreen.java):
Java




package com.example.topdownshooter.screens;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Screen;
import com.badlogic.gdx.scenes.scene2d.Actor;
import com.badlogic.gdx.scenes.scene2d.Stage;
import com.badlogic.gdx.scenes.scene2d.ui.Label;
import com.badlogic.gdx.scenes.scene2d.ui.ScrollPane;
import com.badlogic.gdx.scenes.scene2d.ui.Skin;
import com.badlogic.gdx.scenes.scene2d.ui.Table;
import com.badlogic.gdx.scenes.scene2d.ui.TextButton;
import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener;
import com.badlogic.gdx.utils.Align;
import com.badlogic.gdx.utils.ScreenUtils;
import com.example.topdownshooter.MainGame;

public class AboutScreen implements Screen {

    final MainGame game;
    Stage stage;
    Skin skin;

    public AboutScreen(final MainGame game) {
        this.game = game;
        this.stage = new Stage();
        Gdx.input.setInputProcessor(stage);
        this.skin = new Skin(Gdx.files.internal("uiskin.json"));

        Label titleLabel = new Label("حول اللعبة", skin);
        titleLabel.setFontScale(2);
        titleLabel.setAlignment(Align.center);

        String aboutText = "Top Down Shooter\n\n"
                + "Developed by: Your Name/Team Name\n"  // قم بتغيير هذا
                + "Version: 1.0\n"                      // قم بتغيير هذا
                + "Contact: your.email@example.com\n\n" // قم بتغيير هذا
                + "This game was created using LibGDX for Android.\n\n"
                + "Credits:\n"
                + "-  LibGDX Library\n"
                + "-  Free assets from [Asset Source]\n"  // قم بتغيير هذا إذا استخدمت أصول مجانية
                + "-  [Other Credits]\n\n"              // قم بإضافة أي اعتمادات أخرى
                + "Thank you for playing!";

        Label aboutLabel = new Label(aboutText, skin);
        aboutLabel.setAlignment(Align.center);
        aboutLabel.setWrap(true);

        ScrollPane scrollPane = new ScrollPane(aboutLabel, skin);
        scrollPane.setFadeScrollBars(false);

        TextButton backButton = new TextButton("رجوع", skin);
        backButton.addListener(new ChangeListener() {
            @Override
            public void changed(ChangeEvent event, Actor actor) {
                game.setScreen(new SettingsScreen(game)); // أو الشاشة التي تريد العودة إليها
                dispose();
            }
        });

        Table table = new Table();
        table.setFillParent(true);
        table.center();
        table.add(titleLabel).expandX().fillX().padBottom(20).row();
        table.add(scrollPane).expand().fill().padBottom(20).row();  // استخدم expand و fill مع ScrollPane
        table.add(backButton).fillX();

        stage.addActor(table);
    }

    @Override
    public void show() {
        Gdx.input.setInputProcessor(stage);
    }

    @Override
    public void render(float delta) {
        ScreenUtils.clear(0.2f, 0.2f, 0.2f, 1);
        stage.act(Math.min(Gdx.graphics.getDeltaTime(), 1 / 30f));
        stage.draw();
    }

    @Override
    public void resize(int width, int height) {
        stage.getViewport().update(width, height, true);
    }

    @Override
    public void pause() {
    }

    @Override
    public void resume() {
        Gdx.input.setInputProcessor(stage);
    }

    @Override
    public void hide() {
        Gdx.input.setInputProcessor(null);
    }

    @Override
    public void dispose() {
        stage.dispose();
        skin.dispose();
    }
}


--

يجب كتابة هذا الكود في ملف جديد باسم AboutScreen.java داخل الحزمة
 com.example.topdownshooter.screens.

* الخطوات التفصيلية:
- تصفح إلى مجلد الحزمة com.example.topdownshooter.
- داخل مجلد com.example.topdownshooter، ابحث عن مجلد فرعي باسم
 screens. إذا لم يكن موجودًا، فقم بإنشائه.
- داخل مجلد screens، قم بإنشاء ملف Java جديد وقم بتسميته 
AboutScreen.java (يجب أن يكون اسم الملف مطابقًا لاسم الكلاس تمامًا).
- افتح ملف AboutScreen.java والصق الكود الذي قدمته فيه.

شرح الكود:

هذا الكود ينشئ شاشة "حول اللعبة" (AboutScreen) تعرض معلومات أساسية عن اللعبة مثل اسمها، والمطور، والإصدار، ومعلومات الاتصال، والاعتمادات (المكتبات والأصول المستخدمة).
يستخدم Stage و Skin لإنشاء واجهة المستخدم.
يتم عرض عنوان باستخدام Label.
يتم عرض نص معلومات اللعبة باستخدام Label آخر مع خاصية setWrap(true) لضمان التفاف النص إذا كان طويلًا.
يتم وضع نص المعلومات داخل ScrollPane لجعل الشاشة قابلة للتمرير إذا كان النص طويلًا جدًا.
يحتوي على زر "رجوع" (TextButton) للعودة إلى الشاشة السابقة (في هذا الكود، تم تعيينه للعودة إلى SettingsScreen).
يتم تنظيم العناصر على الشاشة باستخدام Table.
* لتفعيل هذه الشاشة في لعبتك:
تأكد من استدعاء AboutScreen من مكان ما في لعبتك. على سبيل المثال، في شاشة
 الإعدادات (SettingsScreen)، قمت بإضافة زر "About Game". في المستمع الخاص
 بهذا الزر، يجب عليك إنشاء مثيل لـ AboutScreen وتعيينه كالشاشة الحالية باستخدام:
game.setScreen(new AboutScreen(game));

تأكد من استيراد كلاس AboutScreen في أي ملف Java تستخدمه فيه.
باتباع هذه الخطوات، ستتمكن من إضافة شاشة "حول اللعبة" إلى تطبيقك.

10. نشر اللعبة:

نشر تطبيق Android تم تطويره باستخدام AIDE يتضمن الخطوات التالية
 (قد تختلف التفاصيل قليلاً حسب إصدار AIDE):
- توقيع التطبيق: قبل نشر تطبيقك على متجر Google Play، يجب توقيعه باستخدام 
مفتاح خاص. يمكنك إنشاء مفتاح توقيع في AIDE من خلال قائمة "Build" أو
 "Export" (ابحث عن خيار يتعلق بتوقيع APK). اتبع التعليمات لإنشاء ملف
 keystore وكلمة مرور. احتفظ بملف keystore وكلمة المرور في مكان آمن، 
حيث أنهما ضروريان لتحديث تطبيقك في المستقبل.
- بناء APK: بعد توقيع التطبيق، يمكنك بناء ملف APK القابل للتثبيت.
 في AIDE، ابحث عن خيار "Build APK" أو "Run" ثم 
"Export Signed APK". سيقوم AIDE بإنشاء ملف APK في مجلد مشروعك أو في مجلد محدد.
- إنشاء حساب مطور Google Play: إذا لم يكن لديك حساب مطور Google Play،
 فستحتاج إلى إنشائه وتسجيله على موقع
 Google Play Console (play.google.com/console). 
هناك رسوم تسجيل تدفع مرة واحدة.
- إنشاء تطبيق في Google Play Console: قم بتسجيل الدخول إلى
 حساب مطور Google Play Console وانقر على "إنشاء تطبيق".
 املأ التفاصيل المطلوبة مثل اسم التطبيق، واللغة الافتراضية، وما إذا كان تطبيقًا أو لعبة.
- تحضير بيانات قائمة المتجر: ستحتاج إلى توفير معلومات مختلفة
 لتطبيقك في قائمة متجر Google Play، بما في ذلك:
عنوان ووصف قصير وطويل للتطبيق، أيقونة التطبيق،
لقطات شاشة أو مقاطع فيديو تعرض طريقة اللعب، نوع التطبيق (لعبة) وفئة،
تفاصيل الاتصال (موقع الويب، البريد الإلكتروني، رقم الهاتف)،
سياسة الخصوصية، تصنيف المحتوى.
- تحميل ملف APK: في قسم الإصدارات في Google Play Console، قم
 بتحميل ملف APK الذي قمت بإنشائه باستخدام AIDE.
- مراجعة ونشر: بعد ملء جميع المعلومات المطلوبة وتحميل ملف APK،
 يمكنك إرسال تطبيقك للمراجعة. قد تستغرق عملية المراجعة بعض الوقت. 
بمجرد الموافقة على تطبيقك، يمكنك نشره ليصبح متاحًا للمستخدمين على متجر Google Play.

* ملاحظات هامة حول النشر باستخدام AIDE:

قد تكون عملية توقيع وبناء APK أكثر تعقيدًا في AIDE مقارنة بأدوات تطوير
 Android Studio الأكثر تقدمًا. تأكد من اتباع التعليمات بعناية.
قد تحتاج إلى تثبيت أدوات بناء إضافية أو تكوين إعدادات معينة في AIDE لإكمال عملية البناء بنجاح.
راقب سجلات البناء والأخطاء بعناية أثناء عملية بناء APK.
هذا دليل تفصيلي يغطي الخطوات الأساسية لإنشاء لعبة إطلاق نار من الأعلى إلى الأسفل 
بسيطة وحفظ النقاط ونشرها باستخدام AIDE. تذكر أن تطوير الألعاب عملية
 تكرارية وقد تحتاج إلى إضافة المزيد من الميزات، وتحسين طريقة اللعب،
 وإصلاح الأخطاء أثناء تقدمك. حظًا سعيدًا في تطوير لعبتك!


* الخاتمة :

في هذا الدليل المفصل، استعرضنا الخطوات الأساسية لتطوير لعبة إطلاق نار
 من الأعلى إلى الأسفل ثنائية الأبعاد بسيطة على نظام Android باستخدام بيئة
 تطوير AIDE ومكتبة LibGDX. بدءًا من إعداد المشروع وإنشاء واجهة
 المستخدم الأولية، مرورًا بتنفيذ حركة اللاعب والأعداء، وإضافة آلية إطلاق النار
 ومعالجة الاصطدامات وتجميع النقاط، وصولًا إلى حفظ النتائج ونظرة عامة على 
عملية نشر اللعبة على متجر Google Play.
على الرغم من أن AIDE يوفر بيئة تطوير مباشرة على جهاز Android، إلا أن تطوير
 ألعاب أكثر تعقيدًا يتطلب فهمًا جيدًا لمفاهيم برمجة الألعاب واستخدام مكتبات مثل LibGDX.
 تذكر أن هذا المقال يقدم أساسًا متينًا، وأن إضافة المزيد من الميزات، وتحسين طريقة اللعب،
 وتصميم مستويات جذابة هي خطوات أساسية لإنشاء لعبة ممتعة وجذابة. 
استمر في التعلم والتجربة لتطوير مهاراتك في تطوير ألعاب Android.


جدول المحتويات