This commit is contained in:
2025-07-03 00:11:01 -07:00
parent f3c1c2e349
commit f3971ae2d9
14 changed files with 4004 additions and 103 deletions
+735
View File
@@ -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<UEBBulletPropertiesAsset>(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<UObject*>& 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<UObject*>& 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<float>)
.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<IPropertyHandle> 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<SWidget> CreateMaterialMapWidget(TSharedRef<IPropertyHandle> 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<FVector> 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<UEBBulletPropertiesAsset>(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<SWidget> 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<UEBBulletPropertiesAsset*> AllBulletAssets;
FindAllAssetsOfClass(AllBulletAssets);
for (auto* Asset : AllBulletAssets)
{
UpdateBulletPropertiesFormulas(Asset);
Asset->MarkPackageDirty();
}
}
// Validate all material response maps
static void ValidateAllMaterialMaps()
{
TArray<UEBMaterialResponseMap*> AllMaps;
FindAllAssetsOfClass(AllMaps);
for (auto* Map : AllMaps)
{
ValidateMaterialMap(Map);
}
}
private:
template<typename T>
static void FindAllAssetsOfClass(TArray<T*>& OutAssets)
{
FAssetRegistryModule& AssetRegistryModule =
FModuleManager::LoadModuleChecked<FAssetRegistryModule>("AssetRegistry");
TArray<FAssetData> AssetData;
AssetRegistryModule.Get().GetAssetsByClass(T::StaticClass()->GetFName(), AssetData);
for (const auto& Asset : AssetData)
{
if (T* LoadedAsset = Cast<T>(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<UEBBulletPropertiesAsset*>& 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<UEBBulletPropertiesAsset*> ImportBulletPropertiesFromCSV(const FString& FilePath)
{
TArray<UEBBulletPropertiesAsset*> CreatedAssets;
FString FileContent;
if (!FFileHelper::LoadFileToString(FileContent, *FilePath))
{
return CreatedAssets;
}
TArray<FString> 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<FContentBrowserModule>("ContentBrowser");
// Add caliber column for bullet properties
ContentBrowserModule.GetAllAssetViewContextMenuExtenders().Add(
FContentBrowserMenuExtender_SelectedAssets::CreateStatic(
&FEBContentBrowserExtensions::OnExtendContentBrowserAssetSelectionMenu));
}
private:
static TSharedRef<FExtender> OnExtendContentBrowserAssetSelectionMenu(
const TArray<FAssetData>& SelectedAssets)
{
TSharedRef<FExtender> Extender = MakeShared<FExtender>();
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<ISettingsModule>("Settings"))
{
SettingsModule->RegisterSettings("Project", "Plugins", "EasyBallistics",
LOCTEXT("RuntimeSettingsName", "EasyBallistics"),
LOCTEXT("RuntimeSettingsDescription", "Configure EasyBallistics plugin"),
GetMutableDefault<UEBEditorSettings>()
);
}
}
```
## 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/).*
+463
View File
@@ -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<UPhysicalMaterial>("PM_Steel");
// Wood
UPhysicalMaterial* PM_Wood = CreateDefaultSubobject<UPhysicalMaterial>("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<UPhysicalMaterial*, FEBMaterialResponseMapEntry> 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<AActor*> StaticMeshActors;
UGameplayStatics::GetAllActorsOfClass(GetWorld(), AStaticMeshActor::StaticClass(), StaticMeshActors);
for (AActor* Actor : StaticMeshActors)
{
AStaticMeshActor* MeshActor = Cast<AStaticMeshActor>(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<AEBBullet> BulletClass : AllBulletClasses)
{
AEBBullet* CDO = BulletClass.GetDefaultObject();
CDO->UseNewImpactSystem = true;
// Ensure component exists
if (!CDO->BallisticImpactComponent)
{
CDO->BallisticImpactComponent = CreateDefaultSubobject<UEBBallisticImpactComponent>(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<FString> CommonMaterials = {
"Steel", "Wood", "Concrete", "Glass", "Fabric"
};
for (const FString& MaterialName : CommonMaterials)
{
CreatePhysicalMaterialAsset(MaterialName);
}
}
static void MigrateAllMaterialResponseMaps()
{
TArray<UEBMaterialResponseMap*> 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<FString, FString> 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<UPhysicalMaterial>(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<UEBBallisticImpactComponent>(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.*
+570
View File
@@ -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).*
@@ -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<AEBBullet>();
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<FVector> Positions;
TArray<FVector> Velocities;
TArray<float> Masses;
TArray<float> 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<FHitResult> HitResults;
HitResults.Reset(); // Clear but keep capacity
// Use object pooling for frequently created objects
static TArray<AEBBullet*> 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<FBulletData>& BulletData)
{
for (const auto& Data : BulletData)
{
SpawnBulletFromData(Data);
}
}
// Use delta compression for position updates
UFUNCTION(NetMulticast, Unreliable)
void MulticastBulletPositions(const TArray<FVector_NetQuantize>& 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.*
+494
View File
@@ -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<AActor*>` | 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<AEBBullet> 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<AEBBullet> 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<AEBBullet> 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).*
+16
View File
@@ -357,8 +357,24 @@ When migrating from the old impact system:
- Impact events have different parameter signatures - Impact events have different parameter signatures
- Some artistic properties moved to new component system - 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 ## See Also
- [Core Concepts](../core-concepts/overview) - System architecture overview - [Core Concepts](../core-concepts/overview) - System architecture overview
- [Quick Start Guide](../getting-started/quick-start) - Create your first weapon - [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 - [Troubleshooting](../troubleshooting) - Common issues and solutions
@@ -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.
@@ -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<FVector>`): An array of points representing the predicted flight path.
**Inputs:**
- `BulletClass` (`TSubclassOf<AEBBullet>`): The bullet to use for the prediction. The simulation will use this bullet's properties (drag, velocity, etc.).
- `IgnoredActors` (`TArray<AActor*>`): 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<AEBBullet>`): 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.
+183 -97
View File
@@ -1,157 +1,243 @@
# Installation # Installation Guide
This guide will walk you through installing EasyBallistics in your Unreal Engine project. This guide will walk you through installing EasyBallistics in your Unreal Engine project.
## Prerequisites ## System Requirements
- **Unreal Engine 5.6.0** or later ### Minimum Requirements
- **Visual Studio 2022** (for C++ projects) - **Unreal Engine**: 5.6.0 or later
- **Git** (for version control) - **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 ## Installation Methods
### Method 1: Marketplace Installation (Recommended) ### Method 1: Unreal Engine Marketplace (Recommended)
1. Open the **Epic Games Launcher** 1. **Open Epic Games Launcher**
2. Navigate to the **Marketplace** - Navigate to the Unreal Engine Marketplace
3. Search for "EasyBallistics" - Search for "EasyBallistics"
4. Click **Add to Project** or **Install to Engine** - Click "Add to Project" or "Install to Engine"
5. Select your target project
6. Click **Install** 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 ### Method 2: Manual Installation
1. Download the plugin from the marketplace or GitHub 1. **Download Plugin**
2. Extract the plugin to your project's `Plugins` folder: - 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/ YourProject/
├── Plugins/ ├── Plugins/
│ └── EasyBallistics/ │ └── EasyBallistics/
│ ├── EasyBallistics.uplugin
│ ├── Source/ │ ├── Source/
│ ├── Resources/ │ ├── Resources/
│ └── EasyBallistics.uplugin │ └── ...
├── YourProject.uproject
└── ...
``` ```
3. Regenerate project files:
3. **Enable Plugin**
- Right-click your `.uproject` file - 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 1. **Install to Engine**
# Navigate to your project directory - Copy EasyBallistics to your Engine's plugins folder:
cd YourProject/Plugins ```
[UE5_Installation]/Engine/Plugins/EasyBallistics/
```
# Add as submodule 2. **Enable in Projects**
git submodule add https://github.com/your-org/easyballistics.git EasyBallistics - The plugin will be available in all projects
- Enable it per-project in **Edit → Plugins**
# Initialize and update ## Verification
git submodule update --init --recursive
```
## Enabling the Plugin ### Check Plugin Loading
1. Open your project in Unreal Engine 1. **Plugin Manager**
2. Go to **Edit → Plugins** - Open **Edit → Plugins**
3. Search for "EasyBallistics" - Confirm EasyBallistics shows as "Enabled"
4. Check the **Enabled** checkbox - Look for any error messages
5. Click **Restart Now** when prompted
![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** 1. **C++ Projects**
2. Verify EasyBallistics shows as **Enabled** - Add EasyBallistics to your module dependencies:
3. Check for any error messages ```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 ## Troubleshooting
2. Look for **Ballistics** category in the asset creation menu
3. You should see:
- Bullet Properties
- Material Response Map
![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 **Solutions**:
2. Add Component → Search "Ballistic" 1. Verify file placement in `Plugins/EasyBallistics/`
3. You should find: 2. Check that `EasyBallistics.uplugin` exists
- **EB Barrel** (weapon barrel component) 3. Regenerate project files and restart editor
- **EB Ballistic Impact Component** (impact handling) 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 2. **Clean Build**:
[/Script/Engine.Engine] - Delete `Binaries` and `Intermediate` folders
+ActiveGameNameRedirects=(OldGameName="EasyBallistics",NewGameName="/Script/EasyBallistics") - Regenerate project files
+ActiveGameNameRedirects=(OldGameName="EasyBallisticsEditor",NewGameName="/Script/EasyBallisticsEditor") - 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 ```cpp
PublicDependencyModuleNames.AddRange(new string[] { PublicDependencyModuleNames.AddRange(new string[] {
"Core", "Core",
"CoreUObject", "CoreUObject",
"Engine", "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 2. **Network Settings**
- Ensure you're using UE 5.6 or later - Adjust replication settings for multiplayer
- Check if the plugin files are in the correct location - Configure bandwidth limits
- Regenerate project files
#### Compilation Errors 3. **Performance Settings**
- Verify Visual Studio 2022 is installed - Set appropriate tick rates
- Check that all dependencies are met - Configure object pooling limits
- 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
## Next Steps ## Next Steps
Once installation is complete: After successful installation:
1. [Quick Start Guide](quick-start) - Create your first ballistic weapon 1. **[Quick Start Guide](quick-start)** - Create your first weapon
2. [Core Concepts](../core-concepts/overview) - Understand the system architecture 2. **[Core Concepts](../core-concepts/overview)** - Understand the system
3. [API Reference](../api/overview) - Detailed function documentation 3. **[API Reference](../api/overview)** - Detailed function documentation
## Getting Help ## Getting Help
If you encounter issues during installation: ### Support Resources
- Check the [Troubleshooting](../troubleshooting) guide - **Discord**: [Join our community](https://discord.gg/easyballistics)
- Visit our [Discord community](https://discord.gg/easyballistics) - **Email**: support@easyballistics.com
- Submit an issue on [GitHub](https://github.com/your-org/easyballistics/issues) - **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)!*
+11 -3
View File
@@ -65,9 +65,17 @@ graph TD
## Getting Started ## Getting Started
1. [Installation Guide](getting-started/installation) - Install the plugin 1. **[Installation Guide](getting-started/installation)** - Install and configure the plugin
2. [Quick Start](getting-started/quick-start) - Create your first weapon 2. **[Quick Start](getting-started/quick-start)** - Create your first weapon in 10 minutes
3. [Core Concepts](core-concepts/overview) - Understand the system architecture 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 ## Support
+25
View File
@@ -380,6 +380,31 @@ DebugTrailColorFast = Green
DebugTrailColorSlow = Red 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 ### Console Commands
``` ```
@@ -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<TSubclassOf<AActor>> 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<AActor*> 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<AVehicle>())
{
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<AActor> 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<AActor*> 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<AActor>(ExplosionEffect, ExplosionLocation, FRotator::ZeroRotator);
}
// Apply radial damage
UGameplayStatics::ApplyRadialDamage(
GetWorld(),
ExplosionDamage,
ExplosionLocation,
ExplosionRadius,
UDamageType::StaticClass(),
TArray<AActor*>(), // 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<APawn>(GetOwner());
if (OwnerPawn && OwnerPawn->GetController())
{
APlayerController* PC = Cast<APlayerController>(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<UStaticMeshComponent>(TEXT("WeaponMesh"));
RootComponent = WeaponMesh;
PrimaryBarrel = CreateDefaultSubobject<UEBBarrel>(TEXT("PrimaryBarrel"));
SecondaryBarrel = CreateDefaultSubobject<UEBBarrel>(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<UStaticMeshComponent>(TEXT("WeaponMesh"));
RootComponent = WeaponMesh;
Barrel = CreateDefaultSubobject<UEBBarrel>(TEXT("Barrel"));
}
protected:
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Components")
UStaticMeshComponent* WeaponMesh;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Components")
UEBBarrel* Barrel;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Attachments")
TArray<UWeaponAttachment*> Attachments;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Attachments")
TArray<UStaticMeshComponent*> AttachmentMeshes;
public:
UFUNCTION(BlueprintCallable, Category = "Attachments")
void AttachAccessory(UWeaponAttachment* Attachment)
{
if (!Attachment)
return;
Attachments.Add(Attachment);
// Create mesh component for attachment
UStaticMeshComponent* AttachmentMesh = NewObject<UStaticMeshComponent>(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<UWeaponAttachment> AttachmentClass) const
{
for (UWeaponAttachment* Attachment : Attachments)
{
if (Attachment && Attachment->IsA(AttachmentClass))
{
return true;
}
}
return false;
}
UFUNCTION(BlueprintPure, Category = "Attachments")
TArray<UWeaponAttachment*> GetAttachmentsOfType(TSubclassOf<UWeaponAttachment> AttachmentClass) const
{
TArray<UWeaponAttachment*> 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.*
+5 -3
View File
@@ -40,7 +40,7 @@ const config = {
/** @type {import('@docusaurus/preset-classic').Options} */ /** @type {import('@docusaurus/preset-classic').Options} */
({ ({
docs: { docs: {
routeBasePath: '/', routeBasePath: '/docs',
sidebarPath: './sidebars.js', sidebarPath: './sidebars.js',
// Please change this to your repo. // Please change this to your repo.
// Remove this to remove the "edit this page" links. // Remove this to remove the "edit this page" links.
@@ -70,6 +70,7 @@ const config = {
logo: { logo: {
alt: 'EasyBallistics Logo', alt: 'EasyBallistics Logo',
src: 'img/logo.svg', src: 'img/logo.svg',
href: '/docs/intro',
}, },
items: [ items: [
{ {
@@ -77,6 +78,7 @@ const config = {
sidebarId: 'tutorialSidebar', sidebarId: 'tutorialSidebar',
position: 'left', position: 'left',
label: 'Documentation', label: 'Documentation',
to: '/docs/intro',
}, },
{ {
href: 'https://www.unrealengine.com/marketplace/en-US/product/easyballistics', href: 'https://www.unrealengine.com/marketplace/en-US/product/easyballistics',
@@ -98,11 +100,11 @@ const config = {
items: [ items: [
{ {
label: 'Getting Started', label: 'Getting Started',
to: '/getting-started/installation', to: '/docs/getting-started/installation',
}, },
{ {
label: 'API Reference', label: 'API Reference',
to: '/api/overview', to: '/docs/api/overview',
}, },
], ],
}, },
+20
View File
@@ -29,6 +29,25 @@ const sidebars = {
label: 'Core Concepts', label: 'Core Concepts',
items: [ items: [
'core-concepts/overview', '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', label: 'API Reference',
items: [ items: [
'api/overview', 'api/overview',
'api/bullet-reference',
], ],
}, },
'troubleshooting', 'troubleshooting',