JavaFX طريقة إنشاء لعبة من سيربح المليون
في هذا الدرس ستتعلم طريقة إنشاء لعبة من سيربح المليون ( Who will win the million ) إحترافية بإستخدام إطار JavaFX.
In this lesson, you will learn how to create a professional Who Will Win the Million Game using the JavaFX framework.
مميزات لعبة من سيربح المليون ( Who will win the million ) إحترافية بإستخدام إطار JavaFX.
تلائم حجم أي شاشة كمبيوتر يتم تشغيلها عليه لأنها مبنية بطريقة ( Responsive ).
فيها أشكال هندسية مخصصة و مصممة بطريقة تجذب المستخدم, و عدة أصوات و مؤثرات بصرية يتم تشغيلها عندما يتفاعل المستخدم مع اللعبة.
تحتوي على 100 سؤال و 400 إجابة يتم عرضهم بشكل عشوائي.
فيها نفس وسائل المساعدة الموجودة في لعبة من سيربح المليون.
يمكنك تطوير اللعبة و تغيير الأسئلة و الإجابات بسهولة إذا أردت إنشاء نسختك الخاصة من اللعبة.
بناء لعبة من سيربح المليون ( Who will win the million ) إحترافية بإستخدام إطار JavaFX.
ملفات الجافا وضعناها مباشرةً في المشروع.
إستخدمنا خط خاص وضعناه في مجلد إسمه
fonts
.الصور وضعناه بداخل مجلد إسمه
images
.الأصوات وضعناه بداخل مجلد إسمه
sounds
.
خيارات التحميل
⇓ تحميل اللعبة ⇓ تحميل المشروع كاملاً
معلومات عامة عن الكود
الكلاس
AboutButtonShape
قمنا ببنائه خصيصاً لنحصل على شكل الزر الذي أظهرناه في صفحة حول التطبيقالكلاس
AboutPane
قمنا ببنائه خصيصاً لنحصل على الحاوية الأساسية التي سنعرضها في صفحة حول التطبيق مع الإشارة إلى أننا وضعنا فيه كل محتوى الصفحة.الكلاس
GameAnswerButton
قمنا ببنائه خصيصاً لنحصل على شكل الأزرار التي يمكن النقر عليها لاختيار الإجابة في صفحة اللعبالكلاس
GamePane
قمنا ببنائه خصيصاً لتمثيل صفحة اللعبالكلاس
GameQuestionShape
قمنا ببنائه خصيصاً لنحصل على شكل الحاوية التي ستوضع فيها الأسئلة في صفحة اللعبالكلاس
Main
قمنا ببناء نافذة اللعبة كل الصفحات الموجودة فيها بالإضافة إلى أنه يعتبر نقطة البداية في هذا المشروع.الكلاس
MenuItemShape
قمنا ببنائه خصيصاً لبناء شكل الأزرار التي وضعناها في صفحة القائمة الرئيسيةالكلاس
MenuPane
قمنا ببنائه خصيصاً لتمثيل صفحة القائمة الرئيسيةالكلاس
Questions
وضعنا فيه جميع أسئلة اللعبة مع الإجابات الخاصة بها.الكلاس
ResultPane
قمنا ببنائه خصيصاً لتمثيل صفحة النتيجة النهائيةالكلاس
Sounds
قمنا ببنائه خصيصاً لتجهيز دوال يمكن إستخدامها لتشغيل أصوات في اللعبة.الإنترفيس
ScreenBounds
وضعنا فيه المعلومات الأساسية و المشتركة التي يجب أن تتوفر في كل حاوية تمثل صفحة في اللعبة.
كود لعبة من سيربح المليون ( Who will win the million ) إحترافية بإستخدام إطار JavaFX.
import javafx.beans.binding.Bindings; import javafx.scene.paint.Color; import javafx.scene.shape.Polygon; import javafx.scene.shape.Rectangle; // و جعله قابل للنقر (Width + Height) هو لتمكيننا من إعطائه حجم Rectangle يرث من الكلاس AboutButtonShape سبب جعل الكلاس public class AboutButtonShape extends Rectangle { // AboutButtonShape لأننا سنعتمد عليه لنرسم شكل الزر الذي نريد الحصول عليه عند إنشاء كائن من الكلاس Polygon هنا قمنا بتعريف كائن نوعه Polygon polygon; // هنا قمنا بتجهيز هذا الكونستركتور حتى نستطيع تحديد حجم الزر مباشرةً عند إنشاء كائن من هذا الكلاس public AboutButtonShape(int width, int height) { // عند إنشاء كائن من الكلاس height و width لاحظ أن شكل الزر الذي سيتم رسمه يعتمد بشكل أساسي على القيم التي سنمررها للباراميترين polygon = new Polygon( 0, height/2, 20, 0, width-20, 0, width, height/2, width-20, height, 20, height, 0, height/2 ); // لأننا سندمجه معه AboutButtonShape و الذي بدوره سيتم تطبيقه على الكائن الذي ننشئه من الكلاس polygon هنا قمنا بإضافة لون أبيض باهت حول الكائن polygon.setStroke(Color.color(1, 1, 1, 0.75)); // الطبيعي هو غامق بنسبة 25 بالمئة و سيصبح أغمق بنسبة 50 بالمئة حين ننقر فوقه بالفأرة polygon هنا حددنا أن لون خلفية الكائن polygon.fillProperty().bind(Bindings.when(pressedProperty()) .then(Color.color(0, 0, 0, 0.50)) .otherwise(Color.color(0, 0, 0, 0.25)) ); // AboutButtonShape عند إنشاء كائن من الكلاس height و width حددنا أن حجم الشكل الذي سنحصل عليه سيكون مطابقاً للقيم التي نمررها مكان البارميترين // AboutButtonShape يساوي حجم الكائن الذي سنحصل عليه عند دمجه مع الكائن الذي ننشئه من الكلاس polygon بهذه الطريقة يكون حجم الكائن this.setWidth(width); this.setHeight(height); // هو أزرق AboutButtonShape هنا حددنا أن لون خلفية الكائن الذي سنحصل عليه عند إنشاء كائن من الكلاس // كما أنه عند تمرير الفأرة فوقه سيتحول شكل السهم إلى شكل إصبع, مما يجعل المستخدم يدرك أن هذا الشكل قابل للنقر this.setFill(Color.BLUE); this.setStyle("-fx-cursor: hand;"); // AboutButtonShape على الكائن الذي ننشئه من الكلاس polygon هنا قمنا بدمج و تطبيق خصائص الكائن this.setClip(polygon); } }
import javafx.geometry.Insets; import javafx.geometry.Pos; import javafx.scene.control.Label; import javafx.scene.input.MouseEvent; import javafx.scene.layout.StackPane; import javafx.scene.layout.VBox; import javafx.scene.paint.Color; import javafx.scene.text.Font; import javafx.scene.text.TextAlignment; // حتى يظهر محتواه في وسط النافذة StackPane يرث من الكلاس AboutPane هنا جعلنا الكلاس // حتى يكون حجمه مطابق لحجم شاشة المستخدم ScreenBounds و جعلناه يطبق الإنترفيس public class AboutPane extends StackPane implements ScreenBounds { // حتى نستطيع إستدعاء دوال تشغيل الأصوات التي جهزناها فيه Sounds هنا قمنا بإنشاء كائن من الكلاس Sounds mySounds = new Sounds(); // لأننا سنعرض النص عليه Label هنا قمنا بإنشاء كائن من الكلاس Label label = new Label("تم تصميم هذه اللعبة لتشجيع الطلاب على التعلم و لمساعدتهم في إختبار قدراتهم على الحفظ\n" + "اللعبة من إعداد المبرمج محمد هرموش و هي مجانية بالكامل"); // حتى نحصل على شكل زر خاص لونه لون خلفيته أزرق, مع تحديد حجمه AboutButtonShape هنا قمنا بإنشاء كائن من الكلاس AboutButtonShape buttonShape = new AboutButtonShape(220, 40); // buttonShape بهدف وضعه كنص للزر الذي يمثله الكائن Label هنا قمنا بإنشاء كائن من الكلاس Label buttonLabel = new Label("رجوع"); // label لأننا ننوي إنشاء حاوية عامودية حتى نعرض بواسطتها نص الكائن VBox هنا قمنا بإنشاء كائن من الكلاس // buttonLabel نص الزر الذي يمثله الكائن + buttonShape و تحته الزر الذي يمثله الكائن VBox vBox = new VBox(30); // AboutPane هنا قمنا بتجهيز هذا الكونستركتور لتحديد ما سيحدث عند إنشاء كائن من الكلاس public AboutPane() { // AboutPane كخلفية للحاوية التي سنحصل عليها عند إنشاء كائن من الكلاس GetBGImage() هنا قمنا بوضع الصورة التي ترجعها الدالة this.setBackground(Main.GetBGImage()); // ( لون النص, نوع الخط, حجم الخط و مكان ظهوره ) label هنا قمنا بتحديد خصائص ظهور الكائن label.setTextFill(Color.WHITE); label.setFont(Font.loadFont(Main.class.getResource("res/fonts/droidnaskh-regular-webfon.ttf").toExternalForm(), 18)); label.setTextAlignment(TextAlignment.CENTER); // ( حجمه, مكان ظهوره, لون النص, نوع الخط, حجم الخط و حجم الفراغ حوله ) buttonLabel هنا قمنا بتحديد خصائص ظهور الكائن buttonLabel.setPrefSize(220, 40); buttonLabel.setAlignment(Pos.CENTER); buttonLabel.setTextFill(Color.WHITE); buttonLabel.setFont(Font.loadFont(Main.class.getResource("res/fonts/droidnaskh-regular-webfon.ttf").toExternalForm(), 14)); buttonLabel.setPadding(new Insets(-5, 0, 0, 0)); // buttonShape يظهر فوق شكل الزر الذي يمثله الكائن buttonLabel خصيصاً لنجعل نص الكائن StackPane قمنا بإنشاء كائن من الكلاس // buttonPane و أصبحنا نستطيع تحريكهما معاً بواسطة الكائن buttonShape بالكائن buttonLabel أي كأننا ألصقنا الكائن StackPane buttonPane = new StackPane(); buttonPane.setPrefSize(220, 40); buttonPane.getChildren().addAll(buttonLabel, buttonShape); // buttonPane و تحته الزر الذي تمثله الحاوية label هكذا سيظهر في الصفحة نص الكائن .vBox في الكائن buttonPane و من ثم الكائن label هنا قمنا بإضافة الكائن vBox.getChildren().addAll(label, buttonPane); // AboutPane يظهر في وسطها و من ثم أضفناها إلى الحاوية التي سنحصل عليها عند إنشاء كائن من الكلاس vBox هنا جعلنا محتوى الحاوية vBox.setAlignment(Pos.CENTER); this.getChildren().add(vBox); // buttonShape هنا قمنا بتحديد ما سيحدث عند النقر على الزر الذي يمثله الكائن buttonShape.setOnMouseClicked((MouseEvent t) -> { // Scene لتشغيل صوت نقرة. بعدها سيتم تبديل الحاوية الأساسية في الـ clickSound() سيتم إستدعاء الدالة // و بالتالي سيظهر للمستخدم كأنه عاد لصفحة القائمة الأساسية في البرنامج .PANE_MENU بالحاوية mySounds.clickSound(); Main.STAGE.getScene().setRoot(Main.PANE_MENU); }); } }
import javafx.beans.binding.Bindings; import javafx.geometry.Insets; import javafx.geometry.Pos; import javafx.scene.control.Label; import javafx.scene.layout.Pane; import javafx.scene.paint.Color; import javafx.scene.shape.Polygon; import javafx.scene.shape.Rectangle; import javafx.scene.text.Font; import javafx.scene.text.TextAlignment; // و جعله قابل للنقر (Width + Height) هو لتمكيننا من إعطائه حجم Rectangle يرث من الكلاس GameAnswerButton سبب جعل الكلاس public class GameAnswerButton extends Rectangle { // GameAnswerButton لأننا سنعتمد عليه لنرسم شكل الزر الذي نريد الحصول عليه عند إنشاء كائن من الكلاس Polygon قمنا بتعريف كائن من الكلاس // GameAnswerButton لأننا سنعتمد عليه لعرض النص الذي نريد وضعه على الزر الذي سيملثه الكائن الذي ننشئه من الكلاس Label و قمنا بتعريف كائن من الكلاس Polygon clip; Label label = new Label(); // clip يظهر فوق شكل الزر الذي يمثله الكائن label خصيصاً لنجعل نص الكائن Pane قمنا بإنشاء كائن من الكلاس Pane pane = new Pane(); // هنا قمنا بتجهيز هذا الكونستركتور حتى نستطيع تحديد حجم الزر + مكان ظهوره مباشرةً عند إنشاء كائن من هذا الكلاس public GameAnswerButton(int width, int height, int x, int y) { // عند إنشاء كائن من الكلاس height و width لاحظ أن شكل الزر الذي سيتم رسمه يعتمد بشكل أساسي على القيم التي سنمررها للباراميترين clip = new Polygon( 0, height / 2, 20, height / 2, 40, 0, width - 40, 0, width - 20, height / 2, width, height / 2, width - 20, height / 2, width - 40, height, 40, height, 20, height / 2 ); // لأننا سندمجه معه GameAnswerButton و الذي بدوره سيتم تطبيقه على الكائن الذي ننشئه من الكلاس polygon هنا قمنا بإضافة لون أبيض باهت حول الكائن clip.setStroke(Color.color(1, 1, 1, 0.75)); // الطبيعي هو غامق بنسبة 25 بالمئة و سيصبح أغمق بنسبة 50 بالمئة حين ننقر فوقه بالفأرة polygon هنا حددنا أن لون خلفية الكائن clip.fillProperty().bind(Bindings.when(pressedProperty()) .then(Color.color(0, 0, 0, 0.50)) .otherwise(Color.color(0, 0, 0, 0.25)) ); // GameAnswerButton عند إنشاء كائن من الكلاس height و width حددنا أن حجم الشكل الذي سنحصل عليه سيكون مطابقاً للقيم التي نمررها مكان البارميترين // GameAnswerButton يساوي حجم الكائن الذي سنحصل عليه عند دمجه مع الكائن الذي ننشئه من الكلاس polygon بهذه الطريقة يكون حجم الكائن this.setWidth(width); this.setHeight(height); // هو أزرق GameAnswerButton هنا حددنا أن لون خلفية الكائن الذي سنحصل عليه عند إنشاء كائن من الكلاس // كما أنه عند تمرير الفأرة فوقه سيتحول شكل السهم إلى شكل إصبع, مما يجعل المستخدم يدرك أن هذا الشكل قابل للنقر this.setDefaultBg(); this.setStyle("-fx-cursor: hand;"); // GameAnswerButton على الكائن الذي ننشئه من الكلاس polygon هنا قمنا بدمج و تطبيق خصائص الكائن this.setClip(clip); // ( حجمه, مكان ظهوره, لون النص, نوع الخط, حجم الخط و حجم الفراغ حوله ) label هنا قمنا بتحديد خصائص ظهور الكائن label.setFont(new Font(16)); label.setTextFill(Color.WHITE); label.setTextAlignment(TextAlignment.CENTER); label.setPrefSize(width, height); label.setTextFill(Color.WHITE); label.setAlignment(Pos.CENTER_RIGHT); label.setPadding(new Insets(-5, 45, 0, 45)); // pane في الكائن GameAnswerButton ثم الكائن الأساسي الذي ننشئه من الكلاس label هنا قمنا بوضع الكائن // pane و أصبحنا نستطيع تحريكهما معاً بواسطة الكائن GameAnswerButton بالكائن الذي يتم إنشاؤه من الكلاس label أي كأننا ألصقنا الكائن pane.getChildren().addAll(label, this); // GameAnswerButton و حجمها و جعلناها مطابقة لحجم الكائن الذي ننشئه من الكلاس pane هنا قمنا بتحديد مكان ظهور الحاوية pane.setTranslateX(x); pane.setTranslateY(y); pane.setPrefSize(width, height); } // أخضر, و نستدعيها في حال نقر المستخدم على الإجابة الصحيحة GameAnswerButton هذه الدالة تجعل لون خلفية الزر الذي يمثله الكائن الذي ننشئه من الكلاس public void setWinBg() { this.setFill(Color.GREEN); } // برتقالي, و نستدعيها في حال نقر المستخدم على إجابة خطائة GameAnswerButton هذه الدالة تجعل لون خلفية الزر الذي يمثله الكائن الذي ننشئه من الكلاس public void setLooseBg() { this.setFill(Color.ORANGE); } // أزرق, و نستدعيها لوضع اللون الإفتراضي للزر GameAnswerButton هذه الدالة تجعل لون خلفية الزر الذي يمثله الكائن الذي ننشئه من الكلاس public void setDefaultBg() { this.setFill(Color.BLUE); } // GameAnswerButton هذه الدالة نمرر لها النص الذي نريد وضعه كنس للزر الذي يمثله الكائن الذي ننشئه من الكلاس public void setText(String s) { this.label.setText(s); } // GameAnswerButton هذه الدالة ترجع النص الظاهر على الزر الذي يمثله الكائن الذي ننشئه من الكلاس public String getText() { return this.label.getText(); } // و النص الموضوع فوقه GameAnswerButton هذه الدالة ترجع الحاوية التي تحتوي على الزر الذي يمثله الكائن الذي ننشئه من الكلاس public Pane getPane() { return pane; } // و النص الموضوع فوقه GameAnswerButton هذه الدالة تستخدم لإخفاء الزر الذي يمثله الكائن الذي ننشئه من الكلاس public void hide() { this.setVisible(false); label.setVisible(false); } // و النص الموضوع فوقه GameAnswerButton هذه الدالة تستخدم لعرض الزر الذي يمثله الكائن الذي ننشئه من الكلاس public void show() { this.setVisible(true); label.setVisible(true); } }
import java.util.ArrayList; import java.util.Collections; import javafx.animation.KeyFrame; import javafx.animation.Timeline; import javafx.application.Platform; import javafx.event.ActionEvent; import javafx.geometry.Insets; import javafx.geometry.Pos; import javafx.scene.control.Button; import javafx.scene.control.ContentDisplay; import javafx.scene.control.Label; import javafx.scene.image.Image; import javafx.scene.image.ImageView; import javafx.scene.input.MouseEvent; import javafx.scene.layout.Background; import javafx.scene.layout.BackgroundFill; import javafx.scene.layout.CornerRadii; import javafx.scene.layout.HBox; import javafx.scene.layout.Pane; import javafx.scene.layout.StackPane; import javafx.scene.layout.VBox; import javafx.scene.paint.Color; import javafx.scene.text.Font; import javafx.util.Duration; public class GamePane extends Pane implements ScreenBounds { // حتى نستطيع إستدعاء دوال تشغيل الأصوات التي جهزناها فيه Sounds هنا قمنا بإنشاء كائن من الكلاس Sounds mySounds = new Sounds(); // هنا قمنا بإنشاء كل العناصر الظاهرة في النافذة Button btnExit = new Button("", new ImageView(new Image(getClass().getResourceAsStream("/res/images/Close-icon.png")))); Button btnBack = new Button("", new ImageView(new Image(getClass().getResourceAsStream("/res/images/Go-back-icon.png")))); Button btnCallFriend = new Button("", new ImageView(new Image(getClass().getResourceAsStream("/res/images/Phone-icon.png")))); Button btnAskAudience = new Button("", new ImageView(new Image(getClass().getResourceAsStream("/res/images/User-Group-icon.png")))); Button btnDeleteTwoAnswers = new Button("", new ImageView(new Image(getClass().getResourceAsStream("/res/images/Number-2-icon.png")))); Button btnPlayGame = new Button("إبدأ الآن"); Label timerLabel = new Label(); // هذا الكائن سنعرض عليه التوقيت الباقي للإجابة عن الأسئلة و الذي يظهر عندما تبدأ اللعبة StackPane playButtonPane = new StackPane(); // هذه الحاوية الأساسية التي وضعنا فيها كل شيء, و التي بدورها ستظهره في وسط النافذة ArrayList<Label> moneyLabels = new ArrayList(); // ArrayList موجود في هذا الـ Label حاوية المال التي تظهر في يمين النافذة, كل مربع فيها عبارة // هذا الكائن يمثل الحاوية التي يظهر فيها السؤال GameQuestionShape questionShape = new GameQuestionShape(640, 60); // هذه الكائنات تمثل الأزرار التي تظهر عليها الإجابات المحتلمة لكل سؤال GameAnswerButton answer1 = new GameAnswerButton(320, 40, 320, 10); GameAnswerButton answer2 = new GameAnswerButton(320, 40, 0, 10); GameAnswerButton answer3 = new GameAnswerButton(320, 40, 320, 60); GameAnswerButton answer4 = new GameAnswerButton(320, 40, 0, 60); // محتوى نافذة اللعب سيتم تقسيمه فعلياً على الخمس حاوية التالية HBox hBox = new HBox(); VBox vBox = new VBox(); Pane answersPane = new Pane(); HBox topMenuBox = new HBox(10); VBox moneyBox = new VBox(4); // سنخزن فيه جميع الأسئلة و الإجابات التي قمنا بإعدادها للعبة questions الكائن Questions questions; // سنخزن فيه في كل مرة سؤال جديد مع الإجابات الخاصة بهذا السؤال question الكائن Question question; // سنستخدم جميع المتغيرات التالية لإظهار المؤثرات بأوقات محددة بالإضافة إلى حفظ نشاط اللاعب بشكل مؤقت boolean isGameOver; int InitialSeconds; Integer RemainingSeconds; boolean anAnswerButtonIsClicked; boolean isAnswerCorrect; String whichButtonIsClicked; int correctAnswersCounter; int totalEarning; // هذا الكائن سنستخدمه عند إعطاء المستخدم مهلة 30 ثانية للإجابة بالإضافة إلى المؤثرات التي سنعرضها خلال فترات مختلفة Timeline timeline; // هذا المتغير سنستخدمه لتخزين عدد الإجابات التي يمكن للمستخدم أن أن ينقر عليها و فعلياً ستتغير قيمته فقط عندما يقوم بحذف إجابتين int hiddenButtonsCounter; // هذا المتغير سنستخدمه كمؤشر لمعرفة ما إن كان المستخدم قد إستخدم وسيلة الإتصال بصديق أم لا boolean aFriendIsCalled; // هذا المتغير سنستخدمه كمؤشر لمعرفة ما إن كان المستخدم قد إستخدم وسيلة سؤال الجمهور أم لا boolean userIsAskingAudience; // لكل شيء Reset هذه الدالة يجب استدعاءها في كل مرة سيتم فيها البدء باللعب بهدف أن تقوم بتصفير اللعبة أو تفعل ما نسميه public void initialValues() { questions = new Questions(); isGameOver = false; timeline = new Timeline(); InitialSeconds = 30; RemainingSeconds = InitialSeconds; anAnswerButtonIsClicked = false; isAnswerCorrect = false; whichButtonIsClicked = ""; correctAnswersCounter = 0; totalEarning = 0; hiddenButtonsCounter = 0; aFriendIsCalled = false; userIsAskingAudience = false; } // هذه الدالة يجب استدعاءها عندما يتم بدأ اللعبة و هي بدورها ستقوم فقط باستدعاء الدوال الموضوعة فيها بالترتيب public void playGame() { initialValues(); mySounds.clickSound(); displayNewQestion(); checkAnswer(); } // هذه الدالة يجب استدعاءها عندما يقوم المستخدم باختيار إجابة صحيحة بهدف أن تحدد له كم ربح حتى الآن, فعلياً ستجعل المرحلة التي وصل إليها تظهر بلون متميز public void markLastPassedLevel() { for (Label label : moneyLabels) { label.setTextFill(Color.YELLOW); label.setBackground(new Background(new BackgroundFill(Color.BLACK, new CornerRadii(5), Insets.EMPTY))); } moneyLabels.get(correctAnswersCounter).setTextFill(Color.WHITE); moneyLabels.get(correctAnswersCounter).setBackground(new Background(new BackgroundFill(Color.BLUE, new CornerRadii(5), Insets.EMPTY))); totalEarning = Integer.parseInt(moneyLabels.get(correctAnswersCounter).getText()); } // و من ثم عرضه في واجهة المستخدم questions هذه الدالة تستخدم لجلب سؤال جديد بشكل عشوائي من الكائن // نلاحظ أنه قبل جلب أي سؤال جديد يجب التأكد من عدة أمور, فمثلاً إذا كان المستخدم // قد أجاب عن 15 سؤال بشكل صحيح, يجب إعلامه بأنه قد ربح بدل عرض سؤال جديد أمامه public void displayNewQestion() { if (userIsAskingAudience == true) { userIsAskingAudience = false; } if (aFriendIsCalled == true) { aFriendIsCalled = false; } if (correctAnswersCounter >= 15) { timeline.stop(); ResultPane.setResult(correctAnswersCounter, totalEarning); Main.STAGE.getScene().setRoot(Main.PANE_RESULT); } else { if (hiddenButtonsCounter != 0) { hiddenButtonsCounter = 0; answer1.show(); answer2.show(); answer3.show(); answer4.show(); } question = questions.getQuestion(); Collections.shuffle(question.answers); answer1.setDefaultBg(); answer2.setDefaultBg(); answer3.setDefaultBg(); answer4.setDefaultBg(); questionShape.setText(question.getPhrase()); answer1.setText(question.getAnswer(0).getText()); answer2.setText(question.getAnswer(1).getText()); answer3.setText(question.getAnswer(2).getText()); answer4.setText(question.getAnswer(3).getText()); } } // هذه الدالة تستخدم لنقل اللاعب إلى الحاوية التي تعرض له نتيجته public void displayResult() { timeline.stop(); ResultPane.setResult(correctAnswersCounter, totalEarning); Main.STAGE.getScene().setRoot(Main.PANE_RESULT); } // هذه الدالة تستخدم للتأكد من إجابة المستخدم, مع الإشارة إلى أنها أكثر دالة معقدة في كل هذا البرنامج // حيث أنها تحلل كل ما يقوم به المستخدم, لعرض كل الأشياء التي يجب أن تظهر له في التوقيت المناسب public void checkAnswer() { timeline.setCycleCount(Timeline.INDEFINITE); timeline.getKeyFrames().add(new KeyFrame(Duration.seconds(1), (ActionEvent event) -> { if (RemainingSeconds == 0) { timerLabel.setText("إنتهى الوقت"); // سيتم استدعاءها بعد ثانيتين displayResult() قمنا بإضافة الأسطر الثلاثة التالية فقك لضمان أن الدالة RemainingSeconds = -5; isAnswerCorrect = false; anAnswerButtonIsClicked = true; } else { // إذا لم يقم المستخدم بالنقر على أي إجابة, سيتم عرض الوقت المتبقي له للإجابة فقط if (anAnswerButtonIsClicked == false) { // في حال قام بالنقر على زر الإتصال بصديق, سيتم طباعة الجمل التالية مع عرض كل جملة مدة ثانيتين تقريباً // و في النهاية سيتم عرض الجواب الصحيح أمامه if (aFriendIsCalled == true) { if (RemainingSeconds == 40) { timerLabel.setText("يتم الآن الإتصال بصديقك"); } else if (RemainingSeconds == 37) { timerLabel.setText("مرحباً بك أيها الصديق"); } else if (RemainingSeconds == 34) { timerLabel.setText("معك 30 ثانية للإجابة على السؤال التالي"); } else if (RemainingSeconds == 30) { timerLabel.setText(question.getPhrase()); } else if (RemainingSeconds == 22) { timerLabel.setText("أعتقد أن الجواب الصحيح هو"); } else if (RemainingSeconds == 18) { if (question.getAnswer(0).isCorrect == true) { timerLabel.setText(question.getAnswer(0).getText()); } else if (question.getAnswer(1).isCorrect == true) { timerLabel.setText(question.getAnswer(1).getText()); } else if (question.getAnswer(2).isCorrect == true) { timerLabel.setText(question.getAnswer(2).getText()); } else if (question.getAnswer(3).isCorrect == true) { timerLabel.setText(question.getAnswer(3).getText()); } } else if (RemainingSeconds == 1) { aFriendIsCalled = false; RemainingSeconds = InitialSeconds; } } ///////////////////////////////////////////////////////////// // في حال قام بالنقر على زر طلب المساعدة من الجمهور, سيتم طباعة الجمل التالية مع عرض كل جملة مدة خمس ثواني // و في النهاية سيتم عرض الجواب الصحيح أمامه else if (userIsAskingAudience == true) { if (RemainingSeconds == 40) { timerLabel.setText("سيساعدك الآن الجمهور باختيار الإجابة الصحيحة"); } else if (RemainingSeconds == 35) { timerLabel.setText("النسبة الأكبر من الأصوات إختارت الإجابة"); } else if (RemainingSeconds == 30) { if (question.getAnswer(0).isCorrect == true) { timerLabel.setText(question.getAnswer(0).getText()); } else if (question.getAnswer(1).isCorrect == true) { timerLabel.setText(question.getAnswer(1).getText()); } else if (question.getAnswer(2).isCorrect == true) { timerLabel.setText(question.getAnswer(2).getText()); } else if (question.getAnswer(3).isCorrect == true) { timerLabel.setText(question.getAnswer(3).getText()); } } else if (RemainingSeconds == 20) { userIsAskingAudience = false; RemainingSeconds = InitialSeconds; } } // هذا الأمر, يعني أنه سيتم عرض الوقت المتبقي للإجابة في حال كان المستخدم لا يطلب حالياً مساعدة صديق أو مساعدة جمهور else { timerLabel.setText(RemainingSeconds.toString()); } RemainingSeconds--; } // إذا تم النقر على أي إجابة, سيتم التأكد من ما إذا كانت الإجابة صحيحة أم لا و على أساس ذلك سيتم عرض جمل معينة أمامه else if (anAnswerButtonIsClicked == true) { // أكبر من 0, سيتم عرض جملة جديدة كل ثانيتين RemainingSeconds إذا كانت قيمة المتغير if (RemainingSeconds > 0) { RemainingSeconds = 0; } // RemainingSeconds بعدها سيتم إنقاص ثانية واحدة من المتغير RemainingSeconds--; // هنا قمنا بتحديد الجملة الأولى التي سيتم طباعتها if (RemainingSeconds <= -2 && RemainingSeconds >= -5) { if (isAnswerCorrect == true) { timerLabel.setText("الإجابة صحيحة"); } else { timerLabel.setText("الإجابة غير صحيحة"); // إذا كان المستخدم قد قام باختيار إجابة خاطئة, سيتم جعل لون خلفية الزر الذي نقر عليه برتقالي switch (whichButtonIsClicked) { case "answer1": answer1.setLooseBg(); break; case "answer2": answer2.setLooseBg(); break; case "answer3": answer3.setLooseBg(); break; case "answer4": answer4.setLooseBg(); break; } if (RemainingSeconds == -3) { // بعد أن يقوم المستخدم باختيار أي إجابة, سيتم تلوين خلفية الإجابة الصحيحة باللون الأخضر if (question.getAnswer(0).isCorrect == true) { answer1.setWinBg(); } else if (question.getAnswer(1).isCorrect == true) { answer2.setWinBg(); } else if (question.getAnswer(2).isCorrect == true) { answer3.setWinBg(); } else if (question.getAnswer(3).isCorrect == true) { answer4.setWinBg(); } } } } // هنا قمنا بتحديد الجملة الثانية التي سيتم طباعتها else if (RemainingSeconds <= -6 && RemainingSeconds >= -9) { if (isAnswerCorrect == true) { if (RemainingSeconds == -6) { timerLabel.setText("أصبح رصيدك " + moneyLabels.get(correctAnswersCounter).getText()); markLastPassedLevel(); correctAnswersCounter++; } // حتى يتم نقله لصفحة النتيجة displayResult() إذا تم إنهاء جميع الأسئلة بنجاح سيتم إستدعاء الدالة if (correctAnswersCounter == 16 && RemainingSeconds == -9) { displayResult(); } } else { if (RemainingSeconds == -9) { displayResult(); } } } // هنا قمنا بتحديد الجملة الثالثة التي سيتم طباعتها else if (RemainingSeconds <= -10 && RemainingSeconds >= -13) { timerLabel.setText("إستعد للسؤال التالي"); } // هنا قمنا بوضع السؤال التالي للمستخدم else if (RemainingSeconds <= -14 && RemainingSeconds >= -16) { if (RemainingSeconds == -16) { anAnswerButtonIsClicked = false; RemainingSeconds = InitialSeconds; displayNewQestion(); } } } } // إذا كان المستخدم يملك 10 ثواني أو أقل للإجابة سيتم تشغيل صوت يشبه دقة الثانية في كل ثانية if (RemainingSeconds >= 0 && RemainingSeconds < 10 && aFriendIsCalled == false && userIsAskingAudience == false) { mySounds.clockTickSound(); } } )); // كما كان قبل تشغيله. أي كأنها تقوم بتصفيره timeline حتى تعيد الكائن playFromStart() الدالة timeline.playFromStart(); } // هذا كونستركتور الكلاس public GamePane() { answer1.setOnMousePressed((MouseEvent t) -> { if (anAnswerButtonIsClicked == false) { answer1.setWinBg(); if (question.getAnswer(0).isCorrect == true) { mySounds.ClickOnCorrectAnswerSound(); isAnswerCorrect = true; } else { mySounds.ClickOnWrongAnswerSound(); isAnswerCorrect = false; } anAnswerButtonIsClicked = true; whichButtonIsClicked = "answer1"; } }); answer2.setOnMousePressed((MouseEvent t) -> { if (anAnswerButtonIsClicked == false) { answer2.setWinBg(); if (question.getAnswer(1).isCorrect == true) { mySounds.ClickOnCorrectAnswerSound(); isAnswerCorrect = true; } else { mySounds.ClickOnWrongAnswerSound(); isAnswerCorrect = false; } anAnswerButtonIsClicked = true; whichButtonIsClicked = "answer2"; } }); answer3.setOnMousePressed((MouseEvent t) -> { if (anAnswerButtonIsClicked == false) { answer3.setWinBg(); if (question.getAnswer(2).isCorrect == true) { mySounds.ClickOnCorrectAnswerSound(); isAnswerCorrect = true; } else { mySounds.ClickOnWrongAnswerSound(); isAnswerCorrect = false; } anAnswerButtonIsClicked = true; whichButtonIsClicked = "answer3"; } }); answer4.setOnMousePressed((MouseEvent t) -> { if (anAnswerButtonIsClicked == false) { answer4.setWinBg(); if (question.getAnswer(3).isCorrect == true) { mySounds.ClickOnCorrectAnswerSound(); isAnswerCorrect = true; } else { mySounds.ClickOnWrongAnswerSound(); isAnswerCorrect = false; } anAnswerButtonIsClicked = true; whichButtonIsClicked = "answer4"; } }); this.setPrefSize(WIDTH, HEIGHT); setGameImage(); answersPane.setPrefSize(640, 100); moneyBox.setPrefSize(130, 510); btnExit.setPrefSize(100, 50); btnBack.setPrefSize(100, 50); btnCallFriend.setPrefSize(100, 50); btnAskAudience.setPrefSize(100, 50); btnDeleteTwoAnswers.setPrefSize(100, 50); timerLabel.setPrefSize(640, 300); timerLabel.setFont(new Font(30)); timerLabel.setTextFill(Color.WHITE); timerLabel.setContentDisplay(ContentDisplay.CENTER); timerLabel.setAlignment(Pos.CENTER); String btnStyle = "-fx-focus-color: transparent; -fx-border-width:2; -fx-border-color: #87cefa; -fx-border-radius:50; -fx-background-radius:50; -fx-background-color:rgba(30, 30, 30, 0.5); -fx-cursor: hand;"; btnExit.setStyle(btnStyle); btnBack.setStyle(btnStyle); btnCallFriend.setStyle(btnStyle); btnAskAudience.setStyle(btnStyle); btnDeleteTwoAnswers.setStyle(btnStyle); btnStyle = "-fx-focus-color: transparent; " + "-fx-border-width: 2;" + "-fx-border-color: #00f;" + "-fx-border-radius: 10;" + "-fx-text-fill: white;" + "-fx-background-color: rgba(30, 30, 30, 0.5);" + "-fx-cursor: hand;" + "-fx-font-size: 18;" + "-fx-padding: 10 0 10 0;" + "-fx-pref-width: 220;" + "-fx-pref-height: 40;" + "-fx-padding: 10 0 10 0;"; btnPlayGame.setStyle(btnStyle); playButtonPane.setPrefSize(640, 300); playButtonPane.getChildren().add(btnPlayGame); topMenuBox.setPadding(new Insets(0, 0, 0, 50)); topMenuBox.getChildren().addAll(btnExit, btnBack, btnCallFriend, btnAskAudience, btnDeleteTwoAnswers); answersPane.getChildren().addAll(answer1.getPane(), answer2.getPane(), answer3.getPane(), answer4.getPane()); vBox.getChildren().addAll(topMenuBox, playButtonPane, questionShape, answersPane); hBox.getChildren().addAll(vBox, moneyBox); hBox.autosize(); hBox.setTranslateX((WIDTH / 2) - (hBox.getWidth() / 2)); hBox.setTranslateY((HEIGHT / 2) - (hBox.getHeight() / 2)); this.getChildren().add(hBox); addMoneyBox(); btnExit.setOnAction(e -> { Platform.exit(); }); btnBack.setOnAction(e -> { questionShape.setText(""); mySounds.clickSound(); Main.STAGE.getScene().setRoot(Main.PANE_MENU); timeline.stop(); timeline = null; questions = null; vBox.getChildren().set(1, playButtonPane); answer1.setText(""); answer1.setDefaultBg(); answer1.setVisible(true); answer2.setText(""); answer2.setDefaultBg(); answer2.setVisible(true); answer3.setText(""); answer3.setDefaultBg(); answer3.setVisible(true); answer4.setText(""); answer4.setDefaultBg(); answer4.setVisible(true); initialValues(); btnCallFriend.setDisable(false); btnAskAudience.setDisable(false); btnDeleteTwoAnswers.setDisable(false); }); btnCallFriend.setOnAction(e -> { mySounds.clickSound(); btnCallFriend.setDisable(true); RemainingSeconds = 40; aFriendIsCalled = true; }); btnAskAudience.setOnAction(e -> { mySounds.clickSound(); btnAskAudience.setDisable(true); RemainingSeconds = 40; userIsAskingAudience = true; }); btnDeleteTwoAnswers.setOnAction(e -> { mySounds.clickSound(); btnDeleteTwoAnswers.setDisable(true); if (question.getAnswer(0).isCorrect == false && hiddenButtonsCounter < 2) { answer1.hide(); hiddenButtonsCounter++; } if (question.getAnswer(1).isCorrect == false && hiddenButtonsCounter < 2) { answer2.hide(); hiddenButtonsCounter++; } if (question.getAnswer(2).isCorrect == false && hiddenButtonsCounter < 2) { answer3.hide(); hiddenButtonsCounter++; } if (question.getAnswer(3).isCorrect == false && hiddenButtonsCounter < 2) { answer4.hide(); hiddenButtonsCounter++; } }); btnPlayGame.setOnAction(e -> { vBox.getChildren().set(1, timerLabel); playGame(); }); } // هذه الدالة تستخدم لوضع خلفية للعبة, مع الإشارة إلى أننا استدمنا أيضاً نفس الخلفية التي وضعناها في كل الصفحات public void setGameImage() { this.setBackground(Main.GetBGImage()); } // هذه الدالة تستخدم لإنشاء و إضافة عناصر الحاوية التي يظهر فيها رصيد المستخدم public void addMoneyBox() { moneyLabels.add(new Label("100")); moneyLabels.add(new Label("200")); moneyLabels.add(new Label("300")); moneyLabels.add(new Label("500")); moneyLabels.add(new Label("1000")); moneyLabels.add(new Label("2000")); moneyLabels.add(new Label("4000")); moneyLabels.add(new Label("8000")); moneyLabels.add(new Label("16000")); moneyLabels.add(new Label("22000")); moneyLabels.add(new Label("64000")); moneyLabels.add(new Label("125000")); moneyLabels.add(new Label("250000")); moneyLabels.add(new Label("500000")); moneyLabels.add(new Label("1000000")); for (int i = moneyLabels.size() - 1; i > -1; i--) { moneyLabels.get(i).setAlignment(Pos.CENTER); moneyLabels.get(i).setStyle( "-fx-border-color: #aaa;" + "-fx-border-radius: 5;" + "-fx-background-color: black;" + "-fx-text-fill: yellow;" + "-fx-font-family: calibry;" + "-fx-font-size: 17;" + "-fx-text-alignment: center;" + "-fx-pref-width: 120;" + "-fx-pref-height: 30;" ); moneyBox.getChildren().add(moneyLabels.get(i)); } moneyBox.setAlignment(Pos.CENTER_RIGHT); } }
import javafx.geometry.Insets; import javafx.geometry.Pos; import javafx.scene.control.Label; import javafx.scene.layout.Pane; import javafx.scene.paint.Color; import javafx.scene.shape.Polyline; import javafx.scene.text.Font; // ( لأننا ننوي جعله يكون عبارة عن حاوية لها شكل معين و فيها نص ( السؤال Pane يرث من الكلاس GameQuestionShape هنا جعلنا الكلاس public class GameQuestionShape extends Pane { // لأننا سنعرض النص عليه Label هنا قمنا بإنشاء كائن من الكلاس Label label = new Label(); // هنا قمنا بتجهيز هذا الكونستركتور حتى نستطيع تحديد حجم النص مباشرةً عند إنشاء كائن من هذا الكلاس public GameQuestionShape(int width, int height) { // label سيمثل الشكل الهندسي الذي سيظهر حول السؤال, أي حول نص الكائن polyline الكائن Polyline polyline = new Polyline( 0, 30, 20, 30, 40, 0, 600, 0, 620, 30, 640, 30, 620, 30, 600, 60, 40, 60, 20, 30 ); // لأننا سندمجه معه GameQuestionShape و الذي بدوره سيتم تطبيقه على الكائن الذي ننشئه من الكلاس polyline هنا قمنا بإضافة لون أبيض باهت حول الكائن polyline.setStroke(Color.color(1, 1, 1, 0.75)); // ( حجمه, مكان ظهوره, لون النص, نوع الخط, حجم الخط و حجم الفراغ حوله ) label هنا قمنا بتحديد خصائص ظهور الكائن label.setTranslateX(0); label.setTranslateY(0); label.setPrefSize(width, height); label.setAlignment(Pos.CENTER_RIGHT); label.setPadding(new Insets(-10, 40, 0, 40)); label.setFont(Font.loadFont(Main.class.getResource("res/fonts/droidnaskh-regular-webfon.ttf").toExternalForm(), 16)); label.setTextFill(Color.WHITE); // GameQuestionShape في الحاوية التي يمثلها الكائن الذي ننشئه من الكلاس polyline و label هنا قمنا بوضع الكائن // و أصبحنا نستطيع تحريكهما معاً GameQuestionShape بالكائن الذي يتم إنشاؤه من الكلاس polyline و label أي كأننا ألصقنا الكائن getChildren().addAll(polyline, label); } // GameQuestionShape و الذي بدوره سيوضع في الكائن الذي ننشئه من الكلاس label هذه الدالة نمرر لها النص الذي نريد وضعه للكائن public void setText(String s) { this.label.setText(s); } }
import java.util.Locale; import javafx.application.Application; import javafx.scene.Scene; import javafx.scene.image.Image; import javafx.scene.input.KeyCombination; import javafx.scene.layout.Background; import javafx.scene.layout.BackgroundImage; import javafx.scene.layout.BackgroundPosition; import javafx.scene.layout.BackgroundRepeat; import javafx.scene.layout.BackgroundSize; import javafx.scene.layout.Pane; import javafx.stage.Stage; public class Main extends Application implements ScreenBounds { // لأننا سنعتبر كل واحد منهم كصفحة في التطبيق Pane لأنه سيمثل نافذة التطبيق, و 4 كائنات من الكلاس STAGE هنا قمنا بإنشاء كائن من الكلاس // لتسهيل الوصول إليهم و لعدم الحاجة إلى إنشاء كائن منهم كلما أردنا التنقل بين الصفحات و هذا الأمر يجعل حجم البرنامج أصغر في الذاكرة static و قمنا بتعريفهم كـ static Stage STAGE; static Pane PANE_MENU = new MenuPane(); static Pane PANE_ABOUT = new AboutPane(); static Pane PANE_RESULT = new ResultPane(); static Pane PANE_GAME = new GamePane(); @Override public void start(Stage stage) { // هنا قمنا بإنشاء النافذة و جعلناها تملئ شاشة المستخدم, غير قابلة للتصغير, و وضعنا أيقونة لها, كما أننا وضعنا لها عنوان STAGE = stage; STAGE.setFullScreen(true); STAGE.setResizable(false); STAGE.setFullScreenExitKeyCombination(KeyCombination.NO_MATCH); STAGE.getIcons().add(new Image(Main.class.getResourceAsStream("res/images/icon.png"))); STAGE.setTitle("من سيربح المليون - أسئلة إسلامية"); // STAGE ثم مررناه للكائن ( PANE_MENU وضعنا فيه الحاوية ) Scene هنا قمنا بإنشاء كائن من الكلاس // هي أول حاوية ( أي أول صفحة ) يتم عرضها عند تشغيل اللعبة PANE_MENU هكذا ستكون الحاوية STAGE.setScene(new Scene(PANE_MENU)); // هنا قمنا بإظهار نافذة اللعبة STAGE.show(); } // هذه الدالة قمنا ببنائها لتعيين الصورة التي نريد وضعها كخلفية لأي حاوية ( و نقصد صفحة ) نعرضها في اللعبة, فعلياً ترجع لنا الصورة فقط public static Background GetBGImage() { BackgroundImage myBI = new BackgroundImage( new Image("res/images/black-wallpaper.jpg"), BackgroundRepeat.NO_REPEAT, BackgroundRepeat.NO_REPEAT, BackgroundPosition.DEFAULT, BackgroundSize.DEFAULT); return new Background(myBI); } public static void main(String[] args) { Locale.setDefault(new Locale("ar")); launch(args); } }
import javafx.beans.binding.Bindings; import javafx.scene.paint.Color; import javafx.scene.shape.Polygon; import javafx.scene.shape.Rectangle; // و جعله قابل للنقر (Width + Height) هو لتمكيننا من إعطائه حجم Rectangle يرث من الكلاس MenuItemShape سبب جعل الكلاس public class MenuItemShape extends Rectangle { // MenuItemShape لأننا سنعتمد عليه لنرسم شكل الزر الذي نريد الحصول عليه عند إنشاء كائن من الكلاس Polygon قمنا بتعريف كائن من الكلاس Polygon polygon; // هنا قمنا بتجهيز هذا الكونستركتور حتى نستطيع تحديد حجم الزر مباشرةً عند إنشاء كائن من هذا الكلاس public MenuItemShape(int width, int height) { // عند إنشاء كائن من الكلاس height و width لاحظ أن شكل الزر الذي سيتم رسمه يعتمد بشكل أساسي على القيم التي سنمررها للباراميترين polygon = new Polygon( 0, height/2, 20, 0, width, 0, width, height, 20, height, 0, height/2 ); // لأننا سندمجه معه MenuItemShape و الذي بدوره سيتم تطبيقه على الكائن الذي ننشئه من الكلاس polygon هنا قمنا بإضافة لون أبيض باهت حول الكائن polygon.setStroke(Color.color(1, 1, 1, 0.75)); // الطبيعي هو غامق بنسبة 25 بالمئة و سيصبح أغمق بنسبة 50 بالمئة حين ننقر فوقه بالفأرة polygon هنا حددنا أن لون خلفية الكائن polygon.fillProperty().bind(Bindings.when(pressedProperty()) .then(Color.color(0, 0, 0, 0.50)) .otherwise(Color.color(0, 0, 0, 0.25)) ); // MenuItemShape عند إنشاء كائن من الكلاس height و width حددنا أن حجم الشكل الذي سنحصل عليه سيكون مطابقاً للقيم التي نمررها مكان البارميترين // MenuItemShape يساوي حجم الكائن الذي سنحصل عليه عند دمجه مع الكائن الذي ننشئه من الكلاس polygon بهذه الطريقة يكون حجم الكائن this.setWidth(width); this.setHeight(height); // هو أزرق MenuItemShape هنا حددنا أن لون خلفية الكائن الذي سنحصل عليه عند إنشاء كائن من الكلاس // كما أنه عند تمرير الفأرة فوقه سيتحول شكل السهم إلى شكل إصبع, مما يجعل المستخدم يدرك أن هذا الشكل قابل للنقر this.setFill(Color.BLUE); this.setStyle("-fx-cursor: hand;"); // MenuItemShape على الكائن الذي ننشئه من الكلاس polygon هنا قمنا بدمج و تطبيق خصائص الكائن this.setClip(polygon); } }
import javafx.animation.ScaleTransition; import javafx.animation.TranslateTransition; import javafx.application.Platform; import javafx.geometry.Insets; import javafx.geometry.Pos; import javafx.scene.Node; import javafx.scene.control.Label; import javafx.scene.effect.DropShadow; import javafx.scene.input.MouseEvent; import javafx.scene.layout.Pane; import javafx.scene.layout.VBox; import javafx.scene.paint.Color; import javafx.scene.shape.Line; import javafx.scene.shape.Rectangle; import javafx.scene.text.Font; import javafx.scene.text.Text; import javafx.util.Duration; public class MenuPane extends Pane implements ScreenBounds { Text title = new Text("من سيربح المليون"); VBox vBox = new VBox(5); Line line = new Line(); Sounds mySounds = new Sounds(); // هذه الدالة تستخدم لرسم العامود الأبيض الذي سيظهر على يمين الأزرار private void addLine() { double xStart = (WIDTH / 2) + 110; double yStart = (HEIGHT / 2) - (vBox.getChildren().size() * 40 / 2); double xEnd = xStart; // جعلنا هاتين النقتطين متساويتين حتى يظهر الخط بشكل عامودي double yEnd = (HEIGHT / 2) + (vBox.getChildren().size() * 40 / 2) + (vBox.getChildren().size() * 5) - 5; line = new Line(xStart, yStart, xEnd, yEnd); line.setStrokeWidth(3); line.setStroke(Color.color(0, 0, 1, 0.75)); line.setEffect(new DropShadow(5, Color.BLACK)); line.setScaleY(0); this.getChildren().add(line); } // هذه الدالة تستخدم لتشغيل المؤثرات الموضوعة لعناصر الحاوية private void startAnimation() { ScaleTransition st = new ScaleTransition(Duration.seconds(1)); st.setNode(title); st.setToY(1); st.play(); ScaleTransition st2 = new ScaleTransition(Duration.seconds(1)); st2.setDelay(Duration.seconds(1)); st2.setNode(line); st2.setToY(1); st2.setOnFinished(e -> { for (int i = 0; i < vBox.getChildren().size(); i++) { Node n = vBox.getChildren().get(i); TranslateTransition tt = new TranslateTransition(Duration.seconds(1 + i * 0.15), n); tt.setToX(0); tt.setOnFinished(e2 -> n.setClip(null)); tt.play(); } }); st2.play(); } // هذه الدالة تستخدم لإضافة حاوية الأزرار في حاوية الصفحة الأساسية و لتحديد مكان ظهورها private void addVBox() { double x = (WIDTH / 2) - (220 / 2); double y = (HEIGHT / 2) - (vBox.getChildren().size() * 40 / 2); vBox.setTranslateX(x); vBox.setTranslateY(y); this.getChildren().add(vBox); } // هذه الدالة تستخدم لإضافة عنوان الصفحة ( و الذي في حالتنا يمثل إسم اللعبة ) و لتحديد حجمه, لونه, نوع خطه و مكان ظهوره private void addTitle() { title.setFont(Font.loadFont(Main.class.getResource("res/fonts/droidnaskh-regular-webfon.ttf").toExternalForm(), 36)); title.setFill(Color.WHITE); title.setEffect(new DropShadow(30, Color.BLACK)); title.setTranslateX(WIDTH / 2 - title.getLayoutBounds().getWidth() / 2); title.setTranslateY(HEIGHT / 3); title.setScaleY(0); this.getChildren().add(title); } // vBox هنا قمنا ببناء الأزرار الثلاثة الذين سيظهروا في الصفحة و من ثم إضافتهم على الحاوية // MenuItemShape يحتوي على كائن Pane كل زر, عبارة عن كائن // الذي جلعنا خلفيته شفافة MenuItemShape موضوع خلف الكائن Label و النص الموضوع على كل زر عبارة كائن // إضافة إلى ذلك, قمنا بتحديد النافذة التي نريدها أن تفتح عند النقر على كل زر منهم private void addItems() { MenuItemShape item1 = new MenuItemShape(220, 40); MenuItemShape item2 = new MenuItemShape(220, 40); MenuItemShape item3 = new MenuItemShape(220, 40); Pane pane1 = new Pane(); Pane pane2 = new Pane(); Pane pane3 = new Pane(); pane1.setPrefSize(220, 40); pane2.setPrefSize(220, 40); pane3.setPrefSize(220, 40); Label label1 = new Label("إبدأ التحدي"); label1.setPrefSize(220, 40); label1.setAlignment(Pos.CENTER_RIGHT); label1.setPadding(new Insets(-5, 15, 0, 0)); label1.setFont(Font.loadFont(Main.class.getResource("res/fonts/droidnaskh-regular-webfon.ttf").toExternalForm(), 14)); label1.setTextFill(Color.WHITE); Label label2 = new Label("حول اللعبة"); label2.setPrefSize(220, 40); label2.setAlignment(Pos.CENTER_RIGHT); label2.setPadding(new Insets(-5, 15, 0, 0)); label2.setFont(Font.loadFont(Main.class.getResource("res/fonts/droidnaskh-regular-webfon.ttf").toExternalForm(), 14)); label2.setTextFill(Color.WHITE); Label label3 = new Label("خروج من اللعبة"); label3.setPrefSize(220, 40); label3.setAlignment(Pos.CENTER_RIGHT); label3.setPadding(new Insets(-5, 15, 0, 0)); label3.setFont(Font.loadFont(Main.class.getResource("res/fonts/droidnaskh-regular-webfon.ttf").toExternalForm(), 14)); label3.setTextFill(Color.WHITE); pane1.getChildren().addAll(label1, item1); pane2.getChildren().addAll(label2, item2); pane3.getChildren().addAll(label3, item3); pane1.setTranslateX(220); Rectangle clip1 = new Rectangle(220, 40); pane1.setClip(clip1); clip1.translateXProperty().bind(pane1.translateXProperty().negate()); pane2.setTranslateX(220); Rectangle clip2 = new Rectangle(220, 40); pane2.setClip(clip2); clip2.translateXProperty().bind(pane2.translateXProperty().negate()); pane3.setTranslateX(220); Rectangle clip3 = new Rectangle(220, 40); pane3.setClip(clip3); clip3.translateXProperty().bind(pane3.translateXProperty().negate()); vBox.getChildren().addAll(pane1, pane2, pane3); item1.setOnMouseClicked((MouseEvent t) -> { mySounds.clickSound(); Main.STAGE.getScene().setRoot(Main.PANE_GAME); }); item2.setOnMouseClicked((MouseEvent t) -> { mySounds.clickSound(); Main.STAGE.getScene().setRoot(Main.PANE_ABOUT); }); item3.setOnMouseClicked((MouseEvent t) -> { Platform.exit(); }); } // هذا كونستركتور الكلاس public MenuPane() { setPrefSize(WIDTH, HEIGHT); setBackground(Main.GetBGImage()); addItems(); addTitle(); addLine(); addVBox(); startAnimation(); mySounds.introSound(); } }
// بما أن كل سؤال في اللعبة يجب أن يكون له 4 أجوبة و منهم إجابة واحدة صحيحة فعلنا التالي // لأن كل جواب سيكون له نص ( أي نص الإجابة ) بالإضافة إلى مؤشر لنعرف من خلاله ما إن كانت الإجابة صحيحة أم لا Answer قمنا بتمثيل كل جواب بالكلاس // Answer لأن كل سؤال سيكون له نص ( أي نص السؤال ) مع 4 إجابات, أي مصفوفة فيها 4 كائنات من الكلاس Question قمنا بتمثيل كل جواب بالكلاس // Answer و الكلاس Question الذي بنيناه على أساس الكلاس Questions قمنا بتمثيل كل الأسئلة و الأجوبة التي نريد وضعها في اللعبة في الكلاس import java.util.ArrayList; import java.util.Collections; // هذا الكلاس يمثل كيف سيتم تخزين كل إجابة في اللعبة سواء كانت صحيحة أو خاطئة class Answer { String text; boolean isCorrect; public Answer(String text, boolean isCorrect) { this.text = text; this.isCorrect = isCorrect; } public Answer(String text) { this.text = text; this.isCorrect = false; } public String getText() { return this.text; } public boolean isCorrect() { return this.isCorrect; } } // هذا الكلاس يمثل كيف سيتم تخزين كل سؤال في اللعبة مع الإجابات الأربعة الخاصة فيه class Question { String phrase; ArrayList<Answer> answers = new ArrayList(); public Question(String phrase, Answer[] answers) { this.phrase = phrase; this.answers.add(answers[0]); this.answers.add(answers[1]); this.answers.add(answers[2]); this.answers.add(answers[3]); } public String getPhrase() { return this.phrase; } public Answer getAnswer(int answerIndex) { return this.answers.get(answerIndex); } } // Question و الكلاس Answer هذا الكلاس يستخدم للحصول على مئة سؤال و هو مبني على أساس الكلاس public class Questions { ArrayList<Question> al = new ArrayList(); public Questions() { createQuestions(); } public Question getQuestion() { Question question = al.get(0); al.remove(0); return question; } public void createQuestions() { al.add(new Question("كان من خلق النبي صلى الله عليه وسلم؟", new Answer[]{ new Answer("الصدق", true), new Answer("الغضب"), new Answer("عدم التواضع"), new Answer("عدم الصدق"),}) ); al.add(new Question("ما اسم والد النبي صلى الله عليه وسلم؟", new Answer[]{ new Answer("عبدالله", true), new Answer("محمد"), new Answer("إبراهيم"), new Answer("عبد مناف"),}) ); al.add(new Question("ما اسم والدة النبي صلى الله عليه وسلم؟", new Answer[]{ new Answer("آمنة بنت وهب", true), new Answer("حليمة السعدية"), new Answer("فاطمة بنت حبيش"), new Answer("خديجة بنت خويلد"),}) ); al.add(new Question("في أي يوم ولد النبي صلى الله عليه وسلم؟", new Answer[]{ new Answer("في الثاني عشر من ربيع الأول", true), new Answer("في الأول من صفر"), new Answer("في الثاني من محرم"), new Answer("في السابع من شوال"),}) ); al.add(new Question("كم كان عمر النبي عندما توفي والده؟", new Answer[]{ new Answer("كان جنينا في بطن أمه", true), new Answer("كان رضيعا"), new Answer("كان طفلا"), new Answer("كان شابا"),}) ); al.add(new Question("ما اسم عمه الذي كفله وحماه من المشركين؟", new Answer[]{ new Answer("أبو طالب", true), new Answer("أبو لهب"), new Answer("أبو جهل"), new Answer("أبو عبيدة"),}) ); al.add(new Question("ما اسم زوجة النبي صلى الله عليه وسلم؟", new Answer[]{ new Answer("خديجة بنت خويلد", true), new Answer("فاطمة بنت قبيس"), new Answer("مريم بنت الزبير"), new Answer("الخنساء"),}) ); al.add(new Question("ما اسم الغار الذي كان النبي يعبد ربه فيه؟", new Answer[]{ new Answer("غار حراء", true), new Answer("غار ثور"), new Answer("غار علقمة"), new Answer("غار تميم"),}) ); al.add(new Question("كم كان عمر النبي عندما نزل عليه الوحي؟", new Answer[]{ new Answer("41 سنة", true), new Answer("50 سنة"), new Answer("60 سنة"), new Answer("44 سنة"),}) ); al.add(new Question("ما اسم ملك الوحي الذي نزل على النبي في الغار؟", new Answer[]{ new Answer("جبريل", true), new Answer("ميكائيل"), new Answer("إسرافيل"), new Answer("ملك الجبال"),}) ); al.add(new Question("من أول من أسلم من النساء؟", new Answer[]{ new Answer("خديجة بنت خويلد", true), new Answer("فاطمة بنت قبيس"), new Answer("عائشة بنت أبي بكر"), new Answer("زينب أم المساكين"),}) ); al.add(new Question("من أول من أسلم من الصبيان؟", new Answer[]{ new Answer("علي بن أبي طالب", true), new Answer("زيد بن حارثة"), new Answer("عبدالله بن عمر"), new Answer("عبدالله بن عباس"),}) ); al.add(new Question("من أول من أسلم من الرجال؟", new Answer[]{ new Answer("أبو بكر الصديق", true), new Answer("عثمان بن عفان"), new Answer("عبدالله بن مسعود"), new Answer("عمر بن الخطاب"),}) ); al.add(new Question("ما اسم القبيلة التي حاربت النبي صلى الله عليه وسلم؟", new Answer[]{ new Answer("قريش", true), new Answer("بنو تميم"), new Answer("ثقيف"), new Answer("بنو قيس"),}) ); al.add(new Question("أين كان يعيش النبي صلى الله عليه وسلم؟", new Answer[]{ new Answer("مكة المكرمة", true), new Answer("العراق"), new Answer("الشام"), new Answer("اليمن"),}) ); al.add(new Question("ما اسم عمَ النبي الذي لقب بأسد الله؟", new Answer[]{ new Answer("حمزة بن عبد المطلب", true), new Answer("أبو لهب"), new Answer("أبو طالب"), new Answer("العباس"),}) ); al.add(new Question("إلى أي بلاد هاجر المسلمون أول مرة؟", new Answer[]{ new Answer("الحبشة", true), new Answer("اليمن "), new Answer("الشام"), new Answer("نجد"),}) ); al.add(new Question("ما اسم الصحابي الذي قاد المسلمين إلى الحبشة؟", new Answer[]{ new Answer("جعفر بن أبي طالب", true), new Answer("حذيفة بن اليمان"), new Answer("أبو عبيدة بن الجراح"), new Answer("سعد بن معاذ"),}) ); al.add(new Question("ماذا كان اسم ملك الحبشة؟", new Answer[]{ new Answer("النجاشي", true), new Answer("كسرى"), new Answer("قيصر"), new Answer("النمرود"),}) ); al.add(new Question("ماذا كان اسم ملك الحبشة؟", new Answer[]{ new Answer("النجاشي", true), new Answer("كسرى"), new Answer("قيصر"), new Answer("النمرود"),}) ); al.add(new Question("تقع الكعبة المشرفة في ...", new Answer[]{ new Answer("مكة المكرمة", true), new Answer("خيبر"), new Answer("الشام"), new Answer("يثرب"),}) ); al.add(new Question("يقع المسجد الأقصى في ...", new Answer[]{ new Answer("القدس", true), new Answer("الطائف "), new Answer("يثرب"), new Answer("اليمن"),}) ); al.add(new Question("القدس عاصمة أي من الدول الآتية؟", new Answer[]{ new Answer("فلسطين", true), new Answer("العراق"), new Answer("اليمن"), new Answer("لبنان"),}) ); al.add(new Question("ما هما الرحلتان العظيمتان اللتان قام بهما الرسول؟", new Answer[]{ new Answer("الاسراء والمعراج", true), new Answer("حطين"), new Answer("عين جالوت"), new Answer("أحد"),}) ); al.add(new Question("ماذا فرض الله تعالى في ليلة الاسراء والمعراج؟", new Answer[]{ new Answer("الصلوات الخمس", true), new Answer("صوم رمضان"), new Answer("حج البيت"), new Answer("الزكاة"),}) ); al.add(new Question("ما اسم أول بيعة للأنصار في الإسلام؟", new Answer[]{ new Answer("بيعة العقبة", true), new Answer("بيعة نجد"), new Answer("بيعة ثقيف"), new Answer("بيعة الخزرج"),}) ); al.add(new Question("إلى أين هاجر المسلمون بعد الحبشة؟", new Answer[]{ new Answer("المدينة المنورة", true), new Answer("مكة"), new Answer("اليمن"), new Answer("الشام"),}) ); al.add(new Question("ماذا كان لقب المسلمين من أهل المدينة؟", new Answer[]{ new Answer("الأنصار", true), new Answer("المهاجرين"), new Answer("الفقراء"), new Answer("المسافرين"),}) ); al.add(new Question("ماذا كان لقب المسلمين القادمين من مكة؟", new Answer[]{ new Answer("المهاجرين", true), new Answer("الانصار"), new Answer("المقاتلين"), new Answer("الاغنياء"),}) ); al.add(new Question("من الصحابي الذي هاجر مع النبي إلى المدينة المنورة؟", new Answer[]{ new Answer("أبو بكر الصديق", true), new Answer("عمر بن الخطاب"), new Answer("علي بن أبي طالب"), new Answer("عثمان بن عفان"),}) ); al.add(new Question("ما اسم الغار الذي ارتاح فيه النبي قبل الوصول الى المدينة؟", new Answer[]{ new Answer("غار ثور", true), new Answer("غار حراء"), new Answer("غار شعلان"), new Answer("غار آدم"),}) ); al.add(new Question("ماذا قال النبي لأبي بكر وهما في الغار؟", new Answer[]{ new Answer("لا تحزن إن الله معنا", true), new Answer("لا تحزن سنموت سويا"), new Answer("لا تحزن لن نقتل"), new Answer("لا تحزن سنهزمهم"),}) ); al.add(new Question("ما هو أول أمر فعله النبي عندما وصل إلى المدينة؟", new Answer[]{ new Answer("بنى مسجدا", true), new Answer("أعطاهم مالا"), new Answer("أخذ تمرا"), new Answer("اشترى منزلا"),}) ); al.add(new Question("في بيت من أقام النبي عندما وصل إلى المدينة؟", new Answer[]{ new Answer("أبو أيوب الأنصاري", true), new Answer("سعد بن معاذ"), new Answer("عبادة بن الصامت"), new Answer("معاذ بن جبل"),}) ); al.add(new Question("ماذا فعل النبي بعد بناء المسجد؟", new Answer[]{ new Answer("آخى بين المهاجرين والأنصار", true), new Answer("حاسب الظالمين"), new Answer("بناء القصور"), new Answer("الراحة بعد السفر"),}) ); al.add(new Question("من كان يسكن في المدينة بجانب المسلمين؟", new Answer[]{ new Answer("اليهود", true), new Answer("الروم"), new Answer("الفرس"), new Answer("النصارى"),}) ); al.add(new Question("ماذا فعل النبي بعد المؤخاة بين المسلمين؟", new Answer[]{ new Answer("أقام معاهدة مع اليهود", true), new Answer("حارب اليهود"), new Answer("دعى الناس للطعام"), new Answer("نصب نفسه ملكا"),}) ); al.add(new Question("في أي سنة بعد الهجرة فرض الله صيام رمضان؟", new Answer[]{ new Answer("السنة الثانية", true), new Answer("السنة الأولى"), new Answer("السنة الخامسة"), new Answer("السنة الرابعة"),}) ); al.add(new Question("أول سرية في الاسلام كانت بقيادة من ...", new Answer[]{ new Answer("عبدالله بن جحش", true), new Answer("ابن مسعود"), new Answer("ابو عبيدة"), new Answer("خالد بن الوليد"),}) ); al.add(new Question("ماذا كان اسم رأس المنافقين في المدينة؟", new Answer[]{ new Answer("عبدالله بن أبي سلول", true), new Answer("عبدالله بن سلام"), new Answer("ولعان الأعمى"), new Answer("سعيد المصلوب"),}) ); al.add(new Question("ماذا كان اسم ـول معركة بين المسلمين والمشركين؟", new Answer[]{ new Answer("معركة بدر", true), new Answer("معركة ذات السلاسل"), new Answer("معركة القادسية"), new Answer("معركة أحد"),}) ); al.add(new Question("في أي سنة كانت معركة بدر الكبرى؟", new Answer[]{ new Answer("السنة الثانية", true), new Answer("السنة الثالثة"), new Answer("السنة السابعة"), new Answer("السنة الرابعة"),}) ); al.add(new Question("كم كان عدد المسلمين في معركة بدر؟", new Answer[]{ new Answer("313 رجلا", true), new Answer("500 رجل"), new Answer("1000 رجل"), new Answer("800 رجل"),}) ); al.add(new Question("كم كان عدد المشركين في معركة بدر؟", new Answer[]{ new Answer("1000 رجل", true), new Answer("2000 رجل"), new Answer("1500 رجل"), new Answer("900 رجل"),}) ); al.add(new Question("ما اسم الصحابي الذي اقترح مكان المعركة في بدر؟", new Answer[]{ new Answer("الحباب بن المنذر", true), new Answer("عمر بن الخطاب"), new Answer("أبو عبيدة بن الجراح"), new Answer("خالد بن الوليد"),}) ); al.add(new Question("من انتصر في معركة بدر؟", new Answer[]{ new Answer("المسلمون", true), new Answer("المشركون"), new Answer("الشيطان"), new Answer("الباطل"),}) ); al.add(new Question("كم عدد أركان الإسلام؟", new Answer[]{ new Answer("خمسة أركان", true), new Answer("ركنان"), new Answer("ثلاثة أركان"), new Answer("ركن واحد"),}) ); al.add(new Question("كان من خلق النبي صلى الله عليه وسلم؟", new Answer[]{ new Answer("الأمانة ", true), new Answer("الخيانة"), new Answer("الغش"), new Answer("التكبر"),}) ); al.add(new Question("من هو الصحابي الذي لقب بالصديق؟", new Answer[]{ new Answer("أبو بكر", true), new Answer("عثمان بن عفان"), new Answer("أبو عبيدة بن الجراح"), new Answer("أبو هريرة"),}) ); al.add(new Question("من هو الصحابي الذي لقب بالفاروق؟", new Answer[]{ new Answer("عمر بن الخطاب", true), new Answer("سعد بن معاذ"), new Answer("عبدالله بن الزبير"), new Answer("خالد بن الوليد"),}) ); al.add(new Question("من هو الصحابي الذي لقب بذي النورين؟", new Answer[]{ new Answer("عثمان بن عفان", true), new Answer("الزبير بن العوام"), new Answer("حذيفة بن اليمان"), new Answer("أبو صخر"),}) ); al.add(new Question("من هو الصحابي الذي لقب بأمين الأمة؟", new Answer[]{ new Answer("أبو عبيدة بن الجراح", true), new Answer("عامر بن عبدالله"), new Answer("أبو موسى الأشعري"), new Answer("عيينة بن حصين"),}) ); al.add(new Question("من هو الصحابي الذي لقب بسيف الله المسلول؟", new Answer[]{ new Answer("خالد بن الوليد", true), new Answer("الزبير بن العوام"), new Answer("الاقرع بن الحابس"), new Answer("عبدالله بن عباس"),}) ); al.add(new Question("من هو الصحابي الذي لقب بأمين السر النبوي؟", new Answer[]{ new Answer("حذيفة بن اليمان", true), new Answer("ابن مسعود"), new Answer("ابن عمر"), new Answer("عمر بن الخطاب"),}) ); al.add(new Question("من هو الصحابي الذي لقب بترجمان القرآن؟", new Answer[]{ new Answer("عبدالله بن عباس", true), new Answer("الحباب بن المنذر"), new Answer("قتادة"), new Answer("بلال بن رباح"),}) ); al.add(new Question("من هو مؤذن رسول الله؟", new Answer[]{ new Answer("بلال بن رباح", true), new Answer("عطاء بن أبي رباح"), new Answer("أبي بن كعب"), new Answer("زيد بن ثابت"),}) ); al.add(new Question("ما هو لقب الرسول صلى الله عليه وسلم؟", new Answer[]{ new Answer("الصادق الأمين", true), new Answer("التاجر الصدوق"), new Answer("البر الأمين"), new Answer("الأمين الأمين"),}) ); al.add(new Question("ما هو عمل الرسول في شبابه؟", new Answer[]{ new Answer("التجارة", true), new Answer("الزراعة"), new Answer("السياسة"), new Answer("الحياكة"),}) ); al.add(new Question("إلى من أرسل الرسول صلى الله عليه وسلم؟", new Answer[]{ new Answer("إلى كافة الناس", true), new Answer("إلى قريش"), new Answer("إلى بني هاشم"), new Answer("إلى الحجاز"),}) ); al.add(new Question("ما الذي جاء به الرسول محمد صلى الله عليه وسلم؟", new Answer[]{ new Answer("بالشريعة الإسلامية", true), new Answer("باليهودية"), new Answer("بالمجوسية"), new Answer("بالنصرانية"),}) ); al.add(new Question("ما أكثر طعام الرسول صلى الله عليه وسلم؟", new Answer[]{ new Answer("التمر والماء", true), new Answer("اللحم والخبز"), new Answer("الدجاج واللبن"), new Answer("الفاكهة والخضار"),}) ); al.add(new Question("كم حجة حج النبي صلى الله عليه وسلم؟", new Answer[]{ new Answer("حجة واحدة", true), new Answer("حجتان"), new Answer("ثلاث حجات"), new Answer("خمس حجات"),}) ); al.add(new Question("كم رمضان صام النبي صلى الله عليه وسلم؟", new Answer[]{ new Answer("تسع مرات", true), new Answer("ثلاث مرات"), new Answer("خمس مرات"), new Answer("مرتان"),}) ); al.add(new Question("ما هي كنية الرسول صلى الله عليه وسلم؟", new Answer[]{ new Answer("أبو القاسم", true), new Answer("أبو ابراهيم"), new Answer("أبو يوسف"), new Answer("أبو اسماعيل"),}) ); al.add(new Question("ما آخر غزوة غزاها الرسول؟", new Answer[]{ new Answer("غزوة تبوك", true), new Answer("غزوة الخندق"), new Answer("غزوة بدر"), new Answer("غزوة ذات السلاسل"),}) ); al.add(new Question("ما هي معجزة النبي الخالدة؟", new Answer[]{ new Answer("القرآن الكريم", true), new Answer("الانجيل"), new Answer("التوراة"), new Answer("الزبور"),}) ); al.add(new Question("متى توفي الرسول صلى الله عليه وسلم؟", new Answer[]{ new Answer("شهر ربيع الاول عام 11 للهجرة", true), new Answer("شهر صفر عام 14 للهجرة"), new Answer("شهر محرم عام 8 للهجرة"), new Answer("شهر شعبان عام 20 للهجرة"),}) ); al.add(new Question("كم كان عمره صلى الله عليه وسلم عند وفاته؟", new Answer[]{ new Answer("63 سنة", true), new Answer("64 سنة"), new Answer("70 سنة"), new Answer("55 سنة"),}) ); al.add(new Question("في أي بلد دفن النبي صلى الله عليه وسلم؟", new Answer[]{ new Answer("المدينة المنورة", true), new Answer("مكة المكرمة"), new Answer("فلسطين"), new Answer("اليمن"),}) ); al.add(new Question("ماذا نسمي معرفة حياة الرسول من ولادته حتى مماته؟", new Answer[]{ new Answer("السيرة النبوية", true), new Answer("قصة"), new Answer("فيلم وثائقي"), new Answer("رواية"),}) ); Collections.shuffle(al); } }
import javafx.application.Platform; import javafx.geometry.Pos; import javafx.scene.control.Button; import javafx.scene.control.Label; import javafx.scene.layout.StackPane; import javafx.scene.layout.VBox; // حتى يظهر محتواه في وسط النافذة StackPane يرث من الكلاس ResultPane هنا جعلنا الكلاس // حتى يكون حجمه مطابق لحجم شاشة المستخدم ScreenBounds و جعلناه يطبق الإنترفيس public class ResultPane extends StackPane implements ScreenBounds { // حتى نستطيع إستدعاء دوال تشغيل الأصوات التي جهزناها فيه Sounds هنا قمنا بإنشاء كائن من الكلاس Sounds mySounds = new Sounds(); // ResultPane هنا منا بتعريف جميع الأشياء التي سنعرضها في الحاوية التي سيمثلها الكائن الذي نرجعه من الكلاس static Label label = new Label(); Button buttonClose = new Button("خروج"); Button buttonRetry = new Button("إلعب من جديد"); VBox vBox = new VBox(20); // هذا كونستركتور الكلاس public ResultPane() { // ResultPane كخلفية للحاوية التي سنحصل عليها عند إنشاء كائن من الكلاس GetBGImage() هنا قمنا بوضع الصورة التي ترجعها الدالة this.setBackground(Main.GetBGImage()); // Label هنا قمنا بتجهيز التصميم الذي نريد تطبيقه على الكائن String labelStyle = "-fx-text-fill: white; " + "-fx-font-size: 24;" + "-fx-padding: 0 0 20 0;" + "-fx-alignment: CENTER;"; // buttonRetry و buttonClose هنا قمنا بتجهيز التصميم الذي نريد تطبيقه على الكائنين String btnStyle = "-fx-focus-color: transparent; " + "-fx-border-width: 2;" + "-fx-border-color: #00f;" + "-fx-border-radius: 10;" + "-fx-text-fill: white;" + "-fx-background-color: rgba(30, 30, 30, 0.5);" + "-fx-cursor: hand;" + "-fx-font-size: 18;" + "-fx-padding: 10 0 10 0;" + "-fx-pref-width: 220;" + "-fx-pref-height: 40;" + "-fx-padding: 10 0 10 0;"; // buttonRetry و buttonClose, label هنا قمنا بتطبيق التصاميم على الكائنات label.setStyle(labelStyle); buttonClose.setStyle(btnStyle); buttonRetry.setStyle(btnStyle); // لكي يظهروا عامودياً تحت بعضهم البعض و في وسط الحاويةvBox في الحاوية buttonRetry و buttonClose, label هنا قمنا بإضافة الكائنات vBox.getChildren().addAll(label, buttonRetry, buttonClose); vBox.setAlignment(Pos.CENTER); // أي في الحاوية التي تمثل الصفحة نفسها .ResultPane في الكائن الذي ستم إنشاؤه من الكلاس vBox هنا أضفنا الحاوية this.getChildren().addAll(vBox); // buttonRetry هنا قمنا بتحديد ما سيحدث عند النقر على الزر الذي يمثله الكائن buttonRetry.setOnAction(e -> { mySounds.clickSound(); Main.STAGE.getScene().setRoot(new GamePane()); }); // buttonClose هنا قمنا بتحديد ما سيحدث عند النقر على الزر الذي يمثله الكائن buttonClose.setOnAction(e -> { Platform.exit(); }); } public static void setResult(int answeredQuestions, int totalEarning) { if (answeredQuestions == 0) { label.setText("لم تعرف إجابة أي سؤال لذلك لم تفز بأي مبلغ !"); } else if (answeredQuestions < 15){ label.setText("لقد تخطيت السؤال رقم " + answeredQuestions + " و فزت بمبلغ " + totalEarning + "$"); } else if (answeredQuestions == 15) { label.setText("لقد تخطيت جميع الأسئلة و فزت بمبلغ "+ totalEarning + "$"); } } }
import javafx.geometry.Rectangle2D; import javafx.stage.Screen; // وضعنا في هذا الإنترفيس, المعلومات الأساسية و المشتركة التي يجب أن تتوفر في كل حاوية تمثل صفحة في اللعبة public interface ScreenBounds { Screen SCREEN = Screen.getPrimary(); Rectangle2D BOUNDS = SCREEN.getVisualBounds(); double WIDTH = BOUNDS.getMaxX(); double HEIGHT = BOUNDS.getMaxY(); }
import javafx.scene.media.AudioClip; // وضعنا فيه 5 دوال, كل دالة منهم تعطينا صوت معين عند إستدعاءها Sounds الكلاس public class Sounds { // لتمثلها و لنستطيع تشغيلها من خلالها AudioClip الملفات الصوتية الموضوعة في المشروع قمنا بإنشاء كائنات من الكلاس AudioClip audio_1 = new AudioClip(getClass().getResource("res/sounds/general-click.wav").toString()); AudioClip audio_2 = new AudioClip(getClass().getResource("res/sounds/playing-click.wav").toString()); AudioClip audio_3 = new AudioClip(getClass().getResource("res/sounds/intro.MP3").toString()); AudioClip audio_4 = new AudioClip(getClass().getResource("res/sounds/clock-tick.wav").toString()); AudioClip audio_5 = new AudioClip(getClass().getResource("res/sounds/win-sound.mp3").toString()); public void clickSound() { audio_1.play(); } public void ClickOnWrongAnswerSound() { audio_2.play(); } public void ClickOnCorrectAnswerSound() { audio_5.play(); } public void introSound() { audio_3.play(); } public void clockTickSound() { audio_4.play(); } }
كورس تعلم javaFX