JavaFXطريقة إنشاء لعبة Tic Tac Toe
في هذا الدرس ستتعلم طريقة إنشاء لعبة ( Tic Tac Toe ) إحترافية باستخدام إطار الـ JavaFX.
مميزات اللعبة
- يمكن لعب هذه اللعبة مع صديق أو ضد الكمبيوتر نفسه.
- يمكن تعديل تصميمها بكل سهولة من داخل اللعبة.
بناء اللعبة
- ملفات الجافا وضعناها مباشرةً في المشروع.
- الصور وضعناها بداخل مجلد إسمه images.
خيارات التحميل
⇓ تحميل اللعبة ⇓ تحميل المشروع كاملاً ⇓ تحميل مجلد الصور فقط
كود اللعبة
import javafx.scene.control.Alert;
import javafx.scene.control.Alert.AlertType;
import javafx.scene.control.Button;
import javafx.scene.layout.Pane;
// يمثل الحاوية التي سنظهرها عند تشغيل البرنامج StartPane الكلاس
public class StartPane extends Pane {
// هنا قمنا بإنشاء جميع الأشياء التي سنضعها في الحاوية
Button singlePlayer = new Button("Single Player");
Button multiPlayer = new Button("Multi Player");
Button settings = new Button("Settings");
Button about = new Button("About");
Button exit = new Button("Exit");
// about لأننا سنستخدمه لعرض نافذة منبثقة عندما يقوم المستخدم بالنقر على الزر Alert هنا قمنا بإنشاء كائن من الكلاس
Alert alert = new Alert(AlertType.INFORMATION);
// هذا كونستركور الكلاس
public StartPane() {
// StartPane هنا قمنا بتحديد حجم كل شيء سنضيفه في الحاوية التي يمثلها الكائن الذي ننشئه من الكلاس
singlePlayer.setPrefSize(240, 40);
multiPlayer.setPrefSize(240, 40);
settings.setPrefSize(240, 40);
about.setPrefSize(240, 40);
exit.setPrefSize(240, 40);
// StartPane هنا قمنا بتحديد موقع كل شيء سنضيفه في الحاوية التي يمثلها الكائن الذي ننشئه من الكلاس
singlePlayer.setTranslateX(80);
singlePlayer.setTranslateY(110);
multiPlayer.setTranslateX(80);
multiPlayer.setTranslateY(170);
settings.setTranslateX(80);
settings.setTranslateY(230);
about.setTranslateX(80);
about.setTranslateY(290);
exit.setTranslateX(80);
exit.setTranslateY(350);
// StartPane هنا قمنا بإضافة كل شيء قمنا بإنشائه في الحاوية التي يمثلها الكائن الذي ننشئه من الكلاس
getChildren().add(singlePlayer);
getChildren().add(multiPlayer);
getChildren().add(settings);
getChildren().add(about);
getChildren().add(exit);
// singlePlayer هنا قمنا بتحديد ما سيحدث عند النقر على الزر الذي يمثله الكائن
// مكان الحاوية الحالية singlePlayerPane لعرض الحاوية التي يمثلها الكائن viewPane() سيتم إستدعاء الدالة الثابتة
singlePlayer.setOnAction((Action) -> {
AppManager.viewPane(AppManager.singlePlayerPane);
});
// multiPlayer هنا قمنا بتحديد ما سيحدث عند النقر على الزر الذي يمثله الكائن
// مكان الحاوية الحالية multiPlayerPane لعرض الحاوية التي يمثلها الكائن viewPane() سيتم إستدعاء الدالة الثابتة
multiPlayer.setOnAction((Action) -> {
AppManager.viewPane(AppManager.multiPlayerPane);
});
// settings هنا قمنا بتحديد ما سيحدث عند النقر على الزر الذي يمثله الكائن
// مكان الحاوية الحالية settings لعرض الحاوية التي يمثلها الكائن viewPane() سيتم إستدعاء الدالة الثابتة
settings.setOnAction((Action) -> {
AppManager.viewPane(AppManager.settingsPane);
});
// about هنا قمنا بتحديد ما سيحدث عند النقر على الزر الذي يمثله الكائن
// alert سيتم تجهيز نص يمثل معلومات عامة عن اللعبة و الذي سنعرضه بداخل النافذة المنبثقة التي يمثلها الكائن
about.setOnAction((Action) -> {
String str
= "Prepared by Mhamad Harmush\n\n"
+ "If you have any comments, ideas.. just let me know\n\n"
+ "Email: mhamad.harmush@gmail.com\n"
+ "Twitter & Facebook: @MhamadHarmush\n\n"
+ "Note\n"
+ "I used JDK 1.8 to compile the source code.\n\n"
+ "© Copyright 2019 harmash.com - All Rights Reserved";
alert.setTitle("About Tic Tac Toe");
alert.setHeaderText("About Tic Tac Toe");
alert.setContentText(str);
alert.showAndWait();
});
// exit هنا قمنا بتحديد ما سيحدث عند النقر على الزر الذي يمثله الكائن
exit.setOnAction((Action) -> {
System.exit(0);
});
}
}
import javafx.scene.control.Alert;
import javafx.scene.control.Alert.AlertType;
import javafx.scene.control.Button;
import javafx.scene.layout.Pane;
// يمثل الحاوية التي سنظهرها عند تشغيل البرنامج StartPane الكلاس
public class StartPane extends Pane {
// هنا قمنا بإنشاء جميع الأشياء التي سنضعها في الحاوية
Button singlePlayer = new Button("Single Player");
Button multiPlayer = new Button("Multi Player");
Button settings = new Button("Settings");
Button about = new Button("About");
Button exit = new Button("Exit");
// about لأننا سنستخدمه لعرض نافذة منبثقة عندما يقوم المستخدم بالنقر على الزر Alert هنا قمنا بإنشاء كائن من الكلاس
Alert alert = new Alert(AlertType.INFORMATION);
// هذا كونستركور الكلاس
public StartPane() {
// StartPane هنا قمنا بتحديد حجم كل شيء سنضيفه في الحاوية التي يمثلها الكائن الذي ننشئه من الكلاس
singlePlayer.setPrefSize(240, 40);
multiPlayer.setPrefSize(240, 40);
settings.setPrefSize(240, 40);
about.setPrefSize(240, 40);
exit.setPrefSize(240, 40);
// StartPane هنا قمنا بتحديد موقع كل شيء سنضيفه في الحاوية التي يمثلها الكائن الذي ننشئه من الكلاس
singlePlayer.setTranslateX(80);
singlePlayer.setTranslateY(110);
multiPlayer.setTranslateX(80);
multiPlayer.setTranslateY(170);
settings.setTranslateX(80);
settings.setTranslateY(230);
about.setTranslateX(80);
about.setTranslateY(290);
exit.setTranslateX(80);
exit.setTranslateY(350);
// StartPane هنا قمنا بإضافة كل شيء قمنا بإنشائه في الحاوية التي يمثلها الكائن الذي ننشئه من الكلاس
getChildren().add(singlePlayer);
getChildren().add(multiPlayer);
getChildren().add(settings);
getChildren().add(about);
getChildren().add(exit);
// singlePlayer هنا قمنا بتحديد ما سيحدث عند النقر على الزر الذي يمثله الكائن
// مكان الحاوية الحالية singlePlayerPane لعرض الحاوية التي يمثلها الكائن viewPane() سيتم إستدعاء الدالة الثابتة
singlePlayer.setOnAction((Action) -> {
AppManager.viewPane(AppManager.singlePlayerPane);
});
// multiPlayer هنا قمنا بتحديد ما سيحدث عند النقر على الزر الذي يمثله الكائن
// مكان الحاوية الحالية multiPlayerPane لعرض الحاوية التي يمثلها الكائن viewPane() سيتم إستدعاء الدالة الثابتة
multiPlayer.setOnAction((Action) -> {
AppManager.viewPane(AppManager.multiPlayerPane);
});
// settings هنا قمنا بتحديد ما سيحدث عند النقر على الزر الذي يمثله الكائن
// مكان الحاوية الحالية settings لعرض الحاوية التي يمثلها الكائن viewPane() سيتم إستدعاء الدالة الثابتة
settings.setOnAction((Action) -> {
AppManager.viewPane(AppManager.settingsPane);
});
// about هنا قمنا بتحديد ما سيحدث عند النقر على الزر الذي يمثله الكائن
// alert سيتم تجهيز نص يمثل معلومات عامة عن اللعبة و الذي سنعرضه بداخل النافذة المنبثقة التي يمثلها الكائن
about.setOnAction((Action) -> {
String str
= "Prepared by Mhamad Harmush\n\n"
+ "If you have any comments, ideas.. just let me know\n\n"
+ "Email: mhamad.harmush@gmail.com\n"
+ "Twitter & Facebook: @MhamadHarmush\n\n"
+ "Note\n"
+ "I used JDK 1.8 to compile the source code.\n\n"
+ "© Copyright 2019 harmash.com - All Rights Reserved";
alert.setTitle("About Tic Tac Toe");
alert.setHeaderText("About Tic Tac Toe");
alert.setContentText(str);
alert.showAndWait();
});
// exit هنا قمنا بتحديد ما سيحدث عند النقر على الزر الذي يمثله الكائن
exit.setOnAction((Action) -> {
System.exit(0);
});
}
}
import javafx.beans.value.ObservableValue;
import javafx.scene.control.Button;
import javafx.scene.control.ComboBox;
import javafx.scene.control.Label;
import javafx.scene.layout.Pane;
import javafx.scene.text.Font;
import javafx.scene.text.FontWeight;
// ( Settings ) يمثل الحاوية التي سنظهرها عند النقر على زر ضبط اللعبة SettingsPane الكلاس
public class SettingsPane extends Pane {
// هنا قمنا بإنشاء جميع الأشياء التي سنضعها في الحاوية
Label labelForBoards = new Label("Game Board");
Label labelForFontSizes = new Label("Font Size");
ComboBox boardsComboBox = new ComboBox();
ComboBox fontSizesComboBox = new ComboBox();
Button reset = new Button("Reset Default Settings");
Button back = new Button("Back");
// هذا كونستركور الكلاس
public SettingsPane() {
// fontSizesComboBox و boardsComboBox هنا قمنا بوضع الخيارات التي يمكن للمستخدم اختيارها في الكائنين
boardsComboBox.getItems().addAll("Board 1", "Board 2", "Board 3", "Board 4");
fontSizesComboBox.getItems().addAll("Small", "Medium", "Large");
// SettingsPane هنا قمنا بتحديد حجم كل شيء سنضيفه في الحاوية التي يمثلها الكائن الذي ننشئه من الكلاس
labelForBoards.setPrefSize(100, 30);
boardsComboBox.setPrefSize(120, 30);
labelForFontSizes.setPrefSize(100, 30);
fontSizesComboBox.setPrefSize(120, 30);
reset.setPrefSize(240, 40);
back.setPrefSize(240, 40);
// SettingsPane هنا قمنا بتحديد موقع كل شيء سنضيفه في الحاوية التي يمثلها الكائن الذي ننشئه من الكلاس
labelForBoards.setTranslateX(80);
labelForBoards.setTranslateY(130);
boardsComboBox.setTranslateX(200);
boardsComboBox.setTranslateY(130);
labelForFontSizes.setTranslateX(80);
labelForFontSizes.setTranslateY(190);
fontSizesComboBox.setTranslateX(200);
fontSizesComboBox.setTranslateY(190);
reset.setTranslateX(80);
reset.setTranslateY(250);
back.setTranslateX(80);
back.setTranslateY(310);
// SettingsPane هنا قمنا بإضافة كل شيء قمنا بإنشائه في الحاوية التي يمثلها الكائن الذي ننشئه من الكلاس
getChildren().add(labelForBoards);
getChildren().add(boardsComboBox);
getChildren().add(labelForFontSizes);
getChildren().add(fontSizesComboBox);
getChildren().add(reset);
getChildren().add(back);
// boardsComboBox هنا قمنا بتحديد ما سيحدث عندما يقوم المستخدم بتغيير القيمة الظاهرة في الكائن
// AppManager الموضوع في الكلاس preferredBoard بناءاً على القيمة التي يختارها سيتم تمرير إسم الصورة للمتغير الثابت
boardsComboBox.getSelectionModel().selectedIndexProperty().addListener(
(ObservableValue<? extends Number> ov, Number oldVal, Number newVal) -> {
switch((int)newVal) {
case 0:
AppManager.preferredBoard = "board_1.png";
break;
case 1:
AppManager.preferredBoard = "board_2.png";
break;
case 2:
AppManager.preferredBoard = "board_3.png";
break;
case 3:
AppManager.preferredBoard = "board_4.png";
break;
}
});
// fontSizesComboBox هنا قمنا بتحديد ما سيحدث عندما يقوم المستخدم بتغيير القيمة الظاهرة في الكائن
// AppManager الموضوع في الكلاس preferredFont بناءاً على القيمة التي يختارها سيتم تمرير حجم الخط للكائن الثابت
// لتغيير حجم خط كل الأزرار, النصوص و مربعات النصوص الموضوعة في اللعبة setFont() كما أنه سيتم استدعاء الدالة
fontSizesComboBox.getSelectionModel().selectedIndexProperty().addListener(
(ObservableValue<? extends Number> ov, Number oldVal, Number newVal) -> {
String selectedFont = fontSizesComboBox.getSelectionModel().getSelectedItem().toString();
int fontSize = 0;
switch(selectedFont) {
case "Small":
fontSize = 15;
break;
case "Medium":
fontSize = 16;
break;
case "Large":
fontSize = 17;
break;
}
AppManager.preferredFont = Font.font("Arial", FontWeight.BOLD, fontSize);
AppManager.setFont();
});
// reset هنا قمنا بتحديد ما سيحدث عند النقر على الزر الذي يمثله الكائن
// لإرجاع القيم الإفتراضية التي كانت موضوعة في الحاوية AppManager الموجودة في الكلاس setDefaultSettings() سيتم استدعاء الدالة
reset.setOnAction((Action) -> {
AppManager.setDefaultSettings();
boardsComboBox.getSelectionModel().selectFirst();
fontSizesComboBox.getSelectionModel().select(1);
});
// back هنا قمنا بتحديد ما سيحدث عند النقر على الزر الذي يمثله الكائن
// مكان الحاوية الحالية startPane لعرض الحاوية التي يمثلها الكائن viewPane() سيتم إستدعاء الدالة الثابتة
back.setOnAction((Action) -> {
AppManager.viewPane(AppManager.startPane);
});
}
}
import javafx.beans.value.ObservableValue;
import javafx.scene.control.Button;
import javafx.scene.control.ComboBox;
import javafx.scene.control.Label;
import javafx.scene.layout.Pane;
import javafx.scene.text.Font;
import javafx.scene.text.FontWeight;
// ( Settings ) يمثل الحاوية التي سنظهرها عند النقر على زر ضبط اللعبة SettingsPane الكلاس
public class SettingsPane extends Pane {
// هنا قمنا بإنشاء جميع الأشياء التي سنضعها في الحاوية
Label labelForBoards = new Label("Game Board");
Label labelForFontSizes = new Label("Font Size");
ComboBox boardsComboBox = new ComboBox();
ComboBox fontSizesComboBox = new ComboBox();
Button reset = new Button("Reset Default Settings");
Button back = new Button("Back");
// هذا كونستركور الكلاس
public SettingsPane() {
// fontSizesComboBox و boardsComboBox هنا قمنا بوضع الخيارات التي يمكن للمستخدم اختيارها في الكائنين
boardsComboBox.getItems().addAll("Board 1", "Board 2", "Board 3", "Board 4");
fontSizesComboBox.getItems().addAll("Small", "Medium", "Large");
// SettingsPane هنا قمنا بتحديد حجم كل شيء سنضيفه في الحاوية التي يمثلها الكائن الذي ننشئه من الكلاس
labelForBoards.setPrefSize(100, 30);
boardsComboBox.setPrefSize(120, 30);
labelForFontSizes.setPrefSize(100, 30);
fontSizesComboBox.setPrefSize(120, 30);
reset.setPrefSize(240, 40);
back.setPrefSize(240, 40);
// SettingsPane هنا قمنا بتحديد موقع كل شيء سنضيفه في الحاوية التي يمثلها الكائن الذي ننشئه من الكلاس
labelForBoards.setTranslateX(80);
labelForBoards.setTranslateY(130);
boardsComboBox.setTranslateX(200);
boardsComboBox.setTranslateY(130);
labelForFontSizes.setTranslateX(80);
labelForFontSizes.setTranslateY(190);
fontSizesComboBox.setTranslateX(200);
fontSizesComboBox.setTranslateY(190);
reset.setTranslateX(80);
reset.setTranslateY(250);
back.setTranslateX(80);
back.setTranslateY(310);
// SettingsPane هنا قمنا بإضافة كل شيء قمنا بإنشائه في الحاوية التي يمثلها الكائن الذي ننشئه من الكلاس
getChildren().add(labelForBoards);
getChildren().add(boardsComboBox);
getChildren().add(labelForFontSizes);
getChildren().add(fontSizesComboBox);
getChildren().add(reset);
getChildren().add(back);
// boardsComboBox هنا قمنا بتحديد ما سيحدث عندما يقوم المستخدم بتغيير القيمة الظاهرة في الكائن
// AppManager الموضوع في الكلاس preferredBoard بناءاً على القيمة التي يختارها سيتم تمرير إسم الصورة للمتغير الثابت
boardsComboBox.getSelectionModel().selectedIndexProperty().addListener(
(ObservableValue<? extends Number> ov, Number oldVal, Number newVal) -> {
switch((int)newVal) {
case 0:
AppManager.preferredBoard = "board_1.png";
break;
case 1:
AppManager.preferredBoard = "board_2.png";
break;
case 2:
AppManager.preferredBoard = "board_3.png";
break;
case 3:
AppManager.preferredBoard = "board_4.png";
break;
}
});
// fontSizesComboBox هنا قمنا بتحديد ما سيحدث عندما يقوم المستخدم بتغيير القيمة الظاهرة في الكائن
// AppManager الموضوع في الكلاس preferredFont بناءاً على القيمة التي يختارها سيتم تمرير حجم الخط للكائن الثابت
// لتغيير حجم خط كل الأزرار, النصوص و مربعات النصوص الموضوعة في اللعبة setFont() كما أنه سيتم استدعاء الدالة
fontSizesComboBox.getSelectionModel().selectedIndexProperty().addListener(
(ObservableValue<? extends Number> ov, Number oldVal, Number newVal) -> {
String selectedFont = fontSizesComboBox.getSelectionModel().getSelectedItem().toString();
int fontSize = 0;
switch(selectedFont) {
case "Small":
fontSize = 15;
break;
case "Medium":
fontSize = 16;
break;
case "Large":
fontSize = 17;
break;
}
AppManager.preferredFont = Font.font("Arial", FontWeight.BOLD, fontSize);
AppManager.setFont();
});
// reset هنا قمنا بتحديد ما سيحدث عند النقر على الزر الذي يمثله الكائن
// لإرجاع القيم الإفتراضية التي كانت موضوعة في الحاوية AppManager الموجودة في الكلاس setDefaultSettings() سيتم استدعاء الدالة
reset.setOnAction((Action) -> {
AppManager.setDefaultSettings();
boardsComboBox.getSelectionModel().selectFirst();
fontSizesComboBox.getSelectionModel().select(1);
});
// back هنا قمنا بتحديد ما سيحدث عند النقر على الزر الذي يمثله الكائن
// مكان الحاوية الحالية startPane لعرض الحاوية التي يمثلها الكائن viewPane() سيتم إستدعاء الدالة الثابتة
back.setOnAction((Action) -> {
AppManager.viewPane(AppManager.startPane);
});
}
}
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.image.Image;
import javafx.scene.layout.Pane;
// ( Single Player ) يمثل الحاوية التي سنظهرها عند النقر على زر اللعب ضد الكمبيوتر SinglePlayerPane الكلاس
public class SinglePlayerPane extends Pane {
// هنا قمنا بإنشاء جميع الأشياء التي سنضعها في الحاوية
Label playerNameLabel = new Label("Player Name");
TextField playerName = new TextField("player");
Button start = new Button("Start");
Button back = new Button("Back");
// هذا كونستركور الكلاس
public SinglePlayerPane() {
// SinglePlayerPane هنا قمنا بتحديد حجم كل شيء سنضيفه في الحاوية التي يمثلها الكائن الذي ننشئه من الكلاس
playerNameLabel.setPrefSize(100, 30);
playerName.setPrefSize(130, 30);
start.setPrefSize(240, 40);
back.setPrefSize(240, 40);
// SinglePlayerPane هنا قمنا بتحديد موقع كل شيء سنضيفه في الحاوية التي يمثلها الكائن الذي ننشئه من الكلاس
playerNameLabel.setTranslateX(80);
playerNameLabel.setTranslateY(170);
playerName.setTranslateX(190);
playerName.setTranslateY(170);
start.setTranslateX(80);
start.setTranslateY(220);
back.setTranslateX(80);
back.setTranslateY(280);
// SinglePlayerPane هنا قمنا بإضافة كل شيء قمنا بإنشائه في الحاوية التي يمثلها الكائن الذي ننشئه من الكلاس
getChildren().add(playerNameLabel);
getChildren().add(playerName);
getChildren().add(start);
getChildren().add(back);
// start هنا قمنا بتحديد ما سيحدث عند النقر على الزر الذي يمثله الكائن
// مع وضع القيمة 0 كنتيجة أولية له و للكمبيوتر gamePane سيتم تمرير الإسم الذي يدخله المستخدم, كإسم اللاعب الذي سيظهر في الحاوية
// gamePane بعدها سيتم وضع صورة الخلفية التي اختارها المستخدم أو الصورة المختارة إفتراضياً كخلفية للعبة في الحاوية
// مكان الحاوية الحالية gamePane لعرض الحاوية التي يمثلها الكائن viewPane() في الأخير سيتم إستدعاء الدالة الثابتة
start.setOnAction((Action) -> {
AppManager.gamePane.firstPlayerName.setText(playerName.getText());
AppManager.gamePane.secondPlayerName.setText("Computer");
AppManager.gamePane.firstPlayerScore.setText("0");
AppManager.gamePane.secondPlayerScore.setText("0");
// للإشارة إلى أنه سيتم اللعب ضد الكمبيوتر AppManager الموضوع في الكلاس challengeComputer للمتغير الثابت true مررنا القيمة
AppManager.challengeComputer = true;
AppManager.gamePane.boardBackground
.setImage(new Image(getClass().getResourceAsStream("/images/"+AppManager.preferredBoard)));
AppManager.viewPane(AppManager.gamePane);
});
// back هنا قمنا بتحديد ما سيحدث عند النقر على الزر الذي يمثله الكائن
// مكان الحاوية الحالية startPane لعرض الحاوية التي يمثلها الكائن viewPane() سيتم إستدعاء الدالة الثابتة
back.setOnAction((Action) -> {
AppManager.viewPane(AppManager.startPane);
});
}
}
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.image.Image;
import javafx.scene.layout.Pane;
// ( Single Player ) يمثل الحاوية التي سنظهرها عند النقر على زر اللعب ضد الكمبيوتر SinglePlayerPane الكلاس
public class SinglePlayerPane extends Pane {
// هنا قمنا بإنشاء جميع الأشياء التي سنضعها في الحاوية
Label playerNameLabel = new Label("Player Name");
TextField playerName = new TextField("player");
Button start = new Button("Start");
Button back = new Button("Back");
// هذا كونستركور الكلاس
public SinglePlayerPane() {
// SinglePlayerPane هنا قمنا بتحديد حجم كل شيء سنضيفه في الحاوية التي يمثلها الكائن الذي ننشئه من الكلاس
playerNameLabel.setPrefSize(100, 30);
playerName.setPrefSize(130, 30);
start.setPrefSize(240, 40);
back.setPrefSize(240, 40);
// SinglePlayerPane هنا قمنا بتحديد موقع كل شيء سنضيفه في الحاوية التي يمثلها الكائن الذي ننشئه من الكلاس
playerNameLabel.setTranslateX(80);
playerNameLabel.setTranslateY(170);
playerName.setTranslateX(190);
playerName.setTranslateY(170);
start.setTranslateX(80);
start.setTranslateY(220);
back.setTranslateX(80);
back.setTranslateY(280);
// SinglePlayerPane هنا قمنا بإضافة كل شيء قمنا بإنشائه في الحاوية التي يمثلها الكائن الذي ننشئه من الكلاس
getChildren().add(playerNameLabel);
getChildren().add(playerName);
getChildren().add(start);
getChildren().add(back);
// start هنا قمنا بتحديد ما سيحدث عند النقر على الزر الذي يمثله الكائن
// مع وضع القيمة 0 كنتيجة أولية له و للكمبيوتر gamePane سيتم تمرير الإسم الذي يدخله المستخدم, كإسم اللاعب الذي سيظهر في الحاوية
// gamePane بعدها سيتم وضع صورة الخلفية التي اختارها المستخدم أو الصورة المختارة إفتراضياً كخلفية للعبة في الحاوية
// مكان الحاوية الحالية gamePane لعرض الحاوية التي يمثلها الكائن viewPane() في الأخير سيتم إستدعاء الدالة الثابتة
start.setOnAction((Action) -> {
AppManager.gamePane.firstPlayerName.setText(playerName.getText());
AppManager.gamePane.secondPlayerName.setText("Computer");
AppManager.gamePane.firstPlayerScore.setText("0");
AppManager.gamePane.secondPlayerScore.setText("0");
// للإشارة إلى أنه سيتم اللعب ضد الكمبيوتر AppManager الموضوع في الكلاس challengeComputer للمتغير الثابت true مررنا القيمة
AppManager.challengeComputer = true;
AppManager.gamePane.boardBackground
.setImage(new Image(getClass().getResourceAsStream("/images/"+AppManager.preferredBoard)));
AppManager.viewPane(AppManager.gamePane);
});
// back هنا قمنا بتحديد ما سيحدث عند النقر على الزر الذي يمثله الكائن
// مكان الحاوية الحالية startPane لعرض الحاوية التي يمثلها الكائن viewPane() سيتم إستدعاء الدالة الثابتة
back.setOnAction((Action) -> {
AppManager.viewPane(AppManager.startPane);
});
}
}
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.image.Image;
import javafx.scene.layout.Pane;
// ( Multi Player ) يمثل الحاوية التي سنظهرها عند النقر على زر اللعبة بين شخصين موجودين على نفس الجهاز MultiPlayerPane الكلاس
public class MultiPlayerPane extends Pane {
// هنا قمنا بإنشاء جميع الأشياء التي سنضعها في الحاوية
Label playerXLabel = new Label("Player X");
Label playerOLabel = new Label("Player O");
TextField firstPlayerName = new TextField("player 1");
TextField secondPlayerName = new TextField("player 2");
Button start = new Button("Start");
Button back = new Button("Back");
// هذا كونستركور الكلاس
public MultiPlayerPane() {
// MultiPlayerPane هنا قمنا بتحديد حجم كل شيء سنضيفه في الحاوية التي يمثلها الكائن الذي ننشئه من الكلاس
playerXLabel.setPrefSize(70, 30);
firstPlayerName.setPrefSize(160, 30);
playerOLabel.setPrefSize(70, 30);
secondPlayerName.setPrefSize(160, 30);
start.setPrefSize(240, 40);
back.setPrefSize(240, 40);
// MultiPlayerPane هنا قمنا بتحديد موقع كل شيء سنضيفه في الحاوية التي يمثلها الكائن الذي ننشئه من الكلاس
playerXLabel.setTranslateX(80);
playerXLabel.setTranslateY(130);
firstPlayerName.setTranslateX(160);
firstPlayerName.setTranslateY(130);
playerOLabel.setTranslateX(80);
playerOLabel.setTranslateY(190);
secondPlayerName.setTranslateX(160);
secondPlayerName.setTranslateY(190);
start.setTranslateX(80);
start.setTranslateY(250);
back.setTranslateX(80);
back.setTranslateY(310);
// MultiPlayerPane هنا قمنا بإضافة كل شيء قمنا بإنشائه في الحاوية التي يمثلها الكائن الذي ننشئه من الكلاس
getChildren().add(playerXLabel);
getChildren().add(playerOLabel);
getChildren().add(firstPlayerName);
getChildren().add(secondPlayerName);
getChildren().add(start);
getChildren().add(back);
// start هنا قمنا بتحديد ما سيحدث عند النقر على الزر الذي يمثله الكائن
// مع وضع القيمة 0 كنتيجة أولية لكلا اللاعبين gamePane سيتم تمرير أسماء اللاعبين اللذين سيدخلوهما للحاوية
// gamePane بعدها سيتم وضع صورة الخلفية التي اختاروها أو الصورة المختارة إفتراضياً كخلفية للعبة في الحاوية
// مكان الحاوية الحالية gamePane لعرض الحاوية التي يمثلها الكائن viewPane() في الأخير سيتم إستدعاء الدالة الثابتة
start.setOnAction((Action) -> {
AppManager.gamePane.firstPlayerName.setText(firstPlayerName.getText());
AppManager.gamePane.secondPlayerName.setText(secondPlayerName.getText());
AppManager.gamePane.firstPlayerScore.setText("0");
AppManager.gamePane.secondPlayerScore.setText("0");
// للإشارة إلى أنه لن يتم اللعب ضد الكمبيوتر AppManager الموضوع في الكلاس challengeComputer للمتغير الثابت false مررنا القيمة
AppManager.challengeComputer = false;
AppManager.gamePane.boardBackground
.setImage(new Image(getClass().getResourceAsStream("/images/"+AppManager.preferredBoard)));
AppManager.viewPane(AppManager.gamePane);
});
// back هنا قمنا بتحديد ما سيحدث عند النقر على الزر الذي يمثله الكائن
// مكان الحاوية الحالية startPane لعرض الحاوية التي يمثلها الكائن viewPane() سيتم إستدعاء الدالة الثابتة
back.setOnAction((Action) -> {
AppManager.viewPane(AppManager.startPane);
});
}
}
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.image.Image;
import javafx.scene.layout.Pane;
// ( Multi Player ) يمثل الحاوية التي سنظهرها عند النقر على زر اللعبة بين شخصين موجودين على نفس الجهاز MultiPlayerPane الكلاس
public class MultiPlayerPane extends Pane {
// هنا قمنا بإنشاء جميع الأشياء التي سنضعها في الحاوية
Label playerXLabel = new Label("Player X");
Label playerOLabel = new Label("Player O");
TextField firstPlayerName = new TextField("player 1");
TextField secondPlayerName = new TextField("player 2");
Button start = new Button("Start");
Button back = new Button("Back");
// هذا كونستركور الكلاس
public MultiPlayerPane() {
// MultiPlayerPane هنا قمنا بتحديد حجم كل شيء سنضيفه في الحاوية التي يمثلها الكائن الذي ننشئه من الكلاس
playerXLabel.setPrefSize(70, 30);
firstPlayerName.setPrefSize(160, 30);
playerOLabel.setPrefSize(70, 30);
secondPlayerName.setPrefSize(160, 30);
start.setPrefSize(240, 40);
back.setPrefSize(240, 40);
// MultiPlayerPane هنا قمنا بتحديد موقع كل شيء سنضيفه في الحاوية التي يمثلها الكائن الذي ننشئه من الكلاس
playerXLabel.setTranslateX(80);
playerXLabel.setTranslateY(130);
firstPlayerName.setTranslateX(160);
firstPlayerName.setTranslateY(130);
playerOLabel.setTranslateX(80);
playerOLabel.setTranslateY(190);
secondPlayerName.setTranslateX(160);
secondPlayerName.setTranslateY(190);
start.setTranslateX(80);
start.setTranslateY(250);
back.setTranslateX(80);
back.setTranslateY(310);
// MultiPlayerPane هنا قمنا بإضافة كل شيء قمنا بإنشائه في الحاوية التي يمثلها الكائن الذي ننشئه من الكلاس
getChildren().add(playerXLabel);
getChildren().add(playerOLabel);
getChildren().add(firstPlayerName);
getChildren().add(secondPlayerName);
getChildren().add(start);
getChildren().add(back);
// start هنا قمنا بتحديد ما سيحدث عند النقر على الزر الذي يمثله الكائن
// مع وضع القيمة 0 كنتيجة أولية لكلا اللاعبين gamePane سيتم تمرير أسماء اللاعبين اللذين سيدخلوهما للحاوية
// gamePane بعدها سيتم وضع صورة الخلفية التي اختاروها أو الصورة المختارة إفتراضياً كخلفية للعبة في الحاوية
// مكان الحاوية الحالية gamePane لعرض الحاوية التي يمثلها الكائن viewPane() في الأخير سيتم إستدعاء الدالة الثابتة
start.setOnAction((Action) -> {
AppManager.gamePane.firstPlayerName.setText(firstPlayerName.getText());
AppManager.gamePane.secondPlayerName.setText(secondPlayerName.getText());
AppManager.gamePane.firstPlayerScore.setText("0");
AppManager.gamePane.secondPlayerScore.setText("0");
// للإشارة إلى أنه لن يتم اللعب ضد الكمبيوتر AppManager الموضوع في الكلاس challengeComputer للمتغير الثابت false مررنا القيمة
AppManager.challengeComputer = false;
AppManager.gamePane.boardBackground
.setImage(new Image(getClass().getResourceAsStream("/images/"+AppManager.preferredBoard)));
AppManager.viewPane(AppManager.gamePane);
});
// back هنا قمنا بتحديد ما سيحدث عند النقر على الزر الذي يمثله الكائن
// مكان الحاوية الحالية startPane لعرض الحاوية التي يمثلها الكائن viewPane() سيتم إستدعاء الدالة الثابتة
back.setOnAction((Action) -> {
AppManager.viewPane(AppManager.startPane);
});
}
}
import javafx.scene.layout.Pane;
import javafx.scene.text.Font;
// static قمنا بإنشائه لتمرير القيم المشتركة بين حاويات اللعبة بسهولة لهذا قمنا بتعريف كل شيء فيه كـ AppManager الكلاس
public class AppManager {
// هنا قمنا بإنشاء كائن من كل كلاس يمثل حاوية قمنا بتجهيزه سابقاً
static StartPane startPane = new StartPane();
static SinglePlayerPane singlePlayerPane = new SinglePlayerPane();
static MultiPlayerPane multiPlayerPane = new MultiPlayerPane();
static SettingsPane settingsPane = new SettingsPane();
static GamePane gamePane = new GamePane();
// SettingsPane سنخزن فيه إسم صورة خلفية اللعبة التي يستطيع المستخدم تغييرها من الحاوية preferredBoard المتغير
static String preferredBoard;
// SettingsPane سنخزن فيه حجم خط كل زر, نص و مربع نص أضفناه في اللعبة و الذي يستطيع المستخدم تغييره من الحاوية preferredFont الكائن
static Font preferredFont;
// للإشارة إلى أنه سيتم اللعب ضد الكمبيوتر SinglePlayerPane الموضوع في الحاوية start عند النقر على الزر true سنخزن فيه القيمة challengeComputer المتغير
static boolean challengeComputer;
// pane الدالة التالية نستخدمها لإخفاء أي نافذة معروضة حالياً في النافذة و عرض الحاوية التي نمررها لها فقط مكان الباراميتر
public static void viewPane(Pane pane)
{
startPane.setVisible(false);
singlePlayerPane.setVisible(false);
multiPlayerPane.setVisible(false);
settingsPane.setVisible(false);
gamePane.setVisible(false);
pane.setVisible(true);
}
// settingsPane الدالة التالية نستخدمها لوضع الخيارات الإفتراضية التي يمكن تغييرها في الحاوية
public static void setDefaultSettings()
{
// fontSizesComboBox و ثاني خيار في الكائن boardsComboBox هنا قلنا أنه سيتم إختيار أول خيار في الكائن
settingsPane.boardsComboBox.getSelectionModel().selectFirst();
settingsPane.fontSizesComboBox.getSelectionModel().select(1);
// preferredFont لتغيير حجم خط كل زر, نص و مربع نص موضوع في اللعبة نسبةً لقيمة الكائن setFont() هنا قمنا باستدعاء الدالة
setFont();
}
// preferredFont الدالة التالية نستخدمها لتحديد حجم خط كل زر, نص و مربع نص موضوع في اللعبة نسبةً لقيمة الكائن
public static void setFont()
{
startPane.singlePlayer.setFont(preferredFont);
startPane.multiPlayer.setFont(preferredFont);
startPane.settings.setFont(preferredFont);
startPane.about.setFont(preferredFont);
startPane.exit.setFont(preferredFont);
singlePlayerPane.playerNameLabel.setFont(preferredFont);
singlePlayerPane.playerName.setFont(preferredFont);
singlePlayerPane.start.setFont(preferredFont);
singlePlayerPane.back.setFont(preferredFont);
multiPlayerPane.playerXLabel.setFont(preferredFont);
multiPlayerPane.playerOLabel.setFont(preferredFont);
multiPlayerPane.firstPlayerName.setFont(preferredFont);
multiPlayerPane.secondPlayerName.setFont(preferredFont);
multiPlayerPane.start.setFont(preferredFont);
multiPlayerPane.back.setFont(preferredFont);
gamePane.firstPlayerName.setFont(preferredFont);
gamePane.secondPlayerName.setFont(preferredFont);
gamePane.firstPlayerScore.setFont(preferredFont);
gamePane.secondPlayerScore.setFont(preferredFont);
gamePane.currentPlayerSymbol.setFont(preferredFont);
gamePane.restart.setFont(preferredFont);
gamePane.back.setFont(preferredFont);
settingsPane.labelForBoards.setFont(preferredFont);
settingsPane.labelForFontSizes.setFont(preferredFont);
settingsPane.reset.setFont(preferredFont);
settingsPane.back.setFont(preferredFont);
// لتحديد لهما setStyle() لا يملكان دالة خاصة لتحديد حجم الخط, لذلك قمنا باستخدام الدالة fontSizesComboBox و boardsComboBox الكائنين
settingsPane.boardsComboBox.setStyle(
"-fx-font-family:" + preferredFont.getName() + ";"
+"-fx-font-size: " + preferredFont.getSize() +"px;"
+"-fx-font-weight: bold;"
);
settingsPane.fontSizesComboBox.setStyle(
"-fx-font-family:" + preferredFont.getName() + ";"
+"-fx-font-size: " + preferredFont.getSize() +"px;"
+"-fx-font-weight: bold;"
);
}
}
import javafx.scene.layout.Pane;
import javafx.scene.text.Font;
// static قمنا بإنشائه لتمرير القيم المشتركة بين حاويات اللعبة بسهولة لهذا قمنا بتعريف كل شيء فيه كـ AppManager الكلاس
public class AppManager {
// هنا قمنا بإنشاء كائن من كل كلاس يمثل حاوية قمنا بتجهيزه سابقاً
static StartPane startPane = new StartPane();
static SinglePlayerPane singlePlayerPane = new SinglePlayerPane();
static MultiPlayerPane multiPlayerPane = new MultiPlayerPane();
static SettingsPane settingsPane = new SettingsPane();
static GamePane gamePane = new GamePane();
// SettingsPane سنخزن فيه إسم صورة خلفية اللعبة التي يستطيع المستخدم تغييرها من الحاوية preferredBoard المتغير
static String preferredBoard;
// SettingsPane سنخزن فيه حجم خط كل زر, نص و مربع نص أضفناه في اللعبة و الذي يستطيع المستخدم تغييره من الحاوية preferredFont الكائن
static Font preferredFont;
// للإشارة إلى أنه سيتم اللعب ضد الكمبيوتر SinglePlayerPane الموضوع في الحاوية start عند النقر على الزر true سنخزن فيه القيمة challengeComputer المتغير
static boolean challengeComputer;
// pane الدالة التالية نستخدمها لإخفاء أي نافذة معروضة حالياً في النافذة و عرض الحاوية التي نمررها لها فقط مكان الباراميتر
public static void viewPane(Pane pane)
{
startPane.setVisible(false);
singlePlayerPane.setVisible(false);
multiPlayerPane.setVisible(false);
settingsPane.setVisible(false);
gamePane.setVisible(false);
pane.setVisible(true);
}
// settingsPane الدالة التالية نستخدمها لوضع الخيارات الإفتراضية التي يمكن تغييرها في الحاوية
public static void setDefaultSettings()
{
// fontSizesComboBox و ثاني خيار في الكائن boardsComboBox هنا قلنا أنه سيتم إختيار أول خيار في الكائن
settingsPane.boardsComboBox.getSelectionModel().selectFirst();
settingsPane.fontSizesComboBox.getSelectionModel().select(1);
// preferredFont لتغيير حجم خط كل زر, نص و مربع نص موضوع في اللعبة نسبةً لقيمة الكائن setFont() هنا قمنا باستدعاء الدالة
setFont();
}
// preferredFont الدالة التالية نستخدمها لتحديد حجم خط كل زر, نص و مربع نص موضوع في اللعبة نسبةً لقيمة الكائن
public static void setFont()
{
startPane.singlePlayer.setFont(preferredFont);
startPane.multiPlayer.setFont(preferredFont);
startPane.settings.setFont(preferredFont);
startPane.about.setFont(preferredFont);
startPane.exit.setFont(preferredFont);
singlePlayerPane.playerNameLabel.setFont(preferredFont);
singlePlayerPane.playerName.setFont(preferredFont);
singlePlayerPane.start.setFont(preferredFont);
singlePlayerPane.back.setFont(preferredFont);
multiPlayerPane.playerXLabel.setFont(preferredFont);
multiPlayerPane.playerOLabel.setFont(preferredFont);
multiPlayerPane.firstPlayerName.setFont(preferredFont);
multiPlayerPane.secondPlayerName.setFont(preferredFont);
multiPlayerPane.start.setFont(preferredFont);
multiPlayerPane.back.setFont(preferredFont);
gamePane.firstPlayerName.setFont(preferredFont);
gamePane.secondPlayerName.setFont(preferredFont);
gamePane.firstPlayerScore.setFont(preferredFont);
gamePane.secondPlayerScore.setFont(preferredFont);
gamePane.currentPlayerSymbol.setFont(preferredFont);
gamePane.restart.setFont(preferredFont);
gamePane.back.setFont(preferredFont);
settingsPane.labelForBoards.setFont(preferredFont);
settingsPane.labelForFontSizes.setFont(preferredFont);
settingsPane.reset.setFont(preferredFont);
settingsPane.back.setFont(preferredFont);
// لتحديد لهما setStyle() لا يملكان دالة خاصة لتحديد حجم الخط, لذلك قمنا باستخدام الدالة fontSizesComboBox و boardsComboBox الكائنين
settingsPane.boardsComboBox.setStyle(
"-fx-font-family:" + preferredFont.getName() + ";"
+"-fx-font-size: " + preferredFont.getSize() +"px;"
+"-fx-font-weight: bold;"
);
settingsPane.fontSizesComboBox.setStyle(
"-fx-font-family:" + preferredFont.getName() + ";"
+"-fx-font-size: " + preferredFont.getSize() +"px;"
+"-fx-font-weight: bold;"
);
}
}
import java.util.Random;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.image.ImageView;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.text.Font;
import javafx.scene.text.FontWeight;
// ( Multi Player ) و ( Single Player ) يمثل حاوية اللعب التي سنظهرها عند النقر على زر بدء اللعبة الموجود في كل من الحاويتين GamePane الكلاس
public class GamePane extends Pane {
// هنا قمنا بإنشاء جميع الأشياء التي سنضعها في الحاوية
Label firstPlayerName = new Label();
Label secondPlayerName = new Label();
Label firstPlayerScore = new Label("0");
Label secondPlayerScore = new Label("0");
Label currentPlayerSymbol = new Label();
GridPane boardPane = new GridPane();
Button[] boardButtons = new Button[3*3];
Button back = new Button("Back");
Button newGame = new Button("New Game");
ImageView boardBackground = new ImageView();
// سنستخدم هذا المتغير أيضاً لتحديد ما إذا كان سيتم إيقاف اللعبة بسبب فوز أحد اللاعبين
boolean isGameEnds;
// سنستخدم هذا المتغير لتحديد دور من في اللعب
boolean isFirstPlayerTurn = true;
// سنستخدم هذا المتغير لحساب عدد النقرات و بالتالي لتحديد ما إذا كان سيتم إيقاف اللعبة أم لا
int XOCounter = 0;
// randomNumber لتوليد أرقام عشوائية عند اللعب ضد الكمبيوتر. و سنخزن الرقم في المتغير random سنستخدم الكائن
Random random = new Random();
int randomNumber;
// O و X يمثلان الألوان الإفتراضية التي سنضعها للرموز Color هنا قمنا بإنشاء كائنين من الكلاس
Color xForeground = Color.BLUE;
Color oForeground = Color.RED;
// boardPane لأننا سنستخدمه لتحديد ما سيحدث عند النقر على أي زر موضوع في الحاوية EventHandler هنا قمنا بإنشاء كائن من الإنترفيس
// e و تمرير الكائن الذي يمثل الزر الذي تم النقر عليه مكان الباراميتر actionPerformed() بشكل عام, سيتم استدعاء الدالة
EventHandler<ActionEvent> eventHandler = (ActionEvent e) -> {
actionPerformed(e);
};
// سنستخدم هذه الدالة لتلوين خلفية المربعات التي بسببها فاز اللاعب باللون الأصفر
private void colorBackgroundWinnerButtons(Button b1, Button b2, Button b3)
{
b1.setStyle("-fx-background-color: yellow;");
b2.setStyle("-fx-background-color: yellow;");
b3.setStyle("-fx-background-color: yellow;");
}
// O و X سنستخدم هذه الدالة لإنشاء الأزرار التي يمكن النقر عليها لإظهار الرموز
// أيضاَ boardPane و سنضيفها في الحاوية boardButtons كما أننا سنخزن هذه الأزرار في المصفوفة
private void createGameBoard() {
int row = 0;
int column = 0;
for (int i = 0; i < boardButtons.length; i++) {
boardButtons[i] = new Button();
boardButtons[i].setPrefSize(90, 90);
boardButtons[i].setFocusTraversable(false);
GridPane.setMargin(boardButtons[i], new Insets(5));
boardButtons[i].setFont(Font.font("Arial", FontWeight.BOLD, 40));
boardPane.add(boardButtons[i], column, row);
boardButtons[i].addEventHandler(ActionEvent.ACTION, e -> {
actionPerformed(e);
});
column++;
if(column == 3)
{
row++;
column = 0;
}
}
}
// سنستخدم هذه الدالة في كل مرة يلعب فيها اللاعبون للتأكد ما إذا كان هناك فائز أم لا
// لتلوين خلفية خلفية المربعات التي كانت سبب فوز الاعب colorBackgroundWinnerButtons و في حال كان يوجد فائز سيتم مناداة الدالة
// لإيقاف اللعبة. و سيتم إضافة واحد في نتيجة اللاعب الفائز true إلى isGameEnds كما أننا سنقوم بتغيير قيمة المتغير
private void checkIfGameEnds() {
String t00 = boardButtons[0].getText();
String t01 = boardButtons[1].getText();
String t02 = boardButtons[2].getText();
String t10 = boardButtons[3].getText();
String t11 = boardButtons[4].getText();
String t12 = boardButtons[5].getText();
String t20= boardButtons[6].getText();
String t21 = boardButtons[7].getText();
String t22 = boardButtons[8].getText();
if (t00.equals(t01) && t00.equals(t02) && !t00.equals("")) {
isGameEnds = true;
colorBackgroundWinnerButtons(boardButtons[0], boardButtons[1], boardButtons[2]);
}
if (t10.equals(t11) && t10.equals(t12) && !t10.equals("")) {
isGameEnds = true;
colorBackgroundWinnerButtons(boardButtons[3], boardButtons[4], boardButtons[5]);
}
if (t20.equals(t21) && t20.equals(t22) && !t20.equals("")) {
isGameEnds = true;
colorBackgroundWinnerButtons(boardButtons[6], boardButtons[7], boardButtons[8]);
}
if (t00.equals(t10) && t00.equals(t20) && !t00.equals("")) {
isGameEnds = true;
colorBackgroundWinnerButtons(boardButtons[0], boardButtons[3], boardButtons[6]);
}
if (t01.equals(t11) && t01.equals(t21) && !t01.equals("")) {
isGameEnds = true;
colorBackgroundWinnerButtons(boardButtons[1], boardButtons[4], boardButtons[7]);
}
if (t02.equals(t12) && t02.equals(t22) && !t02.equals("")) {
isGameEnds = true;
colorBackgroundWinnerButtons(boardButtons[2], boardButtons[5], boardButtons[8]);
}
if (t00.equals(t11) && t00.equals(t22) && !t00.equals("")) {
isGameEnds = true;
colorBackgroundWinnerButtons(boardButtons[0], boardButtons[4], boardButtons[8]);
}
if (t02.equals(t11) && t02.equals(t20) && !t02.equals("")) {
isGameEnds = true;
colorBackgroundWinnerButtons(boardButtons[2], boardButtons[4], boardButtons[6]);
}
if( XOCounter >= 9)
{
isGameEnds = true;
isFirstPlayerTurn = true;
XOCounter = 0;
}
if(isGameEnds == true)
{
if(isFirstPlayerTurn)
firstPlayerScore.setText(Integer.valueOf(firstPlayerScore.getText()) + 1 + "");
else
secondPlayerScore.setText(Integer.valueOf(secondPlayerScore.getText()) + 1 + "");
XOCounter = 0;
newGame.requestFocus();
}
}
// موضوع في الحاوية و لإزالة أي O و X نستخدم هذه الدالة في كل مرة عند بدء اللعب من جديد لإزالة أي رمز
// و لتحديد دور اللاعب الذي سيبدأ colorBackgroundWinnerButtons() ألوان موضوعة بسبب الدالة
private void startNewGame() {
isGameEnds = false;
setCurrentPlayerSymbol();
for (Button boardButton : boardButtons) {
boardButton.setText("");
boardButton.setStyle("-fx-background-color: none; -fx-cursor: hand;");
}
}
// مما يجعلنا نعرف دور من الآن في اللعب currentPlayerSymbol كنص للكائن O أو X نستخدم هذه الدالة في كل مرة لإظهار الرمز
private void setCurrentPlayerSymbol() {
if (isFirstPlayerTurn == true) {
currentPlayerSymbol.setText("X");
currentPlayerSymbol.setTextFill(xForeground);
} else {
currentPlayerSymbol.setText("O");
currentPlayerSymbol.setTextFill(oForeground);
}
}
// boardPane في هذه الدالة قمنا بتحديد ما سيحدث عندما يقوم اللاعبون بالنقر على أي زر موضوع في الحاوية
private void actionPerformed(ActionEvent e)
{
// clickedButton سيتم تخزين الزر الذي تم النقر عليه بشكل مؤقت في الكائن
Button clickedButton = (Button) e.getSource();
// سيحدث التالي O أو X إذا لم تكن اللعبة قد انتهت و كان المستخدم قد قام بالنقر على زر لا يوجد عليه رمز
if( isGameEnds == false && clickedButton.getText().equals("") )
{
// إذا كان يوجد لاعبين يلعبان ضد بعضهما سيتم وضع رمز اللاعب الحالي على الزر الذي تم النقر عليه
if(AppManager.challengeComputer == false)
{
if(isFirstPlayerTurn) {
clickedButton.setTextFill(xForeground);
clickedButton.setText("X");
}
else {
clickedButton.setTextFill(oForeground);
clickedButton.setText("O");
}
// بعدها سيتم التأكد ما إن فاز أم لا و سيتم تبديل الأدوار إن لم يكن قد فاز
checkIfGameEnds();
setCurrentPlayerSymbol();
isFirstPlayerTurn = !isFirstPlayerTurn;
setCurrentPlayerSymbol();
}
// إذا كان اللاعب يلعب ضد الكمبيوتر
if (AppManager.challengeComputer == true)
{
// على الزر الذي نقر عليه و من ثم التأكد ما إن فاز أم لا X سيتم وضع الرمز
XOCounter++;
isFirstPlayerTurn = true;
clickedButton.setTextFill(xForeground);
clickedButton.setText("X");
checkIfGameEnds();
// إذا لم يكن المستخدم قد فاز, أي إذا لم يتم إيقاف اللعبة, سيحد التالي
if(isGameEnds == false)
{
// O هنا قمنا بجعل جميع الأزرار غير قابلة للنقر, لأننا نريد جعل الكمبيوتر الآن يقوم بالنقر و وضع الرمز
for (Button boardButton : boardButtons) {
boardButton.removeEventHandler(ActionEvent.ACTION, eventHandler);
}
// في مكان عشوائي و من ثم تأكدنا ما إن كان قد فاز أم لا O هنا جعلنا الكمبيوتر يضع الرمز
XOCounter++;
isFirstPlayerTurn = false;
for (;;) {
randomNumber = random.nextInt(9);
if (boardButtons[randomNumber].getText().equals(""))
{
boardButtons[randomNumber].setTextFill(oForeground);
boardButtons[randomNumber].setText("O");
break;
}
}
checkIfGameEnds();
// X هنا قمنا بجعل جميع الأزرار قابلة للنقر من جديد, لأننا نريد جعل المستخدم قادر على النقر و وضع الرمز
for (Button boardButton : boardButtons) {
boardButton.addEventHandler(ActionEvent.ACTION, eventHandler);
}
}
}
}
}
// هذا كونستركور الكلاس
public GamePane() {
// GamePane هنا قمنا بتحديد حجم كل شيء سنضيفه في الحاوية التي يمثلها الكائن الذي ننشئه من الكلاس
firstPlayerName.setPrefSize(150, 30);
secondPlayerName.setPrefSize(150, 30);
firstPlayerScore.setPrefSize(150, 30);
secondPlayerScore.setPrefSize(150, 30);
currentPlayerSymbol.setPrefSize(150, 30);
boardPane.setPrefSize(300, 300);
newGame.setPrefSize(140, 30);
// GamePane هنا قمنا بتحديد موقع كل شيء سنضيفه في الحاوية التي يمثلها الكائن الذي ننشئه من الكلاس
firstPlayerName.setTranslateY(10);
secondPlayerName.setTranslateX(250);
secondPlayerName.setTranslateY(10);
firstPlayerScore.setTranslateY(40);
secondPlayerScore.setTranslateX(250);
secondPlayerScore.setTranslateY(40);
currentPlayerSymbol.setTranslateX(120);
currentPlayerSymbol.setTranslateY(25);
boardBackground.setFitWidth(300);
boardBackground.setFitHeight(300);
boardBackground.setTranslateX(45);
boardBackground.setTranslateY(105);
boardPane.setTranslateX(45);
boardPane.setTranslateY(105);
back.setPrefSize(140, 30);
back.setTranslateX(20);
back.setTranslateY(455);
newGame.setTranslateX(230);
newGame.setTranslateY(455);
// هنا قمنا بجعل نصوص أسماء اللاعبين, و نتيجتهم تظهر في وسط المكان المخصص لظهورهم
firstPlayerName.setAlignment(Pos.CENTER);
secondPlayerName.setAlignment(Pos.CENTER);
firstPlayerScore.setAlignment(Pos.CENTER);
secondPlayerScore.setAlignment(Pos.CENTER);
currentPlayerSymbol.setAlignment(Pos.CENTER);
// boardPane و التي سيتم عرضها في الحاوية boardButtons حتى تنشئ الأزرار التي سيتم وضعها في المصفوفة createGameBoard() هنا قمنا باستدعاء الدالة
createGameBoard();
// GamePane هنا قمنا بإضافة كل شيء قمنا بإنشائه في الحاوية التي يمثلها الكائن الذي ننشئه من الكلاس
getChildren().add(firstPlayerName);
getChildren().add(secondPlayerName);
getChildren().add(firstPlayerScore);
getChildren().add(secondPlayerScore);
getChildren().add(currentPlayerSymbol);
getChildren().add(boardPane);
getChildren().add(boardBackground);
getChildren().add(back);
getChildren().add(newGame);
// لبدء لعبة جديدة startNewGame() هنا قمنا باستدعاء الدالة
startNewGame();
// back هنا قمنا بتحديد ما سيحدث عند النقر على الزر الذي يمثله الكائن
// لعرض الحاوية التي كانت معروضة قبل عرض الحاوية الحالية viewPane() سيتم إستدعاء الدالة الثابتة
back.setOnAction((Action) -> {
startNewGame();
if (AppManager.challengeComputer)
AppManager.viewPane(AppManager.singlePlayerPane);
else
AppManager.viewPane(AppManager.multiPlayerPane);
});
// newGame هنا قمنا بتحديد ما سيحدث عند النقر على الزر الذي يمثله الكائن
// لبدء اللعبة من جديد startNewGame() سيتم استدعاء الدالة
newGame.setOnAction((Action) -> {
startNewGame();
});
}
}
import java.util.Random;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.image.ImageView;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.text.Font;
import javafx.scene.text.FontWeight;
// ( Multi Player ) و ( Single Player ) يمثل حاوية اللعب التي سنظهرها عند النقر على زر بدء اللعبة الموجود في كل من الحاويتين GamePane الكلاس
public class GamePane extends Pane {
// هنا قمنا بإنشاء جميع الأشياء التي سنضعها في الحاوية
Label firstPlayerName = new Label();
Label secondPlayerName = new Label();
Label firstPlayerScore = new Label("0");
Label secondPlayerScore = new Label("0");
Label currentPlayerSymbol = new Label();
GridPane boardPane = new GridPane();
Button[] boardButtons = new Button[3*3];
Button back = new Button("Back");
Button newGame = new Button("New Game");
ImageView boardBackground = new ImageView();
// سنستخدم هذا المتغير أيضاً لتحديد ما إذا كان سيتم إيقاف اللعبة بسبب فوز أحد اللاعبين
boolean isGameEnds;
// سنستخدم هذا المتغير لتحديد دور من في اللعب
boolean isFirstPlayerTurn = true;
// سنستخدم هذا المتغير لحساب عدد النقرات و بالتالي لتحديد ما إذا كان سيتم إيقاف اللعبة أم لا
int XOCounter = 0;
// randomNumber لتوليد أرقام عشوائية عند اللعب ضد الكمبيوتر. و سنخزن الرقم في المتغير random سنستخدم الكائن
Random random = new Random();
int randomNumber;
// O و X يمثلان الألوان الإفتراضية التي سنضعها للرموز Color هنا قمنا بإنشاء كائنين من الكلاس
Color xForeground = Color.BLUE;
Color oForeground = Color.RED;
// boardPane لأننا سنستخدمه لتحديد ما سيحدث عند النقر على أي زر موضوع في الحاوية EventHandler هنا قمنا بإنشاء كائن من الإنترفيس
// e و تمرير الكائن الذي يمثل الزر الذي تم النقر عليه مكان الباراميتر actionPerformed() بشكل عام, سيتم استدعاء الدالة
EventHandler<ActionEvent> eventHandler = (ActionEvent e) -> {
actionPerformed(e);
};
// سنستخدم هذه الدالة لتلوين خلفية المربعات التي بسببها فاز اللاعب باللون الأصفر
private void colorBackgroundWinnerButtons(Button b1, Button b2, Button b3)
{
b1.setStyle("-fx-background-color: yellow;");
b2.setStyle("-fx-background-color: yellow;");
b3.setStyle("-fx-background-color: yellow;");
}
// O و X سنستخدم هذه الدالة لإنشاء الأزرار التي يمكن النقر عليها لإظهار الرموز
// أيضاَ boardPane و سنضيفها في الحاوية boardButtons كما أننا سنخزن هذه الأزرار في المصفوفة
private void createGameBoard() {
int row = 0;
int column = 0;
for (int i = 0; i < boardButtons.length; i++) {
boardButtons[i] = new Button();
boardButtons[i].setPrefSize(90, 90);
boardButtons[i].setFocusTraversable(false);
GridPane.setMargin(boardButtons[i], new Insets(5));
boardButtons[i].setFont(Font.font("Arial", FontWeight.BOLD, 40));
boardPane.add(boardButtons[i], column, row);
boardButtons[i].addEventHandler(ActionEvent.ACTION, e -> {
actionPerformed(e);
});
column++;
if(column == 3)
{
row++;
column = 0;
}
}
}
// سنستخدم هذه الدالة في كل مرة يلعب فيها اللاعبون للتأكد ما إذا كان هناك فائز أم لا
// لتلوين خلفية خلفية المربعات التي كانت سبب فوز الاعب colorBackgroundWinnerButtons و في حال كان يوجد فائز سيتم مناداة الدالة
// لإيقاف اللعبة. و سيتم إضافة واحد في نتيجة اللاعب الفائز true إلى isGameEnds كما أننا سنقوم بتغيير قيمة المتغير
private void checkIfGameEnds() {
String t00 = boardButtons[0].getText();
String t01 = boardButtons[1].getText();
String t02 = boardButtons[2].getText();
String t10 = boardButtons[3].getText();
String t11 = boardButtons[4].getText();
String t12 = boardButtons[5].getText();
String t20= boardButtons[6].getText();
String t21 = boardButtons[7].getText();
String t22 = boardButtons[8].getText();
if (t00.equals(t01) && t00.equals(t02) && !t00.equals("")) {
isGameEnds = true;
colorBackgroundWinnerButtons(boardButtons[0], boardButtons[1], boardButtons[2]);
}
if (t10.equals(t11) && t10.equals(t12) && !t10.equals("")) {
isGameEnds = true;
colorBackgroundWinnerButtons(boardButtons[3], boardButtons[4], boardButtons[5]);
}
if (t20.equals(t21) && t20.equals(t22) && !t20.equals("")) {
isGameEnds = true;
colorBackgroundWinnerButtons(boardButtons[6], boardButtons[7], boardButtons[8]);
}
if (t00.equals(t10) && t00.equals(t20) && !t00.equals("")) {
isGameEnds = true;
colorBackgroundWinnerButtons(boardButtons[0], boardButtons[3], boardButtons[6]);
}
if (t01.equals(t11) && t01.equals(t21) && !t01.equals("")) {
isGameEnds = true;
colorBackgroundWinnerButtons(boardButtons[1], boardButtons[4], boardButtons[7]);
}
if (t02.equals(t12) && t02.equals(t22) && !t02.equals("")) {
isGameEnds = true;
colorBackgroundWinnerButtons(boardButtons[2], boardButtons[5], boardButtons[8]);
}
if (t00.equals(t11) && t00.equals(t22) && !t00.equals("")) {
isGameEnds = true;
colorBackgroundWinnerButtons(boardButtons[0], boardButtons[4], boardButtons[8]);
}
if (t02.equals(t11) && t02.equals(t20) && !t02.equals("")) {
isGameEnds = true;
colorBackgroundWinnerButtons(boardButtons[2], boardButtons[4], boardButtons[6]);
}
if( XOCounter >= 9)
{
isGameEnds = true;
isFirstPlayerTurn = true;
XOCounter = 0;
}
if(isGameEnds == true)
{
if(isFirstPlayerTurn)
firstPlayerScore.setText(Integer.valueOf(firstPlayerScore.getText()) + 1 + "");
else
secondPlayerScore.setText(Integer.valueOf(secondPlayerScore.getText()) + 1 + "");
XOCounter = 0;
newGame.requestFocus();
}
}
// موضوع في الحاوية و لإزالة أي O و X نستخدم هذه الدالة في كل مرة عند بدء اللعب من جديد لإزالة أي رمز
// و لتحديد دور اللاعب الذي سيبدأ colorBackgroundWinnerButtons() ألوان موضوعة بسبب الدالة
private void startNewGame() {
isGameEnds = false;
setCurrentPlayerSymbol();
for (Button boardButton : boardButtons) {
boardButton.setText("");
boardButton.setStyle("-fx-background-color: none; -fx-cursor: hand;");
}
}
// مما يجعلنا نعرف دور من الآن في اللعب currentPlayerSymbol كنص للكائن O أو X نستخدم هذه الدالة في كل مرة لإظهار الرمز
private void setCurrentPlayerSymbol() {
if (isFirstPlayerTurn == true) {
currentPlayerSymbol.setText("X");
currentPlayerSymbol.setTextFill(xForeground);
} else {
currentPlayerSymbol.setText("O");
currentPlayerSymbol.setTextFill(oForeground);
}
}
// boardPane في هذه الدالة قمنا بتحديد ما سيحدث عندما يقوم اللاعبون بالنقر على أي زر موضوع في الحاوية
private void actionPerformed(ActionEvent e)
{
// clickedButton سيتم تخزين الزر الذي تم النقر عليه بشكل مؤقت في الكائن
Button clickedButton = (Button) e.getSource();
// سيحدث التالي O أو X إذا لم تكن اللعبة قد انتهت و كان المستخدم قد قام بالنقر على زر لا يوجد عليه رمز
if( isGameEnds == false && clickedButton.getText().equals("") )
{
// إذا كان يوجد لاعبين يلعبان ضد بعضهما سيتم وضع رمز اللاعب الحالي على الزر الذي تم النقر عليه
if(AppManager.challengeComputer == false)
{
if(isFirstPlayerTurn) {
clickedButton.setTextFill(xForeground);
clickedButton.setText("X");
}
else {
clickedButton.setTextFill(oForeground);
clickedButton.setText("O");
}
// بعدها سيتم التأكد ما إن فاز أم لا و سيتم تبديل الأدوار إن لم يكن قد فاز
checkIfGameEnds();
setCurrentPlayerSymbol();
isFirstPlayerTurn = !isFirstPlayerTurn;
setCurrentPlayerSymbol();
}
// إذا كان اللاعب يلعب ضد الكمبيوتر
if (AppManager.challengeComputer == true)
{
// على الزر الذي نقر عليه و من ثم التأكد ما إن فاز أم لا X سيتم وضع الرمز
XOCounter++;
isFirstPlayerTurn = true;
clickedButton.setTextFill(xForeground);
clickedButton.setText("X");
checkIfGameEnds();
// إذا لم يكن المستخدم قد فاز, أي إذا لم يتم إيقاف اللعبة, سيحد التالي
if(isGameEnds == false)
{
// O هنا قمنا بجعل جميع الأزرار غير قابلة للنقر, لأننا نريد جعل الكمبيوتر الآن يقوم بالنقر و وضع الرمز
for (Button boardButton : boardButtons) {
boardButton.removeEventHandler(ActionEvent.ACTION, eventHandler);
}
// في مكان عشوائي و من ثم تأكدنا ما إن كان قد فاز أم لا O هنا جعلنا الكمبيوتر يضع الرمز
XOCounter++;
isFirstPlayerTurn = false;
for (;;) {
randomNumber = random.nextInt(9);
if (boardButtons[randomNumber].getText().equals(""))
{
boardButtons[randomNumber].setTextFill(oForeground);
boardButtons[randomNumber].setText("O");
break;
}
}
checkIfGameEnds();
// X هنا قمنا بجعل جميع الأزرار قابلة للنقر من جديد, لأننا نريد جعل المستخدم قادر على النقر و وضع الرمز
for (Button boardButton : boardButtons) {
boardButton.addEventHandler(ActionEvent.ACTION, eventHandler);
}
}
}
}
}
// هذا كونستركور الكلاس
public GamePane() {
// GamePane هنا قمنا بتحديد حجم كل شيء سنضيفه في الحاوية التي يمثلها الكائن الذي ننشئه من الكلاس
firstPlayerName.setPrefSize(150, 30);
secondPlayerName.setPrefSize(150, 30);
firstPlayerScore.setPrefSize(150, 30);
secondPlayerScore.setPrefSize(150, 30);
currentPlayerSymbol.setPrefSize(150, 30);
boardPane.setPrefSize(300, 300);
newGame.setPrefSize(140, 30);
// GamePane هنا قمنا بتحديد موقع كل شيء سنضيفه في الحاوية التي يمثلها الكائن الذي ننشئه من الكلاس
firstPlayerName.setTranslateY(10);
secondPlayerName.setTranslateX(250);
secondPlayerName.setTranslateY(10);
firstPlayerScore.setTranslateY(40);
secondPlayerScore.setTranslateX(250);
secondPlayerScore.setTranslateY(40);
currentPlayerSymbol.setTranslateX(120);
currentPlayerSymbol.setTranslateY(25);
boardBackground.setFitWidth(300);
boardBackground.setFitHeight(300);
boardBackground.setTranslateX(45);
boardBackground.setTranslateY(105);
boardPane.setTranslateX(45);
boardPane.setTranslateY(105);
back.setPrefSize(140, 30);
back.setTranslateX(20);
back.setTranslateY(455);
newGame.setTranslateX(230);
newGame.setTranslateY(455);
// هنا قمنا بجعل نصوص أسماء اللاعبين, و نتيجتهم تظهر في وسط المكان المخصص لظهورهم
firstPlayerName.setAlignment(Pos.CENTER);
secondPlayerName.setAlignment(Pos.CENTER);
firstPlayerScore.setAlignment(Pos.CENTER);
secondPlayerScore.setAlignment(Pos.CENTER);
currentPlayerSymbol.setAlignment(Pos.CENTER);
// boardPane و التي سيتم عرضها في الحاوية boardButtons حتى تنشئ الأزرار التي سيتم وضعها في المصفوفة createGameBoard() هنا قمنا باستدعاء الدالة
createGameBoard();
// GamePane هنا قمنا بإضافة كل شيء قمنا بإنشائه في الحاوية التي يمثلها الكائن الذي ننشئه من الكلاس
getChildren().add(firstPlayerName);
getChildren().add(secondPlayerName);
getChildren().add(firstPlayerScore);
getChildren().add(secondPlayerScore);
getChildren().add(currentPlayerSymbol);
getChildren().add(boardPane);
getChildren().add(boardBackground);
getChildren().add(back);
getChildren().add(newGame);
// لبدء لعبة جديدة startNewGame() هنا قمنا باستدعاء الدالة
startNewGame();
// back هنا قمنا بتحديد ما سيحدث عند النقر على الزر الذي يمثله الكائن
// لعرض الحاوية التي كانت معروضة قبل عرض الحاوية الحالية viewPane() سيتم إستدعاء الدالة الثابتة
back.setOnAction((Action) -> {
startNewGame();
if (AppManager.challengeComputer)
AppManager.viewPane(AppManager.singlePlayerPane);
else
AppManager.viewPane(AppManager.multiPlayerPane);
});
// newGame هنا قمنا بتحديد ما سيحدث عند النقر على الزر الذي يمثله الكائن
// لبدء اللعبة من جديد startNewGame() سيتم استدعاء الدالة
newGame.setOnAction((Action) -> {
startNewGame();
});
}
}
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.stage.Stage;
public class Main extends Application {
@Override
public void start(Stage stage) {
// لتحديد خصائص الخط الإفتراضي الذي سيتم وضعه لكل setDefaultSettings() هنا قمنا باستدعاء الدالة الثابتة
// زر, نص و مربع نص تم وضعه في اللعبة. بالإضافة إلى الصورة التي سيتم وضعها كخلفية في حاوية اللعب
AppManager.setDefaultSettings();
// لكل الحاويات التي سنضعها في اللعبة Root Node و الذي سنضعه كـ Pane هنا قمنا بإنشاء كائن من الكلاس
Pane root = new Pane();
// حتى نكون قادرين على عرضها في النافذة root في الكائن AppManager هنا قمنا بإضافة جميع الحاويات التي أنشأناها في الكلاس
root.getChildren().add(AppManager.startPane);
root.getChildren().add(AppManager.singlePlayerPane);
root.getChildren().add(AppManager.multiPlayerPane);
root.getChildren().add(AppManager.settingsPane);
root.getChildren().add(AppManager.gamePane);
// لها لأننا نريد عرض هذه الحاوية في النافذة عند تشغيل اللعبة startPane و تمرير الحاوية AppManager من الكلاس viewPane() هنا قمنا باستدعاء الدالة الثابتة
AppManager.viewPane(AppManager.startPane);
// فيها و تحديد حجمها Node كأول root هنا قمنا بإنشاء محتوى النافذة مع تعيين الكائن
Scene scene = new Scene(root, 380, 500);
// هنا قمنا بإنشاء و إظهار نافذة اللعبة مع جعل حجمها غير قابل للتكبير أو التصغي
stage.setTitle("Tic Tac Toe");
stage.setScene(scene);
stage.setResizable(false);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.stage.Stage;
public class Main extends Application {
@Override
public void start(Stage stage) {
// لتحديد خصائص الخط الإفتراضي الذي سيتم وضعه لكل setDefaultSettings() هنا قمنا باستدعاء الدالة الثابتة
// زر, نص و مربع نص تم وضعه في اللعبة. بالإضافة إلى الصورة التي سيتم وضعها كخلفية في حاوية اللعب
AppManager.setDefaultSettings();
// لكل الحاويات التي سنضعها في اللعبة Root Node و الذي سنضعه كـ Pane هنا قمنا بإنشاء كائن من الكلاس
Pane root = new Pane();
// حتى نكون قادرين على عرضها في النافذة root في الكائن AppManager هنا قمنا بإضافة جميع الحاويات التي أنشأناها في الكلاس
root.getChildren().add(AppManager.startPane);
root.getChildren().add(AppManager.singlePlayerPane);
root.getChildren().add(AppManager.multiPlayerPane);
root.getChildren().add(AppManager.settingsPane);
root.getChildren().add(AppManager.gamePane);
// لها لأننا نريد عرض هذه الحاوية في النافذة عند تشغيل اللعبة startPane و تمرير الحاوية AppManager من الكلاس viewPane() هنا قمنا باستدعاء الدالة الثابتة
AppManager.viewPane(AppManager.startPane);
// فيها و تحديد حجمها Node كأول root هنا قمنا بإنشاء محتوى النافذة مع تعيين الكائن
Scene scene = new Scene(root, 380, 500);
// هنا قمنا بإنشاء و إظهار نافذة اللعبة مع جعل حجمها غير قابل للتكبير أو التصغي
stage.setTitle("Tic Tac Toe");
stage.setScene(scene);
stage.setResizable(false);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
هذه الصور جميعها من اللعبة.