G
Gelöschtes Mitglied 65838
Gast
Also ich habe versucht irgendwie mvc in javafx umzusetzen was bis zu einem gewissen grad auch funktioniert hat nur komm ich jetzt in das problem dass der controller zu groß wird und im model eig gar nichts mehr passiert
Anmerkungen zuvor für die view
die PlayerView kann ansich gar nix und wäre gleichzusetzen wie in fxml mit import fxml datei
das gleiche gilt für die PointsCounterLayout diese können ansich nur sachen die auch eine View können sollte, die fügt halt punkte hinzu wenn es denn nötig ist
dh diese sind eig. unterviews
[CODE lang="java" title="View"]package playField;
import javafx.geometry.Pos;
import javafx.scene.control.ScrollPane;
import javafx.scene.control.ScrollPane.ScrollBarPolicy;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import layout.PointsCounterLayout;
import player.PlayerView;
import test.CardsModel;
public class PlayFieldView extends BorderPane
{
private HBox handCards = new HBox();
private final PlayerView myView = new PlayerView(true);
private final PlayerView enemyView = new PlayerView(false);
private final VBox phaseLayout;
private final PointsCounterLayout myPoints = new PointsCounterLayout("My Points");
private final PointsCounterLayout enemyPoints = new PointsCounterLayout("Enemy Points");
private StackPane popUpStackPaneForEvents;
public PlayFieldView(VBox phaseLayout)
{
this.phaseLayout = phaseLayout;
this.setHandCardsAtTheBottom();
this.getStylesheets().add(getClass().getResource("playFieldView.css").toExternalForm());
this.setupPlayingInnerField();
this.setupCssForPointsSystem();
this.setPickOnBounds(false);
this.deactivateCreatures();
this.testCards(); // TODO nur für testzwecke
}
private void setupCssForPointsSystem()
{
myPoints.getMyPointsDisplay().setId("PointsBox");
enemyPoints.getMyPointsDisplay().setId("PointsBox");
}
private void setupPlayingInnerField()
{
BorderPane field = new BorderPane();
field.setTop(enemyView);
field.setRight(enemyPoints.getMyPointsDisplay());
field.setCenter(phaseLayout);
field.setBottom(myView);
field.setLeft(myPoints.getMyPointsDisplay());
myPoints.getMyPointsDisplay().setAlignment(Pos.CENTER);
popUpStackPaneForEvents = new StackPane(field);
this.setCenter(popUpStackPaneForEvents);
}
private void setHandCardsAtTheBottom()
{
ScrollPane handCardScrollPane = new ScrollPane(handCards);
handCardScrollPane.hbarPolicyProperty().set(ScrollBarPolicy.ALWAYS);
handCardScrollPane.vbarPolicyProperty().set(ScrollBarPolicy.NEVER);
this.setBottom(handCardScrollPane);
}
//TODO noch useless, erst mit fertigstellung von der sqlite db nützlich
/** public void drawCard()
{
if (phaseLayout.getPlayersTurn().getValue())
{
// handCards.getChildren().add();
}
}*/
public void activateCreatures()
{
myView.getCreatures().setDisable(false);
}
public void deactivateCreatures()
{
myView.getCreatures().setDisable(true);
}
public void testCards()
{
String s = "commander";
for (int i = 0; i < 10; i++)
{
Image image;
int counter = i;
if (i > 3)
{
counter = 3;
}
s = "main";
image = new Image(getClass().getResource("card" + counter + ".gif").toExternalForm());
ImageView imageview = new ImageView(image);
String str = "Once Per Turn -> Discard 1 card: \n Destroy " + i + " Creatures.";
String name = "Draco Wyvern Ruler of Air" + i;
CardsModel card = new CardsModel(s, name, image, imageview, 1 + i, 1 + i, "Kaiju", 3, "Laura Bornea", str,
3);
handCards.getChildren().add(card);
}
}
public HBox getHandCards()
{
return handCards;
}
public PointsCounterLayout getMyPoints()
{
return myPoints;
}
public PointsCounterLayout getEnemyPoints()
{
return enemyPoints;
}
public PlayerView getMyView()
{
return myView;
}
public PlayerView getEnemyView()
{
return enemyView;
}
}
[/CODE]
dann kommt mein bescheidenes model ich dachte ich brauche die gameStateProperty aber es ist irgendwie doch nur zu 1er methode gekommen was schon ein bisschen traurig ist
und dann kommt der controller dazu der irgendwie alles kann gefühlt
das PhaseButtonLayout ist sozusagen "zu klein geraten" um es in mvc umzusetzen dh das ist gleichzeitig alles drei was sich am anfang als gut durchdacht angefühlt hatte, wenigstens implementiert das layout mein controller interface das is ja schon ma was
nur ich weis nicht was ich mit den riesen handlern machen sollte oder wo man das noch irgendwie übersichtlich machen kann , und dass ich gefühlt alles im controller habe der hat jetzt um die 200 zeilen hat obwohl das model ziemlich traurig aussieht irgendwie sollte das doch halbwegs verteilt sein
[CODE lang="java" title="controller"]package playField;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.event.EventTarget;
import javafx.scene.input.MouseEvent;
import layout.PhaseButtonLayout;
import layout.PointsCounterLayout;
import layout.interfaces.ControllerInterface;
import layout.playButtons.CreatureButton;
import layout.playButtons.GamePhases;
import test.CardsModel;
public class PlayFieldController implements ControllerInterface
{
private final PlayFieldView view;
private final PlayFieldModel model = new PlayFieldModel();
private ObjectProperty<GamePhases> gameStateProperty = new SimpleObjectProperty<GamePhases>();
private PhaseButtonLayout phaseLayout;
public PlayFieldController()
{
boolean isMyTurn = true;
this.phaseLayout = new PhaseButtonLayout(isMyTurn);
this.view = new PlayFieldView(phaseLayout.getTheView());
this.model.gameStateProperty().bind(this.gameStateProperty);
this.gameStateProperty.bind(phaseLayout.getPhaseButton().getPhase());
this.gameStateProperty.addListener(eventHandlerController);
this.gameStateProperty.addListener(gameStatePropertyListener);
gameStateProperty.bind(phaseLayout.getPhaseButton().getPhase());
}
private PointsCounterLayout getCurrentPointsLayout()
{
if (phaseLayout.getPlayersTurn().getValue())
{
return view.getMyPoints();
} else
{
return view.getEnemyPoints();
}
}
private CardsModel currentCard;
public EventHandler<MouseEvent> cardClickedHandler = event -> {
setCurrentCard(event.getTarget());
};
private void setCurrentCard(EventTarget eventTarget) {
if (eventTarget instanceof CardsModel cardsModel)
{
currentCard = cardsModel;
}
}
private ChangeListener<GamePhases> gameStatePropertyListener = new ChangeListener<GamePhases>()
{
@Override
public void changed(ObservableValue<? extends GamePhases> observable, GamePhases oldValue, GamePhases newValue)
{
if (oldValue == GamePhases.DRAW_PHASE)
{
getCurrentPointsLayout().addPoints();
}
if (phaseLayout.getPlayersTurn().getValue())
{
switch (newValue)
{
case DRAW_PHASE:
//view.drawCard();
break;
case MAIN_PHASE:
view.activateCreatures();
break;
case BATTLE_PHASE:
view.getMyView().resetAttackBooleans();
break;
case END_PHASE:
view.deactivateCreatures();
}
}
}
};
public EventHandler<ActionEvent> buttonClickedHandler = new EventHandler<ActionEvent>()
{
private CardsModel attackCard;
private CreatureButton attackButton;
private CreatureButton targetButton;
private CreatureButton button;
public void handle(ActionEvent event)
{
setCurrentCard(event.getTarget());
if (event.getTarget()instanceof CreatureButton button)
{
this.button = button;
if (isMainPhase())
{
putDownCard();
} else if (isBattlePhase())
{
prepareAndBattleMonsters();
}
}
}
private void putDownCard()
{
if (currentCard != null && this.button.isPlayer()
&& view.getMyPoints().removePoints(currentCard.getLevel()))
{
putCardOnTheField(button);
}
}
private void prepareAndBattleMonsters()
{
if (this.button.isPlayer() && button.isAbleToAttack())
{
setAttacker();
} else if (attackCard != null)
{
this.button.setAbleToAttack(false);
setDefender();
dealDamage(targetButton, attackButton.getCard().getStrength());
dealDamage(attackButton, targetButton.getCard().getStrength());
resetHandler();
}
}
private void setAttacker()
{
attackCard = this.button.getCard();
attackButton = this.button;
}
private void setDefender()
{
targetButton = this.button;
}
private void resetHandler()
{
attackCard = null;
attackButton = null;
targetButton = null;
}
};
private void dealDamage(CreatureButton targetButton, int damage)
{
if (model.attack(targetButton.getCard(), damage))
targetButton.removeCard();
}
private void putCardOnTheField(CreatureButton button)
{
button.setCard(currentCard);
view.getHandCards().getChildren().remove(currentCard);
currentCard = null;
};
private boolean isMainPhase()
{
return this.gameStateProperty.getValue() == GamePhases.MAIN_PHASE;
}
private boolean isBattlePhase()
{
return this.gameStateProperty.getValue() == GamePhases.BATTLE_PHASE;
}
private boolean isPlayersTurn()
{
return phaseLayout.getPlayersTurn().getValue();
}
public ChangeListener<GamePhases> eventHandlerController = new ChangeListener<GamePhases>()
{
@Override
public void changed(ObservableValue<? extends GamePhases> observable, GamePhases oldValue, GamePhases newValue)
{
if (isPlayersTurn())
{
if (newValue == GamePhases.MAIN_PHASE)
{
view.addEventHandler(MouseEvent.MOUSE_CLICKED, cardClickedHandler);
view.addEventHandler(ActionEvent.ACTION, buttonClickedHandler);
} else if (newValue == GamePhases.END_PHASE)
{
view.removeEventHandler(MouseEvent.MOUSE_CLICKED, cardClickedHandler);
view.removeEventHandler(ActionEvent.ACTION, buttonClickedHandler);
}
}
}
};
@Override
public PlayFieldView getTheView()
{
// TODO Auto-generated method stub
return view;
}
}[/CODE]
EDIT: ja ich weis es ist blöd einen ausschnitt aus einem größeren projekt hier zu zeigen
Anmerkungen zuvor für die view
die PlayerView kann ansich gar nix und wäre gleichzusetzen wie in fxml mit import fxml datei
das gleiche gilt für die PointsCounterLayout diese können ansich nur sachen die auch eine View können sollte, die fügt halt punkte hinzu wenn es denn nötig ist
dh diese sind eig. unterviews
[CODE lang="java" title="View"]package playField;
import javafx.geometry.Pos;
import javafx.scene.control.ScrollPane;
import javafx.scene.control.ScrollPane.ScrollBarPolicy;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import layout.PointsCounterLayout;
import player.PlayerView;
import test.CardsModel;
public class PlayFieldView extends BorderPane
{
private HBox handCards = new HBox();
private final PlayerView myView = new PlayerView(true);
private final PlayerView enemyView = new PlayerView(false);
private final VBox phaseLayout;
private final PointsCounterLayout myPoints = new PointsCounterLayout("My Points");
private final PointsCounterLayout enemyPoints = new PointsCounterLayout("Enemy Points");
private StackPane popUpStackPaneForEvents;
public PlayFieldView(VBox phaseLayout)
{
this.phaseLayout = phaseLayout;
this.setHandCardsAtTheBottom();
this.getStylesheets().add(getClass().getResource("playFieldView.css").toExternalForm());
this.setupPlayingInnerField();
this.setupCssForPointsSystem();
this.setPickOnBounds(false);
this.deactivateCreatures();
this.testCards(); // TODO nur für testzwecke
}
private void setupCssForPointsSystem()
{
myPoints.getMyPointsDisplay().setId("PointsBox");
enemyPoints.getMyPointsDisplay().setId("PointsBox");
}
private void setupPlayingInnerField()
{
BorderPane field = new BorderPane();
field.setTop(enemyView);
field.setRight(enemyPoints.getMyPointsDisplay());
field.setCenter(phaseLayout);
field.setBottom(myView);
field.setLeft(myPoints.getMyPointsDisplay());
myPoints.getMyPointsDisplay().setAlignment(Pos.CENTER);
popUpStackPaneForEvents = new StackPane(field);
this.setCenter(popUpStackPaneForEvents);
}
private void setHandCardsAtTheBottom()
{
ScrollPane handCardScrollPane = new ScrollPane(handCards);
handCardScrollPane.hbarPolicyProperty().set(ScrollBarPolicy.ALWAYS);
handCardScrollPane.vbarPolicyProperty().set(ScrollBarPolicy.NEVER);
this.setBottom(handCardScrollPane);
}
//TODO noch useless, erst mit fertigstellung von der sqlite db nützlich
/** public void drawCard()
{
if (phaseLayout.getPlayersTurn().getValue())
{
// handCards.getChildren().add();
}
}*/
public void activateCreatures()
{
myView.getCreatures().setDisable(false);
}
public void deactivateCreatures()
{
myView.getCreatures().setDisable(true);
}
public void testCards()
{
String s = "commander";
for (int i = 0; i < 10; i++)
{
Image image;
int counter = i;
if (i > 3)
{
counter = 3;
}
s = "main";
image = new Image(getClass().getResource("card" + counter + ".gif").toExternalForm());
ImageView imageview = new ImageView(image);
String str = "Once Per Turn -> Discard 1 card: \n Destroy " + i + " Creatures.";
String name = "Draco Wyvern Ruler of Air" + i;
CardsModel card = new CardsModel(s, name, image, imageview, 1 + i, 1 + i, "Kaiju", 3, "Laura Bornea", str,
3);
handCards.getChildren().add(card);
}
}
public HBox getHandCards()
{
return handCards;
}
public PointsCounterLayout getMyPoints()
{
return myPoints;
}
public PointsCounterLayout getEnemyPoints()
{
return enemyPoints;
}
public PlayerView getMyView()
{
return myView;
}
public PlayerView getEnemyView()
{
return enemyView;
}
}
[/CODE]
dann kommt mein bescheidenes model ich dachte ich brauche die gameStateProperty aber es ist irgendwie doch nur zu 1er methode gekommen was schon ein bisschen traurig ist
Code:
package playField;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import layout.playButtons.GamePhases;
import test.CardsModel;
public class PlayFieldModel {
ObjectProperty<GamePhases> gameStateProperty = new SimpleObjectProperty<GamePhases>();
CardsModel currentCard;
/**
* @return if health is below 0 it returns true
*/
public boolean attack (CardsModel attackedCard, int damage) {
attackedCard.setHealth(attackedCard.getHealth() - damage);
return attackedCard.getHealth() < 0 ? true : false;
}
public ObjectProperty<GamePhases> gameStateProperty()
{
return gameStateProperty;
}
}
das PhaseButtonLayout ist sozusagen "zu klein geraten" um es in mvc umzusetzen dh das ist gleichzeitig alles drei was sich am anfang als gut durchdacht angefühlt hatte, wenigstens implementiert das layout mein controller interface das is ja schon ma was
nur ich weis nicht was ich mit den riesen handlern machen sollte oder wo man das noch irgendwie übersichtlich machen kann , und dass ich gefühlt alles im controller habe der hat jetzt um die 200 zeilen hat obwohl das model ziemlich traurig aussieht irgendwie sollte das doch halbwegs verteilt sein
[CODE lang="java" title="controller"]package playField;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.event.EventTarget;
import javafx.scene.input.MouseEvent;
import layout.PhaseButtonLayout;
import layout.PointsCounterLayout;
import layout.interfaces.ControllerInterface;
import layout.playButtons.CreatureButton;
import layout.playButtons.GamePhases;
import test.CardsModel;
public class PlayFieldController implements ControllerInterface
{
private final PlayFieldView view;
private final PlayFieldModel model = new PlayFieldModel();
private ObjectProperty<GamePhases> gameStateProperty = new SimpleObjectProperty<GamePhases>();
private PhaseButtonLayout phaseLayout;
public PlayFieldController()
{
boolean isMyTurn = true;
this.phaseLayout = new PhaseButtonLayout(isMyTurn);
this.view = new PlayFieldView(phaseLayout.getTheView());
this.model.gameStateProperty().bind(this.gameStateProperty);
this.gameStateProperty.bind(phaseLayout.getPhaseButton().getPhase());
this.gameStateProperty.addListener(eventHandlerController);
this.gameStateProperty.addListener(gameStatePropertyListener);
gameStateProperty.bind(phaseLayout.getPhaseButton().getPhase());
}
private PointsCounterLayout getCurrentPointsLayout()
{
if (phaseLayout.getPlayersTurn().getValue())
{
return view.getMyPoints();
} else
{
return view.getEnemyPoints();
}
}
private CardsModel currentCard;
public EventHandler<MouseEvent> cardClickedHandler = event -> {
setCurrentCard(event.getTarget());
};
private void setCurrentCard(EventTarget eventTarget) {
if (eventTarget instanceof CardsModel cardsModel)
{
currentCard = cardsModel;
}
}
private ChangeListener<GamePhases> gameStatePropertyListener = new ChangeListener<GamePhases>()
{
@Override
public void changed(ObservableValue<? extends GamePhases> observable, GamePhases oldValue, GamePhases newValue)
{
if (oldValue == GamePhases.DRAW_PHASE)
{
getCurrentPointsLayout().addPoints();
}
if (phaseLayout.getPlayersTurn().getValue())
{
switch (newValue)
{
case DRAW_PHASE:
//view.drawCard();
break;
case MAIN_PHASE:
view.activateCreatures();
break;
case BATTLE_PHASE:
view.getMyView().resetAttackBooleans();
break;
case END_PHASE:
view.deactivateCreatures();
}
}
}
};
public EventHandler<ActionEvent> buttonClickedHandler = new EventHandler<ActionEvent>()
{
private CardsModel attackCard;
private CreatureButton attackButton;
private CreatureButton targetButton;
private CreatureButton button;
public void handle(ActionEvent event)
{
setCurrentCard(event.getTarget());
if (event.getTarget()instanceof CreatureButton button)
{
this.button = button;
if (isMainPhase())
{
putDownCard();
} else if (isBattlePhase())
{
prepareAndBattleMonsters();
}
}
}
private void putDownCard()
{
if (currentCard != null && this.button.isPlayer()
&& view.getMyPoints().removePoints(currentCard.getLevel()))
{
putCardOnTheField(button);
}
}
private void prepareAndBattleMonsters()
{
if (this.button.isPlayer() && button.isAbleToAttack())
{
setAttacker();
} else if (attackCard != null)
{
this.button.setAbleToAttack(false);
setDefender();
dealDamage(targetButton, attackButton.getCard().getStrength());
dealDamage(attackButton, targetButton.getCard().getStrength());
resetHandler();
}
}
private void setAttacker()
{
attackCard = this.button.getCard();
attackButton = this.button;
}
private void setDefender()
{
targetButton = this.button;
}
private void resetHandler()
{
attackCard = null;
attackButton = null;
targetButton = null;
}
};
private void dealDamage(CreatureButton targetButton, int damage)
{
if (model.attack(targetButton.getCard(), damage))
targetButton.removeCard();
}
private void putCardOnTheField(CreatureButton button)
{
button.setCard(currentCard);
view.getHandCards().getChildren().remove(currentCard);
currentCard = null;
};
private boolean isMainPhase()
{
return this.gameStateProperty.getValue() == GamePhases.MAIN_PHASE;
}
private boolean isBattlePhase()
{
return this.gameStateProperty.getValue() == GamePhases.BATTLE_PHASE;
}
private boolean isPlayersTurn()
{
return phaseLayout.getPlayersTurn().getValue();
}
public ChangeListener<GamePhases> eventHandlerController = new ChangeListener<GamePhases>()
{
@Override
public void changed(ObservableValue<? extends GamePhases> observable, GamePhases oldValue, GamePhases newValue)
{
if (isPlayersTurn())
{
if (newValue == GamePhases.MAIN_PHASE)
{
view.addEventHandler(MouseEvent.MOUSE_CLICKED, cardClickedHandler);
view.addEventHandler(ActionEvent.ACTION, buttonClickedHandler);
} else if (newValue == GamePhases.END_PHASE)
{
view.removeEventHandler(MouseEvent.MOUSE_CLICKED, cardClickedHandler);
view.removeEventHandler(ActionEvent.ACTION, buttonClickedHandler);
}
}
}
};
@Override
public PlayFieldView getTheView()
{
// TODO Auto-generated method stub
return view;
}
}[/CODE]
EDIT: ja ich weis es ist blöd einen ausschnitt aus einem größeren projekt hier zu zeigen
Zuletzt bearbeitet von einem Moderator: