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>(extendsAbstractAction)- constructor
public Drop()
- constructor
- class
Fire<A extends Armed>(extendsAbstractAction)- constructor
public Fire()
- constructor
- class
Move<A extends Movable>(implementsAction)- constructor
public Move(Direction direction, float duration) - method
public void stop()
- constructor
- class
Shift<K extends Keeper>(extendsAbstractAction)- constructor
public Shift()
- constructor
- class
Take<K extends Keeper>(extendsAbstractAction)- constructor
public Take()
- constructor
- class
Use<A extends Actor>(extendsAbstractAction)- constructor
public Use(Usable<A> usable) - method
public Disposable scheduleForIntersectingWith(Actor mediatingActor)
- constructor
- class
- behaviours:
- interface
Behaviour<A extends Actor>- method
void setUp(A actor)
- method
- class
Observing<T, A extends Actor>(implementsBehaviour)- constructor
public Observing(Topic<T> topic, Predicate<T> predicate, Behaviour<A> delegate)
- constructor
- class
RandomlyMoving(implementsBehaviour)- constructor
public RandomlyMoving()
- constructor
- interface
- characters
- class
Alien(extendsAbstractActor; implementsMovable,Alive, andEnemy)- constructor
public Alien() - constructor
public Alien(int healthValue, Behaviour<? super Alien> behaviour)
- constructor
- interface
Alive(extendsActor)- method
Health getHealth()
- method
- interface
Armed(extendsActor)- method
Firearm getFirearm() - method
void setFirearm(Firearm firearm)
- method
- interface
Enemy(extendsActor) - 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()
- method
- constructor
- class
Ripley(extendsAbstractActor; implementsAlive,Armed,Keeper, andMovable)- constructor
public Ripley() - static field
public static Topic<Ripley> RIPLEY_DIED
- constructor
- class
- controllers:
- class
KeeperController(implementsKeyboardListener)- constructor
public KeeperController(Keeper keeper)
- constructor
- class
MovableController(implementsKeyboardListener)- constructor
public MovableController(Movable actor)
- constructor
- class
ShooterController(implementsKeyboardListener)- constructor
public ShooterController(Armed shooter)
- constructor
- class
- items:
- class
Ammo(extendsAbstractActor, implementsUsable)- constructor
public Ammo()
- constructor
- class
Backpack(implementsActorContainer)- constructor
public Backpack(String name, int capacity)
- constructor
- interface
Collectible(extendsActor) - class
Energy(extendsAbstractActor, implementsUsable)- constructor
public Energy()
- constructor
- interface
Usable<A extends Actor>- method
void useWith(A actor) - method
Class<A> getUsingActorClass()
- method
- class
- openables:
- class
Door(extendsAbstractActor, implementsOpenableandUsable)- 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
- enumeration
- interface
Openable(extendsActor)- method
void open() - method
void close() - method
boolean isOpen()
- method
- class
- weapons:
- class
Bullet(extendsAbstractActor, implementsFireable)- constructor
public Bullet()
- constructor
- interface
Fireable(extendsMovable) - 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()
- constructor
- class
Gun(extendsFirearm)- constructor
public Gun(int initAmmo, int maxAmmo)
- constructor
- class
- 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)
- values
- interface
Keeper(extendsActor)- method
Backpack getBackpack()
- method
- class
Main- static method
public static void main(String[] args)
- static method
- interface
Movable(extendsActor)- method
int getSpeed() - method
default void startedMoving(Direction direction) {} - method
default void stoppedMoving() {} - method
default void collidedWithWall() {}
- method
- class
SpawnPoint(extendsAbstractActor)- constructor
public SpawnPoint(int spawnAliens)
- constructor
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:
- No use of unchecked operations or raw types.
- Use only private member variables (with the exception of static variables).
- Adherence to the rules enforced by the PMD tool, which are defined in this pmd-ruleset.xml file (guide for setting up local execution).
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.gameas 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!