Skip to content

TheBromo/tower-defense

Folders and files

NameName
Last commit message
Last commit date

Latest commit

ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

Copy of ZHAW repo

Team05-java.lang.NullPointerException-projekt2-tower-defense

๐Ÿฐ ๐Ÿฅท ๐Ÿฐ Short Introduction to the Game Tower Defense

Tower Defense is a captivating game that challenges players to strategically place towers to defend their base from waves of relentless enemies. This game is still an MVP. However, with further development, and with a variety of towers, enemies, and maps, players will find themselves immersed in a world of strategic decision-making and excitement.

๐Ÿ“‹ Table of contents

๐Ÿš€ Getting started

  1. Clone the repository
  2. Open the project in your desired IDE (IntteliJ, Eclipse or else)
  3. run gradle build
  4. run gradle run
  5. click start button in separate window
  6. play and have fun

๐Ÿ”‘ Key Features

  1. User-friendly Interface: Navigate the game with ease through an intuitive and visually appealing interface.
  2. Purchase Towers: Buy towers and place them on strategically optimal spots.
  3. Upgrade Tower: Upgrade existing towers to more powerful ones.
  4. Buy Health: Buy health function to invest your earned money into your health recovery.
  5. Pause & Attack Phases: Pause phase without enemy attacking, and different attack phases with increasing level of difficulties.

๐Ÿ”Ž Technical Details

๐Ÿงช Technologies used in the Project

  • Java SDK 17
  • Gradle Version 8.0.1
  • Clean Code Convention

๐Ÿงฎ Class-Diagram

exported_from_idea drawio-6

๐Ÿ— Architecture & MVC

MVC Game

 UI Thread                                                       GameThread


โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚                    โ”‚
โ”‚ GameView.fxml      โ”‚
โ”‚                    โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
          โ–ฒ
          โ”‚ Displays
          โ”‚
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”          โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”         โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚                    โ”‚          โ”‚                     โ”‚         โ”‚                     โ”‚
โ”‚ GameViewController โ”œโ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ–บโ”‚ GameState           โ”‚โ—„โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”ค   Game              โ”‚
โ”‚                    โ”‚    โ”‚     โ”‚                     โ”‚    โ”‚    โ”‚                     โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜    โ”‚     โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜    โ”‚    โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                          โ”‚                                โ”‚
                      Observes                          Updates

The MVC model communicates with the Observer Pattern.

  • GameState holds all the properties that are needed to display in the UI
  • The Game class is the Game Thread. It simulates the game rules and physics and updates the Gamestate accordingly
  • GameViewController displays the given information of the GameState accordingly.

When Rendering on the canvas the UI Thread is awaited because otherwise to many requests would clog up the UI Thread with the Platform.runLater(...) function.

Game Thread

The Game Thread is the main loop of the game. It calls all the important function like render() and update().

The Game Thread is structured like the following:

double previous = getCurrentTime();
double lag = 0.0;
while (true)
{
  double current = getCurrentTime();
  double elapsed = current - previous;
  previous = current;
  lag += elapsed;

  processInput();

  while (lag >= MS_PER_UPDATE)
  {
    update();
    lag -= MS_PER_UPDATE;
  }

  render();
}
  1. The update() method is only called when the given time per update (100ms) is elapsed.
  2. The render() method is always called and renders as many frames as possible

In our case the render() method sets the GameState to trigger a render and awaits for the render to finish.

This was implemented in the following PR #48

Sprite System

Sprite means: In computer graphics, a sprite is a two-dimensional bitmap that is part of a larger scene (e.g., a 2D video game). Sprites can be static images or animated graphics. source

The Sprite System loads images of for the given SpritePath enum. Here the number of variant of the same image and amount of images (more than 2 is animated).

It has its own timer which changes the current image to display in a given interval.

Through this system animations are enabled

This is how the code works:

public class Sprite {
    private List<Image> sprites;
    private int intervalMs = 300;
    private int index = 0;
    private long lastUpdate = 0;

    public Sprite(SpritePath sprite) {
    ...
    intervalMs = randomUtil.getRandomInRange(sprite.minAnimationTimer, sprite.maxAnimationTimer); // not all animations play at the same speed
    lastUpdate = randomUtil.getRandomInRange(sprite.minAnimationTimer, sprite.maxAnimationTimer); // they dont start synchronized
    ...
    }
    
    public Image getSprite() {
        if (System.currentTimeMillis() - lastUpdate >= intervalMs) {
            continueIndex();
            lastUpdate = System.currentTimeMillis();
        }
        return sprites.get(index);
    }
    ...

getSprite() returns the image which should be displayed of the whole set and is incremented, if an interval was passed.

Example sprite of enemy walking

Sprite

Rendering System

The Rendering System is responsible for visualizing elements on the canvas. What classes can be renderd is defined by the Rendreable interface.

The rendering is called each game.loop(). As the Rendering has to be done in the UI Thread the GameThread( game.loop()) is waiting. This is the case, so that the rendering does not spam the UI Thread until it dies and the calling of the render function doesn't have to be locked to a fixed number.

                                                                                          โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
                                                                                          โ”‚                  โ”‚
                                                                                          โ”‚    Game.loop     โ”‚
                                              โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”                      โ”‚                  โ”‚
                          Render in UI Thread โ”‚                    โ”‚                      โ”‚  update          โ”‚
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”                        โ”‚  Game State        โ”‚    Set Val and Waits โ”‚                  โ”‚
โ”‚                    โ”‚                        โ”‚                    โ”‚                      โ”‚                  โ”‚
โ”‚    UI Thread       โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค RenderNeeded:Bool  โ”‚ โ—„โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€setRender(True) โ”‚
โ”‚                    โ”‚                        โ”‚                    โ”‚                      โ”‚                  โ”‚
โ”‚                    โ”‚                        โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜                      โ”‚                  โ”‚
โ”‚                    โ”‚                                                                    โ”‚                  โ”‚
โ”‚                    โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ–บ continues..  โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜                         On finish                                  โ”‚                  โ”‚
                                                                                          โ”‚                  โ”‚
                                                                                          โ”‚                  โ”‚
                                                                                          โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

This graph is from PR #52

The following classes implement the Rendreable interface:

exported_from_idea drawio

The Rendreable interface enforces the render(Canvas canvas) method on it's implementers. Here an Example:

    @Override
    public void render(Canvas canvas) {
        var g2d = canvas.getGraphicsContext2D();
        g2d.drawImage(sprite.getSprite(), position.getX() - width / 2, position.getY() - height / 2,
                width, height);
        g2d.setFill(Color.LIGHTGREEN);
        g2d.fillRect(position.getX() - width / 2, position.getY() - height / 2-10,
                (((double) width / 100) * health), 2);
    }

Here the sprite is drawn with the position of the enemy being in the middle of the Image (hence the - width / 2 and - height / 2). The health of the enemy is also represented by a green Rectangle drawn with it's width being relative to the enemies health.

The top element of the render chain is the Game class which starts the rendering. Here is the order and hierarchy of the rendering process.

exported_from_idea drawio (1)

Update System

The Update System is responsible for updating the physics and businessLogic of the Game in a predifined interval.

The update system has the following steps:

exported_from_idea drawio (1)

His is a overview of all steps done in the update() method. Some of them will be explained further in the next points.

Enemy Spawning

The system that dictates, when, where and how many enemies are spawned and are on the game field.

  1. The currentPhase says how many enemies have to be on the field.
 while (enemies.size() < currentPhase.getEnemyAmount()) {
            spawnEnemy();
 }
  1. When spawning a random Point is selected where no enemy is yet. If an Enemy is already on the generated position the enemy is shifted left (position.x -= 50), if there is another enemy, the position is further shifted until no enemy is at the same position:
    private void spawnEnemy() {
        int radius = path.getRadius();
        int y = (int) path.getStart().getY();
        var startY = RandomUtil.getInstance().getRandomInRange(y - radius, y + radius);
        var startX = RandomUtil.getInstance().getRandomInRange(-200, 0);
        var newPost = new Point2D(startX, startY);
        while (interSects(newPost)) {
            newPost = newPost.add(-50, 0);
        }
        enemies.add(new Enemy(newPost));
    }

the spawn position is always of screen so the spawning of the enemy is not visible to the player.

Enemy Crowd Behaviour

The crowd behaviour is based on a task of the book: The Nature of code by Daniel Shiffman Exercise 6.14, Chapter 6.12 Combinations

Phase System

The system that defines how many enemies are present in the game.

The phase system has two phases

  1. Attack phase here enemies spawns corresponding to the attack pattern
  2. Pause phase no enemies spawn. The player has a chance to recover
Attack Patterns

The patterns are defined through a base level of enemies that attack the player.

            patterns.add(new int[] { 2, 2, 3, 4, 3, 3, 2 });
            patterns.add(new int[] { 2, 2, 2, 5, 2, 2 });
            patterns.add(new int[] { 3, 3, 3, 2, 2, 2 });
            patterns.add(new int[] { 2, 2, 2, 2, 4, 2 });
            patterns.add(new int[] { 2, 3, 3, 4, 2 });

๐ŸŒณ Branching Modell

A feature branch was generated for each task. If the feature was completed, a pull request was created. This had to be reviewed and approved by another team member so that the code from the feature branch could be merged into the main branch.

Branching

๐Ÿ‘จโ€๐Ÿ”ง Pull Requests

Whenever there was a change, it was consequently merged via a pull request. Suggestions for improvements were either commented within the pull request or discussed in person.

Example: Pull-Request

Not every pull-requests have discussion/improvement points in it, as if the reviewer agreed with the proposed changes, he immediately approved it.

๐Ÿ”ฎ Features to come (Post-MVP)

  1. Challenging Gameplay: Engage in an immersive tower defense with increasingly challenging levels, pushing your strategic thinking to the limit.
  2. Multiple Tower Types: Choose from a wide variety of towers, each with unique abilities, upgrades, and attributes.
  3. Diverse Enemy Types: Face off against an array of different enemies with unique abilities and strategies, keeping you on your toes.
  4. Customizable Maps: Play on various maps with distinct terrain, obstacles, and paths, providing new challenges and opportunities.
  5. Achievements and Leaderboards: Unlock achievements as you progress and compare your scores with players from around the world.

๐Ÿ™Œ๐Ÿ“ซ Credits & Contact

Tower Defense is developed by Team 5 java.lang.NullPointerException.

If you have any questions, suggestions or concerns, please feel free to contact us:

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 4

  •  
  •  
  •  
  •  

Languages