Cześć Wszystkim!
Zwracam się do Was z prośbą o pomoc ponieważ nie bardzo mam już pomysł jak rozwiązać problem. Wybaczcie jeżeli pytanie należy do tych "głupich" ale próbowałem coś wyszukać w Google i niestety nie udało mi się. Uczę się programować łącznie od ok 3 tygodni i jest to praktycznie moje pierwsze doświadczenie z programowaniem w życiu więc nie wykluczam, że coś źle szukałem:P
Ostatnio skończyłem dwa poradniki odnośnie Javy i staram się teraz jak najwięcej popracować nad zdobytą wiedzą teoretyczną wykorzystując ja w praktyce, jednocześnie googlując jakieś nowe rzeczy, które uznam za ciekawe i przydatne na przyszłość.
Wczoraj zacząłem pisać swoja drugą własną aplikację i jestem nawet zadowolony z dotychczasowego efektu jednak chciałbym iść krok dalej w swojej nauce i pomyślałem, że fajnie byłoby dodatkowo sterować tą aplikacją za pomocą klawiatury.
Nie mam problemu z przechwytywaniem eventów z klawiatury w klasie Main jednak aplikacje pisałem tak jak było w poradnikach czyli rozbiłem wszystko na osobne pliki. Grafika w FXML, wygląd elementów w CSS oraz sterowanie w Controller.java.
Pytanie moje brzmi czy jest jakiś łatwy sposób na przechwytywanie eventów z klawiatury w klasie Controller? Może jakiś prosty aby odwołać się do pola Scene z klasy Main z której mógłbym wyciągnąć eventy tak jak w owej klasie i na ich podstawie coś zmieniać w kontrolerze?
Na przyszłość chciałbym też sprawić aby aplikacja zapisywała wyniki na serwer. Czytałem ostatnio w informacjach o dropboxie, że można tam się chyba dość łatwo połączyć bo udostępniają całe api do tego i wykorzystać to jako prosty serwer na dane w aplikacjach testowych. Co o tym myślicie?
Chętnie poczytam jakąś krytykę odnośnie obecnego kodu, aby lepiej pisać na przyszłość oraz może jakieś sugestie w jaką stronę dalej iść? Przypominam, że dopiero się uczę i sam widzę już drobne rzeczy do poprawy a to jest moja pierwsza aplikacja, która robi cokolwiek więcej niż wyświetla liczby :P
Póki co chciałbym osiągnąć poziom, który pozwoli mi podjąć prace na stanowisku Juniora w Javie a później myślałem o Androidzie jak ogarnę podstawy pisania aplikacji w Javie na komputerze.
Poniżej oczywiście kod:)
Dorzuciłem plik .jar jeżeli ktoś jest ciekawy jak działa całość z dźwiękami jednak nie wiem jeszcze jak obsłużyć plik *.src z zapisanym rekordem oby później .jar umiał dane w tym zapisać oraz odczytać więc tu kolejne pytanie o wskazówki :)
Main.java
package sample;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class Main extends Application {
@Override
public void start(Stage primaryStage) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("/fxml/sample.fxml"));
primaryStage.setTitle("Gierka");
primaryStage.setScene(new Scene(root, 350, 300));
primaryStage.show();
primaryStage.setResizable(false);
////////////////////////////////////////////////////////////////////////////////
// Test KeyPressed
primaryStage.getScene().setOnKeyPressed(event -> {
System.out.println(event.getCode().toString());
});
}
public static void main(String[] args) {
launch(args);
}
}
package sample;
import javafx.animation.Animation;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.control.CheckBox;
import javafx.scene.control.Label;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.media.AudioClip;
import javafx.scene.media.Media;
import javafx.scene.media.MediaPlayer;
import javafx.util.Duration;
import java.io.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
public class Controller {
@FXML
ImageView img11, img12, img13, img21, img22, img23;
@FXML
Button startButton, resumeButton, pauseButton, restartButton, restartButton2, restartRekord;
@FXML
Label lol;
@FXML
CheckBox mCheckBoxSounds, mCheckBoxMusic, mCheckBoxNiesmiertelnosc;
List<ImageView> mListaImageViews;
Integer mPunkty = 0;
StringProperty pkt, poziom, wynik;
Timeline mTimelineGry;
Integer mWylosowanePole = 0;
Integer mObecnyPoziom = 1;
Integer mEventowNaTimeline = 5;
Integer mRekordowyWynik = 0;
Integer mDlugoscEventu = 1000;
Integer mMinCzasEventu = 210;
Boolean mCzyGraDalej = true;
MediaPlayer mMediaPlayer = new MediaPlayer(new Media(getClass().getResource("/audio/lol.m4a").toExternalForm()));
AudioClip mSoundClick = new AudioClip(getClass().getResource("/audio/click.mp3").toExternalForm());
AudioClip mSoundError = new AudioClip(getClass().getResource("/audio/error.mp3").toExternalForm());
AudioClip mSoundHappy = new AudioClip(getClass().getResource("/audio/happy.mp3").toExternalForm());
Image mObrazOrange = new Image("/img/orangesq.png");
Image mObrazYellow = new Image("/img/yellowsq.png");
Image mObrazGreen = new Image("/img/green.png");
public Controller() {
pkt = new SimpleStringProperty();
poziom = new SimpleStringProperty();
wynik = new SimpleStringProperty();
setPkt(String.format("Punkty: %d", mPunkty));
setPoziom(String.format("Poziom: %d", mObecnyPoziom));
mMediaPlayer.setVolume(0.2);
mRekordowyWynik = odczytPliku();
setWynik(String.format("Najlepszy: %d", mRekordowyWynik));
}
public String getWynik() {
return wynik.get();
}
public StringProperty wynikProperty() {
return wynik;
}
public void setWynik(String wynik) {
this.wynik.set(wynik);
}
public String getPoziom() {
return poziom.get();
}
public void setPoziom(String poziom) {
this.poziom.set(poziom);
}
public StringProperty poziomProperty() {
return poziom;
}
public String getPkt() {
return pkt.get();
}
public void setPkt(String pkt) {
this.pkt.set(pkt);
}
public StringProperty pktProperty() {
return pkt;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// ZACHOWANIE APLIKACJI
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Inicjalizacja planszy
public void start(ActionEvent event) {
im();
mMediaPlayer.play();
restartButton.setVisible(false);
restartRekord.setVisible(false);
for (ImageView iv : mListaImageViews) {
iv.setOnMouseClicked(event1 -> koniec());
}
}
private void im() {
startButton.setVisible(false);
pauseButton.setVisible(true);
petlaGry();
mTimelineGry.play();
restart();
mListaImageViews = new ArrayList<>();
mListaImageViews.add(img11);
mListaImageViews.add(img12);
mListaImageViews.add(img13);
mListaImageViews.add(img21);
mListaImageViews.add(img22);
mListaImageViews.add(img23);
for (ImageView iv : mListaImageViews) {
iv.setImage(mObrazOrange);
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Start Timeline i jego zachowanie
private void petlaGry() {
nowyTimeline();
mTimelineGry.getKeyFrames().add(new KeyFrame(Duration.millis(mDlugoscEventu), event1 -> {
eventGry();
}));
}
private void eventGry() {
losowaniePola();
setPoziom(String.format("Poziom: %d", mObecnyPoziom));
for (ImageView pole : mListaImageViews) {
if (mListaImageViews.get(mWylosowanePole).equals(pole)) {
pole.setImage(mObrazGreen);
pole.setOnMouseClicked(event -> {
mCzyGraDalej = true;
mPunkty += mObecnyPoziom;
setPkt(String.format("Punkty: %d", mPunkty));
pole.setImage(mObrazOrange);
sound(mSoundClick);
pole.setOnMouseClicked(event1 -> {
if (!mCheckBoxNiesmiertelnosc.isSelected()) {
koniec();
} else pole.setOnMouseClicked(null);
});
});
} else {
pole.setImage(mObrazOrange);
if (!mCheckBoxNiesmiertelnosc.isSelected()) {
pole.setOnMouseClicked(event -> koniec());
} else pole.setOnMouseClicked(null);
}
}
czyNiesmiertelny();
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Metody
private void losowaniePola() {
Random random = new Random();
int poprzedniaLosowa = mWylosowanePole;
do {
mWylosowanePole = random.nextInt(5) + 1;
} while (mWylosowanePole == poprzedniaLosowa);
}
private void czyNiesmiertelny() {
if (!mCheckBoxNiesmiertelnosc.isSelected()) {
if (mCzyGraDalej == false) {
koniec();
}
mCzyGraDalej = false;
}
}
private void sound(AudioClip sound) {
if (mCheckBoxSounds.isSelected()) {
sound.play();
}
}
private void infoZapis() {
if (mPunkty > mRekordowyWynik) {
mRekordowyWynik = mPunkty;
sound(mSoundHappy);
wynik.set(String.format("Najlepszy: %d%nNowy rekord!", mRekordowyWynik));
} else {
sound(mSoundError);
wynik.set(String.format("Najlepszy: %d%nPrzegrałeś.", mRekordowyWynik));
}
}
private void koniec() {
stopButtony();
mTimelineGry.stop();
mMediaPlayer.stop();
restartButton2.setVisible(true);
startButton.setVisible(true);
pauseButton.setVisible(false);
resumeButton.setVisible(false);
startButton.setVisible(false);
restartButton.setVisible(false);
startButton.setVisible(true);
infoZapis();
zapisPliku(mRekordowyWynik);
}
private void stopButtony() {
for (ImageView iv : mListaImageViews) {
iv.setOnMouseClicked(null);
}
}
private void nowyTimeline() {
if (mTimelineGry != null && mTimelineGry.getStatus() == Animation.Status.RUNNING) {
mTimelineGry.stop();
}
mTimelineGry = new Timeline();
mTimelineGry.setCycleCount(mEventowNaTimeline);
mTimelineGry.setOnFinished(event2 -> {
mDlugoscEventu = (mDlugoscEventu * 95) / 100;
if (mDlugoscEventu > mMinCzasEventu) {
petlaGry();
mTimelineGry.play();
mObecnyPoziom++;
} else {
infoZapis();
koniec();
}
});
}
private void restart() {
mPunkty = 0;
mDlugoscEventu = 1000;
mObecnyPoziom = 1;
mWylosowanePole = 0;
restartButton.setVisible(false);
setPkt(String.format("Punkty: %d", mPunkty));
setPoziom(String.format("Poziom: %d", mObecnyPoziom));
wynik.set(String.format("Najlepszy: %d", mRekordowyWynik));
restartRekord.setVisible(true);
}
public void Pause(ActionEvent event) {
mTimelineGry.pause();
pauseButton.setVisible(false);
resumeButton.setVisible(true);
stopButtony();
mMediaPlayer.pause();
restartButton.setVisible(true);
}
public void resume(ActionEvent event) {
mTimelineGry.play();
pauseButton.setVisible(true);
resumeButton.setVisible(false);
restartButton.setVisible(false);
mMediaPlayer.play();
}
public void restartGame(ActionEvent event) {
im();
for (ImageView iv : mListaImageViews) {
iv.setImage(mObrazGreen);
}
mTimelineGry.stop();
pauseButton.setVisible(false);
resumeButton.setVisible(false);
startButton.setVisible(true);
restartButton2.setVisible(false);
restartButton.setVisible(false);
mMediaPlayer.stop();
mCzyGraDalej = true;
}
public void checkBox(ActionEvent event) {
if (mCheckBoxMusic.isSelected()) {
mMediaPlayer.setMute(false);
} else {
mMediaPlayer.setMute(true);
}
}
private void zapisPliku(Integer rekordowyWynik) {
try (
FileOutputStream fos = new FileOutputStream("Resources/dane/rekord.ser");
ObjectOutputStream oos = new ObjectOutputStream(fos);
) {
oos.writeObject(rekordowyWynik);
} catch (IOException e) {
e.printStackTrace();
}
}
private int odczytPliku() {
int liczba = 0;
try (
FileInputStream fis = new FileInputStream("Resources/dane/rekord.ser");
ObjectInputStream ois = new ObjectInputStream(fis);
) {
liczba = (int) ois.readObject();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return liczba;
}
public void restartRekord(ActionEvent event) {
mRekordowyWynik = 0;
zapisPliku(mRekordowyWynik);
setWynik(String.format("Najlepszy: %d", mRekordowyWynik));
}
}
Sample.fxml
<?import javafx.scene.control.*?>
<?import javafx.scene.image.*?>
<?import javafx.scene.layout.*?>
<GridPane fx:controller="sample.Controller"
xmlns:fx="http://javafx.com/fxml" alignment="TOP_CENTER" hgap="10" vgap="5"
stylesheets="/css/sample.css"
gridLinesVisible="false">
<ImageView fx:id="img11"
styleClass="Button-Image"
GridPane.columnIndex="0"
GridPane.rowIndex="1"
fitHeight="100"
preserveRatio="true"
></ImageView>
<ImageView fx:id="img12"
styleClass="Button-Image"
GridPane.columnIndex="1"
GridPane.halignment="CENTER"
GridPane.rowIndex="1"
fitHeight="100"
preserveRatio="true"
></ImageView>
<ImageView fx:id="img13"
styleClass="Button-Image"
GridPane.columnIndex="2"
GridPane.rowIndex="1"
fitHeight="100"
preserveRatio="true"
></ImageView>
<ImageView fx:id="img21"
styleClass="Button-Image"
GridPane.columnIndex="0"
GridPane.rowIndex="2"
fitHeight="100"
preserveRatio="true"
></ImageView>
<ImageView fx:id="img22"
styleClass="Button-Image"
GridPane.columnIndex="1"
GridPane.halignment="CENTER"
GridPane.rowIndex="2"
fitHeight="100"
preserveRatio="true"
></ImageView>
<ImageView fx:id="img23"
styleClass="Button-Image"
GridPane.columnIndex="2"
GridPane.rowIndex="2"
fitHeight="100"
preserveRatio="true"
></ImageView>
<Button text="Start Game"
fx:id="startButton"
onAction="#start"
GridPane.columnIndex="1"
GridPane.rowIndex="0"
GridPane.halignment="CENTER"
GridPane.fillWidth="true"
></Button>
<Button text="Pause"
fx:id="pauseButton"
visible="false"
onAction="#Pause"
GridPane.columnIndex="1"
GridPane.rowIndex="0"
GridPane.halignment="CENTER"
GridPane.fillWidth="true"
></Button>
<Button text="Resume"
fx:id="resumeButton"
visible="false"
onAction="#resume"
GridPane.columnIndex="1"
GridPane.rowIndex="0"
GridPane.halignment="CENTER"
GridPane.fillWidth="true"
></Button>
<Button text="Restart"
fx:id="restartButton"
visible="false"
onAction="#restartGame"
GridPane.columnIndex="2"
GridPane.rowIndex="4"
GridPane.halignment="CENTER"
GridPane.fillWidth="true"
styleClass="dark"
></Button>
<Button text="Restart Game"
fx:id="restartButton2"
visible="false"
onAction="#restartGame"
GridPane.columnIndex="1"
GridPane.rowIndex="0"
GridPane.halignment="CENTER"
GridPane.fillWidth="true"
></Button>
<Label text="${controller.pkt}"
GridPane.rowIndex="0"
GridPane.columnIndex="0"
GridPane.halignment="LEFT"
styleClass="info"
></Label>
<Label text="${controller.poziom}"
GridPane.rowIndex="0"
GridPane.columnIndex="2"
GridPane.halignment="RIGHT"
styleClass="info"
></Label>
<StackPane GridPane.columnIndex="0"
GridPane.columnSpan="2"
GridPane.rowIndex="4"
GridPane.halignment="LEFT"
GridPane.valignment="TOP">
<Label text="${controller.wynik}"
StackPane.alignment="TOP_LEFT"
styleClass="info"
></Label>
<Button text="Restart rekord"
fx:id="restartRekord"
visible="true"
onAction="#restartRekord"
styleClass="dark"
StackPane.alignment="BOTTOM_LEFT"
></Button>
</StackPane>
<VBox GridPane.rowIndex="4"
GridPane.columnIndex="1"
GridPane.halignment="RIGHT">
<CheckBox text="Sounds"
fx:id="mCheckBoxSounds"
selected="true"
onAction="#checkBox"
></CheckBox>
<CheckBox text="Music"
fx:id="mCheckBoxMusic"
selected="true"
onAction="#checkBox"
></CheckBox>
<CheckBox text="Nieśmiertelność"
fx:id="mCheckBoxNiesmiertelnosc"
selected="false"
onAction="#checkBox"
></CheckBox>
</VBox>
</GridPane>
Sample.css
.root{
-fx-background-color:
#090a0c,
linear-gradient(#38424b 0%, #1f2429 20%, #191d22 100%),
linear-gradient(#20262b, #191d22),
radial-gradient(center 50% 0%, radius 100%, rgba(114,131,148,0.9), rgba(255,255,255,0));
}
.label {
-fx-text-fill: #ffe4c4;
}
.check-box{
-fx-text-fill: #ffe4c4;
}
.Button-Image{
-fx-image: url('/img/green.png');
-fx-image-width:100%;
-fx-image-height:auto;
-fx-translate-x:0.1;
-fx-translate-y:0.1;
}
.info {
-fx-font-size: 15; -fx-font-weight: bold;
}
.button {
-fx-background-color:
#c3c4c4,
linear-gradient(#d6d6d6 50%, white 100%),
radial-gradient(center 50% -40%, radius 200%, #e6e6e6 45%, rgba(230,230,230,0) 50%);
-fx-background-radius: 30;
-fx-background-insets: 0,1,1;
-fx-text-fill: black;
-fx-effect: dropshadow( three-pass-box , rgba(0,0,0,0.6) , 3, 0.0 , 0 , 1 );
-fx-font-weight: bold;
}