---
# System prepended metadata

title: 'Sprint #1 Presentation'

---

# Sprint #1 Presentation

## Frontend Updates

The color scheme and animations for the application have been defined. Things such as scene transitions all include fade in/out animations which we anticipate being configurable in the global settings

The splashscreen and game selection scene are the two major parts/most visible parts of the view which have been fully implemented. The goal during this sprint for the View was to get the structure for scenes implemented and create much of the UI with the preplanned components.

Splash Screen:

![](https://i.imgur.com/NbWfgpX.png)

Game Selection Scene:

![](https://i.imgur.com/avzYBNs.png)

The View taks in a `meta.json` file and figures out information about the file and translates details into specified locales.

```json=
{
	"author": "TingLong & Friends",
	"dateCreated": "March 5, 2020",
	"levels": [
		"Sunn",
		"Has Levels"
	],
	"tags": [
		"fun",
		"family-friendly"
	]
}
```

It would be entirely possible to allow the user to defined as many different kinds of meta data as they would like, but at the moment it's geared towards allow defined localization by defining these specific tags, but in the future it's planned to allow for localization for specific tags and for the rest allow the user to define them as they wish.

To make error handling uniform among all scenes, there is a factory class that produces the error dialogues.

![](https://i.imgur.com/ekxERWA.png)

The benefit of this is that (as previously stated) errors will be uniform among all parts of the application, making configuration of these errors easier. This also helps in allowing localization to remain consistent (i.e only one kind of string is useed to display an error instead of 3 different ways to say an eror occured).

At the moment, where error handling is needed the resource is passed to the component that could potentially throw errors, but that was because I couldn't find the time to do it properly before the deadline honestly. :/. But as we go into sprint to I want to make it consistent with the callback system that has been used across the entire application.

## Configuration
The configuration factory classes have been setup and uses reflection to save and load object presets from a json file. Using Moshi's adapter features, we were able to add override features to update fields in an object defined in the presets.

A level factory is instantiated by a level file as follows

![](https://i.imgur.com/OFnWXV0.png)

The game objects are then placed in their specified positions. When the level builds itself.
![](https://i.imgur.com/2kcCDbO.png)

### Level Creation
```java=
class GameLevel implements Level {
  private String name;
  int levelID;
  @Json(name = "objects") List<GameObject> gameObjects;
}
```

```java=
public class GameObject implements ObservableObject {
  private List<Component> components;
  private final int id;
  private final String name;
  private double x, y;
  private Vector velocity;
  private double height, width;
}
```

```java=
 public LevelFactory(File objectsDir) throws NotADirectoryException {
    if (!objectsDir.isDirectory()) {
        throw new NotADirectoryException(objectsDir.getName());
    }

    Map<String, GameObject> presetMap = new HashMap<>();

    Moshi moshi = new Moshi.Builder().add(
        PolymorphicJsonAdapterFactory
            .of(Component.class, "type")
            .withSubtype(PlayerComponent.class, "PlayerComponent")).build();

    Type type = Types.newParameterizedType(List.class, GameObject.class);
    JsonAdapter<List<GameObject>> adapter = moshi.adapter(type);

    File[] objectFiles = objectsDir.listFiles((dir, name) -> name.contains(".json"));

    for (File objectFile : objectFiles) {
      addObjects(objectFile, adapter, presetMap);
    }
}
```

```java=
Level buildLevel(File levelFile) 
      throws FileNotFoundException, InvalidDataFileException {
    String levelText;
    try {
        levelText = fileToString(levelFile);
    } catch (IOException e) {
        throw new FileNotFoundException(levelFile.getName());
    }

    GameLevel newLevel;
    try {
      newLevel = levelAdapter.fromJson(levelText);
    } catch (IOException e) {
      throw new InvalidDataFileException(levelFile.getName());
    }

    newLevel.init();
    return newLevel;
}
```


## Keyboard Actions
1. Setting up: 
    1. Another config File for key2action mapping i.e. a->left, d->right, space->jump, etc.
    2. View -> get the valid actions from Model for the certain level
    3. View call the Controller to set up the key2action mapping.
2. Calling:
    1. View pass the key code to the Controller, Controller pass the certain action based on the key2action mapping to the model to execute the action

## Systems:
Concept: Extract all logic into classes dedicated to maintain that logic.

Previously, we intended to create actions (jump, attack enemy, etc.) in the classes that contained the data about this logic. For example:

```java=
class Jump {
    private int maxHeight = 20;
    private GameObject owner
    
    public void jump() {
        owner.setYVelocity(20)
    }
}
```

But instead of this, we decided to make a change toward extracting all logic related to game objects to their own classes. Here's an example from the code:

```java=
package ooga.model.components;

public class PlayerComponent extends Component {
  int maxJumpHeight = 20;
  int walkSpeed = 30;

  public PlayerComponent(int id, GameObject owner) {
    super(id, owner);
  }

}
```

These fields are createable from within the configuration, like this:
```json=

components: [
    {
        "type": "PlayerComponent",
        "walkSpeed": 20,
        "maxJumpHeight": 20;
    }
]
```

The values we set within the instance field are the default values of those components if the user did not specify them within the configuration.

Next, we have a system dedicated to managing all "PlayerComponents"

```java=
package ooga.model.systems;

import ooga.model.components.PlayerComponent;
import ooga.model.objects.GameObject;

public class PlayerSystem extends ComponentBasedSystem<PlayerComponent> {
  int mainPlayerId;
  
  public PlayerSystem(ComponentManager componentManager) {
    super(componentManager, PlayerComponent.class);
  }

  public void init() {
    addMapping("right", this::handleRight);
    addMapping("jump", this::handleJump);
    addMapping("switch_main", this::switchPlayer)
    addCollisionMapping("jump_self", event -> handleJump(event.getSelf()));
  }

  public void handleJump(GameObject obj) {

  }

  // on specifies whether it was the start or end of input
  void handleRight(boolean on) {
  }

  void switchPlayer(boolean on) {
  
  }

  void handleJump(boolean on) {
  }
}
```
**Note**: The logic for this still has to be implemented, which is the goal of the systems workers during this upcoming sprint

The benefit to this is that we can have more logic to certain keyboard events, such as allowing the user to switch players.

We have implemented superclasses which handle things that are common among all the systems


If you see the "addMapping" method call within the init function, it is adding a keypress event that this system listens to. The controller converts keypresses done on the view into these codes.

General systems we're in the process of creating:

So the main distinction between input events and action events is that input events can be triggered by keyboard actions and action events can occur from collisions. The benefits of having a system manage these events is seen here in how duplicate code in input/action events is removed (along with the logic too ofc, but duplicated code is ugly).

1. Transform System: transform the Model coordinate to the View Coordinate
2. Health (life) System: Deal with the health of the destructable GameObjects (Entities, blocks) etc.

Another, very similar part of systems are actions (addCollisionMapping). These are things that can be done on collisions. With that we can have actions that hapen on specific objects. Collisions that systems listen to pass them the two objects that were in a collision along with information about that collision.

## Collision Detection:
Collision detection has been implemented for GameObjects although this detection has not yet been translated into calling the objects to perform an action. This detection is done by examining a list of GameObjects representing the current state of the level and then sorting the objects that are collidable. 

```java=
  private void checkCollisions() {
    List<GameObject> objects = myCurrentLevel.generateObjects();
    List<GameObject> collidableObjects = new ArrayList<>();

    for(GameObject gameObject: objects){
      if(gameObject.isA("collidable")){
        collidableObjects.add(gameObject);
      }
    }
    Collections.sort(collidableObjects);
    findCollisions(collidableObjects);
  }
```

GameObjects implement Comparable allowing Collections.sort() to be used to sort them efficiently based on their x-coordinate.

```java=
public class GameObject{
  @Override
  public int compareTo(GameObject o) {
    double diff = this.getX() - o.getX();
    return (int) Math.signum(diff);
  }
}
```

Objects then are compared to their sorted neighbors using their widths and x-coordinates and if overlap occurs then their y-coordinates and heights are compared to determine if a collision occurred. 

```java=
  private void findCollisions(List<GameObject> collidableObjects) {
    for(int k =0; k<collidableObjects.size()-1; k++){
        executeCollisions(k, collidableObjects);
    }
  }

  private void executeCollisions(int index, List<GameObject> collidableObjects) {
    GameObject collidingObject = collidableObjects.get(index);
    double width = collidingObject.getWidth();
    double height = collidingObject.getHeight();
    double x = collidingObject.getX();
    double y = collidingObject.getY();

    for(int k = index+1; k<collidableObjects.size(); k++){
      GameObject collidedObject = collidableObjects.get(k);

      if(x + width < collidedObject.getX()){
        return;
      }
      
      else if(collidedObject.getY() >= y && collidedObject.getY() <= y+height){
        collide(collidingObject, collidedObject);
      }
    }
  }
```
## Significant Events in this Sprint

### Positive
1. Redesign of the backend structure i.e. introducing the system, components concept, `object oriented` game engine design.

### Negative
We had several events this week occur that challenged our work on the project. Oliver's cat broke his computer. We lost one of our team members and two of our team members are in opposite time zones. 

## Features Planned to implement next Sprint
1. We plan on integrating collision detection with collision action handlers to allow objects to move and collide inside of levels. 
2. All kinds of systems.