Role: Programmer, Game Designer
Tool: LibGDX, Tiled
Team: Redpact, Team of 7
Timeline: 1 semester
Completion Date: May 18, 2024
Role: Programmer, Game Designer
Tool: LibGDX, Tiled
Team: Redpact, Team of 7
Timeline: 1 semester
Completion Date: May 18, 2024
Role: Programmer, Game Designer
Tool: LibGDX, Tiled
Team: Redpact, Team of 7
Timeline: 1 semester
Completion Date: May 18, 2024
Play ->
Play ->
Play ->
GAME DESIGN
GAME DESIGN
GAME DESIGN
design pillars
design pillars
design pillars
Fast-Paced Strategy
Fast-Paced Strategy
Fast-Paced Strategy
Center the gameplay on dynamic mechanics that demand quick, strategic decision-making.
Center the gameplay on dynamic mechanics that demand quick, strategic decision-making.
Center the gameplay on dynamic mechanics that demand quick, strategic decision-making.
Narrative-Driven
Narrative-Driven
Narrative-Driven
Tie progression and rewards to immersive environments and a compelling narrative, guiding players through diverse, challenging levels.
Tie progression and rewards to immersive environments and a compelling narrative, guiding players through diverse, challenging levels.
Tie progression and rewards to immersive environments and a compelling narrative, guiding players through diverse, challenging levels.
Replayability
Replayability
Replayability
Design levels to encourage replays, allowing players to discover varied paths and experiment with alternative tactics for greater enjoyment.
Design levels to encourage replays, allowing players to discover varied paths and experiment with alternative tactics for greater enjoyment.
Design levels to encourage replays, allowing players to discover varied paths and experiment with alternative tactics for greater enjoyment.
mechanics
mechanics
mechanics
PROGRAMMING
PROGRAMMING
PROGRAMMING
software Architecture
software Architecture
software Architecture
The game’s codebase is structured using the MVC architecture, ensuring a clear separation of responsibilities to enhance readability and maintainability. At the top of this structure is the Root section, which serves as the entry point for the LibGDX program. This centralizes setup and initialization, keeping these processes in one place rather than distributing them across multiple components.
The controller layer is the most complex part of the architecture. It is divided into game modes, including MenuMode, LoadingMode, and GameMode, each serving specific purposes. MenuMode and LoadingMode operate with minimal components, managing menus, loading screens, and level tracking using GameCanvas
. GameMode, in contrast, handles the core gameplay mechanics, such as collision detection and resolution, audio, input handling, and the management of player and enemy AI. Specialized controllers are used for many game features, further organizing this layer.
The models represent the state and data of in-game objects. These models are subcomponents of a central Level model responsible for generating entire game levels. Inheritance is used extensively, with abstract classes defining shared behaviors for objects like characters and tiles. Concrete classes then store detailed information for specific elements such as players, enemies, and destructible tiles.
Below is a screenshot of the dependency diagram that illustrates the game’s architecture:
The game’s codebase is structured using the MVC architecture, ensuring a clear separation of responsibilities to enhance readability and maintainability. At the top of this structure is the Root section, which serves as the entry point for the LibGDX program. This centralizes setup and initialization, keeping these processes in one place rather than distributing them across multiple components.
The controller layer is the most complex part of the architecture. It is divided into game modes, including MenuMode, LoadingMode, and GameMode, each serving specific purposes. MenuMode and LoadingMode operate with minimal components, managing menus, loading screens, and level tracking using GameCanvas
. GameMode, in contrast, handles the core gameplay mechanics, such as collision detection and resolution, audio, input handling, and the management of player and enemy AI. Specialized controllers are used for many game features, further organizing this layer.
The models represent the state and data of in-game objects. These models are subcomponents of a central Level model responsible for generating entire game levels. Inheritance is used extensively, with abstract classes defining shared behaviors for objects like characters and tiles. Concrete classes then store detailed information for specific elements such as players, enemies, and destructible tiles.
Below is a screenshot of the dependency diagram that illustrates the game’s architecture:
The game’s codebase is structured using the MVC architecture, ensuring a clear separation of responsibilities to enhance readability and maintainability. At the top of this structure is the Root section, which serves as the entry point for the LibGDX program. This centralizes setup and initialization, keeping these processes in one place rather than distributing them across multiple components.
The controller layer is the most complex part of the architecture. It is divided into game modes, including MenuMode, LoadingMode, and GameMode, each serving specific purposes. MenuMode and LoadingMode operate with minimal components, managing menus, loading screens, and level tracking using GameCanvas
. GameMode, in contrast, handles the core gameplay mechanics, such as collision detection and resolution, audio, input handling, and the management of player and enemy AI. Specialized controllers are used for many game features, further organizing this layer.
The models represent the state and data of in-game objects. These models are subcomponents of a central Level model responsible for generating entire game levels. Inheritance is used extensively, with abstract classes defining shared behaviors for objects like characters and tiles. Concrete classes then store detailed information for specific elements such as players, enemies, and destructible tiles.
Below is a screenshot of the dependency diagram that illustrates the game’s architecture:
Level Parsing and Generation
Level Parsing and Generation
Level Parsing and Generation
The method parses a JSON representation of the level to instantiate and place interactable objects like players, enemies, and waypoints. It iterates through each object in the layer, extracting attributes such as position, rotation, and type, and invokes specific creation methods (e.g., createPlayer()
, createEnemy()
) to add them to the LevelModel
. Additional properties, such as enemy ID, type, and labels, customize object behavior. This modular approach simplifies level updates and allows seamless addition of new object types without modifying core code.
Below is a code snippet illustrating map generation using a Tiled JSON file for characters and destructible tiles:
The method parses a JSON representation of the level to instantiate and place interactable objects like players, enemies, and waypoints. It iterates through each object in the layer, extracting attributes such as position, rotation, and type, and invokes specific creation methods (e.g., createPlayer()
, createEnemy()
) to add them to the LevelModel
. Additional properties, such as enemy ID, type, and labels, customize object behavior. This modular approach simplifies level updates and allows seamless addition of new object types without modifying core code.
Below is a code snippet illustrating map generation using a Tiled JSON file for characters and destructible tiles:
The method parses a JSON representation of the level to instantiate and place interactable objects like players, enemies, and waypoints. It iterates through each object in the layer, extracting attributes such as position, rotation, and type, and invokes specific creation methods (e.g., createPlayer()
, createEnemy()
) to add them to the LevelModel
. Additional properties, such as enemy ID, type, and labels, customize object behavior. This modular approach simplifies level updates and allows seamless addition of new object types without modifying core code.
Below is a code snippet illustrating map generation using a Tiled JSON file for characters and destructible tiles:
private void initializeCharacterLayer(LevelModel level, JsonValue layer, AssetDirectory directory){
int x,y,rotation;
int id;
String enemyType;
int base = 0;
String type;
String label;
JsonValue objects = layer.get("objects").child();
while (objects != null){
x = objects.getInt("x");
y = objects.getInt("y");
rotation = objects.getInt("rotation");
JsonValue properties = objects.get("properties").child();
type = properties.getString("value");
switch (type){
case "player":
x+= 140;
level.createPlayer(x,(height*64-y),rotation,directory);
break;
case "enemy":
properties = properties.next();
x+= 75;
id = properties.getInt("value");
properties = properties.next();
enemyType = properties.getString("value");
//System.out.println(id);
level.createEnemy(x,height*64-y,rotation,directory,enemyType, new int[] {(int)Math.floor((double) x /64), height - (int)Math.floor((double) y /64)}, id);
break;
case "waypoint":
properties = properties.next();
id = properties.getInt("value");
properties = properties.next();
int pointNumber = properties.getInt("value");
x += 32;
//System.out.println(id);
level.addWaypoint(x,height*64 - y,id,pointNumber);
break;
case "bouncy":
properties = properties.next();
id = properties.getInt("value");
properties = properties.next();
label = properties.getString("value");
level.createBouncy(x,(height*64-y),rotation,directory, id, label, -base);
break;
case "breakable":
properties = properties.next();
id = properties.getInt("value");
properties = properties.next();
label = properties.getString("value");
level.createBreakable(x,(height*64-y),rotation,directory, id, label, -base);
break;
case "goal":
properties = properties.next();
label = properties.getString("value");
level.createGoal(x,(height*64-y),rotation,directory, label, -base);
break;
}
objects = objects.next();
}
}
private void initializeCharacterLayer(LevelModel level, JsonValue layer, AssetDirectory directory){
int x,y,rotation;
int id;
String enemyType;
int base = 0;
String type;
String label;
JsonValue objects = layer.get("objects").child();
while (objects != null){
x = objects.getInt("x");
y = objects.getInt("y");
rotation = objects.getInt("rotation");
JsonValue properties = objects.get("properties").child();
type = properties.getString("value");
switch (type){
case "player":
x+= 140;
level.createPlayer(x,(height*64-y),rotation,directory);
break;
case "enemy":
properties = properties.next();
x+= 75;
id = properties.getInt("value");
properties = properties.next();
enemyType = properties.getString("value");
//System.out.println(id);
level.createEnemy(x,height*64-y,rotation,directory,enemyType, new int[] {(int)Math.floor((double) x /64), height - (int)Math.floor((double) y /64)}, id);
break;
case "waypoint":
properties = properties.next();
id = properties.getInt("value");
properties = properties.next();
int pointNumber = properties.getInt("value");
x += 32;
//System.out.println(id);
level.addWaypoint(x,height*64 - y,id,pointNumber);
break;
case "bouncy":
properties = properties.next();
id = properties.getInt("value");
properties = properties.next();
label = properties.getString("value");
level.createBouncy(x,(height*64-y),rotation,directory, id, label, -base);
break;
case "breakable":
properties = properties.next();
id = properties.getInt("value");
properties = properties.next();
label = properties.getString("value");
level.createBreakable(x,(height*64-y),rotation,directory, id, label, -base);
break;
case "goal":
properties = properties.next();
label = properties.getString("value");
level.createGoal(x,(height*64-y),rotation,directory, label, -base);
break;
}
objects = objects.next();
}
}