- Introduction
- Project Structure
- Naming Conventions
- Blueprints
- C++ Coding Standards
- Asset Management
- Level Design
- Performance Optimization
- Multiplayer and Networking
- UI/UX Design
- Animation
- Audio
- Version Control
- Testing and Quality Assurance
- Documentation
- Build and Deployment
- Cross-Platform Development
- Team Collaboration
This document outlines the standard conventions and best practices for Unreal Engine development at Bayat. These guidelines aim to ensure consistency, maintainability, and scalability across all Unreal Engine projects.
ProjectName/
├── Config/ # Project configuration files
├── Content/ # All project assets
│ ├── Characters/ # Character assets
│ │ ├── Player/ # Player character assets
│ │ └── NPCs/ # Non-player character assets
│ ├── Environment/ # Environment assets
│ │ ├── Landscapes/ # Landscape assets
│ │ ├── Props/ # Prop assets
│ │ └── Materials/ # Environment materials
│ ├── Gameplay/ # Gameplay-related assets
│ │ ├── Abilities/ # Ability system assets
│ │ ├── Items/ # Item assets
│ │ └── Mechanics/ # Gameplay mechanics
│ ├── UI/ # User interface assets
│ │ ├── HUD/ # Heads-up display assets
│ │ ├── Menus/ # Menu assets
│ │ └── Common/ # Common UI elements
│ ├── Audio/ # Audio assets
│ │ ├── Music/ # Music tracks
│ │ ├── SFX/ # Sound effects
│ │ └── Dialogue/ # Dialogue recordings
│ ├── VFX/ # Visual effects
│ ├── Maps/ # Level maps
│ │ ├── Levels/ # Gameplay levels
│ │ └── Sublevels/ # Streaming sublevels
│ ├── Core/ # Core systems
│ │ ├── GameModes/ # Game mode assets
│ │ ├── GameStates/ # Game state assets
│ │ └── PlayerStates/ # Player state assets
│ └── _Dev/ # Development-only assets
│ ├── Developers/ # Developer-specific folders
│ └── Testing/ # Testing assets
├── Source/ # C++ source code
│ ├── ProjectName/ # Main project source
│ │ ├── Characters/ # Character classes
│ │ ├── Gameplay/ # Gameplay classes
│ │ ├── UI/ # UI classes
│ │ └── Core/ # Core system classes
│ └── ProjectNameEditor/ # Editor-specific code
├── Plugins/ # Project-specific plugins
└── Documentation/ # Project documentation
- Group assets by type and functionality
- Use consistent naming across folders
- Keep a clean separation between different asset categories
- Maintain a clear hierarchy for ease of navigation
- Use subfolders to avoid overcrowded directories
- Use PascalCase for all asset names
- Use descriptive names that clearly indicate the asset's purpose
- Avoid abbreviations unless they are widely understood
- Use prefixes to indicate asset types
- Be consistent with pluralization
Asset Type | Prefix | Example |
---|---|---|
Blueprint | BP_ | BP_PlayerCharacter |
Material | M_ | M_Wood |
Material Instance | MI_ | MI_WoodPainted |
Texture | T_ | T_WoodDiffuse |
Static Mesh | SM_ | SM_Chair |
Skeletal Mesh | SK_ | SK_PlayerCharacter |
Animation Blueprint | ABP_ | ABP_PlayerCharacter |
Animation Sequence | A_ | A_PlayerIdle |
Particle System | PS_ | PS_Fire |
Widget Blueprint | WBP_ | WBP_MainMenu |
Sound Cue | SC_ | SC_Explosion |
Level | LVL_ | LVL_MainMenu |
Data Asset | DA_ | DA_WeaponStats |
Data Table | DT_ | DT_EnemySpawnRates |
- Classes: Use PascalCase with 'A' prefix for Actors, 'U' for UObjects
- Example:
APlayerCharacter
,UHealthComponent
- Example:
- Interfaces: Use PascalCase with 'I' prefix
- Example:
IInteractable
,IDamageable
- Example:
- Variables: Use camelCase with descriptive names
- Example:
healthPoints
,movementSpeed
- Example:
- Functions: Use PascalCase for public functions, camelCase for private
- Example:
ApplyDamage()
,calculateDamageMultiplier()
- Example:
- Enums: Use PascalCase with 'E' prefix
- Example:
EWeaponType
,EDamageType
- Example:
- Constants: Use ALL_CAPS with underscores
- Example:
MAX_HEALTH
,DEFAULT_SPEED
- Example:
- Keep Blueprint graphs clean and organized
- Use functions and macros for reusable logic
- Group related nodes using comments
- Use event dispatchers for communication between Blueprints
- Implement interfaces for common functionality
- Prefer functions over macros when possible
- Use Blueprint interfaces for polymorphism
- Keep execution chains short and readable
- Break complex logic into smaller functions
- Use Blueprint Function Libraries for utility functions
- Implement proper error handling
- Minimize the use of "Tick" events
- Use timers instead of continuous checks
- Cache references to frequently accessed objects
- Avoid complex calculations in loops
- Use Blueprint nativization for performance-critical Blueprints
- Use direct references for parent-child communication
- Use interfaces for unrelated Blueprint communication
- Use event dispatchers for one-to-many communication
- Use Game Instance, Game State, or Player State for global data
- Follow the Unreal Engine coding standard
- Group related functionality into classes
- Use components for modular functionality
- Keep header files clean and minimal
- Use forward declarations to minimize dependencies
- Use UPROPERTY and UFUNCTION macros for engine integration
- Implement proper memory management
- Use smart pointers for non-UObject pointers
- Follow the Rule of Three/Five for custom resource management
- Use const correctness throughout the codebase
// Good example
UCLASS()
class PROJECTNAME_API AWeapon : public AActor
{
GENERATED_BODY()
public:
AWeapon();
UFUNCTION(BlueprintCallable, Category = "Weapon")
virtual void Fire();
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Weapon")
float Damage;
protected:
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Components")
USkeletalMeshComponent* WeaponMesh;
UPROPERTY(EditDefaultsOnly, Category = "Effects")
UParticleSystem* MuzzleFlash;
private:
UPROPERTY()
ACharacter* OwningCharacter;
float LastFireTime;
};
- Use BlueprintCallable functions for Blueprint access
- Expose properties with appropriate specifiers
- Use BlueprintImplementableEvents for Blueprint overrides
- Create Blueprint function libraries for utility functions
- Use BlueprintNativeEvent for functions with default implementations
- Use appropriate texture sizes (powers of 2)
- Set proper compression settings based on texture type
- Use texture atlases for related small textures
- Implement proper mip-mapping
- Use normal maps for detail on low-poly models
- Create a material library with base materials
- Use material instances for variations
- Implement material functions for reusable operations
- Use material parameter collections for global parameters
- Optimize material complexity for target platforms
- Use appropriate LODs (Levels of Detail)
- Optimize polygon count for target platforms
- Set up proper collision
- Use proper UV mapping
- Implement proper vertex normals and tangents
- Create clean, efficient rigs
- Use appropriate bone counts
- Set up proper physics assets
- Implement socket naming conventions
- Use proper LODs for skeletal meshes
- Use persistent levels for common elements
- Implement streaming sublevels for large worlds
- Group related actors in folders
- Use level blueprints sparingly
- Implement proper level bounds
- Use occlusion culling
- Implement proper LOD transitions
- Use instanced static meshes for repeated elements
- Implement distance-based streaming
- Use light baking for static lighting
- Plan level streaming zones
- Use world composition for large open worlds
- Implement proper level transitions
- Use landscape streaming for large terrains
- Set up proper preloading volumes
- Minimize actors in the world
- Use efficient algorithms
- Implement proper threading
- Optimize AI and behavior trees
- Use timers instead of per-frame checks
- Optimize material complexity
- Reduce overdraw
- Use appropriate texture resolutions
- Implement proper LODs
- Optimize lighting and shadows
- Use asset streaming
- Implement proper garbage collection
- Optimize texture and mesh memory usage
- Use object pooling for frequently spawned objects
- Implement proper reference handling
- Use Unreal Insights for performance analysis
- Implement stat commands for specific metrics
- Use the GPU Visualizer
- Implement memory profiling
- Use automation testing for performance regression
- Design with client-server model in mind
- Implement proper authority checks
- Use replicated properties for synchronized state
- Implement RPC (Remote Procedure Calls) for events
- Design for network bandwidth optimization
- Use replicated properties for state synchronization
- Implement proper replication conditions
- Use RepNotify for change notifications
- Optimize replication frequency
- Implement proper ownership and relevancy
// Good replication example
UPROPERTY(Replicated)
float Health;
UPROPERTY(ReplicatedUsing = OnRep_IsReloading)
bool bIsReloading;
UFUNCTION()
void OnRep_IsReloading();
virtual void GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const override;
// In CPP file
void AWeapon::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
{
Super::GetLifetimeReplicatedProps(OutLifetimeProps);
DOREPLIFETIME(AWeapon, Health);
DOREPLIFETIME_CONDITION(AWeapon, bIsReloading, COND_SkipOwner);
}
- Implement proper network relevancy
- Use network compression
- Optimize RPC frequency
- Implement client-side prediction
- Use network prioritization
- Use widget blueprints for UI elements
- Implement proper widget hierarchy
- Use data binding when possible
- Create reusable UI components
- Implement proper focus navigation
- Design for different screen resolutions
- Implement proper scaling
- Use consistent styling
- Create responsive layouts
- Implement proper input handling
- Use anchors and alignment for responsive design
- Implement proper widget navigation
- Use animation for transitions
- Create style guides for consistent UI
- Implement proper accessibility features
- Use state machines for character animations
- Implement blend spaces for smooth transitions
- Use animation notifies for events
- Create modular animation graphs
- Implement proper animation caching
- Use root motion when appropriate
- Implement proper animation blending
- Use additive animations for variations
- Create reusable animation assets
- Implement proper animation compression
- Use appropriate animation LODs
- Implement animation budgets
- Use animation caching
- Optimize animation blueprint complexity
- Implement proper culling for animations
- Create a consistent audio hierarchy
- Use sound classes for grouping
- Implement sound mixes for audio control
- Use sound cues for complex audio
- Create reusable audio components
- Use attenuation settings for spatial audio
- Implement proper audio prioritization
- Use concurrency settings to manage voice count
- Implement dynamic audio based on gameplay
- Use audio occlusion when appropriate
- Implement proper audio compression
- Use streaming for long audio files
- Implement voice limiting
- Use appropriate sample rates
- Optimize audio memory usage
- Use Git or Perforce for version control
- Implement proper branching strategy
- Use meaningful commit messages
- Create stable release branches
- Implement proper merge procedures
- Use .uasset file locking
- Implement proper binary file handling
- Use the Unreal Editor source control integration
- Create proper .gitignore or P4ignore files
- Implement proper large file handling
- Implement unit tests for C++ code
- Use the Automation Testing framework
- Create functional tests for gameplay features
- Implement performance testing
- Use continuous integration for automated testing
- Create test plans for features
- Implement bug tracking procedures
- Use proper QA environments
- Create regression test suites
- Implement proper versioning for testing
- Document all public APIs
- Use proper comment formatting
- Create class and function documentation
- Document complex algorithms
- Keep documentation up-to-date with code changes
- Create design documents
- Implement technical specifications
- Document asset creation workflows
- Create onboarding documentation
- Maintain up-to-date project guidelines
- Create proper build configurations
- Implement automated build processes
- Use proper versioning
- Create distribution packages
- Implement proper DLC support
- Create release checklists
- Implement proper platform-specific deployment
- Use continuous deployment when appropriate
- Create proper update procedures
- Implement proper version tracking
- Design for multiple platforms from the start
- Implement proper platform abstractions
- Use platform-specific optimizations
- Create scalable content for different hardware
- Implement proper input handling for all platforms
- Create platform-specific asset LODs
- Implement proper shader complexity for each platform
- Use platform-specific rendering features
- Optimize memory usage for mobile platforms
- Implement proper loading screens for slower platforms
- Define clear roles and responsibilities
- Implement proper task tracking
- Use regular code reviews
- Create collaborative design processes
- Implement proper knowledge sharing
- Use clear and concise communication
- Document decisions and rationales
- Create proper handoff procedures
- Implement regular status updates
- Use proper issue reporting procedures