CharmingCraft is a top-down action-adventure game built from scratch in Unreal Engine 5 with C++, inspired by Minecraft: Dungeons and Albion Online. I designed and implemented over 10 interconnected gameplay systems, including a custom Gameplay Ability System (GAS) that powers both player actions and item skill extensions, a data-driven buff framework, a Chain of Responsibility damage pipeline, behavior tree AI with Environment Query System (EQS), modular building and farming, a DataAsset-based crafting system, dynamic level streaming with cross-scene item persistence, and a save slot manager built on a double-linked list. The project showcases my ability to architect complex, loosely coupled game systems in C++ while keeping them fully extensible through Blueprint for rapid content iteration. GitHub Repository
Combat and Ability Framework
Item Skill System (Albion Online-Inspired)
One of the most distinctive features of CharmingCraft is its item skill system, directly inspired by Albion Online. Every item in the game can carry multiple skills across 9 distinct skill slots, and players can choose which skills to bind from each item’s skill pool. This creates deep build diversity where the same sword can behave completely differently depending on the player’s skill selection.
I implemented this through UItemDynamicSkill, a skill pool container attached to each item, with EItemDynamicSkillSlot defining 9 slot types: USE, SHIFT, SHIFT_INTERACT, RIGHT_CLICK, HOTBAR_CAST, INTERACT, PASSIVE, ON_HIT, and ON_ATTACK. Each slot serves a different gameplay purpose. PASSIVE slots provide continuous buffs like armor bonuses, ON_HIT slots trigger effects on weapon contact such as frost or poison, and ON_ATTACK slots fire when the player initiates an attack, enabling effects like chain lightning from a cape.
The binding flow works as follows: each item defines its available skills in ItemDynamicSkill.DynamicSkills. When a player opens the skill selection UI, they see all available skills for each slot. The selected skill is stored in ItemMeta.BindItemDynamicSkill as a TMap mapping slot types to UNativeAction instances. The UCraftActionComponent then manages these bound actions at runtime, triggering them based on the corresponding input or event.
Action and Combat System
The combat system is built on a custom Gameplay Ability System (GAS) using Unreal’s GameplayTags infrastructure. I designed a layered action hierarchy where UNativeAction serves as the base class, UNativeItemAction extends it with item stack requirements, UNativeEquipmentAction adds equipment entity actor support, and specialized classes like UNativeStandardMeleeAction and UNativeStandardRangedAction handle specific combat styles.
graph TD
subgraph Action Hierarchy
NA[UNativeAction]
NIA[UNativeItemAction]
NEA[UNativeEquipmentAction]
NSMA[UNativeStandardMeleeAction]
NSRA[UNativeStandardRangedAction]
NOHA[UNativeOnHitAction]
end
NA --> NIA
NIA --> NEA
NIA --> NOHA
NEA --> NSMA
NEA --> NSRA
subgraph Action Lifecycle
CS[CanStart] --> SA[StartAction]
SA --> IR[IsRunning]
IR --> STA[StopAction]
STA --> CD[StartCoolDown]
CD --> CF[CooldownFinished]
end
The melee action system uses continuous line tracing per frame through StartMeleeActionTrace(), checking for hits via MeleeActionTick() and applying damage through OnActionHit(). Ranged actions spawn ABaseActionActor projectiles with their own lifecycle hooks: OnActionActorSpawn(), OnActionActorTick(), OnActionActorHit(), and OnActionActorDestroy(). These action actors support chained behaviors through OnHitActions, OnSpawnActions, and OnTickActions, enabling complex ability compositions like a projectile that spawns area-of-effect flames on impact.
The damage pipeline follows the Chain of Responsibility pattern. Each FHitData carries physical damage, magic damage, true damage, critical hit data, and an OnHitBuffList for applying buffs on contact. The UDamageChain processes damage through a sequence of handlers: PhysicalDamageHandler applies armor reduction, MagicDamageHandler applies magic defense, TrueDamageHandler passes damage unmitigated, and BuffApplicationHandler applies any on-hit buffs. This pattern makes it trivial to add new damage types or processing steps without modifying existing code.
I also implemented a 5-part modular weapon assembly system through ASwordEntityActorP5, which renders Blade, Fuller, Guard, Hilt, and Pommel as separate mesh components. Each part can use different materials and meshes, allowing runtime customization of weapon appearance through UMaterialInstanceDynamic without creating new asset classes.
Buff and Attribute System
The buff system is a self-contained, data-driven framework where designers define buff behavior entirely through UBuffData templates and UBaseBuffModel Blueprint subclasses. UBuffInfo instances track runtime state including remaining duration, current stack count, and references to the instigator and target. The UBuffHandlerComponent manages the active buff list, ticking durations each frame and removing expired buffs.
Stacking and time policies provide fine-grained control: EBuffTimeUpdate determines whether reapplying a buff adds duration, replaces it, or keeps the existing timer. EBuffRemoveStackUpdate controls whether removal clears all stacks or decrements one at a time. The UModifyPropertyBuffModel subclass directly modifies FPlayerAttribute deltas, enabling buffs that boost attack damage, reduce movement speed, or apply damage-over-time effects.
The attribute system centers on UDAttributeComponent, which tracks Health, Mana, Damage, Ability Power, Armour, Magic Defense, Knockback Resistance, Critical Chance, Critical Damage, Attack Speed, Movement Speed, Level, and XP. This component is shared across players and creatures, ensuring consistent combat mechanics throughout the game.
AI and Creature Behavior
I implemented two distinct AI archetypes to demonstrate behavior tree and EQS capabilities. The skeleton enemy uses EQS to evaluate its environment, maintaining distance from the player while executing ranged attacks and self-healing when health drops below a threshold. The Crimson Furbeak is a neutral creature that roams peacefully until attacked, at which point it chases the aggressor. When the attacker moves out of range, the Furbeak returns to its roaming state.
All creatures inherit from ANativeCreature, which implements IDamageable, IMouseInteractInterface, IGameplayTagAssetInterface, and ILootableInterface. The ANativeCreatureAIController automatically runs the creature’s assigned behavior tree on possession. Each creature supports configurable hit response montages mapped by EDamageResponse, spawn point tracking with return-to-spawn logic, and a drop table system for loot generation.
The drop system uses UDropTableData assets where each entry specifies an item material, min/max quantity, and drop probability. Dropped items spawn as ADropItem actors with rotation and vertical bobbing animations, and players pick them up through the interaction system.
Sandbox Systems
Building System
The building system uses a Strategy pattern through UBaseBuildModel to decouple tool-specific placement logic from the core UBuildModuleManager. The manager handles ray tracing from camera to mouse position, grid snapping at 100-unit intervals, collision validation through FPlaceValidation, and visual feedback via AFrameActor preview frames that change color based on placement validity.
When a player equips a building tool, the corresponding UBaseBuildModel subclass activates. UToolBuildModel handles tools like the hoe and pickaxe, while USeedsBuildModel manages seed placement. Each model implements ActivateBuildModel(), StartTrace(), OnPlace(), and DeactivateBuildModel() for its specific behavior. Buildings placed in the world persist across scene transitions, and structures like houses can contain interior sub-levels loaded through TSoftObjectPtr<UWorld>.
Farming System
The farming system reuses the building infrastructure to minimize code duplication. Equipping a Hoe activates the HoeBuildModel, which shows a farmable grid overlay. Clicking valid ground creates a Farm_Land block. Players then equip seeds, which activate the USeedsBuildModel for planting. The system deducts seeds from inventory on placement and manages crop growth through ABlockEntityActor tick logic.
Crafting System
The crafting system is built on UBaseRecipeEntry DataAssets, where each recipe defines its name, namespace, owning container, category, ingredient list, and output items. The URecipeRegistry serves as a central database, loading all recipes at startup into a TMap<FName, FRecipesContainerCollection> organized by container type.
The UBaseCraftHandler validates ingredients through the OnCheckRecipeIngredientMatch event, then broadcasts OnCraftProcessStart and OnCraftProcessFinish during execution. This event-driven approach allows the UI to display progress animations and sound effects without coupling to the craft logic.
Resource Gathering
Resource gathering integrates with Unreal Engine’s Chaos destruction system for visually satisfying breakable resources. When players mine gems or harvest materials, the resource entity fractures using physics simulation before dropping items into the world.
World and Persistence
World Management and Scene Transition
The world system supports three scene types: Regions (persistent open world), Scenes (instanced interiors like houses), and Dungeons (instanced challenge areas). The UWorldManager orchestrates multiple UNativeCraftWorld instances, each wrapping a ULevelStreamingDynamic for efficient memory management through TSoftObjectPtr<UWorld> lazy loading.
Players travel between worlds through ACraftWarpPoint actors, with the manager handling world loading, visibility toggling, and player list tracking. Only one world is visible at a time, and the system automatically hides others during transitions. Items dropped in the world persist across scene changes, maintaining gameplay continuity.
The chunk system through ALandChunk manages world streaming at a granular level, with each chunk tracking its own EChunkState (LOADED, PENDING_UNLOADED, UNLOADED), biome data, resource entity pools, and creature spawn pools.
Save System and Player Creation
The save system centers on UGameSaveManager, which uses a double-linked list (TDoubleLinkedList<FSaveSlotInfo>) for circular navigation through save slots. Each FSaveSlotInfo contains a unique GUID, slot path, display name, and four data containers: UPlayerData for character state and inventory, URealmData for world state, UProgressData for quest tracking, and ULevelData for level-specific information.
The double-linked list structure enables smooth UI navigation where players can scroll endlessly through their save slots in either direction. The system supports slot creation with GenerateDefaultData(), deletion with a bPrepareDelete safety flag, and preview slots for the selection UI. All game objects implement the ISerializable interface with SerializeToJson() and DeserializeFromJson() methods, enabling any UObject to participate in the save pipeline without modifying core systems.
System Architecture Overview
All systems are orchestrated through UCharmingCraftInstance, the central game instance that owns every manager: UGameSaveManager, UWorldManager, UBuildModuleManager, UCameraManager, URecipeRegistry, UNativeDungeonHandler, and UPlayerModeManager. The UGameEventHandler acts as a global event bus with 40+ multicast delegates, enabling loose coupling between all systems.
graph TD
subgraph Game Instance
GI[UCharmingCraftInstance]
end
subgraph Core Managers
SM[UGameSaveManager]
WM[UWorldManager]
BM[UBuildModuleManager]
CM[UCameraManager]
RR[URecipeRegistry]
DH[UNativeDungeonHandler]
PM[UPlayerModeManager]
end
subgraph Event Bus
GEH[UGameEventHandler]
end
subgraph Entity Systems
PC[ANativePlayerCharacter]
NC[ANativeCreature]
DI[ADropItem]
end
subgraph Shared Components
AC[UCraftActionComponent]
IC[UInventoryComponent]
EC[UEquipmentComponent]
DA[UDAttributeComponent]
BC[UBuffHandlerComponent]
end
GI --> SM
GI --> WM
GI --> BM
GI --> CM
GI --> RR
GI --> DH
GI --> PM
GI --> GEH
GEH -.->|broadcasts| PC
GEH -.->|broadcasts| NC
GEH -.->|broadcasts| BM
GEH -.->|broadcasts| WM
PC --> AC
PC --> IC
PC --> EC
PC --> DA
PC --> BC
NC --> AC
NC --> IC
NC --> DA
NC --> BC
Design Philosophy
Data-Driven Content — Every major system uses DataAssets or Blueprint-subclassable base classes for content definition. Buff behaviors, crafting recipes, drop tables, item skills, and creature configurations are all authored without C++ compilation, enabling rapid iteration.
Event-Driven Decoupling — The UGameEventHandler centralizes 40+ multicast delegates across world management, inventory, building, crafting, combat, and movement categories. Systems communicate through events rather than direct references, eliminating circular dependencies and enabling modular development.
Strategy Pattern for Extensibility — The building system’s UBaseBuildModel, the damage pipeline’s UDamageHandler chain, and the buff system’s UBaseBuffModel all follow the Strategy pattern. New tools, damage types, and buff effects plug in as subclasses without touching existing code, adhering to the Open-Closed Principle.
Component-Based Entity Architecture — Players and creatures share the same component set (UDAttributeComponent, UCraftActionComponent, UBuffHandlerComponent, UInventoryComponent), ensuring consistent combat mechanics across all entities. This composition-over-inheritance approach makes it straightforward to add new entity types with any combination of capabilities.
Interface-Driven Serialization — The ISerializable interface with SerializeToJson() and DeserializeFromJson() allows any UObject to participate in the save pipeline. This decouples persistence logic from game logic, so new saveable objects require zero changes to the save manager.