JavaFXطريقة إنشاء لعبة من سيربح المليون
في هذا الدرس ستتعلم طريقة إنشاء لعبة من سيربح المليون ( Who will win the million ) إحترافية بإستخدام إطار JavaFX.
مميزات اللعبة
- تلائم حجم أي شاشة كمبيوتر يتم تشغيلها عليه لأنها مبنية بطريقة ( Responsive ).
- فيها أشكال هندسية مخصصة و مصممة بطريقة تجذب المستخدم, و عدة أصوات و مؤثرات بصرية يتم تشغيلها عندما يتفاعل المستخدم مع اللعبة.
- تحتوي على 100 سؤال و 400 إجابة يتم عرضهم بشكل عشوائي.
- فيها نفس وسائل المساعدة الموجودة في لعبة من سيربح المليون.
- يمكنك تطوير اللعبة و تغيير الأسئلة و الإجابات بسهولة إذا أردت إنشاء نسختك الخاصة من اللعبة.
بناء اللعبة
- ملفات الجافا وضعناها مباشرةً في المشروع.
- إستخدمنا خط خاص وضعناه في مجلد إسمه
fonts
. - الصور وضعناه بداخل مجلد إسمه
images
. - الأصوات وضعناه بداخل مجلد إسمه
sounds
.
خيارات التحميل
⇓ تحميل اللعبة ⇓ تحميل المشروع كاملاً
معلومات عامة عن الكود
- الكلاس
AboutButtonShape
قمنا ببنائه خصيصاً لنحصل على شكل الزر الذي أظهرناه في صفحة حول التطبيق - الكلاس
AboutPane
قمنا ببنائه خصيصاً لنحصل على الحاوية الأساسية التي سنعرضها في صفحة حول التطبيق مع الإشارة إلى أننا وضعنا فيه كل محتوى الصفحة. - الكلاس
GameAnswerButton
قمنا ببنائه خصيصاً لنحصل على شكل الأزرار التي يمكن النقر عليها لاختيار الإجابة في صفحة اللعب - الكلاس
GamePane
قمنا ببنائه خصيصاً لتمثيل صفحة اللعب - الكلاس
GameQuestionShape
قمنا ببنائه خصيصاً لنحصل على شكل الحاوية التي ستوضع فيها الأسئلة في صفحة اللعب - الكلاس
Main
قمنا ببناء نافذة اللعبة كل الصفحات الموجودة فيها بالإضافة إلى أنه يعتبر نقطة البداية في هذا المشروع. - الكلاس
MenuItemShape
قمنا ببنائه خصيصاً لبناء شكل الأزرار التي وضعناها في صفحة القائمة الرئيسية - الكلاس
MenuPane
قمنا ببنائه خصيصاً لتمثيل صفحة القائمة الرئيسية - الكلاس
Questions
وضعنا فيه جميع أسئلة اللعبة مع الإجابات الخاصة بها. - الكلاس
ResultPane
قمنا ببنائه خصيصاً لتمثيل صفحة النتيجة النهائية - الكلاس
Sounds
قمنا ببنائه خصيصاً لتجهيز دوال يمكن إستخدامها لتشغيل أصوات في اللعبة. - الإنترفيس
ScreenBounds
وضعنا فيه المعلومات الأساسية و المشتركة التي يجب أن تتوفر في كل حاوية تمثل صفحة في اللعبة.
كود اللعبة
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(); 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(); } }