Commits

Anonymous committed 55de5e1

Added some screen flows to start the game.

  • Participants
  • Parent commits eedce74

Comments (0)

Files changed (14)

defender/src/main/java/com/fxexperience/games/defender/DefenderApp.java

  */
 package com.fxexperience.games.defender;
 
-import com.fxexperience.games.defender.games.simple.SimpleGameScene;
+import com.fxexperience.games.defender.games.simple.Game;
 import javafx.application.Application;
+import javafx.scene.Scene;
 import javafx.stage.Stage;
 
 /**
  */
 public class DefenderApp extends Application {
     public void start(Stage stage) throws Exception {
-        // Right now we're hard-coding the creation of the main view to be the simple
-        // version of the app "SimpleGameScene" instance. However, we need to expand this
-        // so that we can load alternate games, perhaps by using reflection, or by
-        // just hard-coding a set of application parameter -> game view instances.
+        Game game = new Game();
+        Scene scene = new Scene(game, 1200, 700);
+        scene.getStylesheets().add("/styles/games/simple/styles.css");
         stage.setTitle("JavaFX Tower Defender");
-        stage.setScene(new SimpleGameScene());
+        stage.setScene(scene);
         stage.show();
+
+        game.showWelcomePanel();
     }
 
     public static void main(String[] args) {

defender/src/main/java/com/fxexperience/games/defender/games/simple/Game.java

  */
 package com.fxexperience.games.defender.games.simple;
 
+import com.fxexperience.games.defender.games.simple.ui.GameControlPanel;
+import com.fxexperience.games.defender.games.simple.ui.NewGamePanel;
+import com.fxexperience.games.defender.games.simple.ui.WelcomePanel;
 import javafx.animation.AnimationTimer;
 import javafx.beans.property.*;
 import javafx.beans.value.ChangeListener;
 import javafx.beans.value.ObservableValue;
+import javafx.scene.layout.BorderPane;
+import javafx.scene.layout.StackPane;
 
 import java.util.ArrayList;
 import java.util.List;
 
-public class Game {
+public class Game extends StackPane {
     public final BooleanProperty paused = new SimpleBooleanProperty(this, "paused", true);
     public final DoubleProperty money = new SimpleDoubleProperty(this, "money", 100);
     public final IntegerProperty lives = new SimpleIntegerProperty(this, "lives", 10);
 
     private final ObjectProperty<LevelPanel> currentLevel = new SimpleObjectProperty<>(this, "currentLevel");
+
     public ObjectProperty<LevelPanel> currentLevelProperty() { return currentLevel; }
     public LevelPanel getCurrentLevel() { return this.currentLevel.get(); }
     public void setCurrentLevel(LevelPanel level) { this.currentLevel.set(level); }
     private AnimationTimer animationTimer;
     private List<GamePulseListener> gamePulseListeners;
 
+    private BorderPane gamePanel;
+    private final WelcomePanel welcomePanel;
+    private final NewGamePanel newGamePanel;
+
     public Game() {
+
+        gamePanel = new BorderPane();
+        gamePanel.setRight(new GameControlPanel(this));
+
+        welcomePanel = new WelcomePanel(this);
+        newGamePanel = new com.fxexperience.games.defender.games.simple.ui.NewGamePanel(this);
+
         gamePulseListeners = new ArrayList<>();
 
         animationTimer = new AnimationTimer() {
             public void changed(ObservableValue<? extends LevelPanel> source, LevelPanel oldLevel, LevelPanel newLevel) {
                 if (oldLevel != null) {
                     gamePulseListeners.remove(oldLevel);
+                    gamePanel.setCenter(null);
                 }
                 if (newLevel != null) {
                     gamePulseListeners.add(newLevel);
+                    gamePanel.setCenter(newLevel);
                 }
             }
         });
         });
     }
 
+    public void showWelcomePanel() {
+        welcomePanel.reset();
+        getChildren().setAll(gamePanel, welcomePanel);
+        welcomePanel.playWelcome();
+    }
+
+    public void showNewGamePanel() {
+        newGamePanel.reset();
+        getChildren().setAll(gamePanel, newGamePanel);
+        newGamePanel.playEntryAnimation();
+    }
+
     public void addGamePulseListener(GamePulseListener listener) {
         gamePulseListeners.add(listener);
     }
             listener.pulse();
         }
     }
+
 }

defender/src/main/java/com/fxexperience/games/defender/games/simple/GameControlPanel.java

-package com.fxexperience.games.defender.games.simple;
-
-import com.fxexperience.games.defender.games.simple.towers.BasicTowerFactory;
-import javafx.event.ActionEvent;
-import javafx.event.EventHandler;
-import javafx.fxml.FXMLLoader;
-import javafx.scene.Parent;
-import javafx.scene.control.Button;
-import javafx.scene.control.ToggleButton;
-import javafx.scene.control.ToggleGroup;
-import javafx.scene.input.MouseEvent;
-import javafx.scene.layout.GridPane;
-import javafx.scene.layout.StackPane;
-import javafx.util.Duration;
-
-/**
- */
-public class GameControlPanel extends StackPane {
-
-    public GameControlPanel(final Game game) {
-        getStyleClass().add("game-control-panel");
-
-        try {
-            Parent content = FXMLLoader.load(getClass().getResource("/styles/games/simple/GameControlPanel.fxml"));
-            getChildren().add(content);
-
-            final Button playButton = (Button)content.lookup("#play-button");
-            playButton.setOnAction(new EventHandler<ActionEvent>() {
-                @Override
-                public void handle(ActionEvent actionEvent) {
-                    game.paused.set(!game.paused.get());
-                    playButton.setText(game.paused.get() ? "Send The Enemies!" : "Pause");
-                }
-            });
-
-            final GridPane towerGrid = (GridPane)content.lookup("#tower-grid");
-
-            ToggleGroup toggleGroup = new ToggleGroup();
-
-            TowerFactory pelletGunFactory = new BasicTowerFactory("Pellet Gun", "pellet-gun", Duration.millis(1000), 100, 5);
-            towerGrid.getChildren().add(createTowerButton(toggleGroup, game, pelletGunFactory, 0, 0));
-
-            TowerFactory rapidFireGunFactory = new BasicTowerFactory("Rapid Fire Gun", "rapid-fire-gun", Duration.millis(200), 100, 5);
-            towerGrid.getChildren().add(createTowerButton(toggleGroup, game, rapidFireGunFactory, 1, 0));
-
-        } catch (Exception e) {
-            e.printStackTrace();
-        }
-    }
-
-    protected ToggleButton createTowerButton(ToggleGroup toggleGroup, final Game game, final TowerFactory towerFactory, int column, int row) {
-        final ToggleButton towerButton = new ToggleButton(towerFactory.getTowerName());
-        toggleGroup.getToggles().add(towerButton);
-        GridPane.setConstraints(towerButton, column, row);
-        towerButton.setOnAction(new EventHandler<ActionEvent>() {
-            @Override
-            public void handle(ActionEvent actionEvent) {
-                final LevelPanel level = game.getCurrentLevel();
-                if (level != null) {
-                    final Tower tower = towerFactory.createTower();
-                    tower.setTranslateX(-100);
-                    tower.setTranslateY(-100);
-                    level.setOnMouseReleased(new EventHandler<MouseEvent>() {
-                        @Override
-                        public void handle(MouseEvent event) {
-                            tower.setTranslateX(event.getX());
-                            tower.setTranslateY(event.getY());
-                            level.addTower(tower);
-                            towerButton.setSelected(false);
-                            level.setOnMouseReleased(null);
-                        }
-                    });
-                }
-            }
-        });
-        return towerButton;
-    }
-}
-

defender/src/main/java/com/fxexperience/games/defender/games/simple/NewGamePanel.java

-/*
- * Copyright (c) 2012, FX Experience. All rights  reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification, are
- * permitted provided that the following conditions are met:
- *
- * Redistributions of source code must retain the above copyright notice, this list of
- * conditions and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright notice, this list of
- * conditions and the following disclaimer in the documentation and/or other materials provided
- * with the distribution.
- *
- * Neither the name of the author nor the names of its contributors may be used to endorse or
- * promote products derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
- * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
- * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
- * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package com.fxexperience.games.defender.games.simple;
-
-import javafx.beans.property.ObjectProperty;
-import javafx.beans.property.ReadOnlyObjectProperty;
-import javafx.beans.property.ReadOnlyObjectWrapper;
-import javafx.beans.property.SimpleObjectProperty;
-import javafx.event.ActionEvent;
-import javafx.event.EventHandler;
-import javafx.geometry.Insets;
-import javafx.scene.control.Button;
-import javafx.scene.layout.Region;
-import javafx.scene.layout.VBox;
-
-/**
- * Shown when it is time to start a new game
- */
-public class NewGamePanel extends Region {
-    private ObjectProperty<EventHandler<ActionEvent>> onAction = new SimpleObjectProperty<>(this, "onAction");
-    private ReadOnlyObjectWrapper<Difficulty> difficulty = new ReadOnlyObjectWrapper<>(this, "difficulty");
-
-    public final EventHandler<ActionEvent> getOnAction() { return onAction.get(); }
-    public final void setOnAction(EventHandler<ActionEvent> value) { onAction.set(value); }
-    public final ObjectProperty<EventHandler<ActionEvent>> onActionProperty() { return onAction; }
-
-    private final void setDifficulty(Difficulty value) { difficulty.set(value); }
-    public final Difficulty getDifficulty() { return difficulty.get(); }
-    public final ReadOnlyObjectProperty<Difficulty> difficultyProperty() { return difficulty.getReadOnlyProperty(); }
-
-    private final VBox buttons;
-
-    public NewGamePanel() {
-        getStyleClass().add("new-game-panel");
-
-        buttons = new VBox();
-        buttons.getStyleClass().add("button-box");
-        getChildren().add(buttons);
-
-        for (final Difficulty difficulty : Difficulty.values()) {
-            String text = difficulty.name().toLowerCase();
-            text = text.substring(0, 1).toUpperCase() + text.substring(1);
-
-            Button button = new Button(text);
-            button.getStyleClass().setAll("game-difficulty-button");
-            button.setMaxWidth(Double.MAX_VALUE); // have to do this or cannot size buttons from CSS
-            button.setOnAction(new EventHandler<ActionEvent>() {
-                @Override
-                public void handle(ActionEvent actionEvent) {
-                    setDifficulty(difficulty);
-                    EventHandler<ActionEvent> onAction = NewGamePanel.this.getOnAction();
-                    if (onAction != null) {
-                        onAction.handle(new ActionEvent(NewGamePanel.this, NewGamePanel.this));
-                    }
-                }
-            });
-            buttons.getChildren().add(button);
-        }
-    }
-
-    @Override
-    protected void layoutChildren() {
-        final Insets insets = getInsets();
-
-        // round up and cast to int to align on pixel boundaries without truncating text
-        double w = (int) (buttons.prefWidth(-1) + 1);
-        double h = (int) (buttons.prefHeight(-1) + 1);
-        buttons.resize(w, h);
-
-        buttons.relocate(
-                (int)((getWidth() - insets.getLeft() - insets.getRight() - w) / 2.0),
-                (int)((getHeight() - insets.getTop() - insets.getBottom() - h) / 2.0));
-    }
-}

defender/src/main/java/com/fxexperience/games/defender/games/simple/SimpleGameScene.java

-/*
- * Copyright (c) 2012, FX Experience. All rights  reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification, are
- * permitted provided that the following conditions are met:
- *
- * Redistributions of source code must retain the above copyright notice, this list of
- * conditions and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright notice, this list of
- * conditions and the following disclaimer in the documentation and/or other materials provided
- * with the distribution.
- *
- * Neither the name of the author nor the names of its contributors may be used to endorse or
- * promote products derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
- * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
- * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
- * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package com.fxexperience.games.defender.games.simple;
-
-import com.fxexperience.games.defender.games.simple.levels.FirstLevel;
-import javafx.scene.Scene;
-import javafx.scene.layout.BorderPane;
-import javafx.scene.layout.StackPane;
-
-/**
- * The Scene which will be used for the simple version of the game. This is
- * created and used by the DefenderApp application instance.
- */
-public class SimpleGameScene extends Scene {
-    public SimpleGameScene() {
-        super(new BorderPane(), 1200, 700);
-
-        final Game game = new Game();
-        getStylesheets().add("/styles/games/simple/styles.css");
-        BorderPane root = (BorderPane) getRoot();
-        StackPane p = new StackPane();
-        FirstLevel level = new FirstLevel();
-        p.getChildren().add(level);
-        game.setCurrentLevel(level);
-        root.setCenter(p);
-        root.setRight(new GameControlPanel(game));
-    }
-}

defender/src/main/java/com/fxexperience/games/defender/games/simple/ui/FxmlHelper.java

+/*
+ * Copyright (c) 2012, FX Experience. All rights  reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * Neither the name of the author nor the names of its contributors may be used to endorse or
+ * promote products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.fxexperience.games.defender.games.simple.ui;
+
+import javafx.fxml.FXMLLoader;
+import javafx.scene.Node;
+
+import java.io.IOException;
+
+public class FxmlHelper {
+
+    public static void load(String fxml, Node node) {
+        FXMLLoader fxmlLoader = new FXMLLoader(FxmlHelper.class.getResource(fxml));
+        fxmlLoader.setRoot(node);
+        fxmlLoader.setController(node);
+        try {
+            fxmlLoader.load();
+        } catch (IOException e) {
+            throw new RuntimeException("Error loading FXML file: " + fxml, e);
+        }
+    }
+}

defender/src/main/java/com/fxexperience/games/defender/games/simple/ui/GameControlPanel.java

+package com.fxexperience.games.defender.games.simple.ui;
+
+import com.fxexperience.games.defender.games.simple.Game;
+import com.fxexperience.games.defender.games.simple.LevelPanel;
+import com.fxexperience.games.defender.games.simple.Tower;
+import com.fxexperience.games.defender.games.simple.TowerFactory;
+import com.fxexperience.games.defender.games.simple.towers.BasicTowerFactory;
+import javafx.event.ActionEvent;
+import javafx.event.EventHandler;
+import javafx.fxml.FXML;
+import javafx.scene.control.Button;
+import javafx.scene.control.ToggleButton;
+import javafx.scene.control.ToggleGroup;
+import javafx.scene.input.MouseEvent;
+import javafx.scene.layout.GridPane;
+import javafx.scene.layout.VBox;
+import javafx.util.Duration;
+
+/**
+ */
+public class GameControlPanel extends VBox {
+
+    private Game game;
+
+    @FXML private GridPane towerGrid;
+    @FXML private Button playButton;
+
+    public GameControlPanel(final Game game) {
+        this.game = game;
+        FxmlHelper.load("/fxml/GameControlPanel.fxml", this);
+
+        // add allowed towers - todo eventually this should be derived off players allowed/baught towers
+        ToggleGroup toggleGroup = new ToggleGroup();
+        TowerFactory pelletGunFactory = new BasicTowerFactory("Pellet Gun", "pellet-gun", Duration.millis(1000), 100, 5);
+        towerGrid.getChildren().add(createTowerButton(toggleGroup, game, pelletGunFactory, 0, 0));
+        TowerFactory rapidFireGunFactory = new BasicTowerFactory("Rapid Fire Gun", "rapid-fire-gun", Duration.millis(200), 100, 5);
+        towerGrid.getChildren().add(createTowerButton(toggleGroup, game, rapidFireGunFactory, 1, 0));
+    }
+
+    public void togglePlaying() {
+        game.paused.set(!game.paused.get());
+        playButton.setText(game.paused.get() ? "Send The Enemies!" : "Pause");
+    }
+
+
+    protected ToggleButton createTowerButton(ToggleGroup toggleGroup, final Game game, final TowerFactory towerFactory, int column, int row) {
+        final ToggleButton towerButton = new ToggleButton(towerFactory.getTowerName());
+        toggleGroup.getToggles().add(towerButton);
+        GridPane.setConstraints(towerButton, column, row);
+        towerButton.setOnAction(new EventHandler<ActionEvent>() {
+            @Override
+            public void handle(ActionEvent actionEvent) {
+                final LevelPanel level = game.getCurrentLevel();
+                if (level != null) {
+                    final Tower tower = towerFactory.createTower();
+                    tower.setTranslateX(-100);
+                    tower.setTranslateY(-100);
+                    level.setOnMouseReleased(new EventHandler<MouseEvent>() {
+                        @Override
+                        public void handle(MouseEvent event) {
+                            tower.setTranslateX(event.getX());
+                            tower.setTranslateY(event.getY());
+                            level.addTower(tower);
+                            towerButton.setSelected(false);
+                            level.setOnMouseReleased(null);
+                        }
+                    });
+                }
+            }
+        });
+        return towerButton;
+    }
+}
+

defender/src/main/java/com/fxexperience/games/defender/games/simple/ui/NewGamePanel.java

+/*
+ * Copyright (c) 2012, FX Experience. All rights  reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * Neither the name of the author nor the names of its contributors may be used to endorse or
+ * promote products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.fxexperience.games.defender.games.simple.ui;
+
+import com.fxexperience.games.defender.games.simple.Game;
+import com.fxexperience.games.defender.games.simple.levels.FirstLevel;
+import javafx.animation.FadeTransitionBuilder;
+import javafx.animation.ParallelTransition;
+import javafx.animation.ParallelTransitionBuilder;
+import javafx.animation.TranslateTransitionBuilder;
+import javafx.event.ActionEvent;
+import javafx.event.EventHandler;
+import javafx.fxml.FXML;
+import javafx.scene.layout.Pane;
+import javafx.scene.layout.StackPane;
+import javafx.util.Duration;
+
+public class NewGamePanel extends StackPane {
+
+    private final Game game;
+
+    @FXML private Pane dialog;
+    @FXML private Pane glassPane;
+
+    public NewGamePanel(final Game game) {
+        this.game = game;
+        FxmlHelper.load("/fxml/NewGamePanel.fxml", this);
+    }
+
+    public void reset() {
+        dialog.setTranslateY(-this.game.getHeight());
+        glassPane.setOpacity(0);
+    }
+
+    public void playEntryAnimation() {
+
+        ParallelTransition transition = ParallelTransitionBuilder.create()
+                .children(
+
+                        TranslateTransitionBuilder.create()
+                                .node(dialog)
+                                .duration(Duration.millis(1000))
+                                .fromY(-game.getHeight())
+                                .toY(0)
+                                .build(),
+
+                        FadeTransitionBuilder.create()
+                                .node(glassPane)
+                                .duration(Duration.millis(500))
+                                .fromValue(0)
+                                .toValue(1)
+                                .build()
+
+                )
+                .build();
+
+        transition.play();
+    }
+
+    public void startGame() {
+        game.paused.set(true);
+        game.setCurrentLevel(new FirstLevel());
+        playExitAnimation();
+    }
+
+    public void playExitAnimation() {
+        ParallelTransition transition = ParallelTransitionBuilder.create()
+                .children(
+
+                        TranslateTransitionBuilder.create()
+                                .node(dialog)
+                                .duration(Duration.millis(1000))
+                                .fromY(0)
+                                .toY(-game.getHeight())
+                                .build(),
+
+                        FadeTransitionBuilder.create()
+                                .node(glassPane)
+                                .duration(Duration.millis(500))
+                                .fromValue(1)
+                                .toValue(0)
+                                .build()
+
+                )
+                .build();
+
+        transition.setOnFinished(new EventHandler<ActionEvent>() {
+            @Override
+            public void handle(ActionEvent actionEvent) {
+                game.getChildren().remove(NewGamePanel.this);
+            }
+        });
+
+        transition.play();
+    }
+}

defender/src/main/java/com/fxexperience/games/defender/games/simple/ui/WelcomePanel.java

+/*
+ * Copyright (c) 2012, FX Experience. All rights  reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * Neither the name of the author nor the names of its contributors may be used to endorse or
+ * promote products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.fxexperience.games.defender.games.simple.ui;
+
+import com.fxexperience.games.defender.games.simple.Game;
+import javafx.animation.*;
+import javafx.event.ActionEvent;
+import javafx.event.EventHandler;
+import javafx.fxml.FXML;
+import javafx.scene.control.Label;
+import javafx.scene.layout.VBox;
+import javafx.util.Duration;
+
+public class WelcomePanel extends VBox {
+
+    private final Game game;
+
+    @FXML private Label titleLabel;
+    @FXML private Label captionLabel;
+    @FXML private VBox topHalf;
+    @FXML private VBox bottomHalf;
+    @FXML private Label producedByLabel;
+
+    public WelcomePanel(final Game game) {
+        this.game = game;
+        FxmlHelper.load("/fxml/WelcomePanel.fxml", this);
+    }
+
+    public void reset() {
+        titleLabel.setScaleX(0);
+        titleLabel.setScaleY(0);
+        captionLabel.setOpacity(0);
+        topHalf.setTranslateY(0);
+        bottomHalf.setTranslateY(0);
+        producedByLabel.setOpacity(0);
+    }
+
+    public void playWelcome() {
+
+        SequentialTransition transition = new SequentialTransition();
+
+        // animate in the text
+
+        transition.getChildren().add(
+                ScaleTransitionBuilder.create()
+                        .node(titleLabel)
+                        .duration(Duration.millis(1500))
+                        .fromX(0).fromY(0)
+                        .toX(1).toY(1)
+                        .build());
+
+        transition.getChildren().add(
+                FadeTransitionBuilder.create()
+                        .node(captionLabel)
+                        .duration(Duration.millis(1500))
+                        .fromValue(0)
+                        .toValue(1)
+                        .build());
+
+        transition.getChildren().add(
+                ParallelTransitionBuilder.create()
+                        .children(
+                                RotateTransitionBuilder.create()
+                                        .node(producedByLabel)
+                                        .duration(Duration.millis(1500))
+                                        .fromAngle(180)
+                                        .toAngle(0)
+                                        .build(),
+
+                                FadeTransitionBuilder.create()
+                                        .node(producedByLabel)
+                                        .duration(Duration.millis(1500))
+                                        .fromValue(0)
+                                        .toValue(1)
+                                        .build(),
+
+                                ScaleTransitionBuilder.create()
+                                        .node(producedByLabel)
+                                        .duration(Duration.millis(1500))
+                                        .fromX(0).fromY(0)
+                                        .toX(1).toY(1)
+                                        .build()
+                        )
+                        .build()
+                );
+
+
+        // give everyone a moment to take it all in
+
+        transition.getChildren().add(new PauseTransition(Duration.seconds(1)));
+
+        // open up the gates when done
+
+        transition.getChildren().add(ParallelTransitionBuilder.create()
+                .children(
+
+                        TranslateTransitionBuilder.create()
+                                .node(topHalf)
+                                .duration(Duration.millis(1000))
+                                .fromY(0)
+                                .toY(-game.getHeight() / 2)
+                                .build(),
+
+                        TranslateTransitionBuilder.create()
+                                .node(bottomHalf)
+                                .duration(Duration.millis(1000))
+                                .fromY(0)
+                                .toY(game.getHeight() / 2)
+                                .build()
+
+                ).build());
+
+        transition.setOnFinished(new EventHandler<ActionEvent>() {
+            public void handle(ActionEvent actionEvent) {
+                game.showNewGamePanel();
+            }
+        });
+        transition.play();
+    }
+}

defender/src/main/resources/fxml/GameControlPanel.fxml

+<?xml version="1.0" encoding="UTF-8"?>
+
+<?import java.lang.*?>
+<?import java.util.*?>
+<?import javafx.scene.control.*?>
+<?import javafx.scene.layout.*?>
+<?import javafx.scene.paint.*?>
+
+<fx:root type="com.fxexperience.games.defender.games.simple.ui.GameControlPanel"
+         styleClass="game-control-panel"
+         spacing="20"
+         xmlns:fx="http://javafx.com/fxml">
+
+    <Label id="title" alignment="CENTER" text="JavaFX Defender"/>
+
+    <GridPane fx:id="towerGrid"/>
+
+<!-- todo lay these out
+    <Label id="towers-label" layoutX="28.0" layoutY="116.0" text="Towers" />
+    <Label id="money-label" layoutX="28.0" layoutY="62.0" text="Money" />
+    <Label id="lives-label" layoutX="28.0" layoutY="87.0" text="Lives" />
+    <Label id="money" layoutY="62.0" prefWidth="157.0" text="" AnchorPane.leftAnchor="91.0" AnchorPane.rightAnchor="14.0" />
+    <Label id="lives" layoutY="87.0" prefWidth="157.0" text="" AnchorPane.leftAnchor="91.0" AnchorPane.rightAnchor="14.0" />
+-->
+
+    <Button fx:id="playButton" text="Send The Enemies!" maxWidth="Infinity" onAction="#togglePlaying"/>
+
+</fx:root>

defender/src/main/resources/fxml/NewGamePanel.fxml

+<?xml version="1.0" encoding="UTF-8"?>
+
+<?import java.lang.*?>
+<?import java.util.*?>
+<?import javafx.scene.control.*?>
+<?import javafx.scene.layout.*?>
+<?import javafx.scene.paint.*?>
+
+<fx:root type="com.fxexperience.games.defender.games.simple.ui.NewGamePanel"
+         styleClass="new-game-view"
+         xmlns:fx="http://javafx.com/fxml">
+
+    <Pane fx:id="glassPane" styleClass="glass-pane"/>
+
+    <VBox alignment="CENTER" fillWidth="false" >
+        <VBox fx:id="dialog" styleClass="dialog" VBox.vgrow="NEVER" fillWidth="false" alignment="CENTER">
+            <Label fx:id="titleLabel" styleClass="title" alignment="CENTER" text="Start New Game"/>
+            <Label fx:id="captionLabel" alignment="CENTER" text="todo: choose difficulty and level"/>
+
+            <Button fx:id="startGameButton" alignment="CENTER" text="Start Game" onAction="#startGame"/>
+        </VBox>
+    </VBox>
+
+</fx:root>

defender/src/main/resources/fxml/WelcomePanel.fxml

+<?xml version="1.0" encoding="UTF-8"?>
+
+<?import java.lang.*?>
+<?import java.util.*?>
+<?import javafx.scene.control.*?>
+<?import javafx.scene.layout.*?>
+<?import javafx.scene.paint.*?>
+
+<fx:root type="com.fxexperience.games.defender.games.simple.ui.WelcomePanel"
+         styleClass="welcome-view"
+         xmlns:fx="http://javafx.com/fxml">
+
+    <VBox fx:id="topHalf" styleClass="top-half" VBox.vgrow="ALWAYS" fillWidth="true" alignment="CENTER">
+        <Label fx:id="titleLabel" styleClass="title" alignment="CENTER" text="JavaFX Defender"/>
+        <Label fx:id="captionLabel" alignment="CENTER" text="Shoot stuff and what not"/>
+    </VBox>
+
+    <VBox fx:id="bottomHalf" styleClass="bottom-half" VBox.vgrow="ALWAYS" fillWidth="true" alignment="TOP_CENTER">
+        <Label fx:id="producedByLabel" alignment="CENTER" text="Brought to you by FX Experience"/>
+    </VBox>
+
+</fx:root>

defender/src/main/resources/styles/games/simple/GameControlPanel.fxml

-<?xml version="1.0" encoding="UTF-8"?>
-
-<?import java.lang.*?>
-<?import java.util.*?>
-<?import javafx.scene.control.*?>
-<?import javafx.scene.layout.*?>
-<?import javafx.scene.paint.*?>
-
-<AnchorPane id="AnchorPane" maxHeight="1.7976931348623157E308" maxWidth="-Infinity" minHeight="-Infinity"
-            minWidth="-Infinity" prefHeight="598.0" prefWidth="262.0">
-  <children>
-    <Label id="title" alignment="CENTER" contentDisplay="LEFT" prefHeight="-1.0" prefWidth="-1.0" text="JavaFX Defender" AnchorPane.leftAnchor="14.0" AnchorPane.rightAnchor="14.0" AnchorPane.topAnchor="14.0" />
-
-    <GridPane id="tower-grid" layoutY="139.0" prefHeight="342.0" prefWidth="206.0" AnchorPane.leftAnchor="28.0" AnchorPane.rightAnchor="28.0">
-      <columnConstraints>
-          <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
-          <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
-          <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
-      </columnConstraints>
-    </GridPane>
-
-    <Button id="new-game-button" layoutY="528.0" mnemonicParsing="false" prefWidth="206.0" text="New Game" AnchorPane.leftAnchor="28.0" AnchorPane.rightAnchor="28.0" />
-    <Label id="towers-label" layoutX="28.0" layoutY="116.0" text="Towers" />
-    <Label id="money-label" layoutX="28.0" layoutY="62.0" text="Money" />
-    <Label id="lives-label" layoutX="28.0" layoutY="87.0" text="Lives" />
-    <Label id="money" layoutY="62.0" prefWidth="157.0" text="" AnchorPane.leftAnchor="91.0" AnchorPane.rightAnchor="14.0" />
-    <Label id="lives" layoutY="87.0" prefWidth="157.0" text="" AnchorPane.leftAnchor="91.0" AnchorPane.rightAnchor="14.0" />
-    <Button id="play-button" layoutY="563.0" mnemonicParsing="false" prefWidth="206.0" text="Send The Enemies!" AnchorPane.leftAnchor="28.0" AnchorPane.rightAnchor="28.0" />
-  </children>
-</AnchorPane>

defender/src/main/resources/styles/games/simple/styles.css

  */
 
 /******************************************
+    General Dialog Styles
+******************************************/
+
+.glass-pane {
+    -fx-background-color: rgba(0.3, 0.3, 0.3, 0.3);
+}
+
+/******************************************
     Styling for the New Game Panel
 ******************************************/
 
 }
 
 /******************************************
+    Styling for the Welcome View
+******************************************/
+
+.welcome-view {
+}
+
+.welcome-view .title {
+    -fx-text-fill: rgba(0,0,0,0.7);
+    -fx-font: 48pt Arial;
+}
+
+.top-half, .bottom-half {
+    -fx-background-color: #FFCC66;
+}
+
+
+/******************************************
+    Styling for the New Game View
+******************************************/
+
+.new-game-view {
+}
+
+
+/******************************************
     Styling for the Game Board
 ******************************************/