我们正在使用Java Serialization制作一个名为Dominion的纸牌游戏,其中包含客户端服务器。我们还使用observer / observable和threads(用于在服务器和客户端读取消息的线程)。
如果玩家能够玩牌或购买牌,我们会用CSS突出显示牌。突出显示由接口Observer的更新方法添加,其中正在观察游戏卡。如果特定条件为真,我们将向游戏卡添加突出显示(类GameCard是实现Observer)。
一般来说它运作正常,但有一张牌(名为民兵)迫使对手从他们手中弃牌,直到他们只剩下3张牌。我们可以多次玩这个没有例外,但突然有几个例外(大约7-10次打了民兵卡)。我们不知道为什么。
这种例外的原因是什么?我认为如果我发布代码没有帮助,我会发布例外:
Exception in thread "JavaFX Application Thread" java.lang.NullPointerException
at com.sun.javafx.text.PrismTextLayout.addTextRun(PrismTextLayout.java:755)
at com.sun.javafx.text.GlyphLayout.addTextRun(GlyphLayout.java:140)
at com.sun.javafx.text.GlyphLayout.breakRuns(GlyphLayout.java:210)
at com.sun.javafx.text.PrismTextLayout.buildRuns(PrismTextLayout.java:770)
at com.sun.javafx.text.PrismTextLayout.layout(PrismTextLayout.java:1021)
at com.sun.javafx.text.PrismTextLayout.ensureLayout(PrismTextLayout.java:223)
at com.sun.javafx.text.PrismTextLayout.getBounds(PrismTextLayout.java:246)
at javafx.scene.text.Text.getLogicalBounds(Text.java:358)
at javafx.scene.text.Text.impl_computeGeomBounds(Text.java:1168)
at javafx.scene.Node.updateGeomBounds(Node.java:3579)
at javafx.scene.Node.getGeomBounds(Node.java:3532)
at javafx.scene.Node.getLocalBounds(Node.java:3480)
at javafx.scene.Node.updateTxBounds(Node.java:3643)
at javafx.scene.Node.getTransformedBounds(Node.java:3426)
at javafx.scene.Parent.getChildTransformedBounds(Parent.java:1732)
at javafx.scene.Parent.recomputeBounds(Parent.java:1524)
at javafx.scene.Parent.impl_computeGeomBounds(Parent.java:1388)
at javafx.scene.Node.updateGeomBounds(Node.java:3579)
at javafx.scene.Node.getGeomBounds(Node.java:3532)
at javafx.scene.Node.getLocalBounds(Node.java:3480)
at javafx.scene.Node.updateTxBounds(Node.java:3643)
at javafx.scene.Node.getTransformedBounds(Node.java:3426)
at javafx.scene.Parent.getChildTransformedBounds(Parent.java:1732)
at javafx.scene.Parent.updateCachedBounds(Parent.java:1596)
at javafx.scene.Parent.recomputeBounds(Parent.java:1535)
at javafx.scene.Parent.impl_computeGeomBounds(Parent.java:1388)
at javafx.scene.layout.Region.impl_computeGeomBounds(Region.java:3078)
at javafx.scene.Node.updateGeomBounds(Node.java:3579)
at javafx.scene.Node.getGeomBounds(Node.java:3532)
at javafx.scene.Node.getLocalBounds(Node.java:3480)
at javafx.scene.Node.updateTxBounds(Node.java:3643)
at javafx.scene.Node.getTransformedBounds(Node.java:3426)
at javafx.scene.Parent.getChildTransformedBounds(Parent.java:1732)
at javafx.scene.Parent.recomputeBounds(Parent.java:1524)
at javafx.scene.Parent.impl_computeGeomBounds(Parent.java:1388)
at javafx.scene.layout.Region.impl_computeGeomBounds(Region.java:3078)
at javafx.scene.Node.updateGeomBounds(Node.java:3579)
at javafx.scene.Node.getGeomBounds(Node.java:3532)
at javafx.scene.Node.getLocalBounds(Node.java:3480)
at javafx.scene.Node.updateTxBounds(Node.java:3643)
at javafx.scene.Node.getTransformedBounds(Node.java:3426)
at javafx.scene.Parent.getChildTransformedBounds(Parent.java:1732)
at javafx.scene.Parent.recomputeBounds(Parent.java:1524)
at javafx.scene.Parent.impl_computeGeomBounds(Parent.java:1388)
at javafx.scene.layout.Region.impl_computeGeomBounds(Region.java:3078)
at javafx.scene.Node.updateGeomBounds(Node.java:3579)
at javafx.scene.Node.getGeomBounds(Node.java:3532)
at javafx.scene.Node.computeLocalBounds(Node.java:3595)
at javafx.scene.Node.updateLocalBounds(Node.java:3625)
at javafx.scene.Node.getLocalBounds(Node.java:3486)
at javafx.scene.Node.updateTxBounds(Node.java:3643)
at javafx.scene.Node.getTransformedBounds(Node.java:3426)
at javafx.scene.Parent.getChildTransformedBounds(Parent.java:1732)
at javafx.scene.Parent.updateCachedBounds(Parent.java:1596)
at javafx.scene.Parent.recomputeBounds(Parent.java:1535)
at javafx.scene.Parent.impl_computeGeomBounds(Parent.java:1388)
at javafx.scene.layout.Region.impl_computeGeomBounds(Region.java:3078)
at javafx.scene.Node.updateGeomBounds(Node.java:3579)
at javafx.scene.Node.getGeomBounds(Node.java:3532)
at javafx.scene.Node.getLocalBounds(Node.java:3480)
at javafx.scene.Node.updateTxBounds(Node.java:3643)
at javafx.scene.Node.getTransformedBounds(Node.java:3426)
at javafx.scene.Parent.getChildTransformedBounds(Parent.java:1732)
at javafx.scene.Parent.recomputeBounds(Parent.java:1524)
at javafx.scene.Parent.impl_computeGeomBounds(Parent.java:1388)
at javafx.scene.layout.Region.impl_computeGeomBounds(Region.java:3078)
at javafx.scene.Node.updateGeomBounds(Node.java:3579)
at javafx.scene.Node.getGeomBounds(Node.java:3532)
at javafx.scene.Node.getLocalBounds(Node.java:3480)
at javafx.scene.Node.updateTxBounds(Node.java:3643)
at javafx.scene.Node.getTransformedBounds(Node.java:3426)
at javafx.scene.Parent.getChildTransformedBounds(Parent.java:1732)
at javafx.scene.Parent.recomputeBounds(Parent.java:1524)
at javafx.scene.Parent.impl_computeGeomBounds(Parent.java:1388)
at javafx.scene.layout.Region.impl_computeGeomBounds(Region.java:3078)
at javafx.scene.Node.updateGeomBounds(Node.java:3579)
at javafx.scene.Node.getGeomBounds(Node.java:3532)
at javafx.scene.Node.getLocalBounds(Node.java:3480)
at javafx.scene.Node.updateTxBounds(Node.java:3643)
at javafx.scene.Node.getTransformedBounds(Node.java:3426)
at javafx.scene.Parent.getChildTransformedBounds(Parent.java:1732)
at javafx.scene.Parent.updateCachedBounds(Parent.java:1596)
at javafx.scene.Parent.recomputeBounds(Parent.java:1535)
at javafx.scene.Parent.impl_computeGeomBounds(Parent.java:1388)
at javafx.scene.layout.Region.impl_computeGeomBounds(Region.java:3078)
at javafx.scene.Node.updateGeomBounds(Node.java:3579)
at javafx.scene.Node.getGeomBounds(Node.java:3532)
at javafx.scene.Node.getLocalBounds(Node.java:3480)
at javafx.scene.Node.updateTxBounds(Node.java:3643)
at javafx.scene.Node.getTransformedBounds(Node.java:3426)
at javafx.scene.Parent.getChildTransformedBounds(Parent.java:1732)
at javafx.scene.Parent.recomputeBounds(Parent.java:1524)
at javafx.scene.Parent.impl_computeGeomBounds(Parent.java:1388)
at javafx.scene.layout.Region.impl_computeGeomBounds(Region.java:3078)
at javafx.scene.Node.updateGeomBounds(Node.java:3579)
at javafx.scene.Node.getGeomBounds(Node.java:3532)
at javafx.scene.Node.getLocalBounds(Node.java:3480)
at javafx.scene.Node.updateTxBounds(Node.java:3643)
at javafx.scene.Node.getTransformedBounds(Node.java:3426)
at javafx.scene.Parent.getChildTransformedBounds(Parent.java:1732)
at javafx.scene.Parent.updateCachedBounds(Parent.java:1596)
at javafx.scene.Parent.recomputeBounds(Parent.java:1535)
at javafx.scene.Parent.impl_computeGeomBounds(Parent.java:1388)
at javafx.scene.layout.Region.impl_computeGeomBounds(Region.java:3078)
at javafx.scene.Node.updateGeomBounds(Node.java:3579)
at javafx.scene.Node.getGeomBounds(Node.java:3532)
at javafx.scene.Node.getLocalBounds(Node.java:3480)
at javafx.scene.Node.impl_intersectsBounds(Node.java:5015)
at javafx.scene.layout.Region.impl_pickNodeLocal(Region.java:2931)
at javafx.scene.Node.impl_pickNode(Node.java:4914)
at javafx.scene.Scene$MouseHandler.pickNode(Scene.java:3899)
at javafx.scene.Scene$MouseHandler.access$1600(Scene.java:3485)
at javafx.scene.Scene.pick(Scene.java:1942)
at javafx.scene.Scene.access$6700(Scene.java:159)
at javafx.scene.Scene$MouseHandler.process(Scene.java:3711)
at javafx.scene.Scene$MouseHandler.access$1500(Scene.java:3485)
at javafx.scene.Scene.impl_processMouseEvent(Scene.java:1762)
at javafx.scene.Scene$ScenePeerListener.mouseEvent(Scene.java:2494)
at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:381)
at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:295)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.javafx.tk.quantum.GlassViewEventHandler.lambda$handleMouseEvent$353(GlassViewEventHandler.java:417)
at com.sun.javafx.tk.quantum.QuantumToolkit.runWithoutRenderLock(QuantumToolkit.java:389)
at com.sun.javafx.tk.quantum.GlassViewEventHandler.handleMouseEvent(GlassViewEventHandler.java:416)
at com.sun.glass.ui.View.handleMouseEvent(View.java:555)
at com.sun.glass.ui.View.notifyMouse(View.java:937)
at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at com.sun.glass.ui.win.WinApplication.lambda$null$147(WinApplication.java:177)
at java.lang.Thread.run(Unknown Source)
Exception in thread "JavaFX Application Thread" java.lang.ArrayIndexOutOfBoundsException: -1
at java.util.ArrayList.elementData(Unknown Source)
at java.util.ArrayList.get(Unknown Source)
at com.sun.javafx.collections.ObservableListWrapper.get(ObservableListWrapper.java:89)
at com.sun.javafx.collections.VetoableListDecorator.get(VetoableListDecorator.java:306)
at javafx.scene.Parent.updateCachedBounds(Parent.java:1591)
at javafx.scene.Parent.recomputeBounds(Parent.java:1535)
at javafx.scene.Parent.impl_computeGeomBounds(Parent.java:1388)
at javafx.scene.layout.Region.impl_computeGeomBounds(Region.java:3078)
at javafx.scene.Node.updateGeomBounds(Node.java:3579)
at javafx.scene.Node.getGeomBounds(Node.java:3532)
at javafx.scene.Node.getLocalBounds(Node.java:3480)
at javafx.scene.Node.impl_intersectsBounds(Node.java:5015)
at javafx.scene.layout.Region.impl_pickNodeLocal(Region.java:2931)
at javafx.scene.Node.impl_pickNode(Node.java:4914)
at javafx.scene.Scene$MouseHandler.pickNode(Scene.java:3899)
at javafx.scene.Scene$MouseHandler.access$1600(Scene.java:3485)
at javafx.scene.Scene.pick(Scene.java:1942)
at javafx.scene.Scene.access$6700(Scene.java:159)
at javafx.scene.Scene$MouseHandler.process(Scene.java:3711)
at javafx.scene.Scene$MouseHandler.access$1500(Scene.java:3485)
at javafx.scene.Scene.impl_processMouseEvent(Scene.java:1762)
at javafx.scene.Scene$ScenePeerListener.mouseEvent(Scene.java:2494)
at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:381)
at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:295)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.javafx.tk.quantum.GlassViewEventHandler.lambda$handleMouseEvent$353(GlassViewEventHandler.java:417)
at com.sun.javafx.tk.quantum.QuantumToolkit.runWithoutRenderLock(QuantumToolkit.java:389)
at com.sun.javafx.tk.quantum.GlassViewEventHandler.handleMouseEvent(GlassViewEventHandler.java:416)
at com.sun.glass.ui.View.handleMouseEvent(View.java:555)
at com.sun.glass.ui.View.notifyMouse(View.java:937)
at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at com.sun.glass.ui.win.WinApplication.lambda$null$147(WinApplication.java:177)
at java.lang.Thread.run(Unknown Source)
Exception in thread "JavaFX Application Thread"
...如果我们只是将鼠标悬停在舞台上,则会抛出数百次此异常:
Exception in thread "JavaFX Application Thread" java.lang.ArrayIndexOutOfBoundsException
可能导致例外的代码: 1.在本课程中,我们将突出显示对手必须丢弃的牌(直到他留下3张牌;见croupier.isDiscardModeMilitia ......行。)
public class GameCard extends Button implements Observer {
protected static final boolean MoneyCard = false;
ServiceLocatorClient sl = ServiceLocatorClient.getServiceLocator();
Croupier croupier = Croupier.getCroupier();
Label lbl_cardName;
String text_DE;
boolean holeCard = false;
int costs;
StackSizeInfo stackSizeInfo;
public GameCard(Label cardName, String text_DE) {
super();
this.lbl_cardName = cardName;
this.text_DE=text_DE;
this.assignPicture();
}
public GameCard(){
}
GameCard gc = this;
@Override
public void update(Observable arg0, Object arg1) {
getStyleClass().remove("highlight");
getStyleClass().remove("highlight2");
getStyleClass().remove("highlight3");
//Highlighte alle Karten im Kaufmodus, welche ich mit der aktuelln Buypower und buys kaufen kann
if (croupier.isBuyMode() == true && croupier.getBuyPower() >= this.costs && !this.isHoleCard() && croupier.getBuys() > 0){
this.getStyleClass().add("highlight");
}
//Highlighte alle Geldkarten im Kaufmodus
if (croupier.isBuyMode() == true && this.isHoleCard() && this instanceof MoneyCard){
this.getStyleClass().add("highlight");
}
//Highlighte alle Aktionskarten im Aktionsmodus
if (croupier.isActionMode() == true && this.isHoleCard() && this instanceof ActionCard){
this.getStyleClass().add("highlight");
}
//Highlighte alle HoleCards im Discardmodus (basement)
if (croupier.isDiscardMode() == true && this.isHoleCard()){
this.getStyleClass().add("highlight3");
}
//Highlighte alle HoleCards im TrashModus Kapelle
if (croupier.isTrashModeChapel() == true && this.isHoleCard()){
this.getStyleClass().add("highlight3");
}
//Highlighte alle MoneyCards im TrashModus Mine
if (croupier.isTrashModeMine() == true && this instanceof MoneyCard && this.isHoleCard()){
this.getStyleClass().add("highlight3");
}
//Highlighte alle Karten auf der Hand, welche im Umbaumodus weggeworfen werden können
if (croupier.isTrashModeRebuilding() == true && this.isHoleCard()){
this.getStyleClass().add("highlight3");
}
//Highlighte alle Kupferkarten auf der Hand, die gegen +3Geld weggeworfen werden können (ActionCard Geldverleiher)
if (croupier.isTrashModeMoneylender() == true && this.isHoleCard() && this.getLbl_cardName().getText().equals("copper")){
this.getStyleClass().add("highlight3");
}
//Highlighte alle MoneyCards, welche erworben werden können im Minen-Modus
if (croupier.isModeForMine() == true && this instanceof MoneyCard && !this.isHoleCard() && this.costs <= croupier.getSavedMCValueForMineMode()){
this.getStyleClass().add("highlight");
}
//Highlighte alle Karten zum Kauf, welche erworben werden können im Rebuilding-Modus
if (croupier.isModeForRebuilding() == true && !this.isHoleCard() && this.costs <= croupier.getCardValueForRebuildingMode()){
this.getStyleClass().add("highlight");
}
//Highlighte alle Karten zum Kauf, welche erworben werden können im Rebuilding-Modus
if (croupier.isModeForWorkshop() == true && !this.isHoleCard() && this.costs <= 4){
this.getStyleClass().add("highlight3");
}
//Highlighte alle Moat-Karten wenn ein Angriff gemacht worden ist
if (croupier.isReactionMode() == true && this.isHoleCard() && this.getLbl_cardName().getText().equals("moat")){
this.getStyleClass().add("highlight3");
}
//Highlighte alle Moat-Karten wenn ein Angriff gemacht worden ist
if (croupier.isDiscardModeMilitia() == true && this.isHoleCard()){
this.getStyleClass().add("highlight2");
}
//Highlighte alle Moat-Karten wenn ein Angriff gemacht worden ist
if (croupier.isModeForCurseCard() == true && !this.isHoleCard() && this.getLbl_cardName().getText().equals("curse")){
this.getStyleClass().add("highlight2");
}
//wenn stacksize auf 0, wird highlighting ebenfalls deaktiviert
if (croupier.getStackSize(gc) == 0) {
this.getStyleClass().remove("highlight");
}
//update das STackSize infoLabel auf der Karte
if (this.stackSizeInfo != null){
stackSizeInfo.updateStackSizeInfo();
}
}
public void assignStackSizeInfo(){
stackSizeInfo = new StackSizeInfo(gc,croupier.getStackSize(gc));
}
public void assignPicture(){
if (this.holeCard == false)
this.getStyleClass().addAll("card_mini",lbl_cardName.getText());
else
this.getStyleClass().addAll("card",lbl_cardName.getText()+"_big");
}
public boolean isHoleCard() {
return holeCard;
}
public void setHoleCard(boolean holeCard) {
this.holeCard = holeCard;
}
public Label getLbl_cardName() {
return lbl_cardName;
}
public String getText_DE(){
return this.text_DE;
}
public void setLbl_cardName(Label lbl_cardName) {
this.lbl_cardName = lbl_cardName;
}
}
可能的代码片段:这里我们正在更新GUI。每当我们从手牌上打牌时就会发生这种情况。我们将在另一个方法中首先从LinkedList(HoleCards)中删除它,然后我们调用updateGUI
public void updateGUI(){
// Zeichne holeCards Neu
hb_wrapper_holeCards.getChildren().clear();
for (int i = 0; i < croupier.getHoleCards().size(); i++) {
GameCard gc1 = croupier.getHoleCards().get(i);
try{
hb_wrapper_holeCards.getChildren().add(gc1);
gc1.setPrefSize(160, 260);
gc1.setMaxWidth(160);
}catch (NullPointerException e){
//
}
// Zeichne Ablagekarte neu
hb_wrapper_stapel.getChildren().clear();
dummyCardAblagestapel.getStyleClass().clear();
try {
String cssSelector = new String(croupier.getAblagestapel().peekLast().getLbl_cardName().getText()+"_big");
dummyCardAblagestapel.getStyleClass().addAll("card",cssSelector);
hb_wrapper_stapel.getChildren().addAll(dummyCardAblagestapel,nachziehstapel);
} catch(Exception e){
hb_wrapper_stapel.getChildren().addAll(this.dummyCardAblagestapel,nachziehstapel);
}
}
}
note1:我猜它发生在我们突出显示卡片的第一个片段中。在玩家丢弃牌之后,他只剩下3张牌,我们将删除高亮显示。正好当他丢弃他的最后一张牌时,抛出异常(但正如我所说,我们可以在没有例外的情况下玩这种情况大约7-10次,但突然出现例外情况)
note2:我已经在这两个代码片段上尝试使用Platform.runLater但它没有帮助