WARNING: Site Under Maintenance
Many things are still unfinished.
Project in Active Development
This project is an FPS game which is heavily inspired by the System Shock Remake. The development of this project came about because I wanted to learn how to effectively create Modules and use them in my projects. Almost all core features are stored in their own Modules making the code portable and hopefully more organized.
Whenever adding a new feature into the project, I always try to separate the code into modules that make sense.
Some modules are dependent on others. An example of this being how the Equippables Module requires the
Interaction Modules. The current setup for dependencies looks something like this:
Interaction System
Equippables
Weapons
Inventory System
Inventory System Editor
For a character to interact with a target they need to have a Character Interact Component. This component has two different modes that can be enabled, an Area Interact Mode, and a Forward Interact Mode. The Area Interact Mode will check in a specified radius around the character for Interactables and will select the best one based on distance and how "in-front" (using Dot Product) of the character it is. The Forward Interact requires that the character has a camera, if they do, it shoots a trace from the Cameras position forward. If Area Interact is enabled alongside Forward Interact, the Forward Interact will always take priority.
Interactable Actors are the base class for any object that wants to easily include interaction logic. Utilizing an Interface, the object will toggle a UI Widget describing the interactable and will have a virtual function that defines what happens when interacted with. The UI widget can either be set to static on screen, or hover over the object in the world. This is controlled in the Interact Settings globally, or it can be overridden on a per-actor basis.
An Equippable is the base class for an object that can be picked up and equipped. The Actor that requests the pickup needs to have an Equipment Inventory Component for the pickup to be successful. The component will keep track of all carried Equipment and has slots that can carry a specified amount of equippables.
Guns inherit from Equippables, meaning they share the same pickup and Equip logic. By default, they include a Shooting Component and will fire when used. The shooting component, like it's name implies, handles everything an actor would need to shoot a projectile. It can fire either a Hitscan or Physical projectile with various parameters like ammo, fire rate, spread, recoil, and more being easily modifiable. Secondary and Tertiary actions can be easily added to guns via virtual functions both in C++ or in Blueprints, making it easier to design weapons that perform unique actions, e.g. A grenade launcher secondary fire.
Shooting Components have the option to enable recoil. Recoil works by setting a target rotation that the camera will attempt to interpolate to. Recoil Recovery has been implemented, meaning that once the recoil reaches its target, it will quickly snap back to where the first shot was fired.
The logic of Explosions is handled in an Explosive Component. They feature Fuse Times, a Health feature, and customizable Blast Radius, Damage, and Physics Impulse. To avoid the issue of invalid references when an explosion triggers another explosion, I've made an Explosion Queue system. This way whenever an explosion is supposed to occur, instead of immediately activating, it adds itself to a global queue. Every tick the queue triggers its next available explosive.
The Inventory uses a slot system. In the Inventory Component you can specify the number of slots available and the number of columns (for the UI elements). Inventory Items are stored as Data Assets. The Data Assets contain information like the name of the item and the icon to show in the inventory UI. The UI is split into 3 widget classes (Inventory Widget, Inventory Slot Widget, and Inventory Move Widget). The Inventory Slots are assigned by fetching the Index of an inventory item based upon their row and column position. They can be picked up and moved by clicking on an occupied slot and then clicking on a target slot.