A 2D game developed with LibGDX where players navigate a boat through ocean waters to collect floating trash before the sea turtle does, while avoiding hazardous rocks. Players must strategically maneuver to collect debris while managing collisions with environmental obstacles. The sea turtle actively competes with the player for trash, using sophisticated AI movement strategies to seek out and collect debris, making it a race against time and clever navigation to clean the ocean first.
- LibGDX Framework: Cross-platform Java game development framework
- Box2D Physics: For collision detection and realistic movement physics
- Component-Based Architecture: Clear separation between engine and game implementation
- Design Patterns: Strategy, Builder, Factory Method, Composite, Visitor, and more
project/
├── game/
│ ├── Main.java # Application entry point
│ ├── application/ # Game-specific implementations
│ │ ├── entity/ # Game entities (Boat, Rock, Trash, etc.)
│ │ │ ├── api/ # Entity-related interfaces
│ │ │ ├── factory/ # Entity factory implementations
│ │ │ ├── flyweight/ # Texture flyweight implementations
│ │ │ ├── item/ # Collectible item implementations
│ │ │ ├── npc/ # Non-player character implementations
│ │ │ ├── obstacle/ # Obstacle implementations
│ │ │ └── player/ # Player entity implementations
│ │ ├── movement/ # Movement system implementations
│ │ │ ├── api/ # Movement interfaces
│ │ │ ├── builder/ # Movement builder implementations
│ │ │ ├── composite/ # Composite movement strategies
│ │ │ ├── decorator/ # Strategy decorators
│ │ │ ├── factory/ # Movement factory implementations
│ │ │ └── strategy/ # Concrete movement strategies
│ │ └── scene/ # Game scenes (Menu, Game, etc.)
│ │ ├── factory/ # Scene factory implementations
│ │ ├── main/ # Main gameplay scenes
│ │ ├── overlay/ # Overlay and transition scenes
│ │ └── ui/ # User interface components
│ ├── common/ # Common utilities and exceptions
│ │ ├── config/ # Configuration management
│ │ ├── exception/ # Custom exceptions
│ │ ├── logging/ # Logging utilities
│ │ └── util/ # General utilities
│ └── engine/ # Core engine (abstract, reusable)
│ ├── asset/ # Asset management
│ ├── audio/ # Audio system
│ ├── constant/ # Configuration system
│ ├── entitysystem/ # Entity component system
│ │ ├── entity/ # Base entity framework
│ │ ├── movement/ # Movement management
│ │ └── physics/ # Physics and collision system
│ ├── io/ # Input/output handling
│ ├── logging/ # Logging implementation
│ └── scene/ # Scene management
The engine provides a framework of abstract components that can be reused across different games:
- API Interfaces: Define contracts for core game components
- Scene Management: Abstract scene handling, transitions, rendering pipeline
- Entity System: Generic entity framework with collision, movement, and rendering
- Audio System: Music and sound effect management
- Input/Output: Input handling and IO operations
- Logging: Extensible logging system
- Configuration: Profile-based configurable constants system
Game-specific implementations built on top of the engine:
- Entities: Boat, Sea Turtle, Rock, Trash with specific behaviors
- Movement Strategies: Different AI patterns (interceptor, obstacle avoidance, etc.)
- Scene Implementation: Menu, Game, Options, GameOver screens
- Game Constants: Game-specific configurations and parameters
- Factories: Creates game objects with appropriate configurations
- Advanced Movement AI: Various enemy movement patterns using the Strategy Pattern
- Configurable Controls: Rebindable key controls
- Audio Management: Background music and sound effects with volume controls
- Physics-Based Collisions: Using Box2D for realistic interactions
- Scene Management: Smooth transitions between game states
- Configuration Management: JSON-based configuration with profiles
The codebase demonstrates exemplary use of OOP principles and design patterns across various systems:
-
Single Responsibility Principle:
- Each class has a well-defined purpose (e.g.,
MovementManagermanages movement,SceneManagermanages scenes) - Abstract base classes like
AbstractMovementStrategyhandle common functionality while concrete implementations focus on specific behaviors
- Each class has a well-defined purpose (e.g.,
-
Open/Closed Principle:
- The engine is designed to be extended without modification
- Movement system can be extended with new strategies without modifying existing code
- New scenes can be added without changing the scene management system
-
Liskov Substitution Principle:
- Extensive use of interfaces ensures subtypes can substitute base types
- For example, any
IMovementStrategyimplementation can be used with anyMovementManager
-
Interface Segregation Principle:
- Specialized interfaces like
IMovable,IPositionable, andIMovementStrategy - Each interface focuses on specific behaviors rather than being overly broad
- Specialized interfaces like
-
Dependency Inversion Principle:
- Heavy use of dependency injection through constructors
- Components depend on abstractions (interfaces) rather than concrete implementations
- Factory patterns further decouple component creation from usage
-
Singleton:
AudioManager,MusicManager, andSoundManageruse singleton patternMovementStrategyFactoryimplements singleton for centralized strategy creation- Provides global access while ensuring single instance management
-
Factory Method:
MovementStrategyFactorycreates various movement strategiesSceneFactoryhandles scene creation and registrationRockFactoryandTrashFactorycreate game objects
-
Abstract Factory:
IMovementStrategyFactorydefines an interface for creating movement strategies- Different factory implementations can produce different families of related objects
- Allows for swapping out entire families of strategies
-
Builder:
AbstractMovementBuilderprovides a base for fluent buildersPlayerMovementBuilderandNPCMovementBuilderextend it with specific configurations- Method chaining with type-safe generics (e.g.,
withObstacleAvoidance().withConstantMovement())
-
Prototype:
- Entities can be cloned to create new instances with similar properties
ObjectPoolimplementation leverages prototype-like behavior- Efficient creation of multiple similar objects
-
Adapter (6):
- Adapts external libraries (like Box2D) to the game's interfaces
- Shields game code from third-party API changes
CollidableEntityHandleradapts collision interfaces
-
Composite:
CompositeMovementStrategycombines multiple strategies with weighted influences- Allows complex behaviors through composition of simple strategies
InterceptorAvoidanceStrategyandOceanCurrentStrategydemonstrate practical usage
-
Proxy:
- Lazy loading of audio resources through proxy objects
- Audio files are only loaded when needed
- Reduces initial loading time and memory usage
-
Flyweight:
TextureFlyweightFactoryshares texture resources- Shared assets minimize memory usage
- Ensures assets are loaded only once with efficient reference management
-
Facade:
AudioManagerprovides a simplified interface to the complex audio subsystems- Clients interact with a single class rather than multiple audio components
- Encapsulates the complexities of audio resource management
-
Bridge:
- Separation between entity abstraction and implementation
- Movement behaviors can be changed independently of entity types
- Decouples abstraction hierarchies from implementation hierarchies
-
Decorator:
MovementStrategyDecoratorallows for dynamic enhancement of strategies- Strategies can be combined and enhanced without changing their base implementation
- Additional behaviors can be added at runtime
-
Template Method:
AbstractLoggerdefines the logging algorithm structureAbstractConfigurationLoaderprovides template methods for configuration operationsAbstractMovementStrategyprovides template for common movement behavior- Subclasses implement the specific behaviors
-
Mediator:
CollisionManageracts as a mediator between collidable objects- Centralizes collision logic instead of distributing it across entities
- Reduces dependencies between individual entities
-
Chain of Responsibility:
- Collision handlers form a chain for processing different collision types
- Each handler decides whether to process the collision or pass it to the next handler
- Allows for flexible handling of various collision scenarios
-
Observer:
- Audio volume changes notify registered listeners
- UI components observe and respond to audio state changes
- Entity removal listeners observe when entities are destroyed
- Decouples event sources from event handlers
-
Strategy:
- Multiple movement strategies implement the
IMovementStrategyinterface - Strategies like
ObstacleAvoidanceStrategy,FollowMovementStrategy, andZigZagMovementStrategy - Movement strategies can be swapped at runtime
- Multiple movement strategies implement the
-
Command:
ICollisionOperationencapsulates collision responses- Collision callbacks execute appropriate commands based on collision type
- Decouples collision detection from collision response logic
-
State:
- Scene transitions represent different game states
- Each scene encapsulates state-specific behavior
SceneManagerhandles state transitions
-
Visitor:
ICollidableVisitorinterface for type-safe collision handling- Double dispatch with
visitandacceptmethods to handle different entity types - Eliminates the need for type checking and casting
The game includes multiple AI movement strategies including:
- Obstacle Avoidance: NPCs navigate around obstacles with dynamic path adjustment
- Interceptor Movement: Entities predict and intercept moving targets
- Spring-Follow: Physics-based following with spring-like behavior
- Orbital Movement: Entities orbit around a target
- Zigzag Movement: Creates unpredictable zigzag patterns
- Spiral Approach: Entities approach a target in a spiral pattern
- Randomized Movement: Randomly selects from a pool of strategies
- Composite Movement: Combines multiple strategies with weighted influence
All strategies are composable through the Strategy and Composite patterns, enabling complex behaviors from simpler components.
- JDK 8 or higher
- Gradle 7.x or higher
To set up the project:
git clone [repository-url]
cd Ocean-SweepersRun the game using Gradle:
./gradlew lwjgl3:runBuild a distributable JAR:
./gradlew lwjgl3:jarThis project uses Gradle to manage dependencies.
The Gradle wrapper was included, so you can run Gradle tasks using gradlew.bat or ./gradlew commands.
Useful Gradle tasks and flags:
--continue: when using this flag, errors will not stop the tasks from running.--daemon: thanks to this flag, Gradle daemon will be used to run chosen tasks.--offline: when using this flag, cached dependency archives will be used.--refresh-dependencies: this flag forces validation of all dependencies. Useful for snapshot versions.build: builds sources and archives of every project.cleanEclipse: removes Eclipse project data.cleanIdea: removes IntelliJ project data.clean: removesbuildfolders, which store compiled classes and built archives.eclipse: generates Eclipse project data.idea: generates IntelliJ project data.lwjgl3:jar: builds application's runnable jar, which can be found atlwjgl3/build/libs.lwjgl3:run: starts the application.test: runs unit tests (if any).
Note that most tasks that are not specific to a single project can be run with name: prefix, where the name should be replaced with the ID of a specific project.
For example, core:clean removes build folder only from the core project.
The architecture follows a layered approach:
- Engine Layer: Provides abstractions and reusable components
- Application Layer: Implements game-specific logic on top of the engine
- API Layer: Interfaces that define contracts between components
- Implementation Layer: Concrete implementations of those interfaces
This separation allows:
- Clean dependency management (lower layers don't depend on higher layers)
- Easier testing through interface-based mock objects
- Flexibility to change implementations without affecting other parts of the system
- Potential reuse of the engine for different game projects