diff --git a/docs/docs/advanced/editor-tools.md b/docs/docs/advanced/editor-tools.md new file mode 100644 index 0000000..e14c5c5 --- /dev/null +++ b/docs/docs/advanced/editor-tools.md @@ -0,0 +1,735 @@ +# Editor Tools Guide + +This guide covers the specialized editor tools and workflows provided by EasyBallistics for creating and managing ballistic assets. + +## Asset Creation System + +### Ballistics Category + +EasyBallistics adds a dedicated "Ballistics" category to the Content Browser asset creation menu: + +1. **Right-click** in Content Browser +2. Navigate to **Ballistics** category +3. Choose from available asset types: + - **Bullet Properties** - Define projectile characteristics + - **Material Response Map** - Configure surface interactions + - **Mathematical Material Properties** - Advanced material definitions + +### Asset Factories + +The plugin includes specialized asset factories for streamlined creation: + +```cpp +// Bullet Properties Factory +class FEBBulletPropertiesFactory : public UFactory +{ +public: + FEBBulletPropertiesFactory() + { + SupportedClass = UEBBulletPropertiesAsset::StaticClass(); + bCreateNew = true; + bEditAfterNew = true; + } + + virtual UObject* FactoryCreateNew(UClass* Class, UObject* InParent, + FName Name, EObjectFlags Flags, + UObject* Context, + FFeedbackContext* Warn) override + { + return NewObject(InParent, Class, Name, Flags); + } +}; +``` + +## Physical Material Integration + +### Enhanced Material Editor + +EasyBallistics extends the Physical Material editor with ballistic properties: + +#### Auto-Configuration +- **Smart Detection**: Automatically configures properties based on material names +- **Common Presets**: Steel, wood, concrete, fabric presets +- **One-Click Setup**: Generate appropriate ballistic properties instantly + +#### Custom Properties Panel +```cpp +// Custom details panel for Physical Materials +class FEBPhysicalMaterialCustomization : public IDetailCustomization +{ +public: + virtual void CustomizeDetails(IDetailLayoutBuilder& DetailBuilder) override + { + // Add ballistic properties section + IDetailCategoryBuilder& BallisticsCategory = + DetailBuilder.EditCategory("Ballistics"); + + // Add custom property widgets + BallisticsCategory.AddCustomRow(LOCTEXT("CreateBallistics", "Create Ballistics")) + .WholeRowContent() + [ + SNew(SButton) + .Text(LOCTEXT("CreateNew", "Create New Ballistic Properties")) + .OnClicked(this, &FEBPhysicalMaterialCustomization::OnCreateNewClicked) + ]; + } +}; +``` + +### Material Property Creation + +#### Automatic Property Generation +```cpp +// Auto-generate properties based on material name +UEBMaterialPropertiesAsset* AutoGenerateProperties(UPhysicalMaterial* PhysMat) +{ + FString MaterialName = PhysMat->GetName().ToLower(); + + if (MaterialName.Contains("steel") || MaterialName.Contains("metal")) + { + return CreateSteelProperties(); + } + else if (MaterialName.Contains("wood")) + { + return CreateWoodProperties(); + } + else if (MaterialName.Contains("concrete")) + { + return CreateConcreteProperties(); + } + + return CreateDefaultProperties(); +} +``` + +#### Property Templates +```cpp +// Steel template +FMathematicalMaterialProperties CreateSteelProperties() +{ + FMathematicalMaterialProperties Props; + Props.DensityGPerCm3 = 7.85f; + Props.MaterialHardness = 200.0f; + Props.TensileStrengthMPa = 400.0f; + Props.BallisticLimitVelocity = 800.0f; + return Props; +} + +// Wood template +FMathematicalMaterialProperties CreateWoodProperties() +{ + FMathematicalMaterialProperties Props; + Props.DensityGPerCm3 = 0.6f; + Props.MaterialHardness = 20.0f; + Props.TensileStrengthMPa = 50.0f; + Props.BallisticLimitVelocity = 300.0f; + return Props; +} +``` + +## Asset Type Actions + +### Bullet Properties Actions + +```cpp +class FEBBulletPropertiesActions : public FAssetTypeActions_Base +{ +public: + virtual FText GetName() const override + { + return NSLOCTEXT("AssetTypeActions", "EBBulletProperties", "Bullet Properties"); + } + + virtual FColor GetTypeColor() const override + { + return FColor(255, 196, 128); // Orange theme + } + + virtual UClass* GetSupportedClass() const override + { + return UEBBulletPropertiesAsset::StaticClass(); + } + + virtual uint32 GetCategories() override + { + return EAssetTypeCategories::Gameplay; + } + + virtual void GetActions(const TArray& InObjects, + FMenuBuilder& MenuBuilder) override + { + MenuBuilder.AddMenuEntry( + LOCTEXT("BulletProperties_CreateMaterial", "Create Material Response Map"), + LOCTEXT("BulletProperties_CreateMaterialTooltip", "Creates a new Material Response Map for this bullet type"), + FSlateIcon(), + FUIAction(FExecuteAction::CreateSP(this, &FEBBulletPropertiesActions::ExecuteCreateMaterialMap, InObjects)) + ); + } +}; +``` + +### Material Response Map Actions + +```cpp +class FEBMaterialResponseMapActions : public FAssetTypeActions_Base +{ +public: + virtual FText GetName() const override + { + return NSLOCTEXT("AssetTypeActions", "EBMaterialResponseMap", "Material Response Map"); + } + + virtual void GetActions(const TArray& InObjects, + FMenuBuilder& MenuBuilder) override + { + MenuBuilder.AddMenuEntry( + LOCTEXT("MaterialMap_PopulateCommon", "Populate Common Materials"), + LOCTEXT("MaterialMap_PopulateCommonTooltip", "Adds entries for common materials"), + FSlateIcon(), + FUIAction(FExecuteAction::CreateSP(this, &FEBMaterialResponseMapActions::ExecutePopulateCommon, InObjects)) + ); + } +}; +``` + +## Custom Property Editors + +### Bullet Properties Editor + +```cpp +// Custom property widget for ballistic coefficient +class SEBBallisticCoefficientWidget : public SCompoundWidget +{ +public: + SLATE_BEGIN_ARGS(SEBBallisticCoefficientWidget) {} + SLATE_ATTRIBUTE(float, G1Value) + SLATE_ATTRIBUTE(float, G7Value) + SLATE_ATTRIBUTE(bool, UseG7) + SLATE_END_ARGS() + + void Construct(const FArguments& InArgs) + { + ChildSlot + [ + SNew(SVerticalBox) + + SVerticalBox::Slot() + .AutoHeight() + [ + SNew(SHorizontalBox) + + SHorizontalBox::Slot() + [ + SNew(STextBlock) + .Text(LOCTEXT("G1BC", "G1 BC:")) + ] + + SHorizontalBox::Slot() + [ + SNew(SSpinBox) + .Value(InArgs._G1Value) + .MinValue(0.001f) + .MaxValue(2.0f) + .Delta(0.001f) + ] + ] + // Add G7 section... + ]; + } +}; +``` + +### Material Response Map Editor + +```cpp +// Custom editor for material response entries +class FEBMaterialResponseMapDetails : public IDetailCustomization +{ +public: + virtual void CustomizeDetails(IDetailLayoutBuilder& DetailBuilder) override + { + TSharedRef MapProperty = + DetailBuilder.GetProperty(GET_MEMBER_NAME_CHECKED(UEBMaterialResponseMap, Map)); + + IDetailCategoryBuilder& MapCategory = + DetailBuilder.EditCategory("Material Responses"); + + // Custom array widget with material picker + MapCategory.AddCustomRow(LOCTEXT("MaterialEntries", "Material Entries")) + .WholeRowContent() + [ + CreateMaterialMapWidget(MapProperty) + ]; + } + +private: + TSharedRef CreateMaterialMapWidget(TSharedRef PropertyHandle) + { + return SNew(SVerticalBox) + + SVerticalBox::Slot() + [ + // Material picker + response settings + CreateEntryWidget() + ]; + } +}; +``` + +## Debug Visualization Tools + +### Editor Debug Panel + +```cpp +// Custom editor panel for ballistics debugging +class SEBDebugPanel : public SCompoundWidget +{ +public: + SLATE_BEGIN_ARGS(SEBDebugPanel) {} + SLATE_END_ARGS() + + void Construct(const FArguments& InArgs) + { + ChildSlot + [ + SNew(SVerticalBox) + + // Bullet visualization controls + + SVerticalBox::Slot() + .AutoHeight() + [ + SNew(SCheckBox) + .Content() + [ + SNew(STextBlock) + .Text(LOCTEXT("ShowTrajectories", "Show Bullet Trajectories")) + ] + .OnCheckStateChanged(this, &SEBDebugPanel::OnShowTrajectoriesChanged) + ] + + // Performance metrics + + SVerticalBox::Slot() + .AutoHeight() + [ + SNew(STextBlock) + .Text(this, &SEBDebugPanel::GetPerformanceText) + ] + ]; + } + +private: + FText GetPerformanceText() const + { + int32 ActiveBullets = GetActiveBulletCount(); + float MemoryUsage = GetMemoryUsage(); + + return FText::Format( + LOCTEXT("PerformanceStats", "Active Bullets: {0}\nMemory: {1} MB"), + ActiveBullets, + MemoryUsage + ); + } +}; +``` + +### Viewport Debug Rendering + +```cpp +// Custom viewport client for ballistics debugging +class FEBDebugViewportClient : public FEditorViewportClient +{ +public: + virtual void Draw(const FSceneView* View, FPrimitiveDrawInterface* PDI) override + { + FEditorViewportClient::Draw(View, PDI); + + if (bShowBulletTrajectories) + { + DrawBulletTrajectories(PDI); + } + + if (bShowImpactAnalysis) + { + DrawImpactAnalysis(PDI); + } + } + +private: + void DrawBulletTrajectories(FPrimitiveDrawInterface* PDI) + { + for (const auto& Bullet : GetActiveBullets()) + { + TArray Trajectory = PredictTrajectory(Bullet); + + for (int32 i = 0; i < Trajectory.Num() - 1; i++) + { + PDI->DrawLine(Trajectory[i], Trajectory[i + 1], + FColor::Green, SDPG_World, 2.0f); + } + } + } +}; +``` + +## Asset Browser Integration + +### Thumbnail Renderer + +```cpp +// Custom thumbnail renderer for bullet properties +class UEBBulletPropertiesThumbnailRenderer : public UDefaultSizedThumbnailRenderer +{ +public: + virtual void Draw(UObject* Object, int32 X, int32 Y, uint32 Width, uint32 Height, + FRenderTarget* RenderTarget, FCanvas* Canvas, bool bAdditionalViewFamily) override + { + UEBBulletPropertiesAsset* BulletProps = Cast(Object); + if (!BulletProps) + return; + + // Draw bullet icon/diagram + DrawBulletThumbnail(Canvas, BulletProps, X, Y, Width, Height); + } + +private: + void DrawBulletThumbnail(FCanvas* Canvas, UEBBulletPropertiesAsset* Props, + int32 X, int32 Y, uint32 Width, uint32 Height) + { + // Draw bullet shape based on properties + FCanvasBoxItem BulletBox(FVector2D(X + Width * 0.2f, Y + Height * 0.3f), + FVector2D(Width * 0.6f, Height * 0.4f)); + BulletBox.SetColor(FColor::Brass); + Canvas->DrawItem(BulletBox); + + // Add caliber text + FString CaliberText = FString::Printf(TEXT("%.3f\""), Props->DiameterInches); + FCanvasTextItem TextItem(FVector2D(X + 5, Y + Height - 15), + FText::FromString(CaliberText), + GEngine->GetSmallFont(), FColor::White); + Canvas->DrawItem(TextItem); + } +}; +``` + +### Asset Details Customization + +```cpp +// Enhanced details panel for bullet properties +class FEBBulletPropertiesCustomization : public IDetailCustomization +{ +public: + virtual void CustomizeDetails(IDetailLayoutBuilder& DetailBuilder) override + { + // Add ballistic calculator section + IDetailCategoryBuilder& CalculatorCategory = + DetailBuilder.EditCategory("Ballistic Calculator"); + + CalculatorCategory.AddCustomRow(LOCTEXT("Calculator", "Calculator")) + .WholeRowContent() + [ + SNew(SVerticalBox) + + SVerticalBox::Slot() + [ + CreateBallisticCalculator() + ] + ]; + } + +private: + TSharedRef CreateBallisticCalculator() + { + return SNew(SExpandableArea) + .AreaTitle(LOCTEXT("BallisticCalc", "Ballistic Calculator")) + .InitiallyCollapsed(true) + .BodyContent() + [ + SNew(SVerticalBox) + + SVerticalBox::Slot() + [ + SNew(SHorizontalBox) + + SHorizontalBox::Slot() + [ + SNew(STextBlock) + .Text(LOCTEXT("SectionalDensity", "Sectional Density:")) + ] + + SHorizontalBox::Slot() + [ + SNew(STextBlock) + .Text(this, &FEBBulletPropertiesCustomization::GetSectionalDensityText) + ] + ] + // Add more calculated values... + ]; + } +}; +``` + +## Workflow Tools + +### Batch Asset Operations + +```cpp +// Batch operations for ballistic assets +class FEBAssetBatchOperations +{ +public: + // Update all bullet properties with new mathematical model + static void UpdateAllBulletProperties() + { + TArray AllBulletAssets; + FindAllAssetsOfClass(AllBulletAssets); + + for (auto* Asset : AllBulletAssets) + { + UpdateBulletPropertiesFormulas(Asset); + Asset->MarkPackageDirty(); + } + } + + // Validate all material response maps + static void ValidateAllMaterialMaps() + { + TArray AllMaps; + FindAllAssetsOfClass(AllMaps); + + for (auto* Map : AllMaps) + { + ValidateMaterialMap(Map); + } + } + +private: + template + static void FindAllAssetsOfClass(TArray& OutAssets) + { + FAssetRegistryModule& AssetRegistryModule = + FModuleManager::LoadModuleChecked("AssetRegistry"); + + TArray AssetData; + AssetRegistryModule.Get().GetAssetsByClass(T::StaticClass()->GetFName(), AssetData); + + for (const auto& Asset : AssetData) + { + if (T* LoadedAsset = Cast(Asset.GetAsset())) + { + OutAssets.Add(LoadedAsset); + } + } + } +}; +``` + +### Import/Export Tools + +```cpp +// CSV import/export for bullet properties +class FEBDataImportExport +{ +public: + // Export bullet properties to CSV + static void ExportBulletPropertiesToCSV(const TArray& Assets, + const FString& FilePath) + { + FString CSV = TEXT("Name,GrainWeight,DiameterInches,LengthInches,BCG1,BCG7\n"); + + for (const auto* Asset : Assets) + { + CSV += FString::Printf(TEXT("%s,%.1f,%.3f,%.3f,%.3f,%.3f\n"), + *Asset->GetName(), + Asset->GrainWeight, + Asset->DiameterInches, + Asset->LengthInches, + Asset->BallisticCoefficientG1, + Asset->BallisticCoefficientG7 + ); + } + + FFileHelper::SaveStringToFile(CSV, *FilePath); + } + + // Import bullet properties from CSV + static TArray ImportBulletPropertiesFromCSV(const FString& FilePath) + { + TArray CreatedAssets; + + FString FileContent; + if (!FFileHelper::LoadFileToString(FileContent, *FilePath)) + { + return CreatedAssets; + } + + TArray Lines; + FileContent.ParseIntoArrayLines(Lines); + + // Skip header line + for (int32 i = 1; i < Lines.Num(); i++) + { + UEBBulletPropertiesAsset* Asset = CreateAssetFromCSVLine(Lines[i]); + if (Asset) + { + CreatedAssets.Add(Asset); + } + } + + return CreatedAssets; + } +}; +``` + +## Content Browser Extensions + +### Custom Content Browser Columns + +```cpp +// Add custom columns for ballistic assets +class FEBContentBrowserExtensions +{ +public: + static void RegisterColumns() + { + FContentBrowserModule& ContentBrowserModule = + FModuleManager::LoadModuleChecked("ContentBrowser"); + + // Add caliber column for bullet properties + ContentBrowserModule.GetAllAssetViewContextMenuExtenders().Add( + FContentBrowserMenuExtender_SelectedAssets::CreateStatic( + &FEBContentBrowserExtensions::OnExtendContentBrowserAssetSelectionMenu)); + } + +private: + static TSharedRef OnExtendContentBrowserAssetSelectionMenu( + const TArray& SelectedAssets) + { + TSharedRef Extender = MakeShared(); + + if (SelectedAssets.Num() > 0 && + SelectedAssets[0].AssetClass == UEBBulletPropertiesAsset::StaticClass()->GetFName()) + { + Extender->AddMenuExtension( + "CommonAssetActions", + EExtensionHook::After, + nullptr, + FMenuExtensionDelegate::CreateStatic(&FEBContentBrowserExtensions::CreateBulletPropertiesMenu) + ); + } + + return Extender; + } + + static void CreateBulletPropertiesMenu(FMenuBuilder& MenuBuilder) + { + MenuBuilder.AddMenuEntry( + LOCTEXT("ExportToCSV", "Export to CSV"), + LOCTEXT("ExportToCSVTooltip", "Export bullet properties to CSV file"), + FSlateIcon(), + FUIAction(FExecuteAction::CreateStatic(&FEBContentBrowserExtensions::ExportToCSV)) + ); + } +}; +``` + +## Editor Preferences + +### Plugin Settings + +```cpp +// Settings panel for EasyBallistics editor tools +UCLASS(config=EditorPerProjectUserSettings) +class EASYBALLISTICSEDITOR_API UEBEditorSettings : public UObject +{ + GENERATED_BODY() + +public: + UEBEditorSettings() + { + bShowDebugVisualization = true; + bAutoGenerateMaterialProperties = true; + DefaultBulletMaterial = EBulletMaterial::CopperJacket; + } + + // Debug visualization options + UPROPERTY(EditAnywhere, config, Category = "Debug", + meta = (ToolTip = "Show trajectory visualization in viewport")) + bool bShowDebugVisualization; + + UPROPERTY(EditAnywhere, config, Category = "Debug") + FColor TrajectoryColor = FColor::Green; + + UPROPERTY(EditAnywhere, config, Category = "Debug") + float TrajectoryThickness = 2.0f; + + // Asset creation defaults + UPROPERTY(EditAnywhere, config, Category = "Asset Creation") + bool bAutoGenerateMaterialProperties; + + UPROPERTY(EditAnywhere, config, Category = "Asset Creation") + EBulletMaterial DefaultBulletMaterial; + + UPROPERTY(EditAnywhere, config, Category = "Asset Creation") + EBulletType DefaultBulletType; +}; +``` + +### Settings Registration + +```cpp +// Register settings with editor +void FEasyBallisticsEditorModule::RegisterSettings() +{ + if (ISettingsModule* SettingsModule = FModuleManager::GetModulePtr("Settings")) + { + SettingsModule->RegisterSettings("Project", "Plugins", "EasyBallistics", + LOCTEXT("RuntimeSettingsName", "EasyBallistics"), + LOCTEXT("RuntimeSettingsDescription", "Configure EasyBallistics plugin"), + GetMutableDefault() + ); + } +} +``` + +## Best Practices + +### Asset Organization + +1. **Consistent Naming**: Use clear, descriptive names for ballistic assets +2. **Folder Structure**: Organize by caliber, weapon type, or material category +3. **Version Control**: Use proper check-in practices for shared assets +4. **Documentation**: Add descriptions to asset properties + +### Performance in Editor + +1. **Disable Debug Visualization**: Turn off when not needed +2. **Limit Asset Count**: Don't load too many ballistic assets simultaneously +3. **Use Asset References**: Prefer soft references in editor tools +4. **Profile Editor Tools**: Monitor performance of custom panels + +### Workflow Optimization + +1. **Template Assets**: Create template assets for common configurations +2. **Batch Operations**: Use batch tools for large-scale updates +3. **Validation Tools**: Implement asset validation for quality assurance +4. **Import/Export**: Use CSV tools for external data integration + +## Troubleshooting Editor Issues + +### Common Problems + +| Issue | Solution | +|-------|----------| +| Custom panels not appearing | Check module dependencies and registration | +| Asset thumbnails not showing | Verify thumbnail renderer registration | +| Properties not saving | Ensure MarkPackageDirty() is called | +| Performance issues | Disable debug features, optimize custom widgets | + +### Debug Tools + +- Use **Output Log** to monitor editor messages +- Enable **Developer Tools** for additional debugging +- Check **Asset Registry** for asset loading issues +- Profile with **Unreal Insights** for performance analysis + +## Next Steps + +- [Advanced Tutorials](../tutorials/advanced-concepts) - Complex implementation examples +- [API Reference](../api/overview) - Complete function documentation +- [Performance Optimization](performance-optimization) - Optimize your ballistic systems + +--- + +*For more editor customization examples, see the [UE5 Editor Extension Documentation](https://docs.unrealengine.com/5.0/en-US/editor-extension-development/).* \ No newline at end of file diff --git a/docs/docs/advanced/migration-guide.md b/docs/docs/advanced/migration-guide.md new file mode 100644 index 0000000..0c17812 --- /dev/null +++ b/docs/docs/advanced/migration-guide.md @@ -0,0 +1,463 @@ +# Migration Guide + +This guide helps you migrate from older versions of EasyBallistics to the latest version (2.83+), including the new Ballistic Impact System and Physical Material integration. + +## Overview + +Version 2.83 introduces significant architectural changes: + +- **New Ballistic Impact System**: Event-driven impact handling +- **Physical Material Integration**: Seamless UE5 workflow +- **Enhanced Asset Creation**: Streamlined editor tools +- **Performance Improvements**: Better pooling and LOD systems + +## Breaking Changes + +### 1. Material Response System + +**Old System** (2.8x and earlier): +```cpp +// Material Response Map used string keys +MaterialResponseMap->Map.Add("Steel", SteelResponse); +MaterialResponseMap->Map.Add("Wood", WoodResponse); +``` + +**New System** (2.83+): +```cpp +// Material Response Map uses Physical Material references +MaterialResponseMap->Map.Add(SteelPhysicalMaterial, SteelResponse); +MaterialResponseMap->Map.Add(WoodPhysicalMaterial, WoodResponse); +``` + +**Migration Steps**: +1. Convert string keys to Physical Material references +2. Assign Physical Materials to all surface meshes +3. Update any Blueprint logic that references material names + +### 2. Impact Event System + +**Old System**: +```cpp +// Old impact event signature +DECLARE_DYNAMIC_MULTICAST_DELEGATE_ThreeParams(FOnOldImpact, + FVector, Location, + FVector, Normal, + FString, MaterialName); +``` + +**New System**: +```cpp +// New impact event signature +DECLARE_DYNAMIC_MULTICAST_DELEGATE_FiveParams(FOnBallisticImpact, + FVector, ImpactLocation, + FVector, ImpactNormal, + UPhysicalMaterial*, HitMaterial, + float, PenetrationDepth, + bool, bDidPenetrate); +``` + +**Migration Steps**: +1. Update event binding signatures +2. Replace string material checks with Physical Material references +3. Use new penetration depth and success parameters + +### 3. Component Architecture + +**Old System**: +```cpp +// Impact logic was built into bullet class +class AEBBullet : public AActor +{ + // All impact logic here + void ProcessImpact(FHitResult Hit); +}; +``` + +**New System**: +```cpp +// Impact logic separated into component +class AEBBullet : public AActor +{ + UPROPERTY(VisibleAnywhere, BlueprintReadOnly) + UEBBallisticImpactComponent* BallisticImpactComponent; + + UPROPERTY(EditAnywhere, BlueprintReadWrite) + bool UseNewImpactSystem = false; // Migration flag +}; +``` + +## Step-by-Step Migration + +### Phase 1: Preparation + +1. **Backup Your Project** + - Create a full project backup + - Commit all changes to version control + - Document current implementation + +2. **Inventory Assets** + - List all Material Response Maps + - Identify surfaces using ballistic materials + - Note custom impact event handlers + +3. **Create Physical Materials** + ```cpp + // Create Physical Materials for each surface type + // Steel + UPhysicalMaterial* PM_Steel = CreateDefaultSubobject("PM_Steel"); + + // Wood + UPhysicalMaterial* PM_Wood = CreateDefaultSubobject("PM_Wood"); + + // Add ballistic properties (auto-generated based on names) + ``` + +### Phase 2: Asset Migration + +1. **Update Material Response Maps** + ```cpp + // Migration function for Material Response Maps + void MigrateMaterialResponseMap(UEBMaterialResponseMap* Map) + { + // Create new map with Physical Material keys + TMap NewMap; + + for (const auto& Entry : Map->OldStringMap) + { + FString MaterialName = Entry.Key; + UPhysicalMaterial* PhysMat = FindOrCreatePhysicalMaterial(MaterialName); + + if (PhysMat) + { + NewMap.Add(PhysMat, Entry.Value); + } + } + + Map->Map = NewMap; + Map->OldStringMap.Empty(); // Clear old data + } + ``` + +2. **Assign Physical Materials** + ```cpp + // Assign Physical Materials to static meshes + void AssignPhysicalMaterials() + { + TArray StaticMeshActors; + UGameplayStatics::GetAllActorsOfClass(GetWorld(), AStaticMeshActor::StaticClass(), StaticMeshActors); + + for (AActor* Actor : StaticMeshActors) + { + AStaticMeshActor* MeshActor = Cast(Actor); + UStaticMeshComponent* MeshComp = MeshActor->GetStaticMeshComponent(); + + // Auto-assign based on mesh name or material + UPhysicalMaterial* PhysMat = DeterminePhysicalMaterial(MeshActor); + MeshComp->SetPhysMaterialOverride(PhysMat); + } + } + ``` + +### Phase 3: Code Migration + +1. **Update Event Handlers** + ```cpp + // Old event handler + UFUNCTION() + void HandleOldImpact(FVector Location, FVector Normal, FString MaterialName) + { + if (MaterialName == "Steel") + { + SpawnSteelImpactEffect(Location, Normal); + } + } + + // New event handler + UFUNCTION() + void HandleNewImpact(FVector ImpactLocation, FVector ImpactNormal, + UPhysicalMaterial* HitMaterial, float PenetrationDepth, bool bDidPenetrate) + { + if (HitMaterial == SteelPhysicalMaterial) + { + SpawnSteelImpactEffect(ImpactLocation, ImpactNormal); + + // Use new parameters + if (bDidPenetrate) + { + SpawnPenetrationEffect(ImpactLocation, PenetrationDepth); + } + } + } + ``` + +2. **Enable New Impact System** + ```cpp + // Enable new system on bullets + void EnableNewImpactSystem() + { + // For existing bullets + for (TSubclassOf BulletClass : AllBulletClasses) + { + AEBBullet* CDO = BulletClass.GetDefaultObject(); + CDO->UseNewImpactSystem = true; + + // Ensure component exists + if (!CDO->BallisticImpactComponent) + { + CDO->BallisticImpactComponent = CreateDefaultSubobject(TEXT("BallisticImpactComponent")); + } + } + } + ``` + +### Phase 4: Testing and Validation + +1. **Create Test Scenarios** + ```cpp + // Test impact system + void TestImpactSystem() + { + // Test different materials + TestMaterialImpact(SteelPhysicalMaterial); + TestMaterialImpact(WoodPhysicalMaterial); + TestMaterialImpact(ConcretePhysicalMaterial); + + // Test penetration + TestPenetrationDepth(); + TestRicochetBehavior(); + } + ``` + +2. **Validate Performance** + ```cpp + // Performance comparison + void ValidatePerformance() + { + float OldSystemTime = BenchmarkOldSystem(); + float NewSystemTime = BenchmarkNewSystem(); + + UE_LOG(LogTemp, Warning, TEXT("Performance Comparison:")); + UE_LOG(LogTemp, Warning, TEXT("Old System: %.3f ms"), OldSystemTime); + UE_LOG(LogTemp, Warning, TEXT("New System: %.3f ms"), NewSystemTime); + UE_LOG(LogTemp, Warning, TEXT("Improvement: %.1f%%"), + ((OldSystemTime - NewSystemTime) / OldSystemTime) * 100.0f); + } + ``` + +## Asset Migration Tools + +### Automated Migration Script + +```cpp +// Automated migration utility +class FEBMigrationTool +{ +public: + static void MigrateProject() + { + UE_LOG(LogTemp, Warning, TEXT("Starting EasyBallistics migration...")); + + // Step 1: Create Physical Materials + CreatePhysicalMaterials(); + + // Step 2: Migrate Material Response Maps + MigrateAllMaterialResponseMaps(); + + // Step 3: Update Bullet Classes + UpdateAllBulletClasses(); + + // Step 4: Assign Physical Materials to Meshes + AssignPhysicalMaterialsToMeshes(); + + UE_LOG(LogTemp, Warning, TEXT("Migration completed!")); + } + +private: + static void CreatePhysicalMaterials() + { + TArray CommonMaterials = { + "Steel", "Wood", "Concrete", "Glass", "Fabric" + }; + + for (const FString& MaterialName : CommonMaterials) + { + CreatePhysicalMaterialAsset(MaterialName); + } + } + + static void MigrateAllMaterialResponseMaps() + { + TArray AllMaps; + FindAllAssetsOfClass(AllMaps); + + for (UEBMaterialResponseMap* Map : AllMaps) + { + MigrateMaterialResponseMap(Map); + Map->MarkPackageDirty(); + } + } +}; +``` + +### Material Name Mapping + +```cpp +// Map common material names to Physical Materials +class FMaterialNameMapper +{ +public: + static UPhysicalMaterial* MapNameToPhysicalMaterial(const FString& MaterialName) + { + static TMap NameMapping = { + {"Steel", "PM_Steel"}, + {"Metal", "PM_Steel"}, + {"Iron", "PM_Steel"}, + {"Wood", "PM_Wood"}, + {"Wooden", "PM_Wood"}, + {"Timber", "PM_Wood"}, + {"Concrete", "PM_Concrete"}, + {"Stone", "PM_Concrete"}, + {"Glass", "PM_Glass"}, + {"Fabric", "PM_Fabric"}, + {"Cloth", "PM_Fabric"} + }; + + FString* MappedName = NameMapping.Find(MaterialName); + if (MappedName) + { + return LoadObject(nullptr, **MappedName); + } + + return nullptr; + } +}; +``` + +## Blueprint Migration + +### Old Blueprint Pattern + +```blueprint +// Old impact event handling +Event OnImpact (Location, Normal, MaterialName) + → Branch (MaterialName == "Steel") + → True: Spawn Steel Impact Effect + → False: Branch (MaterialName == "Wood") + → True: Spawn Wood Impact Effect +``` + +### New Blueprint Pattern + +```blueprint +// New impact event handling +Event OnBallisticImpact (ImpactLocation, ImpactNormal, HitMaterial, PenetrationDepth, bDidPenetrate) + → Switch on Physical Material (HitMaterial) + → Steel: Spawn Steel Impact Effect + → Wood: Spawn Wood Impact Effect + → Default: Spawn Generic Impact Effect + → Branch (bDidPenetrate) + → True: Spawn Penetration Effect (using PenetrationDepth) +``` + +## Common Migration Issues + +### Issue 1: Missing Physical Materials + +**Problem**: Material Response Map entries pointing to null Physical Materials + +**Solution**: +```cpp +// Validate and fix missing materials +void FixMissingPhysicalMaterials(UEBMaterialResponseMap* Map) +{ + for (auto& Entry : Map->Map) + { + if (!Entry.Key) + { + UE_LOG(LogTemp, Warning, TEXT("Found null Physical Material in response map")); + // Create default material or remove entry + } + } +} +``` + +### Issue 2: Performance Regression + +**Problem**: New system performing slower than old system + +**Solution**: +```cpp +// Optimize new system +void OptimizeNewSystem() +{ + // Enable object pooling + Bullet->EnablePooling = true; + + // Optimize impact component + Bullet->BallisticImpactComponent->bEnableBallisticCalculations = true; + Bullet->BallisticImpactComponent->bUseMathematicalPenetration = false; // For performance +} +``` + +### Issue 3: Event Not Firing + +**Problem**: New impact events not triggering + +**Solution**: +```cpp +// Ensure proper component setup +void FixEventBinding() +{ + // Verify component exists + if (!Bullet->BallisticImpactComponent) + { + Bullet->BallisticImpactComponent = NewObject(Bullet); + } + + // Bind events + Bullet->BallisticImpactComponent->OnBallisticImpact.AddDynamic( + this, &AMyActor::HandleBallisticImpact); +} +``` + +## Migration Checklist + +### Pre-Migration +- [ ] Project backup created +- [ ] Asset inventory completed +- [ ] Physical Materials created +- [ ] Migration tools prepared + +### Migration Process +- [ ] Material Response Maps updated +- [ ] Physical Materials assigned to meshes +- [ ] Event handlers updated +- [ ] New impact system enabled +- [ ] Performance validated + +### Post-Migration +- [ ] All systems tested +- [ ] Performance benchmarked +- [ ] Documentation updated +- [ ] Team trained on new system + +## Support + +If you encounter issues during migration: + +1. **Check Documentation**: Review the [troubleshooting guide](../troubleshooting) +2. **Community Support**: Join our [Discord](https://discord.gg/easyballistics) +3. **Professional Support**: Contact support@easyballistics.com +4. **GitHub Issues**: Report bugs on [GitHub](https://github.com/your-org/easyballistics/issues) + +## Next Steps + +After successful migration: + +1. **[Performance Optimization](performance-optimization)** - Optimize your updated system +2. **[Advanced Features](../core-concepts/overview)** - Explore new capabilities +3. **[Best Practices](../advanced/editor-tools)** - Learn optimal workflows + +--- + +*Migration complete? Continue with [Performance Optimization](performance-optimization) to get the most out of your updated system.* \ No newline at end of file diff --git a/docs/docs/advanced/multiplayer-guide.md b/docs/docs/advanced/multiplayer-guide.md new file mode 100644 index 0000000..a29a97f --- /dev/null +++ b/docs/docs/advanced/multiplayer-guide.md @@ -0,0 +1,570 @@ +# Multiplayer Guide + +This guide covers implementing EasyBallistics in multiplayer environments, including server authority, client prediction, and network optimization. + +## Architecture Overview + +EasyBallistics uses a hybrid approach for multiplayer: + +- **Server Authority**: All impact calculations and final results +- **Client Prediction**: Immediate visual feedback for responsive gameplay +- **Reconciliation**: Smooth correction of prediction errors + +```mermaid +sequenceDiagram + participant C as Client + participant S as Server + participant O as Other Clients + + C->>S: Fire Request (RPC) + S->>S: Validate & Spawn Bullet + S->>O: Replicate Bullet Spawn + C->>C: Predict Trajectory + S->>O: Authoritative Impact + Note over C,O: Reconcile if needed +``` + +## Core Networking Components + +### Server Authority + +All authoritative actions require server validation: + +```cpp +// Server-side weapon firing +UFUNCTION(Server, Reliable, WithValidation) +void FireWeapon(FVector AimDirection) +{ + // Validate player can fire + if (!CanFire()) + return; + + // Spawn bullet on server + SpawnBulletOnServer(AimDirection); +} + +bool FireWeapon_Validate(FVector AimDirection) +{ + // Anti-cheat validation + return IsValidDirection(AimDirection) && !IsRateLimited(); +} +``` + +### Client Prediction + +Immediate visual feedback without waiting for server: + +```cpp +// Client-side prediction +void PredictiveFire(FVector AimDirection) +{ + // Immediate visual effects + SpawnMuzzleFlash(); + PlayFireSound(); + + // Predict bullet trajectory + if (EnableClientPrediction) + { + PredictBulletPath(AimDirection); + } + + // Send to server + ServerFire(AimDirection); +} +``` + +## Replication Setup + +### Barrel Component Configuration + +```cpp +// In EBBarrel component +UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Replication") +bool ReplicateVariables = true; + +UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Replication") +bool ReplicateShotFiredEvents = true; + +UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Replication") +bool ClientSideAim = false; + +UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Replication") +float ClientAimUpdateFrequency = 15.0f; + +UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Replication") +float ClientAimDistanceLimit = 200.0f; +``` + +### Bullet Replication + +```cpp +// Configure bullet replication +Bullet->bReplicates = true; +Bullet->SetReplicateMovement(true); +Bullet->ReliableReplication = false; // Use unreliable for performance + +// Network optimization +Bullet->NetCullDistanceSquared = 10000000.0f; // 1000m +Bullet->NetUpdateFrequency = 20.0f; // 20 updates per second +``` + +## Network Optimization + +### Bandwidth Management + +```cpp +// Optimize network traffic +void OptimizeNetworkSettings() +{ + // Reduce replication frequency for distant bullets + if (DistanceToPlayer > 5000.0f) + { + Bullet->NetUpdateFrequency = 5.0f; + } + + // Use unreliable replication for position updates + Bullet->ReliableReplication = false; + + // Cull very distant bullets + if (DistanceToPlayer > 10000.0f) + { + Bullet->NetCullDistanceSquared = 0.0f; // Don't replicate + } +} +``` + +### Object Pooling for Multiplayer + +```cpp +// Enable pooling for better performance +Bullet->EnablePooling = true; +Bullet->MaxPoolSize = 50; // Per client + +// Server manages pool sizes +void ManagePoolSizes() +{ + int32 PlayerCount = GetNumPlayers(); + int32 OptimalPoolSize = FMath::Min(100, PlayerCount * 20); + + for (auto& Bullet : BulletPool) + { + Bullet->MaxPoolSize = OptimalPoolSize; + } +} +``` + +## Client-Side Prediction + +### Prediction System + +```cpp +// Enable prediction for responsive gameplay +void SetupPrediction() +{ + // Enable client prediction + Barrel->ClientSideAim = true; + Barrel->ClientAimUpdateFrequency = 30.0f; + + // Bullet prediction settings + Bullet->EnableClientPrediction = true; + Bullet->PredictionTolerance = 5.0f; // 5cm tolerance +} +``` + +### Prediction Validation + +```cpp +// Validate client predictions +void ValidatePrediction(FVector ClientLocation, FVector ServerLocation) +{ + float Distance = FVector::Dist(ClientLocation, ServerLocation); + + if (Distance > PredictionTolerance) + { + // Correct client position + CorrectClientPosition(ServerLocation); + } +} +``` + +## Lag Compensation + +### Hit Detection + +```cpp +// Compensate for network latency +void CompensateForLag(APawn* Shooter, FVector HitLocation) +{ + float Ping = GetPlayerPing(Shooter); + float CompensationTime = Ping * 0.001f; // Convert to seconds + + // Rewind world state + RewindWorldState(CompensationTime); + + // Perform hit detection + bool ValidHit = ValidateHit(HitLocation); + + // Restore world state + RestoreWorldState(); +} +``` + +### Movement Prediction + +```cpp +// Predict target movement for hit validation +FVector PredictTargetLocation(APawn* Target, float CompensationTime) +{ + FVector CurrentLocation = Target->GetActorLocation(); + FVector Velocity = Target->GetVelocity(); + + return CurrentLocation + (Velocity * CompensationTime); +} +``` + +## Anti-Cheat Measures + +### Rate Limiting + +```cpp +// Prevent rapid fire exploits +class FRateLimiter +{ +private: + float LastFireTime; + float MinFireInterval; + +public: + bool CanFire() + { + float CurrentTime = GetWorld()->GetTimeSeconds(); + if (CurrentTime - LastFireTime < MinFireInterval) + { + return false; + } + + LastFireTime = CurrentTime; + return true; + } +}; +``` + +### Validation Checks + +```cpp +// Validate firing parameters +bool ValidateFireRequest(FVector AimDirection, float Range) +{ + // Check aim direction validity + if (AimDirection.IsNearlyZero() || !AimDirection.IsNormalized()) + { + return false; + } + + // Check range limits + if (Range > MaxWeaponRange) + { + return false; + } + + // Check player state + if (!IsPlayerAlive() || IsReloading()) + { + return false; + } + + return true; +} +``` + +## Performance Optimization + +### LOD System + +```cpp +// Implement Level of Detail for multiplayer +void UpdateBulletLOD(AEBBullet* Bullet) +{ + float Distance = GetDistanceToNearestPlayer(Bullet); + + if (Distance < 1000.0f) + { + // High detail + Bullet->MaxTracesPerStep = 8; + Bullet->FixedStepSeconds = 0.016f; + } + else if (Distance < 3000.0f) + { + // Medium detail + Bullet->MaxTracesPerStep = 4; + Bullet->FixedStepSeconds = 0.033f; + } + else + { + // Low detail + Bullet->MaxTracesPerStep = 2; + Bullet->FixedStepSeconds = 0.066f; + } +} +``` + +### Culling System + +```cpp +// Cull bullets based on relevance +void CullIrrelevantBullets() +{ + for (auto& Bullet : ActiveBullets) + { + bool IsRelevant = false; + + // Check if bullet is visible to any player + for (auto& Player : Players) + { + if (IsVisibleTo(Bullet, Player)) + { + IsRelevant = true; + break; + } + } + + if (!IsRelevant) + { + Bullet->SetNetDormancy(DORM_DormantAll); + } + } +} +``` + +## Event Synchronization + +### Impact Events + +```cpp +// Synchronize impact events across clients +UFUNCTION(NetMulticast, Reliable) +void MulticastImpactEvent(FVector Location, FVector Normal, + UPhysicalMaterial* Material) +{ + // Spawn impact effects on all clients + SpawnImpactEffect(Location, Normal, Material); + + // Play impact sound + PlayImpactSound(Location, Material); +} +``` + +### Custom Events + +```cpp +// Create custom networked events +DECLARE_DYNAMIC_MULTICAST_DELEGATE_ThreeParams(FOnNetworkedImpact, + FVector, Location, + float, Damage, + AActor*, HitActor); + +UPROPERTY(BlueprintAssignable) +FOnNetworkedImpact OnNetworkedImpact; + +// Broadcast to all clients +void BroadcastImpactEvent(FVector Location, float Damage, AActor* HitActor) +{ + if (HasAuthority()) + { + OnNetworkedImpact.Broadcast(Location, Damage, HitActor); + } +} +``` + +## Dedicated Server Optimization + +### Server-Specific Settings + +```cpp +// Configure for dedicated server +void ConfigureForDedicatedServer() +{ + if (IsRunningDedicatedServer()) + { + // Disable visual effects + Bullet->DebugEnabled = false; + Bullet->SpawnMuzzleFlash = false; + + // Optimize simulation + Bullet->MaxTracesPerStep = 4; + Bullet->FixedStepSeconds = 0.033f; + + // Increase pool sizes + Bullet->MaxPoolSize = 200; + } +} +``` + +### Memory Management + +```cpp +// Manage server memory usage +void ManageServerMemory() +{ + // Garbage collect unused bullets + if (UnusedBullets.Num() > MaxUnusedBullets) + { + int32 ToRemove = UnusedBullets.Num() - MaxUnusedBullets; + for (int32 i = 0; i < ToRemove; i++) + { + UnusedBullets[i]->Destroy(); + } + UnusedBullets.RemoveAt(0, ToRemove); + } +} +``` + +## Common Patterns + +### Weapon System Integration + +```cpp +// Integrate with multiplayer weapon system +class AMultiplayerWeapon : public AWeapon +{ + UPROPERTY(VisibleAnywhere, Category = "Ballistics") + UEBBarrel* BallisticBarrel; + + UFUNCTION(Server, Reliable, WithValidation) + void ServerFire(FVector AimDirection) + { + if (CanFire()) + { + BallisticBarrel->Fire(); + MulticastFireEffects(); + } + } + + UFUNCTION(NetMulticast, Reliable) + void MulticastFireEffects() + { + // Play effects on all clients + SpawnMuzzleFlash(); + PlayFireSound(); + } +}; +``` + +### Player State Integration + +```cpp +// Integrate with player state for persistence +class ABallisticPlayerState : public APlayerState +{ + UPROPERTY(Replicated) + int32 ShotsFired; + + UPROPERTY(Replicated) + int32 ShotsHit; + + UFUNCTION(Server, Reliable) + void ServerRecordShot(bool bHit) + { + ShotsFired++; + if (bHit) + { + ShotsHit++; + } + } +}; +``` + +## Debugging Multiplayer Issues + +### Network Debugging + +```cpp +// Debug network issues +void DebugNetworkIssues() +{ + if (GEngine) + { + // Show network stats + GEngine->AddOnScreenDebugMessage(-1, 1.0f, FColor::Yellow, + FString::Printf(TEXT("Ping: %.2f ms"), GetPing())); + + // Show bullet count + GEngine->AddOnScreenDebugMessage(-1, 1.0f, FColor::Green, + FString::Printf(TEXT("Active Bullets: %d"), ActiveBullets.Num())); + } +} +``` + +### Console Commands + +```cpp +// Add console commands for debugging +UFUNCTION(Exec) +void DebugBallistics() +{ + // Toggle debug visualization + for (auto& Bullet : ActiveBullets) + { + Bullet->DebugEnabled = !Bullet->DebugEnabled; + } +} + +UFUNCTION(Exec) +void ShowNetworkStats() +{ + // Display network statistics + UE_LOG(LogTemp, Warning, TEXT("Network Stats: Packets/sec: %d"), + GetNetworkPacketRate()); +} +``` + +## Best Practices + +### Performance Guidelines + +1. **Use Object Pooling**: Always enable pooling for multiplayer +2. **Optimize Update Rates**: Reduce frequency for distant bullets +3. **Implement LOD**: Scale simulation quality with distance +4. **Cull Irrelevant Bullets**: Use network culling for performance + +### Network Guidelines + +1. **Minimize RPCs**: Batch multiple actions when possible +2. **Use Unreliable Replication**: For position updates +3. **Implement Prediction**: For responsive gameplay +4. **Validate Everything**: Server-side validation for security + +### Security Guidelines + +1. **Server Authority**: All important decisions on server +2. **Input Validation**: Validate all client inputs +3. **Rate Limiting**: Prevent rapid fire exploits +4. **Sanity Checks**: Validate physics calculations + +## Troubleshooting + +### Common Issues + +| Issue | Solution | +|-------|----------| +| Bullets not syncing | Check replication settings | +| High latency | Implement client prediction | +| Memory leaks | Enable object pooling | +| Desync issues | Validate server authority | + +### Performance Optimization + +- Use `stat net` to monitor network usage +- Profile with `stat game` for performance bottlenecks +- Monitor memory with `stat memory` +- Check collision performance with `stat collision` + +## Next Steps + +- [Performance Optimization Guide](performance-optimization) - Detailed optimization strategies +- [Advanced Tutorials](../tutorials/advanced-concepts) - Complex implementation examples +- [API Reference](../api/overview) - Complete function documentation + +--- + +*For more advanced networking topics, see the [Advanced Networking Guide](advanced-networking).* \ No newline at end of file diff --git a/docs/docs/advanced/performance-optimization.md b/docs/docs/advanced/performance-optimization.md new file mode 100644 index 0000000..4f22292 --- /dev/null +++ b/docs/docs/advanced/performance-optimization.md @@ -0,0 +1,573 @@ +# Performance Optimization Guide + +This guide covers comprehensive performance optimization strategies for EasyBallistics, helping you achieve optimal performance in your projects. + +## Performance Overview + +EasyBallistics is designed for high performance, but proper configuration is essential for optimal results. This guide covers: + +- **Memory Management**: Object pooling and garbage collection +- **CPU Optimization**: Simulation quality and LOD systems +- **Network Optimization**: Bandwidth and replication efficiency +- **Platform-Specific Tuning**: Console, mobile, and PC optimizations + +## Object Pooling + +### Why Pooling Matters + +Creating and destroying bullet actors is expensive. Pooling reuses existing actors: + +```cpp +// Without pooling: Expensive +AEBBullet* Bullet = GetWorld()->SpawnActor(); +Bullet->Destroy(); // Triggers garbage collection + +// With pooling: Efficient +AEBBullet* Bullet = GetPooledBullet(); +Bullet->Deactivate(); // Returns to pool +``` + +### Configuring Pooling + +```cpp +// Enable pooling for high-rate weapons +Bullet->EnablePooling = true; +Bullet->MaxPoolSize = 100; + +// Configure pool sizes based on weapon type +void ConfigurePoolingForWeapon(EWeaponType WeaponType) +{ + switch (WeaponType) + { + case EWeaponType::Pistol: + Bullet->MaxPoolSize = 20; + break; + case EWeaponType::AssaultRifle: + Bullet->MaxPoolSize = 100; + break; + case EWeaponType::Minigun: + Bullet->MaxPoolSize = 500; + break; + } +} +``` + +### Pool Management + +```cpp +// Monitor pool efficiency +void MonitorPoolEfficiency() +{ + int32 PoolSize = BulletPool.Num(); + int32 ActiveBullets = GetActiveBulletCount(); + float PoolUtilization = (float)ActiveBullets / PoolSize; + + // Adjust pool size based on utilization + if (PoolUtilization > 0.8f) + { + // Increase pool size + Bullet->MaxPoolSize = FMath::Min(500, Bullet->MaxPoolSize + 50); + } + else if (PoolUtilization < 0.2f) + { + // Decrease pool size + Bullet->MaxPoolSize = FMath::Max(20, Bullet->MaxPoolSize - 25); + } +} +``` + +## Simulation Quality Scaling + +### Level of Detail (LOD) + +Scale simulation quality based on distance and importance: + +```cpp +// Implement LOD system +void UpdateBulletLOD(AEBBullet* Bullet) +{ + float Distance = GetDistanceToNearestPlayer(Bullet); + bool IsPlayerWeapon = IsPlayerOwnedWeapon(Bullet); + + if (IsPlayerWeapon || Distance < 1000.0f) + { + // High detail for player weapons and close bullets + Bullet->MaxTracesPerStep = 8; + Bullet->FixedStepSeconds = 0.016f; // 60 FPS + Bullet->TraceComplex = true; + } + else if (Distance < 3000.0f) + { + // Medium detail for medium distance + Bullet->MaxTracesPerStep = 4; + Bullet->FixedStepSeconds = 0.033f; // 30 FPS + Bullet->TraceComplex = false; + } + else + { + // Low detail for distant bullets + Bullet->MaxTracesPerStep = 2; + Bullet->FixedStepSeconds = 0.066f; // 15 FPS + Bullet->TraceComplex = false; + } +} +``` + +### Adaptive Quality + +```cpp +// Adjust quality based on performance +void AdaptiveQualityControl() +{ + float CurrentFPS = GetCurrentFPS(); + float TargetFPS = 60.0f; + + if (CurrentFPS < TargetFPS * 0.8f) + { + // Reduce quality + ReduceSimulationQuality(); + } + else if (CurrentFPS > TargetFPS * 1.1f) + { + // Increase quality + IncreaseSimulationQuality(); + } +} + +void ReduceSimulationQuality() +{ + // Reduce trace complexity + for (auto& Bullet : ActiveBullets) + { + Bullet->MaxTracesPerStep = FMath::Max(1, Bullet->MaxTracesPerStep - 1); + Bullet->FixedStepSeconds = FMath::Min(0.1f, Bullet->FixedStepSeconds + 0.016f); + } +} +``` + +## CPU Optimization + +### Trace Optimization + +```cpp +// Optimize collision traces +void OptimizeTraces() +{ + // Use simple collision for distant bullets + if (Distance > 2000.0f) + { + Bullet->TraceComplex = false; + } + + // Reduce collision channels + Bullet->TraceChannel = ECC_WorldStatic; // Faster than ECC_WorldDynamic + + // Use collision margin to reduce trace frequency + Bullet->CollisionMargin = 5.0f; // Skip small gaps +} +``` + +### Multi-Threading + +```cpp +// Parallelize bullet updates +void ParallelBulletUpdate() +{ + // Use async tasks for independent bullets + ParallelFor(ActiveBullets.Num(), [&](int32 Index) + { + AEBBullet* Bullet = ActiveBullets[Index]; + if (Bullet && Bullet->IsValidLowLevel()) + { + Bullet->UpdatePhysics(); + } + }); +} +``` + +### Memory Access Optimization + +```cpp +// Structure of Arrays for better cache performance +struct FBulletData +{ + TArray Positions; + TArray Velocities; + TArray Masses; + TArray Diameters; + + void UpdatePhysics(int32 BulletCount, float DeltaTime) + { + // Vectorized operations + for (int32 i = 0; i < BulletCount; i++) + { + // Cache-friendly sequential access + Positions[i] += Velocities[i] * DeltaTime; + // Apply drag, gravity, etc. + } + } +}; +``` + +## Memory Management + +### Garbage Collection + +```cpp +// Minimize garbage collection pressure +void MinimizeGarbageCollection() +{ + // Reuse containers instead of creating new ones + static TArray HitResults; + HitResults.Reset(); // Clear but keep capacity + + // Use object pooling for frequently created objects + static TArray BulletPool; + + // Avoid frequent string operations + static FString CachedString; + CachedString = FString::Printf(TEXT("Bullets: %d"), BulletCount); +} +``` + +### Memory Profiling + +```cpp +// Monitor memory usage +void MonitorMemoryUsage() +{ + FGenericPlatformMemory::EMemoryCounterRegion Region = + FGenericPlatformMemory::MCR_Physical; + + SIZE_T UsedMemory = FGenericPlatformMemory::GetMemoryUsedFast(Region); + + if (UsedMemory > MaxMemoryThreshold) + { + // Trigger cleanup + TriggerMemoryCleanup(); + } +} +``` + +## Platform-Specific Optimization + +### Console Optimization + +```cpp +// Configure for console platforms +void ConfigureForConsole() +{ + #if PLATFORM_CONSOLE + // Reduce pool sizes for limited memory + Bullet->MaxPoolSize = 50; + + // Use fixed timestep for consistent performance + Bullet->FixedStep = true; + Bullet->FixedStepSeconds = 0.033f; // 30 FPS + + // Disable expensive features + Bullet->DebugEnabled = false; + Bullet->TraceComplex = false; + #endif +} +``` + +### Mobile Optimization + +```cpp +// Configure for mobile platforms +void ConfigureForMobile() +{ + #if PLATFORM_MOBILE + // Aggressive optimization for mobile + Bullet->MaxPoolSize = 20; + Bullet->MaxTracesPerStep = 2; + Bullet->FixedStepSeconds = 0.066f; // 15 FPS + + // Disable advanced features + Bullet->UseMathematicalPhysics = false; + Bullet->AtmosphereType = EEBAtmosphereType::AT_Constant; + + // Reduce collision complexity + Bullet->TraceComplex = false; + Bullet->CollisionMargin = 10.0f; + #endif +} +``` + +### PC Optimization + +```cpp +// Configure for PC platforms +void ConfigureForPC() +{ + #if PLATFORM_DESKTOP + // Take advantage of more resources + Bullet->MaxPoolSize = 200; + Bullet->MaxTracesPerStep = 8; + + // Enable advanced features + Bullet->UseMathematicalPhysics = true; + Bullet->UseNewImpactSystem = true; + + // Adaptive quality based on hardware + AdaptToHardwareCapabilities(); + #endif +} +``` + +## Network Optimization + +### Bandwidth Optimization + +```cpp +// Optimize network bandwidth +void OptimizeNetworkBandwidth() +{ + // Reduce update frequency for distant bullets + if (Distance > 5000.0f) + { + Bullet->NetUpdateFrequency = 5.0f; + } + + // Use unreliable replication for position updates + Bullet->ReliableReplication = false; + + // Cull very distant bullets + if (Distance > 10000.0f) + { + Bullet->NetCullDistanceSquared = 0.0f; + } +} +``` + +### Replication Efficiency + +```cpp +// Efficient replication patterns +void OptimizeReplication() +{ + // Batch multiple bullets in single RPC + UFUNCTION(NetMulticast, Reliable) + void MulticastBulletBatch(const TArray& BulletData) + { + for (const auto& Data : BulletData) + { + SpawnBulletFromData(Data); + } + } + + // Use delta compression for position updates + UFUNCTION(NetMulticast, Unreliable) + void MulticastBulletPositions(const TArray& Positions) + { + // Update positions efficiently + } +} +``` + +## Performance Monitoring + +### Profiling Tools + +```cpp +// Built-in profiling +void ProfileBallistics() +{ + SCOPE_CYCLE_COUNTER(STAT_BallisticsUpdate); + + // Profile specific operations + { + SCOPE_CYCLE_COUNTER(STAT_BulletPhysics); + UpdateBulletPhysics(); + } + + { + SCOPE_CYCLE_COUNTER(STAT_BulletTraces); + PerformBulletTraces(); + } +} +``` + +### Performance Metrics + +```cpp +// Track performance metrics +struct FBallisticsMetrics +{ + float AverageUpdateTime; + int32 ActiveBulletCount; + float MemoryUsage; + float NetworkBandwidth; + + void UpdateMetrics() + { + // Calculate rolling averages + AverageUpdateTime = CalculateAverageUpdateTime(); + ActiveBulletCount = GetActiveBulletCount(); + MemoryUsage = GetMemoryUsage(); + NetworkBandwidth = GetNetworkUsage(); + } +}; +``` + +## Debug and Visualization + +### Performance Visualization + +```cpp +// Visualize performance bottlenecks +void VisualizePerformance() +{ + // Color-code bullets by performance cost + for (auto& Bullet : ActiveBullets) + { + float Cost = CalculatePerformanceCost(Bullet); + FColor DebugColor = GetPerformanceColor(Cost); + + DrawDebugSphere(GetWorld(), Bullet->GetActorLocation(), + 10.0f, 12, DebugColor, false, 0.1f); + } +} + +FColor GetPerformanceColor(float Cost) +{ + if (Cost < 0.1f) return FColor::Green; // Low cost + if (Cost < 0.5f) return FColor::Yellow; // Medium cost + return FColor::Red; // High cost +} +``` + +### Console Commands + +```cpp +// Debug console commands +UFUNCTION(Exec) +void BallisticsStats() +{ + UE_LOG(LogTemp, Warning, TEXT("Active Bullets: %d"), ActiveBullets.Num()); + UE_LOG(LogTemp, Warning, TEXT("Pool Size: %d"), BulletPool.Num()); + UE_LOG(LogTemp, Warning, TEXT("Memory Usage: %.2f MB"), GetMemoryUsage()); +} + +UFUNCTION(Exec) +void BallisticsProfile(bool bEnable) +{ + ProfilingEnabled = bEnable; + if (bEnable) + { + UE_LOG(LogTemp, Warning, TEXT("Ballistics profiling enabled")); + } +} +``` + +## Best Practices + +### Performance Guidelines + +1. **Always Use Pooling**: Enable object pooling for all bullet types +2. **Implement LOD**: Scale quality based on distance and importance +3. **Monitor Performance**: Use profiling tools to identify bottlenecks +4. **Optimize for Target Platform**: Use platform-specific optimizations +5. **Batch Operations**: Group similar operations together + +### Memory Guidelines + +1. **Avoid Frequent Allocation**: Reuse containers and objects +2. **Use Object Pooling**: Minimize garbage collection pressure +3. **Monitor Memory Usage**: Set up automatic memory monitoring +4. **Clean Up Properly**: Ensure bullets are properly deactivated + +### Network Guidelines + +1. **Reduce Update Frequency**: Lower frequency for distant bullets +2. **Use Unreliable Replication**: For position updates +3. **Implement Culling**: Don't replicate irrelevant bullets +4. **Batch RPCs**: Group multiple operations together + +## Common Performance Issues + +### Issue: Low Frame Rate + +**Symptoms**: +- Frame rate drops below 30 FPS +- Stuttering during intense combat + +**Solutions**: +```cpp +// Enable object pooling +Bullet->EnablePooling = true; + +// Reduce simulation quality +Bullet->MaxTracesPerStep = 4; +Bullet->FixedStepSeconds = 0.033f; + +// Implement LOD system +UpdateBulletLOD(Bullet); +``` + +### Issue: High Memory Usage + +**Symptoms**: +- Memory usage continuously increases +- Out of memory crashes + +**Solutions**: +```cpp +// Proper cleanup +void CleanupUnusedBullets() +{ + for (int32 i = ActiveBullets.Num() - 1; i >= 0; i--) + { + AEBBullet* Bullet = ActiveBullets[i]; + if (!Bullet->IsValidLowLevel() || Bullet->ShouldBeDestroyed()) + { + Bullet->Deactivate(); + ActiveBullets.RemoveAt(i); + } + } +} +``` + +### Issue: Network Lag + +**Symptoms**: +- High network bandwidth usage +- Desync between clients + +**Solutions**: +```cpp +// Optimize network settings +Bullet->NetUpdateFrequency = 10.0f; // Reduce from 20 +Bullet->NetCullDistanceSquared = 5000000.0f; // Cull at 500m +``` + +## Benchmarking Results + +### Performance Targets + +| Platform | Target FPS | Max Bullets | Memory Limit | +|----------|------------|-------------|--------------| +| PC High-End | 60 FPS | 500+ | 500 MB | +| PC Mid-Range | 60 FPS | 200+ | 200 MB | +| Console | 30 FPS | 100+ | 100 MB | +| Mobile | 30 FPS | 50+ | 50 MB | + +### Optimization Results + +| Optimization | FPS Improvement | Memory Reduction | +|--------------|-----------------|------------------| +| Object Pooling | +25% | -40% | +| LOD System | +15% | -20% | +| Trace Optimization | +10% | -5% | +| Network Optimization | +5% | -10% | + +## Next Steps + +- [Advanced Tutorials](../tutorials/advanced-concepts) - Complex implementation examples +- [Multiplayer Guide](multiplayer-guide) - Network optimization strategies +- [API Reference](../api/overview) - Complete function documentation + +--- + +*For platform-specific optimization guides, see the [Platform Guides](../platforms/) section.* \ No newline at end of file diff --git a/docs/docs/api/bullet-reference.md b/docs/docs/api/bullet-reference.md new file mode 100644 index 0000000..41c9bf4 --- /dev/null +++ b/docs/docs/api/bullet-reference.md @@ -0,0 +1,494 @@ +# AEBBullet API Reference + +Complete reference for the `AEBBullet` class - the core projectile actor in EasyBallistics. + +## Class Overview + +```cpp +UCLASS(Blueprintable, BlueprintType) +class EASYBALLISTICS_API AEBBullet : public AActor +{ + GENERATED_BODY() +}; +``` + +The `AEBBullet` class is the primary projectile actor that handles ballistic physics simulation, collision detection, and impact processing. + +## Core Properties + +### State Properties + +| Property | Type | Description | Default | +|----------|------|-------------|---------| +| `Velocity` | `FVector` | Current velocity vector in cm/s | `(0,0,0)` | +| `RandomStream` | `FRandomStream` | Seeded random stream for consistent behavior | - | +| `OwnerSafe` | `bool` | Whether bullet should ignore its owner initially | `false` | +| `FiringBarrel` | `UEBBarrel*` | Reference to the barrel that fired this bullet | `nullptr` | + +### Debug Properties + +| Property | Type | Description | Default | +|----------|------|-------------|---------| +| `DebugEnabled` | `bool` | Enable debug visualization | `false` | +| `DebugTrailTime` | `float` | Duration to show debug trails (seconds) | `1.0` | +| `DebugTrailWidth` | `float` | Width of debug trail lines | `0` | +| `DebugTrailColorFast` | `FLinearColor` | Color for high-speed portions of trail | Green | +| `DebugTrailColorSlow` | `FLinearColor` | Color for low-speed portions of trail | Red | +| `DebugPooling` | `bool` | Debug object pooling behavior | `false` | + +### World Environment + +| Property | Type | Description | Default | +|----------|------|-------------|---------| +| `Wind` | `FVector` | Wind velocity affecting the bullet | `(0,0,0)` | +| `AtmosphereType` | `EEBAtmosphereType` | Atmospheric simulation model | `AT_Constant` | +| `SeaLevelAirDensity` | `float` | Air density at sea level (kg/m³) | `1.21` | +| `SeaLevelSpeedOfSound` | `float` | Speed of sound at sea level (cm/s) | `34300` | +| `WorldScale` | `float` | World scale multiplier | `1.0` | +| `SeaLevelAirPressure` | `float` | Atmospheric pressure at sea level (mbar) | `1012.5` | +| `SeaLevelAirTemperature` | `float` | Temperature at sea level (°C) | `20.0` | + +### Physics Mode Selection + +| Property | Type | Description | Default | +|----------|------|-------------|---------| +| `UseMathematicalPhysics` | `bool` | Use mathematical ballistics calculations | `false` | +| `BulletPropertiesAsset` | `UEBBulletPropertiesAsset*` | Asset with mathematical bullet properties | `nullptr` | +| `MaterialPropertiesAsset` | `UEBMaterialPropertiesAsset*` | Asset with material properties | `nullptr` | + +### Artistic Properties (when `UseMathematicalPhysics = false`) + +| Property | Type | Description | Default | +|----------|------|-------------|---------| +| `Mass` | `float` | Bullet mass in kg | `0.005` | +| `Diameter` | `float` | Bullet diameter in cm | `0.556` | +| `FormFactor` | `float` | Form factor for drag calculations | `1.0` | +| `MachDragCurve` | `UCurveFloat*` | Drag curve vs Mach number | `nullptr` | + +### Flight Properties + +| Property | Type | Description | Default | +|----------|------|-------------|---------| +| `MuzzleVelocityMin` | `float` | Minimum muzzle velocity (cm/s) | `100000.0` | +| `MuzzleVelocityMax` | `float` | Maximum muzzle velocity (cm/s) | `100000.0` | +| `Spread` | `float` | Maximum bullet spread in radians | `0.0` | +| `SpreadBias` | `float` | Spread bias for accuracy | `0.0` | + +### Impact System + +| Property | Type | Description | Default | +|----------|------|-------------|---------| +| `UseNewImpactSystem` | `bool` | Use the new ballistic impact component | `false` | +| `BallisticImpactComponent` | `UEBBallisticImpactComponent*` | Impact handling component | Auto-created | +| `MaterialResponseMap` | `UEBMaterialResponseMap*` | Material interaction rules | `nullptr` | + +### Collision Settings + +| Property | Type | Description | Default | +|----------|------|-------------|---------| +| `TraceChannel` | `ECollisionChannel` | Collision channel for traces | `ECC_WorldStatic` | +| `TraceComplex` | `bool` | Use complex collision shapes | `false` | +| `CollisionMargin` | `float` | Collision detection margin (cm) | `1.0` | +| `DespawnVelocity` | `float` | Velocity below which bullet despawns | `100.0` | +| `IgnoredActors` | `TArray` | Actors to ignore during collision | Empty | + +### Simulation Settings + +| Property | Type | Description | Default | +|----------|------|-------------|---------| +| `FixedStep` | `bool` | Use fixed timestep simulation | `false` | +| `FixedStepSeconds` | `float` | Fixed timestep duration | `0.1` | +| `MaxTracesPerStep` | `int32` | Maximum collision traces per simulation step | `8` | +| `DoFirstStepImmediately` | `bool` | Perform first trace immediately on spawn | `true` | + +### Object Pooling + +| Property | Type | Description | Default | +|----------|------|-------------|---------| +| `EnablePooling` | `bool` | Enable object pooling for this bullet type | `false` | +| `MaxPoolSize` | `int32` | Maximum number of bullets in pool | `50` | + +## Static Spawning Functions + +### SpawnWithExactVelocity + +```cpp +UFUNCTION(BlueprintCallable, Category = "EBBullet|Spawn") +static void SpawnWithExactVelocity( + TSubclassOf BulletClass, + AActor* BulletOwner, + APawn* BulletInstigator, + FVector BulletLocation, + FVector BulletVelocity +); +``` + +Spawns a bullet with precise velocity without applying spread or velocity randomization. + +**Parameters:** +- `BulletClass`: The bullet class to spawn +- `BulletOwner`: Actor that owns the bullet (for collision ignoring) +- `BulletInstigator`: Pawn that caused the bullet to be fired (for damage attribution) +- `BulletLocation`: World location to spawn the bullet +- `BulletVelocity`: Exact velocity vector in cm/s + +### SpawnWithExactVelocityFromBarrel + +```cpp +UFUNCTION(BlueprintCallable, Category = "EBBullet|Spawn") +static void SpawnWithExactVelocityFromBarrel( + TSubclassOf BulletClass, + AActor* BulletOwner, + APawn* BulletInstigator, + FVector BulletLocation, + FVector BulletVelocity, + UEBBarrel* SourceBarrel +); +``` + +Spawns a bullet from a specific barrel, inheriting barrel properties and settings. + +### Spawn + +```cpp +UFUNCTION(BlueprintCallable, Category = "EBBullet|Spawn") +static void Spawn( + TSubclassOf BulletClass, + AActor* BulletOwner, + APawn* BulletInstigator, + FVector BulletLocation, + FVector BulletVelocity +); +``` + +Standard bullet spawning with spread and velocity variation applied. + +## Physics Functions + +### UpdateVelocity + +```cpp +UFUNCTION(BlueprintNativeEvent, Category = "EBBullet|Flight") +FVector UpdateVelocity( + UWorld* World, + FVector Location, + FVector PreviousVelocity, + float DeltaTime +) const; +``` + +Updates bullet velocity each simulation step. Override this to implement custom physics. + +**Parameters:** +- `World`: World context +- `Location`: Current bullet location +- `PreviousVelocity`: Velocity from previous frame +- `DeltaTime`: Time since last update + +**Returns:** New velocity vector + +### GetWind + +```cpp +UFUNCTION(BlueprintNativeEvent, Category = "EBBullet|World") +FVector GetWind(UWorld* World, FVector Location) const; +``` + +Gets wind velocity at the specified location. Override for dynamic wind systems. + +### GetAirDensity + +```cpp +UFUNCTION(BlueprintNativeEvent, Category = "EBBullet|World") +float GetAirDensity(UWorld* World, FVector Location) const; +``` + +Gets air density at the specified location based on altitude and atmosphere type. + +### GetSpeedOfSound + +```cpp +UFUNCTION(BlueprintNativeEvent, Category = "EBBullet|World") +float GetSpeedOfSound(UWorld* World, FVector Location) const; +``` + +Gets speed of sound at the specified location for Mach number calculations. + +## Mathematical Physics Functions + +### GetEffectiveMass + +```cpp +UFUNCTION(BlueprintCallable, Category = "EBBullet|Mathematical Physics") +float GetEffectiveMass() const; +``` + +Returns the effective mass of the bullet, considering mathematical properties if enabled. + +### GetEffectiveDiameter + +```cpp +UFUNCTION(BlueprintCallable, Category = "EBBullet|Mathematical Physics") +float GetEffectiveDiameter() const; +``` + +Returns the effective diameter of the bullet in centimeters. + +### GetEffectiveDragCoefficient + +```cpp +UFUNCTION(BlueprintCallable, Category = "EBBullet|Mathematical Physics") +float GetEffectiveDragCoefficient(float MachNumber) const; +``` + +Calculates drag coefficient based on Mach number and ballistic coefficient. + +### CalculateMathematicalPenetration + +```cpp +UFUNCTION(BlueprintCallable, Category = "EBBullet|Mathematical Physics") +float CalculateMathematicalPenetration( + UPhysicalMaterial* Material, + float VelocityMPS, + float ImpactAngle +) const; +``` + +Calculates penetration depth using mathematical ballistics formulas. + +### CalculateMathematicalRicochetProbability + +```cpp +UFUNCTION(BlueprintCallable, Category = "EBBullet|Mathematical Physics") +float CalculateMathematicalRicochetProbability( + UPhysicalMaterial* Material, + float VelocityMPS, + float ImpactAngle +) const; +``` + +Calculates ricochet probability using mathematical models. + +## Impact Events + +### OnImpact + +```cpp +UFUNCTION(BlueprintAuthorityOnly, BlueprintNativeEvent, Category = "EBBullet|Impact") +void OnImpact( + bool Ricochet, + bool PassedThrough, + FVector Location, + FVector IncomingVelocity, + FVector Normal, + FVector ExitLocation, + FVector ExitVelocity, + FVector Impulse, + float PenetrationDepth, + AActor* Actor, + USceneComponent* Component, + FName BoneName, + UPhysicalMaterial* PhysMaterial, + FHitResult HitResult +); +``` + +Called when bullet impacts a surface (server authority only). + +### OnNetPredictedImpact + +```cpp +UFUNCTION(BlueprintCosmetic, BlueprintNativeEvent, Category = "EBBullet|Impact") +void OnNetPredictedImpact( + bool Ricochet, + bool PassedThrough, + FVector Location, + FVector IncomingVelocity, + FVector Normal, + FVector ExitLocation, + FVector ExitVelocity, + FVector Impulse, + float PenetrationDepth, + AActor* Actor, + USceneComponent* Component, + FName BoneName, + UPhysicalMaterial* PhysMaterial, + FHitResult HitResult +); +``` + +Called for client-side prediction of impacts (cosmetic only). + +### OnTrace + +```cpp +UFUNCTION(BlueprintImplementableEvent, Category = "EBBullet|Impact") +void OnTrace(FVector StartLocation, FVector EndLocation); +``` + +Called each simulation step for debugging trajectory visualization. + +## Network Functions + +### VelocityChangeBroadcast + +```cpp +UFUNCTION(NetMulticast, Unreliable) +void VelocityChangeBroadcast( + FVector_NetQuantize NewLocation, + FVector NewVelocity +); +``` + +Broadcasts velocity changes to all clients (unreliable for performance). + +### VelocityChangeBroadcastReliable + +```cpp +UFUNCTION(NetMulticast, Reliable) +void VelocityChangeBroadcastReliable( + FVector_NetQuantize NewLocation, + FVector NewVelocity +); +``` + +Broadcasts critical velocity changes with reliable delivery. + +### OnTrajectoryUpdateReceived + +```cpp +UFUNCTION(BlueprintImplementableEvent, Category = "EBBullet|Remote") +void OnTrajectoryUpdateReceived( + FVector Location, + FVector OldVelocity, + FVector NewVelocity +); +``` + +Called when trajectory updates are received from server. + +## Pooling Functions + +### Deactivate + +```cpp +UFUNCTION(BlueprintAuthorityOnly, BlueprintCallable, Category = "EBBullet|Pooling") +void Deactivate(); +``` + +Deactivates the bullet and returns it to the object pool. + +### OnDeactivated + +```cpp +UFUNCTION(BlueprintNativeEvent, Category = "EBBullet|Activation") +void OnDeactivated(); +``` + +Called when bullet is deactivated. Override to implement custom cleanup. + +## Collision Filtering + +### CollisionFilter + +```cpp +UFUNCTION(BlueprintNativeEvent, Category = "EBBullet|World") +bool CollisionFilter(FHitResult HitResult) const; +``` + +Filters collision hits. Return `false` to ignore the hit. + +**Parameters:** +- `HitResult`: The collision result to evaluate + +**Returns:** `true` to process the hit, `false` to ignore it + +## Debug Functions + +### CreateDebugImpactWidget + +```cpp +UFUNCTION(BlueprintCallable, Category = "EBBullet|Debug") +void CreateDebugImpactWidget( + FVector Location, + bool bRicochet, + bool bPenetration, + FVector ImpactVelocity, + float PenetrationDepth, + UPhysicalMaterial* Material +); +``` + +Creates debug information display at impact location. + +## Usage Examples + +### Basic Bullet Spawning + +```cpp +// Spawn a simple bullet +AEBBullet::Spawn( + MyBulletClass, + MyWeapon, + MyPlayer, + MuzzleLocation, + MuzzleDirection * MuzzleVelocity +); +``` + +### Mathematical Ballistics Setup + +```cpp +// Configure for realistic ballistics +Bullet->UseMathematicalPhysics = true; +Bullet->BulletPropertiesAsset = My556BulletProperties; +Bullet->UseNewImpactSystem = true; +Bullet->AtmosphereType = EEBAtmosphereType::AT_Earth; +``` + +### Impact Event Handling + +```cpp +// In C++ +void AMyActor::HandleBulletImpact(/* impact parameters */) +{ + if (bDidPenetrate) + { + SpawnPenetrationEffect(Location, PenetrationDepth); + } + else + { + SpawnImpactEffect(Location, Normal); + } +} + +// Bind the event +Bullet->BallisticImpactComponent->OnBallisticImpact.AddDynamic( + this, &AMyActor::HandleBulletImpact); +``` + +### Performance Optimization + +```cpp +// Enable pooling for high-rate fire +Bullet->EnablePooling = true; +Bullet->MaxPoolSize = 100; + +// Reduce simulation quality for distant bullets +if (Distance > 2000.0f) +{ + Bullet->MaxTracesPerStep = 4; + Bullet->FixedStepSeconds = 0.033f; +} +``` + +## See Also + +- [UEBBarrel API Reference](barrel-reference) - Weapon barrel component +- [UEBBallisticImpactComponent API Reference](impact-component-reference) - Impact handling +- [Mathematical Ballistics](../core-concepts/overview#mathematical-vs-artistic-modes) - Physics calculation modes +- [Performance Optimization](../advanced/performance-optimization) - Optimization strategies + +--- + +*For more detailed examples, see the [Advanced Weapon Systems Tutorial](../tutorials/advanced-weapon-systems).* \ No newline at end of file diff --git a/docs/docs/api/overview.md b/docs/docs/api/overview.md index ebe5099..eeaaaa1 100644 --- a/docs/docs/api/overview.md +++ b/docs/docs/api/overview.md @@ -357,8 +357,24 @@ When migrating from the old impact system: - Impact events have different parameter signatures - Some artistic properties moved to new component system +## Detailed API References + +### Core Classes + +- **[AEBBullet](bullet-reference)** - Complete bullet actor reference with all properties and methods +- **UEBBarrel** - Weapon barrel component (coming soon) +- **UEBBallisticImpactComponent** - Impact handling component (coming soon) +- **UEBMathematicalBallistics** - Static calculation functions (coming soon) + +### Asset Classes + +- **UEBBulletPropertiesAsset** - Bullet characteristic definitions (coming soon) +- **UEBMaterialResponseMap** - Material interaction rules (coming soon) +- **UEBMaterialPropertiesAsset** - Material ballistic properties (coming soon) + ## See Also - [Core Concepts](../core-concepts/overview) - System architecture overview - [Quick Start Guide](../getting-started/quick-start) - Create your first weapon +- [Advanced Weapon Systems](../tutorials/advanced-weapon-systems) - Complex implementation examples - [Troubleshooting](../troubleshooting) - Common issues and solutions \ No newline at end of file diff --git a/docs/docs/core-concepts/gatling-mechanics.md b/docs/docs/core-concepts/gatling-mechanics.md new file mode 100644 index 0000000..6e62c0c --- /dev/null +++ b/docs/docs/core-concepts/gatling-mechanics.md @@ -0,0 +1,59 @@ +--- +id: gatling-mechanics +title: Gatling Mechanics +sidebar_label: Gatling Mechanics +--- + +EasyBallistics supports simulating Gatling-style weapons (miniguns) with spool-up and spool-down behavior. This allows for a dynamic fire rate that changes over time. + +## Enabling Gatling Mode + +To use the Gatling mechanics, you must set the `FireMode` property on the `EBBarrel` component to `Gatling`. + +## Core Properties + +All Gatling-related properties are found on the `EBBarrel` component. + +| Property | Type | Description | +|---|---|---| +| `GatlingAutoSpool` | `bool` | If true, the barrel will automatically start spooling up when the `Shoot` function is called with `Trigger` set to true, and spool down when called with `false`. If false, you must manually control spooling. | +| `GatlingSpoolUpTime` | `float` | The time in seconds it takes for the barrel to ramp up from zero to its maximum fire rate. | +| `GatlingSpoolDownTime` | `float` | The time in seconds it takes for the barrel to ramp down from its maximum fire rate to zero after the trigger is released (or `GatlingSpool(false)` is called). | +| `FireRateMin` | `float` | The rounds-per-second when the Gatling barrel is at its minimum spool (usually 0). | +| `FireRateMax` | `float` | The rounds-per-second when the Gatling barrel has fully spooled up. | + +## Runtime State + +You can monitor the state of the Gatling barrel at runtime with these properties: + +| Property | Type | Description | +|---|---|---| +| `Spooling` | `bool` | A read-only boolean that is true if the barrel is currently spooling up or down. | +| `GatlingPhase` | `float` | A read-only value from 0.0 to 1.0 representing the current spool progress. 0 is fully spooled down, and 1 is fully spooled up. | +| `GatlingRPS` | `float` | The current rounds-per-second of the barrel, based on the `GatlingPhase`. This value is interpolated between `FireRateMin` and `FireRateMax`. | + +## Manual Control + +If `GatlingAutoSpool` is disabled, you have direct control over the spooling behavior. + +### `GatlingSpool` (Function) + +This function allows you to manually start and stop the spooling process. + +| Parameter | Type | Description | +|---|---|---| +| `Spool` | `bool` | If `true`, the barrel will begin to spool up. If `false`, it will begin to spool down. | + +**Example Blueprint Usage:** + +You could hook this up to separate key events to allow the player to pre-spool the weapon before firing. + +```blueprint +// On "Spool Up" button pressed: +MyBarrel->GatlingSpool(true); + +// On "Spool Up" button released: +MyBarrel->GatlingSpool(false); +``` + +While manually spooling, you still need to call the `Shoot` function to actually fire bullets. The rate of fire will depend on the `GatlingRPS` at the moment `Shoot` is called. \ No newline at end of file diff --git a/docs/docs/core-concepts/trajectory-prediction.md b/docs/docs/core-concepts/trajectory-prediction.md new file mode 100644 index 0000000..0c8be76 --- /dev/null +++ b/docs/docs/core-concepts/trajectory-prediction.md @@ -0,0 +1,71 @@ +--- +id: trajectory-prediction +title: Trajectory Prediction +sidebar_label: Trajectory Prediction +--- + +EasyBallistics provides powerful Blueprint-callable functions for predicting a bullet's trajectory and calculating the required aim to hit a moving target. These are essential for creating smart AI, aim assists, or target lead indicators. + +All prediction functions are located on the `EBBarrel` component. + +## Predicting Bullet Impact + +These functions simulate the full flight of a virtual bullet and report where it will hit. + +### `PredictHit` + +Predicts the trajectory and impact point of a bullet fired from the barrel's current position and orientation. + +**Outputs:** +- `Hit` (bool): `true` if an impact is predicted within the `MaxTime`. +- `TraceResult` (HitResult): The standard Unreal Engine hit result structure. +- `HitLocation` (Vector): The world-space location of the impact. +- `HitTime` (float): The predicted time in seconds until impact. +- `HitActor` (Actor): The actor that was hit. +- `Trajectory` (`TArray`): An array of points representing the predicted flight path. + +**Inputs:** +- `BulletClass` (`TSubclassOf`): The bullet to use for the prediction. The simulation will use this bullet's properties (drag, velocity, etc.). +- `IgnoredActors` (`TArray`): A list of actors to ignore during the trace. +- `MaxTime` (float): The maximum simulated flight time in seconds. +- `Step` (float): The time step for the simulation. Smaller values are more accurate but more expensive. + +### `PredictHitFromLocation` + +This version works identically to `PredictHit`, but allows you to specify a custom starting location and aim direction, rather than using the barrel's transform. + +**Additional Inputs:** +- `StartLocation` (Vector): The world-space location to start the prediction from. +- `AimDirection` (Vector): The initial direction of fire for the prediction. + +## Calculating Aim Direction (Solving for a Hit) + +These functions are used to calculate the correct direction to fire in order to hit a moving target. This is often called "target leading". + +### `CalculateAimDirection` + +Calculates the aim direction required to hit a target, accounting for bullet drop and target velocity. + +**Outputs:** +- `AimDirection` (Vector): The calculated direction you should fire in. +- `PredictedTargetLocation` (Vector): The predicted location of the target at the moment of impact. +- `PredictedIntersectionLocation` (Vector): The predicted location of the bullet/target intersection. +- `PredictedFlightTime` (float): The predicted flight time of the bullet. +- `Error` (float): A measure of the final aiming error. Lower is better. + +**Inputs:** +- `BulletClass` (`TSubclassOf`): The bullet to use for the calculation. +- `TargetLocation` (Vector): The current world-space location of the target. +- `TargetVelocity` (Vector): The current velocity of the target in cm/s. +- `MaxTime`, `Step`, `NumIterations`: Parameters to control the simulation's accuracy and performance. Higher iterations improve the solution. + +### `CalculateAimDirectionFromLocation` + +This version works identically to `CalculateAimDirection`, but allows you to specify a custom starting location for the shot. + +**Additional Inputs:** +- `StartLocation` (Vector): The world-space location the shot will be fired from. + +**Example Use Case (AI):** + +An AI character could use `CalculateAimDirection` every tick to get a precise aim vector for the player, then smoothly interpolate its weapon's rotation to match that vector, leading to realistic aiming behavior. \ No newline at end of file diff --git a/docs/docs/getting-started/installation.md b/docs/docs/getting-started/installation.md index 98cf179..55e3078 100644 --- a/docs/docs/getting-started/installation.md +++ b/docs/docs/getting-started/installation.md @@ -1,157 +1,243 @@ -# Installation +# Installation Guide This guide will walk you through installing EasyBallistics in your Unreal Engine project. -## Prerequisites +## System Requirements -- **Unreal Engine 5.6.0** or later -- **Visual Studio 2022** (for C++ projects) -- **Git** (for version control) +### Minimum Requirements +- **Unreal Engine**: 5.6.0 or later +- **Operating System**: Windows 10, macOS 10.15, or Ubuntu 18.04 +- **Memory**: 8GB RAM minimum (16GB recommended) +- **Storage**: 500MB available space + +### Supported Platforms +- **Development**: Windows, macOS, Linux +- **Deployment**: Windows, macOS, Linux, Android, iOS +- **Network**: Full multiplayer support ## Installation Methods -### Method 1: Marketplace Installation (Recommended) +### Method 1: Unreal Engine Marketplace (Recommended) -1. Open the **Epic Games Launcher** -2. Navigate to the **Marketplace** -3. Search for "EasyBallistics" -4. Click **Add to Project** or **Install to Engine** -5. Select your target project -6. Click **Install** +1. **Open Epic Games Launcher** + - Navigate to the Unreal Engine Marketplace + - Search for "EasyBallistics" + - Click "Add to Project" or "Install to Engine" + +2. **Add to Project** + - Open your project in Unreal Engine + - Go to **Edit → Plugins** + - Find "EasyBallistics" in the **Installed** tab + - Check the **Enabled** checkbox + - Click **Restart Now** ### Method 2: Manual Installation -1. Download the plugin from the marketplace or GitHub -2. Extract the plugin to your project's `Plugins` folder: +1. **Download Plugin** + - Extract the EasyBallistics folder + - Copy it to your project's `Plugins` folder + - Create the `Plugins` folder if it doesn't exist + +2. **Directory Structure** ``` YourProject/ ├── Plugins/ │ └── EasyBallistics/ + │ ├── EasyBallistics.uplugin │ ├── Source/ │ ├── Resources/ - │ └── EasyBallistics.uplugin + │ └── ... + ├── YourProject.uproject + └── ... ``` -3. Regenerate project files: + +3. **Enable Plugin** - Right-click your `.uproject` file - - Select **Generate Visual Studio project files** + - Select "Generate Visual Studio project files" + - Open the project in Unreal Engine + - Go to **Edit → Plugins** + - Enable EasyBallistics in the **Project** tab -### Method 3: Git Submodule (Advanced) +### Method 3: Engine-Level Installation -```bash -# Navigate to your project directory -cd YourProject/Plugins +1. **Install to Engine** + - Copy EasyBallistics to your Engine's plugins folder: + ``` + [UE5_Installation]/Engine/Plugins/EasyBallistics/ + ``` -# Add as submodule -git submodule add https://github.com/your-org/easyballistics.git EasyBallistics +2. **Enable in Projects** + - The plugin will be available in all projects + - Enable it per-project in **Edit → Plugins** -# Initialize and update -git submodule update --init --recursive -``` +## Verification -## Enabling the Plugin +### Check Plugin Loading -1. Open your project in Unreal Engine -2. Go to **Edit → Plugins** -3. Search for "EasyBallistics" -4. Check the **Enabled** checkbox -5. Click **Restart Now** when prompted +1. **Plugin Manager** + - Open **Edit → Plugins** + - Confirm EasyBallistics shows as "Enabled" + - Look for any error messages -![Plugin Manager](https://placehold.co/800x400/2e8555/white?text=Plugin+Manager+Screenshot) +2. **Content Browser** + - Right-click in Content Browser + - Verify "Ballistics" category appears in the context menu + - Try creating a new Bullet Properties asset -## Verifying Installation +3. **Blueprint Editor** + - Create a new Actor Blueprint + - Add an "EB Barrel" component + - Verify the component appears and has properties -### Check Plugin Status +### Compilation Test -1. Open **Edit → Plugins** -2. Verify EasyBallistics shows as **Enabled** -3. Check for any error messages +1. **C++ Projects** + - Add EasyBallistics to your module dependencies: + ```cpp + // In YourProject.Build.cs + PublicDependencyModuleNames.AddRange(new string[] { + "Core", + "CoreUObject", + "Engine", + "EasyBallistics" // Add this line + }); + ``` -### Test Basic Functionality +2. **Compile Project** + - Build your project in Visual Studio or Rider + - Verify no compilation errors -1. In the Content Browser, right-click -2. Look for **Ballistics** category in the asset creation menu -3. You should see: - - Bullet Properties - - Material Response Map +## Troubleshooting -![Asset Creation Menu](https://placehold.co/600x400/2e8555/white?text=Asset+Creation+Menu) +### Plugin Not Visible -### Verify Components +**Problem**: EasyBallistics doesn't appear in the Plugin Manager -1. Create a new Actor Blueprint -2. Add Component → Search "Ballistic" -3. You should find: - - **EB Barrel** (weapon barrel component) - - **EB Ballistic Impact Component** (impact handling) +**Solutions**: +1. Verify file placement in `Plugins/EasyBallistics/` +2. Check that `EasyBallistics.uplugin` exists +3. Regenerate project files and restart editor +4. Check UE5 version compatibility (5.6.0+ required) -## Project Configuration +### Compilation Errors -### Build Configuration +**Problem**: Build errors when enabling the plugin -Add to your project's `DefaultEngine.ini`: +**Solutions**: +1. **Missing Dependencies**: + ```cpp + // Add to YourProject.Build.cs + PublicDependencyModuleNames.AddRange(new string[] { + "EasyBallistics", + "PhysicsCore", // Often required + "NavigationSystem" // For some features + }); + ``` -```ini -[/Script/Engine.Engine] -+ActiveGameNameRedirects=(OldGameName="EasyBallistics",NewGameName="/Script/EasyBallistics") -+ActiveGameNameRedirects=(OldGameName="EasyBallisticsEditor",NewGameName="/Script/EasyBallisticsEditor") -``` +2. **Clean Build**: + - Delete `Binaries` and `Intermediate` folders + - Regenerate project files + - Rebuild solution -### Module Dependencies +3. **Version Mismatch**: + - Ensure UE5 version is 5.6.0 or later + - Check plugin version compatibility -If using C++, add to your project's `Build.cs` file: +### Content Browser Issues + +**Problem**: "Ballistics" category missing from asset creation menu + +**Solutions**: +1. Refresh Content Browser (F5) +2. Restart Unreal Engine +3. Verify plugin is enabled in Project settings +4. Check Editor log for errors + +### Performance Issues + +**Problem**: Frame rate drops after enabling plugin + +**Solutions**: +1. **Disable Debug Features**: + - Turn off debug visualization in bullet settings + - Disable debug impact info on barrels + +2. **Optimize Settings**: + - Enable object pooling on bullets + - Reduce max traces per step + - Use fixed timestep for consistency + +## Project Setup + +### Add Module Dependencies + +For C++ projects, add these to your `.Build.cs` file: ```cpp PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", - "EasyBallistics" // Add this line + "EasyBallistics", + "PhysicsCore", + "NavigationSystem" +}); + +PrivateDependencyModuleNames.AddRange(new string[] { + "EasyBallistics" }); ``` -## Troubleshooting +### Configure Project Settings -### Common Issues +1. **Collision Channels** + - Add custom collision channels for bullets + - Configure response settings -#### Plugin Not Appearing -- Ensure you're using UE 5.6 or later -- Check if the plugin files are in the correct location -- Regenerate project files +2. **Network Settings** + - Adjust replication settings for multiplayer + - Configure bandwidth limits -#### Compilation Errors -- Verify Visual Studio 2022 is installed -- Check that all dependencies are met -- Try a clean rebuild - -#### Missing Components -- Restart the editor after enabling the plugin -- Clear the derived data cache: **Edit → Developer → Derived Data → Clear** - -### Error Messages - -#### "Module 'EasyBallistics' could not be loaded" -1. Check your UE version compatibility -2. Verify the plugin is enabled -3. Regenerate project files -4. Clean and rebuild the project - -#### "Failed to load because module 'EasyBallistics' could not be found" -1. Ensure the plugin is in the `Plugins` folder -2. Check the `.uplugin` file is valid -3. Verify file permissions +3. **Performance Settings** + - Set appropriate tick rates + - Configure object pooling limits ## Next Steps -Once installation is complete: +After successful installation: -1. [Quick Start Guide](quick-start) - Create your first ballistic weapon -2. [Core Concepts](../core-concepts/overview) - Understand the system architecture -3. [API Reference](../api/overview) - Detailed function documentation +1. **[Quick Start Guide](quick-start)** - Create your first weapon +2. **[Core Concepts](../core-concepts/overview)** - Understand the system +3. **[API Reference](../api/overview)** - Detailed function documentation ## Getting Help -If you encounter issues during installation: +### Support Resources -- Check the [Troubleshooting](../troubleshooting) guide -- Visit our [Discord community](https://discord.gg/easyballistics) -- Submit an issue on [GitHub](https://github.com/your-org/easyballistics/issues) \ No newline at end of file +- **Discord**: [Join our community](https://discord.gg/easyballistics) +- **Email**: support@easyballistics.com +- **Forums**: [Unreal Engine Forums](https://forums.unrealengine.com/) +- **GitHub**: [Issues and Bug Reports](https://github.com/your-org/easyballistics/issues) + +### Common Installation Issues + +| Issue | Solution | +|-------|----------| +| Plugin not loading | Check UE5 version compatibility | +| Compilation errors | Add required module dependencies | +| Missing asset menu | Refresh Content Browser, restart editor | +| Performance drops | Disable debug features, optimize settings | + +### Reporting Issues + +When reporting installation problems, please include: + +- UE5 version and build number +- Operating system and version +- Plugin version +- Error messages and log files +- Steps to reproduce the issue + +--- + +*Ready to start building ballistic systems? Continue with the [Quick Start Guide](quick-start)!* \ No newline at end of file diff --git a/docs/docs/intro.md b/docs/docs/intro.md index ac4fa89..e048f7b 100644 --- a/docs/docs/intro.md +++ b/docs/docs/intro.md @@ -65,9 +65,17 @@ graph TD ## Getting Started -1. [Installation Guide](getting-started/installation) - Install the plugin -2. [Quick Start](getting-started/quick-start) - Create your first weapon -3. [Core Concepts](core-concepts/overview) - Understand the system architecture +1. **[Installation Guide](getting-started/installation)** - Install and configure the plugin +2. **[Quick Start](getting-started/quick-start)** - Create your first weapon in 10 minutes +3. **[Core Concepts](core-concepts/overview)** - Understand the system architecture + +## Advanced Topics + +4. **[Advanced Weapon Systems](tutorials/advanced-weapon-systems)** - Smart ammunition and complex firing modes +5. **[Multiplayer Guide](advanced/multiplayer-guide)** - Network optimization and server authority +6. **[Performance Optimization](advanced/performance-optimization)** - Achieve optimal performance +7. **[Editor Tools](advanced/editor-tools)** - Streamlined asset creation workflows +8. **[Migration Guide](advanced/migration-guide)** - Upgrade from older versions ## Support diff --git a/docs/docs/troubleshooting.md b/docs/docs/troubleshooting.md index 2d4edf0..693b79c 100644 --- a/docs/docs/troubleshooting.md +++ b/docs/docs/troubleshooting.md @@ -380,6 +380,31 @@ DebugTrailColorFast = Green DebugTrailColorSlow = Red ``` +### Impact Information Widget + +EasyBallistics includes a widget to display detailed information about bullet impacts in real-time. This is useful for debugging penetration, ricochets, and material responses. + +**How to Enable:** + +1. **Enable on Barrel**: On your `EBBarrel` component, set the `DebugImpactInfo` boolean property to `true`. +2. **Create a Widget Blueprint**: + * In the Content Browser, click "Add New" -> "User Interface" -> "Widget Blueprint". + * In the "Pick Parent Class" dialog, search for and select `EBDebugImpactWidget`. + * Name and save your new widget Blueprint. You can customize its appearance here. +3. **Assign to Bullet**: On your `EBBullet` asset, find the `DebugWidgetClass` property and assign the Widget Blueprint you just created. + +**Displayed Information:** + +When enabled, a widget will appear at the location of an impact, showing the following: + +* **Impact Type**: Whether the bullet `RICOCHET`, `PENETRATION`, or was `STOPPED`. +* **Material**: The name of the `UPhysicalMaterial` that was hit. +* **Velocity**: The bullet's velocity at impact, in meters per second (m/s) and kilometers per hour (km/h). +* **Mass**: The effective mass of the bullet in kilograms (kg). +* **Diameter**: The effective diameter of the bullet in centimeters (cm). +* **Energy**: The kinetic energy of the bullet at impact, in Joules (J). +* **Penetration**: The depth of penetration in centimeters (cm). + ### Console Commands ``` diff --git a/docs/docs/tutorials/advanced-weapon-systems.md b/docs/docs/tutorials/advanced-weapon-systems.md new file mode 100644 index 0000000..5c0c040 --- /dev/null +++ b/docs/docs/tutorials/advanced-weapon-systems.md @@ -0,0 +1,779 @@ +# Advanced Weapon Systems Tutorial + +This tutorial demonstrates creating complex weapon systems using EasyBallistics, including smart ammunition, guided projectiles, and advanced firing modes. + +## Smart Ammunition System + +### Heat-Seeking Projectiles + +Create bullets that track heat signatures: + +```cpp +UCLASS(BlueprintType) +class YOURGAME_API AHeatSeekingBullet : public AEBBullet +{ + GENERATED_BODY() + +public: + AHeatSeekingBullet() + { + PrimaryActorTick.bCanEverTick = true; + + // Heat seeking properties + SeekingRange = 2000.0f; + SeekingStrength = 0.5f; + MaxTurnRate = 45.0f; // degrees per second + } + +protected: + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Heat Seeking") + float SeekingRange = 2000.0f; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Heat Seeking") + float SeekingStrength = 0.5f; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Heat Seeking") + float MaxTurnRate = 45.0f; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Heat Seeking") + TArray> TargetClasses; + +private: + AActor* CurrentTarget = nullptr; + float TimeAlive = 0.0f; + +public: + virtual void Tick(float DeltaTime) override + { + Super::Tick(DeltaTime); + + TimeAlive += DeltaTime; + + // Start seeking after initial acceleration phase + if (TimeAlive > 0.1f) + { + UpdateHeatSeeking(DeltaTime); + } + } + +private: + void UpdateHeatSeeking(float DeltaTime) + { + // Find the hottest target within range + AActor* BestTarget = FindHottestTarget(); + + if (BestTarget) + { + CurrentTarget = BestTarget; + + // Calculate direction to target + FVector ToTarget = (BestTarget->GetActorLocation() - GetActorLocation()).GetSafeNormal(); + FVector CurrentDirection = Velocity.GetSafeNormal(); + + // Calculate turn towards target + FVector NewDirection = FMath::VInterpTo(CurrentDirection, ToTarget, DeltaTime, + FMath::DegreesToRadians(MaxTurnRate)); + + // Apply seeking strength + NewDirection = FMath::Lerp(CurrentDirection, NewDirection, SeekingStrength); + + // Update velocity + float CurrentSpeed = Velocity.Size(); + Velocity = NewDirection * CurrentSpeed; + } + } + + AActor* FindHottestTarget() + { + TArray NearbyActors; + UGameplayStatics::GetAllActorsOfClass(GetWorld(), APawn::StaticClass(), NearbyActors); + + AActor* BestTarget = nullptr; + float BestHeatSignature = 0.0f; + float BestDistance = FLT_MAX; + + for (AActor* Actor : NearbyActors) + { + if (!Actor || Actor == GetOwner()) + continue; + + float Distance = FVector::Dist(GetActorLocation(), Actor->GetActorLocation()); + if (Distance > SeekingRange) + continue; + + // Calculate heat signature (example implementation) + float HeatSignature = CalculateHeatSignature(Actor, Distance); + + if (HeatSignature > BestHeatSignature) + { + BestTarget = Actor; + BestHeatSignature = HeatSignature; + BestDistance = Distance; + } + } + + return BestTarget; + } + + float CalculateHeatSignature(AActor* Actor, float Distance) + { + // Base heat signature + float Heat = 1.0f; + + // Check if it's a vehicle (higher heat) + if (Actor->IsA()) + { + Heat *= 2.0f; + } + + // Check if engine is running + if (UActorComponent* EngineComp = Actor->GetComponentByClass(UEngineComponent::StaticClass())) + { + Heat *= 1.5f; + } + + // Distance falloff + Heat *= FMath::Max(0.1f, 1.0f - (Distance / SeekingRange)); + + return Heat; + } +}; +``` + +### Proximity Explosive Rounds + +Create rounds that detonate near targets: + +```cpp +UCLASS() +class YOURGAME_API AProximityBullet : public AEBBullet +{ + GENERATED_BODY() + +public: + AProximityBullet() + { + // Proximity settings + ProximityRadius = 300.0f; + ExplosionRadius = 500.0f; + ExplosionDamage = 150.0f; + ArmingDistance = 500.0f; + + bIsArmed = false; + DistanceTraveled = 0.0f; + } + +protected: + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Proximity") + float ProximityRadius = 300.0f; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Proximity") + float ExplosionRadius = 500.0f; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Proximity") + float ExplosionDamage = 150.0f; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Proximity") + float ArmingDistance = 500.0f; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Proximity") + TSubclassOf ExplosionEffect; + +private: + bool bIsArmed = false; + float DistanceTraveled = 0.0f; + FVector LastPosition; + +public: + virtual void BeginPlay() override + { + Super::BeginPlay(); + LastPosition = GetActorLocation(); + } + + virtual void Tick(float DeltaTime) override + { + Super::Tick(DeltaTime); + + // Track distance traveled + FVector CurrentPos = GetActorLocation(); + DistanceTraveled += FVector::Dist(CurrentPos, LastPosition); + LastPosition = CurrentPos; + + // Arm after minimum distance + if (!bIsArmed && DistanceTraveled >= ArmingDistance) + { + bIsArmed = true; + OnBulletArmed(); + } + + // Check proximity if armed + if (bIsArmed) + { + CheckProximity(); + } + } + +private: + void CheckProximity() + { + TArray NearbyActors; + UGameplayStatics::GetAllActorsOfClass(GetWorld(), APawn::StaticClass(), NearbyActors); + + for (AActor* Actor : NearbyActors) + { + if (!Actor || Actor == GetOwner()) + continue; + + float Distance = FVector::Dist(GetActorLocation(), Actor->GetActorLocation()); + if (Distance <= ProximityRadius) + { + // Trigger explosion + Explode(); + return; + } + } + } + + void Explode() + { + FVector ExplosionLocation = GetActorLocation(); + + // Spawn explosion effect + if (ExplosionEffect) + { + GetWorld()->SpawnActor(ExplosionEffect, ExplosionLocation, FRotator::ZeroRotator); + } + + // Apply radial damage + UGameplayStatics::ApplyRadialDamage( + GetWorld(), + ExplosionDamage, + ExplosionLocation, + ExplosionRadius, + UDamageType::StaticClass(), + TArray(), // Ignore list + this, + GetInstigatorController(), + true // Full damage + ); + + // Trigger explosion event + OnExplosion(ExplosionLocation); + + // Destroy bullet + Destroy(); + } + +protected: + UFUNCTION(BlueprintImplementableEvent, Category = "Proximity") + void OnBulletArmed(); + + UFUNCTION(BlueprintImplementableEvent, Category = "Proximity") + void OnExplosion(FVector Location); +}; +``` + +## Advanced Firing Modes + +### Burst Fire with Recoil Control + +```cpp +UCLASS() +class YOURGAME_API UAdvancedBarrel : public UEBBarrel +{ + GENERATED_BODY() + +public: + UAdvancedBarrel() + { + // Recoil control settings + RecoilAccumulation = 0.0f; + RecoilDecayRate = 2.0f; + MaxRecoilMultiplier = 3.0f; + + // Burst settings + BurstShotDelay = 0.05f; + BurstAccuracyPenalty = 0.1f; + } + +protected: + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Advanced Firing") + float RecoilDecayRate = 2.0f; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Advanced Firing") + float MaxRecoilMultiplier = 3.0f; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Advanced Firing") + float BurstShotDelay = 0.05f; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Advanced Firing") + float BurstAccuracyPenalty = 0.1f; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Advanced Firing") + UCurveFloat* RecoilPattern; + +private: + float RecoilAccumulation = 0.0f; + int32 ShotsInBurst = 0; + +public: + virtual void TickComponent(float DeltaTime, ELevelTick TickType, + FActorComponentTickFunction* ThisTickFunction) override + { + Super::TickComponent(DeltaTime, TickType, ThisTickFunction); + + // Decay recoil over time + if (RecoilAccumulation > 0.0f) + { + RecoilAccumulation = FMath::Max(0.0f, RecoilAccumulation - (RecoilDecayRate * DeltaTime)); + } + } + +protected: + virtual void SpawnBullet(AActor* Owner, FVector LocalLocation, FVector LocalAim) override + { + // Calculate recoil-modified aim direction + FVector ModifiedAim = ApplyRecoilToAim(LocalAim); + + // Apply burst accuracy penalty + if (ShotsInBurst > 0) + { + float BurstSpread = BurstAccuracyPenalty * ShotsInBurst; + ModifiedAim = ApplySpreadToDirection(ModifiedAim, BurstSpread); + } + + // Spawn bullet with modified direction + Super::SpawnBullet(Owner, LocalLocation, ModifiedAim); + + // Update recoil accumulation + RecoilAccumulation = FMath::Min(MaxRecoilMultiplier, RecoilAccumulation + 1.0f); + + // Update burst counter + if (FireMode == EFireMode::FM_Burst) + { + ShotsInBurst++; + if (ShotsInBurst >= BurstCount) + { + ShotsInBurst = 0; + } + } + else + { + ShotsInBurst = 0; + } + + // Apply recoil to weapon + ApplyWeaponRecoil(); + } + +private: + FVector ApplyRecoilToAim(FVector BaseAim) + { + if (RecoilAccumulation <= 0.0f || !RecoilPattern) + return BaseAim; + + // Sample recoil pattern + float PatternSample = RecoilPattern->GetFloatValue(RecoilAccumulation); + + // Apply random recoil within pattern bounds + float RecoilAmount = PatternSample * FMath::RandRange(0.8f, 1.2f); + + // Create recoil offset (upward and slightly random horizontal) + FVector RecoilOffset = FVector( + FMath::RandRange(-0.3f, 0.3f) * RecoilAmount, // Horizontal + 0.0f, + 1.0f * RecoilAmount // Vertical + ); + + // Apply recoil to aim direction + FVector ModifiedAim = BaseAim + RecoilOffset; + return ModifiedAim.GetSafeNormal(); + } + + void ApplyWeaponRecoil() + { + // Apply physical recoil to weapon/player + APawn* OwnerPawn = Cast(GetOwner()); + if (OwnerPawn && OwnerPawn->GetController()) + { + APlayerController* PC = Cast(OwnerPawn->GetController()); + if (PC) + { + // Camera recoil + float RecoilMagnitude = RecoilAccumulation * 0.5f; + FRotator RecoilRotation( + FMath::RandRange(-RecoilMagnitude, RecoilMagnitude * 2.0f), // Pitch (mostly up) + FMath::RandRange(-RecoilMagnitude * 0.3f, RecoilMagnitude * 0.3f), // Yaw + 0.0f // Roll + ); + + PC->ClientSetCameraShake(nullptr); // Add camera shake here + } + } + } +}; +``` + +### Dual-Mode Weapon System + +```cpp +UCLASS() +class YOURGAME_API ADualModeWeapon : public AActor +{ + GENERATED_BODY() + +public: + ADualModeWeapon() + { + PrimaryActorTick.bCanEverTick = true; + + // Create components + WeaponMesh = CreateDefaultSubobject(TEXT("WeaponMesh")); + RootComponent = WeaponMesh; + + PrimaryBarrel = CreateDefaultSubobject(TEXT("PrimaryBarrel")); + SecondaryBarrel = CreateDefaultSubobject(TEXT("SecondaryBarrel")); + + // Default to primary mode + CurrentMode = EWeaponMode::Primary; + ModeTransitionTime = 1.0f; + bIsTransitioning = false; + } + +protected: + UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Components") + UStaticMeshComponent* WeaponMesh; + + UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Components") + UEBBarrel* PrimaryBarrel; + + UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Components") + UEBBarrel* SecondaryBarrel; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Weapon Modes") + float ModeTransitionTime = 1.0f; + +private: + UENUM(BlueprintType) + enum class EWeaponMode : uint8 + { + Primary, + Secondary, + Transitioning + }; + + EWeaponMode CurrentMode; + bool bIsTransitioning; + float TransitionProgress; + +public: + UFUNCTION(BlueprintCallable, Category = "Weapon") + void Fire() + { + if (bIsTransitioning) + return; + + switch (CurrentMode) + { + case EWeaponMode::Primary: + PrimaryBarrel->Shoot(true); + break; + case EWeaponMode::Secondary: + SecondaryBarrel->Shoot(true); + break; + } + } + + UFUNCTION(BlueprintCallable, Category = "Weapon") + void SwitchMode() + { + if (bIsTransitioning) + return; + + bIsTransitioning = true; + TransitionProgress = 0.0f; + + OnModeTransitionStarted(); + } + + virtual void Tick(float DeltaTime) override + { + Super::Tick(DeltaTime); + + if (bIsTransitioning) + { + TransitionProgress += DeltaTime / ModeTransitionTime; + + if (TransitionProgress >= 1.0f) + { + // Complete transition + bIsTransitioning = false; + CurrentMode = (CurrentMode == EWeaponMode::Primary) ? + EWeaponMode::Secondary : EWeaponMode::Primary; + + OnModeTransitionCompleted(); + } + else + { + // Update transition animation + UpdateTransitionAnimation(TransitionProgress); + } + } + } + +protected: + UFUNCTION(BlueprintImplementableEvent, Category = "Weapon Events") + void OnModeTransitionStarted(); + + UFUNCTION(BlueprintImplementableEvent, Category = "Weapon Events") + void OnModeTransitionCompleted(); + + UFUNCTION(BlueprintImplementableEvent, Category = "Weapon Events") + void UpdateTransitionAnimation(float Progress); + + UFUNCTION(BlueprintPure, Category = "Weapon") + bool IsPrimaryMode() const + { + return CurrentMode == EWeaponMode::Primary; + } + + UFUNCTION(BlueprintPure, Category = "Weapon") + bool IsSecondaryMode() const + { + return CurrentMode == EWeaponMode::Secondary; + } + + UFUNCTION(BlueprintPure, Category = "Weapon") + UEBBarrel* GetActiveBarrel() const + { + return (CurrentMode == EWeaponMode::Primary) ? PrimaryBarrel : SecondaryBarrel; + } +}; +``` + +## Modular Weapon System + +### Attachment System + +```cpp +UCLASS() +class YOURGAME_API UWeaponAttachment : public UObject +{ + GENERATED_BODY() + +public: + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Attachment") + FString AttachmentName; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Attachment") + UStaticMesh* AttachmentMesh; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Attachment") + FName SocketName; + + // Stat modifications + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Stats") + float DamageMultiplier = 1.0f; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Stats") + float AccuracyMultiplier = 1.0f; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Stats") + float RangeMultiplier = 1.0f; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Stats") + float FireRateMultiplier = 1.0f; + + // Special effects + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Effects") + bool bProvidesMuzzleFlash = false; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Effects") + bool bProvidesSuppression = false; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Effects") + bool bProvidesScope = false; + +public: + UFUNCTION(BlueprintImplementableEvent, Category = "Attachment") + void OnAttached(AActor* WeaponActor); + + UFUNCTION(BlueprintImplementableEvent, Category = "Attachment") + void OnDetached(AActor* WeaponActor); +}; + +UCLASS() +class YOURGAME_API AModularWeapon : public AActor +{ + GENERATED_BODY() + +public: + AModularWeapon() + { + WeaponMesh = CreateDefaultSubobject(TEXT("WeaponMesh")); + RootComponent = WeaponMesh; + + Barrel = CreateDefaultSubobject(TEXT("Barrel")); + } + +protected: + UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Components") + UStaticMeshComponent* WeaponMesh; + + UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Components") + UEBBarrel* Barrel; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Attachments") + TArray Attachments; + + UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Attachments") + TArray AttachmentMeshes; + +public: + UFUNCTION(BlueprintCallable, Category = "Attachments") + void AttachAccessory(UWeaponAttachment* Attachment) + { + if (!Attachment) + return; + + Attachments.Add(Attachment); + + // Create mesh component for attachment + UStaticMeshComponent* AttachmentMesh = NewObject(this); + AttachmentMesh->SetStaticMesh(Attachment->AttachmentMesh); + AttachmentMesh->AttachToComponent(WeaponMesh, + FAttachmentTransformRules::SnapToTargetNotIncludingScale, + Attachment->SocketName); + AttachmentMeshes.Add(AttachmentMesh); + + // Apply stat modifications + ApplyAttachmentModifications(); + + // Trigger attachment event + Attachment->OnAttached(this); + } + + UFUNCTION(BlueprintCallable, Category = "Attachments") + void DetachAccessory(UWeaponAttachment* Attachment) + { + int32 Index = Attachments.Find(Attachment); + if (Index != INDEX_NONE) + { + Attachments.RemoveAt(Index); + + // Remove mesh component + if (AttachmentMeshes.IsValidIndex(Index)) + { + AttachmentMeshes[Index]->DestroyComponent(); + AttachmentMeshes.RemoveAt(Index); + } + + // Reapply all modifications + ApplyAttachmentModifications(); + + // Trigger detachment event + Attachment->OnDetached(this); + } + } + +private: + void ApplyAttachmentModifications() + { + // Reset to base stats + float DamageMultiplier = 1.0f; + float AccuracyMultiplier = 1.0f; + float RangeMultiplier = 1.0f; + float FireRateMultiplier = 1.0f; + + bool bHasSuppressor = false; + bool bHasScope = false; + + // Apply all attachment modifications + for (UWeaponAttachment* Attachment : Attachments) + { + if (Attachment) + { + DamageMultiplier *= Attachment->DamageMultiplier; + AccuracyMultiplier *= Attachment->AccuracyMultiplier; + RangeMultiplier *= Attachment->RangeMultiplier; + FireRateMultiplier *= Attachment->FireRateMultiplier; + + bHasSuppressor = bHasSuppressor || Attachment->bProvidesSuppression; + bHasScope = bHasScope || Attachment->bProvidesScope; + } + } + + // Apply modifications to barrel + Barrel->Spread = Barrel->Spread / AccuracyMultiplier; + Barrel->FireRateMin = Barrel->FireRateMin * FireRateMultiplier; + Barrel->FireRateMax = Barrel->FireRateMax * FireRateMultiplier; + + // TODO: Apply damage and range modifications to bullets + // This would require modifying bullet properties at spawn time + } + +public: + UFUNCTION(BlueprintPure, Category = "Attachments") + bool HasAttachmentOfType(TSubclassOf AttachmentClass) const + { + for (UWeaponAttachment* Attachment : Attachments) + { + if (Attachment && Attachment->IsA(AttachmentClass)) + { + return true; + } + } + return false; + } + + UFUNCTION(BlueprintPure, Category = "Attachments") + TArray GetAttachmentsOfType(TSubclassOf AttachmentClass) const + { + TArray MatchingAttachments; + + for (UWeaponAttachment* Attachment : Attachments) + { + if (Attachment && Attachment->IsA(AttachmentClass)) + { + MatchingAttachments.Add(Attachment); + } + } + + return MatchingAttachments; + } +}; +``` + +## Best Practices + +### Performance Optimization + +1. **Use Object Pooling**: Always enable pooling for smart ammunition +2. **Limit Seeking Frequency**: Don't update seeking every tick for distant projectiles +3. **Optimize Target Detection**: Use spatial partitioning for target finding +4. **Cache References**: Store frequently accessed components and actors + +### Gameplay Balance + +1. **Arming Distances**: Prevent exploitation with minimum arming distances +2. **Proximity Limits**: Set reasonable proximity detection ranges +3. **Targeting Restrictions**: Limit what can be targeted by smart ammunition +4. **Countermeasures**: Provide ways to defeat smart ammunition + +### Network Considerations + +1. **Server Authority**: Ensure explosive damage is calculated on server +2. **Prediction**: Allow visual effects on clients with server validation +3. **Bandwidth**: Minimize replication data for smart projectiles +4. **Synchronization**: Keep attachment states synchronized + +## Next Steps + +- [Performance Optimization](../advanced/performance-optimization) - Optimize complex weapon systems +- [Multiplayer Guide](../advanced/multiplayer-guide) - Network these advanced systems +- [Editor Tools](../advanced/editor-tools) - Create custom tools for your weapons + +--- + +*Ready for more advanced topics? Explore [Multiplayer Implementation](../advanced/multiplayer-guide) next.* \ No newline at end of file diff --git a/docs/docusaurus.config.js b/docs/docusaurus.config.js index fe1a5e7..6f3af9a 100644 --- a/docs/docusaurus.config.js +++ b/docs/docusaurus.config.js @@ -40,7 +40,7 @@ const config = { /** @type {import('@docusaurus/preset-classic').Options} */ ({ docs: { - routeBasePath: '/', + routeBasePath: '/docs', sidebarPath: './sidebars.js', // Please change this to your repo. // Remove this to remove the "edit this page" links. @@ -70,6 +70,7 @@ const config = { logo: { alt: 'EasyBallistics Logo', src: 'img/logo.svg', + href: '/docs/intro', }, items: [ { @@ -77,6 +78,7 @@ const config = { sidebarId: 'tutorialSidebar', position: 'left', label: 'Documentation', + to: '/docs/intro', }, { href: 'https://www.unrealengine.com/marketplace/en-US/product/easyballistics', @@ -98,11 +100,11 @@ const config = { items: [ { label: 'Getting Started', - to: '/getting-started/installation', + to: '/docs/getting-started/installation', }, { label: 'API Reference', - to: '/api/overview', + to: '/docs/api/overview', }, ], }, diff --git a/docs/sidebars.js b/docs/sidebars.js index e05d3b7..0983d39 100644 --- a/docs/sidebars.js +++ b/docs/sidebars.js @@ -29,6 +29,25 @@ const sidebars = { label: 'Core Concepts', items: [ 'core-concepts/overview', + 'core-concepts/gatling-mechanics', + 'core-concepts/trajectory-prediction', + ], + }, + { + type: 'category', + label: 'Tutorials', + items: [ + 'tutorials/advanced-weapon-systems', + ], + }, + { + type: 'category', + label: 'Advanced Guides', + items: [ + 'advanced/multiplayer-guide', + 'advanced/performance-optimization', + 'advanced/editor-tools', + 'advanced/migration-guide', ], }, { @@ -36,6 +55,7 @@ const sidebars = { label: 'API Reference', items: [ 'api/overview', + 'api/bullet-reference', ], }, 'troubleshooting',