11. week

Problemset 2: Project Ellen

Goals

  • Implement your own game level.
  • Implement your own actors.
  • Design and implement custom functionality in an object-oriented way.
  • Identify and use design patterns in your own solution.

Assignment description

Create a single playable game level using the GameLib library (version 2.6.1) in Java. For its graphical representation, you may use the sprites from the Alien Breed video game. Create the level map using the Tiled editor. Implement the basic functionality of the game according to the tasks from labs 7 to 10. Your custom game level must be completable, and its solution must require the use of a series of adventure-style steps. This means that the level cannot be linearly completable, for example only by shooting enemies or collecting some items, but must contain actors that you need to interact with.

The requirements for the solution are described in detail below.

When working on the assignment, follow the honor code!

Important deadlines

  • The assignment (both parts) must be submitted to the GitLab system no later than Friday, December 12, 2025, 23:59 (FOREIGN STUDENTS => Friday, December 19, 2025, 23:59).
  • Project evaluations in the Arena system will run every 3 hours daily. The last evaluation will take place on Friday, December 19, 2025 at midnight.
  • After successful automated testing, you will come for an oral defense of your custom game part of the solution (which cannot be covered by the tests in Arena). The defense will take place before the exams (you will come to exam and before the exam you will defend your solution).

Warning

The oral defense is necessary in order to be able to obtain the full number of points for the assignment.

1. Basic implementation part (graded by tests)

The following classes (their constructor signatures) and interfaces with defined methods represent the state of the basic implementation after completing all tasks from labs 7–10 and will be evaluated by Arena tests:

  • actions:
    • class Drop<K extends Keeper> (extends AbstractAction)
      • constructor public Drop()
    • class Fire<A extends Armed> (extends AbstractAction)
      • constructor public Fire()
    • class Move<A extends Movable> (implements Action)
      • constructor public Move(Direction direction, float duration)
      • method public void stop()
    • class Shift<K extends Keeper> (extends AbstractAction)
      • constructor public Shift()
    • class Take<K extends Keeper> (extends AbstractAction)
      • constructor public Take()
    • class Use<A extends Actor> (extends AbstractAction)
      • constructor public Use(Usable<A> usable)
      • method public Disposable scheduleForIntersectingWith(Actor mediatingActor)
  • behaviours:
    • interface Behaviour<A extends Actor>
      • method void setUp(A actor)
    • class Observing<T, A extends Actor> (implements Behaviour)
      • constructor public Observing(Topic<T> topic, Predicate<T> predicate, Behaviour<A> delegate)
    • class RandomlyMoving (implements Behaviour)
      • constructor public RandomlyMoving()
  • characters
    • class Alien (extends AbstractActor; implements Movable, Alive, and Enemy)
      • constructor public Alien()
      • constructor public Alien(int healthValue, Behaviour<? super Alien> behaviour)
    • interface Alive (extends Actor)
      • method Health getHealth()
    • interface Armed (extends Actor)
      • method Firearm getFirearm()
      • method void setFirearm(Firearm firearm)
    • interface Enemy (extends Actor)
    • class Health
      • constructor public Health(int initHealth, int maxHealth)
      • constructor public Health(int initHealth)
      • method public int getValue()
      • method public void refill(int amount)
      • method public void restore()
      • method public void drain(int amount)
      • method public void exhaust()
      • method public void onFatigued(FatigueEffect effect)
      • interface FatigueEffect
        • method void apply()
    • class Ripley (extends AbstractActor; implements Alive, Armed, Keeper, and Movable)
      • constructor public Ripley()
      • static field public static Topic<Ripley> RIPLEY_DIED
  • controllers:
    • class KeeperController (implements KeyboardListener)
      • constructor public KeeperController(Keeper keeper)
    • class MovableController (implements KeyboardListener)
      • constructor public MovableController(Movable actor)
    • class ShooterController (implements KeyboardListener)
      • constructor public ShooterController(Armed shooter)
  • items:
    • class Ammo (extends AbstractActor, implements Usable)
      • constructor public Ammo()
    • class Backpack (implements ActorContainer)
      • constructor public Backpack(String name, int capacity)
    • interface Collectible (extends Actor)
    • class Energy (extends AbstractActor, implements Usable)
      • constructor public Energy()
    • interface Usable<A extends Actor>
      • method void useWith(A actor)
      • method Class<A> getUsingActorClass()
  • openables:
    • class Door (extends AbstractActor, implements Openable and Usable)
      • enumeration Orientation { VERTICAL, HORIZONTAL }
      • constructor public Door(String name, Orientation orientation)
      • static field public static Topic<Door> DOOR_OPENED
      • static field public static Topic<Door> DOOR_CLOSED
    • interface Openable (extends Actor)
      • method void open()
      • method void close()
      • method boolean isOpen()
  • weapons:
    • class Bullet (extends AbstractActor, implements Fireable)
      • constructor public Bullet()
    • interface Fireable (extends Movable)
    • abstract class Firearm
      • constructor public Firearm(int initAmmo, int maxAmmo)
      • constructor public Firearm(int initAmmo)
      • method public int getAmmo()
      • method public void reload(int amount)
      • method public Fireable fire()
      • abstract method protected Fireable createBullet()
    • class Gun (extends Firearm)
      • constructor public Gun(int initAmmo, int maxAmmo)
  • enumeration Direction
    • values NORTH, EAST, SOUTH, WEST
    • constructor Direction(int dx, int dy)
    • method public int getDx()
    • method public int getDy()
    • method public float getAngle()
    • static method public static Direction fromAngle(float angle)
  • interface Keeper (extends Actor)
    • method Backpack getBackpack()
  • class Main
    • static method public static void main(String[] args)
  • interface Movable (extends Actor)
    • method int getSpeed()
    • method default void startedMoving(Direction direction) {}
    • method default void stoppedMoving() {}
    • method default void collidedWithWall() {}
  • class SpawnPoint (extends AbstractActor)
    • constructor public SpawnPoint(int spawnAliens)

Note: Your implementation should be built on this foundation, even though it is not necessary to use absolutely everything from it in your own game. If needed, you may extend the listed classes with your own methods, as long as you preserve the functionality of the existing ones.

Warning

You must not modify the listed mandatory interfaces in any way in your solution! The tests in Arena are compiled against the interface definitions described here, and if your interfaces do not match them, it may happen that tests which test or otherwise use a given interface cannot even be initialized.

Warning

Due to testing the required three controllers in the sk.tuke.kpi.oop.game.controllers package, you must keep the key bindings for individual actions as described in the labs. If you want to customize the key bindings, do so only by adding another accepted key for a particular action, so that the keys from the labs remain accepted.

2. Requirements for your own game part of the assignment

To be able to obtain the full number of points for the assignment, you must create the previously mentioned playable level. During the assignment defense, fulfillment of the following requirements will be checked.

2.1 Functionality and playability

The project submitted to GitLab must be complete and runnable using the command ./gradlew run (Linux, Mac OS) or gradlew.bat run (Windows).

Note: The project must be runnable in this way also on a computer other than your own. Therefore, remember to include all sprite images and maps in the project on GitLab.

The game must be successfully completable. The ending itself (the final, but not the only step of the game) may be reachable in various ways, such as: destroying all enemies (or the final boss), leaving the level through specific doors or an elevator, pressing a switch or a set of switches, and similar.

2.2 Custom level map

You must create your own game level map named map.tmx, whose area is at least 500 tiles (for example 20 x 25) but not larger than 6400 tiles (e.g. 80 x 80). More about the level map is described below.

Create the level map according to the tutorial for integration with the GameLib library.

2.3 Custom actors

In the game, create at least 7 custom classes that implement the Actor interface or extend the abstract class AbstractActor. Follow these requirements:

  • These classes and their instances must be necessary for successfully achieving the game’s goal, i.e., they must be actively involved in the game scenario. Examples of active involvement in the scenario include using a cabinet, opening doors, moving a brick onto a floor switch, and similar.
  • They must not be empty actors – they must not contain only an animation (constructor) without any additional code (without methods).
  • Actors whose implementation was the task of the first assignment (for example reactor, cooler, hammer, etc.) and which are a mandatory part of the game (their list is given above) are not counted towards the required number. Also not counted are actors with the same behaviour and properties as those defined in the lab tasks.

2.4 Use of design patterns

Use at least 4 design patterns in the game. Prefer patterns from the structural and behavioral groups. It is also possible to use the Builder and Prototype patterns from the creational group.

Warning

Only your own implementations of design patterns will count towards the required four, not those implemented based on the lab tasks.

2.5 Programming style

When programming, follow these principles:

  • In the course Object-Oriented Programming, a solution written in an object-oriented style is required – use data encapsulation, class hierarchies, interfaces, composition, polymorphism. As a bonus, appropriately use custom type parameters to generalize your solution.
  • Create classes with as few member variables as possible (member variables should only be those that are necessary to record the state of objects!) and with a useful and understandable API in the form of public methods. Methods that deal with implementation details should be defined as private.
  • Avoid duplicating functionality.
  • Format your code according to established conventions for the Java language.
  • Pay attention to naming identifiers (names of classes, methods, variables, etc.). Names should be meaningful and follow Java naming conventions.

3. Testing

For testing your solution in Arena, the following will be required:

Warning

Your code will be compiled in Arena with the switches -Xlint:unchecked,rawtypes -Werror, which convert warnings regarding the use of unchecked operations or raw types into errors, and their presence will therefore cause the compilation to fail.
You can also set these switches for local compilation of your code by modifying the existing configuration of JavaCompile tasks in the build.gradle.kts file to the following form:

tasks {
    withType<JavaCompile> {
        options.compilerArgs.addAll(listOf("-parameters", "-Xlint:unchecked,rawtypes", "-Werror"))
    }
}

4. Submission

The assignment is submitted using the Git version control system on the school GitLab server https://git.kpi.fei.tuke.sk.

Use the same project that you created via the OOP Gitlab Classroom application at the beginning of the semester, and that you also used for the first assignment. The classes required for the first testing will no longer be tested. The only conditions are that the project as a whole must compile using the compiler switches mentioned above, and that all non-static member variables are private.

4.1 Project structure

The structure of your project, with the specified placement of mandatory implementation parts, must look as follows:

. // root directory of repository
├── gradle  // contains gradle files
├── src
│  ├── main
│  │  ├── java
│  │  │  └── sk
│  │  │     └── tuke
│  │  │        └── kpi
│  │  │           └── oop
│  │  │              └── game
│  │  │                 ├── actions
│  │  │                 │  ├── Drop.java
│  │  │                 │  ├── Fire.java
│  │  │                 │  ├── Move.java
│  │  │                 │  ├── Shift.java
│  │  │                 │  ├── Take.java
│  │  │                 │  └── Use.java
│  │  │                 ├── behaviours
│  │  │                 │  ├── Behaviour.java
│  │  │                 │  ├── Observing.java
│  │  │                 │  └── RandomlyMoving.java
│  │  │                 ├── characters
│  │  │                 │  ├── Alien.java
│  │  │                 │  ├── Alive.java
│  │  │                 │  ├── Armed.java
│  │  │                 │  ├── Enemy.java
│  │  │                 │  ├── Health.java
│  │  │                 │  └── Ripley.java
│  │  │                 ├── controllers
│  │  │                 │  ├── KeeperController.java
│  │  │                 │  ├── MovableController.java
│  │  │                 │  └── ShooterController.java
│  │  │                 ├── items
│  │  │                 │  ├── Ammo.java
│  │  │                 │  ├── Backpack.java
│  │  │                 │  ├── Collectible.java
│  │  │                 │  ├── Energy.java
│  │  │                 │  └── Usable.java
│  │  │                 ├── openables
│  │  │                 │  ├── Door.java
│  │  │                 │  └── Openable.java
│  │  │                 ├── scenarios  // obsahuje triedy scenarov
│  │  │                 ├── weapons
│  │  │                 │  ├── Bullet.java
│  │  │                 │  ├── Fireable.java
│  │  │                 │  ├── Firearm.java
│  │  │                 │  └── Gun.java
│  │  │                 ├── Direction.java
│  │  │                 ├── Keeper.java
│  │  │                 ├── Main.java
│  │  │                 ├── Movable.java
│  │  │                 └── SpawnPoint.java
│  │  └── resources
│  │     ├── maps
│  │     │  ├── tilesets // contains used tilesets from map
│  │     │  └── map.tmx  // map of your game level
│  │     └── sprites  // contains used sprites of actors
├── .editorconfig
├── .gitignore
├── build.gradle.kts
├── gradlew
├── gradlew.bat
├── README.md
└── settings.gradle.kts

Note: Place the files created as part of your own game level either into one of the listed packages as needed, or create appropriately named and organized new packages. However, keep sk.tuke.kpi.oop.game as the parent package of all classes and interfaces in the project.

Warning

The encoding of all submitted files must be UTF-8. The case of letters in file and directory names matters! It is important that the required files are located in the specified places in the project, otherwise the tests for particular files will fail because they cannot be found.

4.2 Project dependencies

The following dependency settings in the build.gradle.kts file will be assumed when compiling and testing the project:

val gamelibVersion = "2.6.1"

dependencies {
    implementation("sk.tuke.kpi.gamelib:gamelib-framework:$gamelibVersion")
}

5. Evaluation

You can obtain a maximum of 30 points for the assignment. Of this, 15 points are reserved for evaluation of the basic part by automated tests and 15 points for the defense of your own game part of the assignment.

The basic functionality of the game will be evaluated by automated tests (15 points) in the Arena system.

During the assignment defense (15 points), your implementation will be evaluated:

  • from the player’s point of view (max. 5 points)
    • functionality and playability
    • presence of adventure-style steps
    • number of actors involved in the game
    • visual aspect (bonus)
  • from the programmer’s point of view (max. 10 points)
    • programming style (~4 points)
    • use of design patterns (~6 points)

Naturally, the student must be able to answer questions regarding the submitted project. In borderline evaluation cases, additional programming tasks to extend or modify the game may be expected as part of the defense.

Your solutions will be checked for originality. Therefore, when working on your assignment, behave according to the rules of the honor code! If you submit an assignment that is not your own, you will be excluded from the course!