Initial Commit
This commit is contained in:
commit
9c4061da5b
1795
Unreal/Backup/PS_Ballistics.sln
Normal file
1795
Unreal/Backup/PS_Ballistics.sln
Normal file
File diff suppressed because it is too large
Load Diff
0
Unreal/Config/DefaultEditor.ini
Normal file
0
Unreal/Config/DefaultEditor.ini
Normal file
92
Unreal/Config/DefaultEngine.ini
Normal file
92
Unreal/Config/DefaultEngine.ini
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
|
||||||
|
|
||||||
|
[/Script/EngineSettings.GameMapsSettings]
|
||||||
|
GameDefaultMap=/Engine/Maps/Templates/OpenWorld
|
||||||
|
|
||||||
|
[/Script/Engine.RendererSettings]
|
||||||
|
r.AllowStaticLighting=False
|
||||||
|
|
||||||
|
r.GenerateMeshDistanceFields=True
|
||||||
|
|
||||||
|
r.DynamicGlobalIlluminationMethod=1
|
||||||
|
|
||||||
|
r.ReflectionMethod=1
|
||||||
|
|
||||||
|
r.SkinCache.CompileShaders=True
|
||||||
|
|
||||||
|
r.RayTracing=True
|
||||||
|
|
||||||
|
r.Shadow.Virtual.Enable=1
|
||||||
|
|
||||||
|
r.DefaultFeature.AutoExposure.ExtendDefaultLuminanceRange=True
|
||||||
|
|
||||||
|
r.DefaultFeature.LocalExposure.HighlightContrastScale=0.8
|
||||||
|
|
||||||
|
r.DefaultFeature.LocalExposure.ShadowContrastScale=0.8
|
||||||
|
|
||||||
|
[/Script/WindowsTargetPlatform.WindowsTargetSettings]
|
||||||
|
DefaultGraphicsRHI=DefaultGraphicsRHI_DX12
|
||||||
|
DefaultGraphicsRHI=DefaultGraphicsRHI_DX12
|
||||||
|
-D3D12TargetedShaderFormats=PCD3D_SM5
|
||||||
|
+D3D12TargetedShaderFormats=PCD3D_SM6
|
||||||
|
-D3D11TargetedShaderFormats=PCD3D_SM5
|
||||||
|
+D3D11TargetedShaderFormats=PCD3D_SM5
|
||||||
|
Compiler=Default
|
||||||
|
AudioSampleRate=48000
|
||||||
|
AudioCallbackBufferFrameSize=1024
|
||||||
|
AudioNumBuffersToEnqueue=1
|
||||||
|
AudioMaxChannels=0
|
||||||
|
AudioNumSourceWorkers=4
|
||||||
|
SpatializationPlugin=
|
||||||
|
SourceDataOverridePlugin=
|
||||||
|
ReverbPlugin=
|
||||||
|
OcclusionPlugin=
|
||||||
|
CompressionOverrides=(bOverrideCompressionTimes=False,DurationThreshold=5.000000,MaxNumRandomBranches=0,SoundCueQualityIndex=0)
|
||||||
|
CacheSizeKB=65536
|
||||||
|
MaxChunkSizeOverrideKB=0
|
||||||
|
bResampleForDevice=False
|
||||||
|
MaxSampleRate=48000.000000
|
||||||
|
HighSampleRate=32000.000000
|
||||||
|
MedSampleRate=24000.000000
|
||||||
|
LowSampleRate=12000.000000
|
||||||
|
MinSampleRate=8000.000000
|
||||||
|
CompressionQualityModifier=1.000000
|
||||||
|
AutoStreamingThreshold=0.000000
|
||||||
|
SoundCueCookQualityIndex=-1
|
||||||
|
|
||||||
|
[/Script/LinuxTargetPlatform.LinuxTargetSettings]
|
||||||
|
-TargetedRHIs=SF_VULKAN_SM5
|
||||||
|
+TargetedRHIs=SF_VULKAN_SM6
|
||||||
|
|
||||||
|
[/Script/HardwareTargeting.HardwareTargetingSettings]
|
||||||
|
TargetedHardwareClass=Desktop
|
||||||
|
AppliedTargetedHardwareClass=Desktop
|
||||||
|
DefaultGraphicsPerformance=Maximum
|
||||||
|
AppliedDefaultGraphicsPerformance=Maximum
|
||||||
|
|
||||||
|
[/Script/WorldPartitionEditor.WorldPartitionEditorSettings]
|
||||||
|
CommandletClass=Class'/Script/UnrealEd.WorldPartitionConvertCommandlet'
|
||||||
|
|
||||||
|
[/Script/Engine.UserInterfaceSettings]
|
||||||
|
bAuthorizeAutomaticWidgetVariableCreation=False
|
||||||
|
FontDPIPreset=Standard
|
||||||
|
FontDPI=72
|
||||||
|
|
||||||
|
[/Script/Engine.Engine]
|
||||||
|
+ActiveGameNameRedirects=(OldGameName="TP_Blank",NewGameName="/Script/PS_Ballistics")
|
||||||
|
+ActiveGameNameRedirects=(OldGameName="/Script/TP_Blank",NewGameName="/Script/PS_Ballistics")
|
||||||
|
|
||||||
|
[/Script/AndroidFileServerEditor.AndroidFileServerRuntimeSettings]
|
||||||
|
bEnablePlugin=True
|
||||||
|
bAllowNetworkConnection=True
|
||||||
|
SecurityToken=488367AA4E45F3B86D51FD85BEDFD355
|
||||||
|
bIncludeInShipping=False
|
||||||
|
bAllowExternalStartInShipping=False
|
||||||
|
bCompileAFSProject=False
|
||||||
|
bUseCompression=False
|
||||||
|
bLogFiles=False
|
||||||
|
bReportStats=False
|
||||||
|
ConnectionType=USBOnly
|
||||||
|
bUseManualIPAddress=False
|
||||||
|
ManualIPAddress=
|
||||||
|
|
||||||
3
Unreal/Config/DefaultGame.ini
Normal file
3
Unreal/Config/DefaultGame.ini
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
|
||||||
|
[/Script/EngineSettings.GeneralProjectSettings]
|
||||||
|
ProjectID=256345A449041A43ADB1968A8E9E7C8D
|
||||||
84
Unreal/Config/DefaultInput.ini
Normal file
84
Unreal/Config/DefaultInput.ini
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
[/Script/Engine.InputSettings]
|
||||||
|
-AxisConfig=(AxisKeyName="Gamepad_LeftX",AxisProperties=(DeadZone=0.25,Exponent=1.f,Sensitivity=1.f))
|
||||||
|
-AxisConfig=(AxisKeyName="Gamepad_LeftY",AxisProperties=(DeadZone=0.25,Exponent=1.f,Sensitivity=1.f))
|
||||||
|
-AxisConfig=(AxisKeyName="Gamepad_RightX",AxisProperties=(DeadZone=0.25,Exponent=1.f,Sensitivity=1.f))
|
||||||
|
-AxisConfig=(AxisKeyName="Gamepad_RightY",AxisProperties=(DeadZone=0.25,Exponent=1.f,Sensitivity=1.f))
|
||||||
|
-AxisConfig=(AxisKeyName="MouseX",AxisProperties=(DeadZone=0.f,Exponent=1.f,Sensitivity=0.07f))
|
||||||
|
-AxisConfig=(AxisKeyName="MouseY",AxisProperties=(DeadZone=0.f,Exponent=1.f,Sensitivity=0.07f))
|
||||||
|
-AxisConfig=(AxisKeyName="Mouse2D",AxisProperties=(DeadZone=0.f,Exponent=1.f,Sensitivity=0.07f))
|
||||||
|
+AxisConfig=(AxisKeyName="Gamepad_LeftX",AxisProperties=(DeadZone=0.250000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
|
||||||
|
+AxisConfig=(AxisKeyName="Gamepad_LeftY",AxisProperties=(DeadZone=0.250000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
|
||||||
|
+AxisConfig=(AxisKeyName="Gamepad_RightX",AxisProperties=(DeadZone=0.250000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
|
||||||
|
+AxisConfig=(AxisKeyName="Gamepad_RightY",AxisProperties=(DeadZone=0.250000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
|
||||||
|
+AxisConfig=(AxisKeyName="MouseX",AxisProperties=(DeadZone=0.000000,Sensitivity=0.070000,Exponent=1.000000,bInvert=False))
|
||||||
|
+AxisConfig=(AxisKeyName="MouseY",AxisProperties=(DeadZone=0.000000,Sensitivity=0.070000,Exponent=1.000000,bInvert=False))
|
||||||
|
+AxisConfig=(AxisKeyName="Mouse2D",AxisProperties=(DeadZone=0.000000,Sensitivity=0.070000,Exponent=1.000000,bInvert=False))
|
||||||
|
+AxisConfig=(AxisKeyName="MouseWheelAxis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
|
||||||
|
+AxisConfig=(AxisKeyName="Gamepad_LeftTriggerAxis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
|
||||||
|
+AxisConfig=(AxisKeyName="Gamepad_RightTriggerAxis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
|
||||||
|
+AxisConfig=(AxisKeyName="Gamepad_Special_Left_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
|
||||||
|
+AxisConfig=(AxisKeyName="Gamepad_Special_Left_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
|
||||||
|
+AxisConfig=(AxisKeyName="Vive_Left_Trigger_Axis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
|
||||||
|
+AxisConfig=(AxisKeyName="Vive_Left_Trackpad_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
|
||||||
|
+AxisConfig=(AxisKeyName="Vive_Left_Trackpad_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
|
||||||
|
+AxisConfig=(AxisKeyName="Vive_Right_Trigger_Axis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
|
||||||
|
+AxisConfig=(AxisKeyName="Vive_Right_Trackpad_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
|
||||||
|
+AxisConfig=(AxisKeyName="Vive_Right_Trackpad_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
|
||||||
|
+AxisConfig=(AxisKeyName="MixedReality_Left_Trigger_Axis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
|
||||||
|
+AxisConfig=(AxisKeyName="MixedReality_Left_Thumbstick_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
|
||||||
|
+AxisConfig=(AxisKeyName="MixedReality_Left_Thumbstick_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
|
||||||
|
+AxisConfig=(AxisKeyName="MixedReality_Left_Trackpad_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
|
||||||
|
+AxisConfig=(AxisKeyName="MixedReality_Left_Trackpad_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
|
||||||
|
+AxisConfig=(AxisKeyName="MixedReality_Right_Trigger_Axis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
|
||||||
|
+AxisConfig=(AxisKeyName="MixedReality_Right_Thumbstick_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
|
||||||
|
+AxisConfig=(AxisKeyName="MixedReality_Right_Thumbstick_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
|
||||||
|
+AxisConfig=(AxisKeyName="MixedReality_Right_Trackpad_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
|
||||||
|
+AxisConfig=(AxisKeyName="MixedReality_Right_Trackpad_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
|
||||||
|
+AxisConfig=(AxisKeyName="OculusTouch_Left_Grip_Axis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
|
||||||
|
+AxisConfig=(AxisKeyName="OculusTouch_Left_Trigger_Axis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
|
||||||
|
+AxisConfig=(AxisKeyName="OculusTouch_Left_Thumbstick_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
|
||||||
|
+AxisConfig=(AxisKeyName="OculusTouch_Left_Thumbstick_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
|
||||||
|
+AxisConfig=(AxisKeyName="OculusTouch_Right_Grip_Axis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
|
||||||
|
+AxisConfig=(AxisKeyName="OculusTouch_Right_Trigger_Axis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
|
||||||
|
+AxisConfig=(AxisKeyName="OculusTouch_Right_Thumbstick_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
|
||||||
|
+AxisConfig=(AxisKeyName="OculusTouch_Right_Thumbstick_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
|
||||||
|
+AxisConfig=(AxisKeyName="ValveIndex_Left_Grip_Axis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
|
||||||
|
+AxisConfig=(AxisKeyName="ValveIndex_Left_Grip_Force",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
|
||||||
|
+AxisConfig=(AxisKeyName="ValveIndex_Left_Trigger_Axis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
|
||||||
|
+AxisConfig=(AxisKeyName="ValveIndex_Left_Thumbstick_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
|
||||||
|
+AxisConfig=(AxisKeyName="ValveIndex_Left_Thumbstick_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
|
||||||
|
+AxisConfig=(AxisKeyName="ValveIndex_Left_Trackpad_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
|
||||||
|
+AxisConfig=(AxisKeyName="ValveIndex_Left_Trackpad_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
|
||||||
|
+AxisConfig=(AxisKeyName="ValveIndex_Left_Trackpad_Force",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
|
||||||
|
+AxisConfig=(AxisKeyName="ValveIndex_Right_Grip_Axis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
|
||||||
|
+AxisConfig=(AxisKeyName="ValveIndex_Right_Grip_Force",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
|
||||||
|
+AxisConfig=(AxisKeyName="ValveIndex_Right_Trigger_Axis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
|
||||||
|
+AxisConfig=(AxisKeyName="ValveIndex_Right_Thumbstick_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
|
||||||
|
+AxisConfig=(AxisKeyName="ValveIndex_Right_Thumbstick_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
|
||||||
|
+AxisConfig=(AxisKeyName="ValveIndex_Right_Trackpad_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
|
||||||
|
+AxisConfig=(AxisKeyName="ValveIndex_Right_Trackpad_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
|
||||||
|
+AxisConfig=(AxisKeyName="ValveIndex_Right_Trackpad_Force",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
|
||||||
|
bAltEnterTogglesFullscreen=True
|
||||||
|
bF11TogglesFullscreen=True
|
||||||
|
bUseMouseForTouch=False
|
||||||
|
bEnableMouseSmoothing=True
|
||||||
|
bEnableFOVScaling=True
|
||||||
|
bCaptureMouseOnLaunch=True
|
||||||
|
bEnableLegacyInputScales=True
|
||||||
|
bEnableMotionControls=True
|
||||||
|
bFilterInputByPlatformUser=False
|
||||||
|
bShouldFlushPressedKeysOnViewportFocusLost=True
|
||||||
|
bAlwaysShowTouchInterface=False
|
||||||
|
bShowConsoleOnFourFingerTap=True
|
||||||
|
bEnableGestureRecognizer=False
|
||||||
|
bUseAutocorrect=False
|
||||||
|
DefaultViewportMouseCaptureMode=CapturePermanently_IncludingInitialMouseDown
|
||||||
|
DefaultViewportMouseLockMode=LockOnCapture
|
||||||
|
FOVScale=0.011110
|
||||||
|
DoubleClickTime=0.200000
|
||||||
|
DefaultPlayerInputClass=/Script/EnhancedInput.EnhancedPlayerInput
|
||||||
|
DefaultInputComponentClass=/Script/EnhancedInput.EnhancedInputComponent
|
||||||
|
DefaultTouchInterface=/Engine/MobileResources/HUD/DefaultVirtualJoysticks.DefaultVirtualJoysticks
|
||||||
|
-ConsoleKeys=Tilde
|
||||||
|
+ConsoleKeys=Tilde
|
||||||
|
|
||||||
1796
Unreal/PS_Ballistics.sln
Normal file
1796
Unreal/PS_Ballistics.sln
Normal file
File diff suppressed because it is too large
Load Diff
22
Unreal/PS_Ballistics.uproject
Normal file
22
Unreal/PS_Ballistics.uproject
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
{
|
||||||
|
"FileVersion": 3,
|
||||||
|
"EngineAssociation": "5.5",
|
||||||
|
"Category": "",
|
||||||
|
"Description": "",
|
||||||
|
"Modules": [
|
||||||
|
{
|
||||||
|
"Name": "PS_Ballistics",
|
||||||
|
"Type": "Runtime",
|
||||||
|
"LoadingPhase": "Default"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"Plugins": [
|
||||||
|
{
|
||||||
|
"Name": "ModelingToolsEditorMode",
|
||||||
|
"Enabled": true,
|
||||||
|
"TargetAllowList": [
|
||||||
|
"Editor"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
Binary file not shown.
@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"BuildId": "37670630",
|
||||||
|
"Modules":
|
||||||
|
{
|
||||||
|
"EasyBallistics": "UnrealEditor-EasyBallistics.dylib"
|
||||||
|
}
|
||||||
|
}
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"BuildId": "37670630",
|
||||||
|
"Modules":
|
||||||
|
{
|
||||||
|
"EasyBallistics": "UnrealEditor-EasyBallistics-Win64-DebugGame.dll"
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"BuildId": "37670630",
|
||||||
|
"Modules":
|
||||||
|
{
|
||||||
|
"EasyBallistics": "UnrealEditor-EasyBallistics.dll"
|
||||||
|
}
|
||||||
|
}
|
||||||
29
Unreal/Plugins/EasyBallistics/EasyBallistics.uplugin
Normal file
29
Unreal/Plugins/EasyBallistics/EasyBallistics.uplugin
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
{
|
||||||
|
"FileVersion": 3,
|
||||||
|
"Version": 0,
|
||||||
|
"VersionName": "2.82",
|
||||||
|
"FriendlyName": "EasyBallistics",
|
||||||
|
"Description": "",
|
||||||
|
"Category": "Gameplay",
|
||||||
|
"CreatedBy": "Mookie",
|
||||||
|
"CreatedByURL": "",
|
||||||
|
"DocsURL": "",
|
||||||
|
"MarketplaceURL": "com.epicgames.launcher://ue/marketplace/content/bbecde0f66914263b57fd2af5a0c7ffe",
|
||||||
|
"SupportURL": "",
|
||||||
|
"EngineVersion": "5.5.0",
|
||||||
|
"CanContainContent": false,
|
||||||
|
"Installed": true,
|
||||||
|
"Modules": [
|
||||||
|
{
|
||||||
|
"Name": "EasyBallistics",
|
||||||
|
"Type": "Runtime",
|
||||||
|
"LoadingPhase": "Default",
|
||||||
|
"PlatformAllowList": [
|
||||||
|
"Win64",
|
||||||
|
"Linux",
|
||||||
|
"Mac",
|
||||||
|
"Android"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
BIN
Unreal/Plugins/EasyBallistics/Resources/Icon128.png
Normal file
BIN
Unreal/Plugins/EasyBallistics/Resources/Icon128.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 10 KiB |
@ -0,0 +1,38 @@
|
|||||||
|
// Copyright 1998-2016 Epic Games, Inc. All Rights Reserved.
|
||||||
|
using UnrealBuildTool;
|
||||||
|
|
||||||
|
public class EasyBallistics : ModuleRules
|
||||||
|
{
|
||||||
|
public EasyBallistics(ReadOnlyTargetRules Target) : base(Target)
|
||||||
|
{
|
||||||
|
PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs;
|
||||||
|
DefaultBuildSettings = BuildSettingsVersion.Latest;
|
||||||
|
IncludeOrderVersion = EngineIncludeOrderVersion.Latest;
|
||||||
|
|
||||||
|
PublicDependencyModuleNames.AddRange(
|
||||||
|
new string[]
|
||||||
|
{
|
||||||
|
"Core"
|
||||||
|
// ... add other public dependencies that you statically link with here ...
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
PrivateDependencyModuleNames.AddRange(
|
||||||
|
new string[]
|
||||||
|
{
|
||||||
|
"CoreUObject",
|
||||||
|
"Engine",
|
||||||
|
"PhysicsCore"
|
||||||
|
// ... add private dependencies that you statically link with here ...
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
DynamicallyLoadedModuleNames.AddRange(
|
||||||
|
new string[]
|
||||||
|
{
|
||||||
|
// ... add any modules that your module loads dynamically here ...
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,32 @@
|
|||||||
|
// Copyright 2016 Mookie. All Rights Reserved.
|
||||||
|
|
||||||
|
#include "EBBullet.h"
|
||||||
|
|
||||||
|
FVector AEBBullet::UpdateVelocity_Implementation(UWorld* World, FVector Location, FVector PreviousVelocity, float DeltaTime) const {
|
||||||
|
FVector NewVelocity = PreviousVelocity;
|
||||||
|
|
||||||
|
//airDensity
|
||||||
|
float air;
|
||||||
|
float speedOfSound;
|
||||||
|
|
||||||
|
air = GetAirDensity(World, Location);
|
||||||
|
speedOfSound = GetSpeedOfSound(World, Location);
|
||||||
|
|
||||||
|
//gravity
|
||||||
|
if (!OverrideGravity) {
|
||||||
|
NewVelocity += FVector(0, 0, World->GetGravityZ())*DeltaTime;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
NewVelocity += Gravity*DeltaTime;
|
||||||
|
};
|
||||||
|
|
||||||
|
//drag
|
||||||
|
FVector relVel = (NewVelocity - GetWind(World, Location));
|
||||||
|
float speed = relVel.Size();
|
||||||
|
float mach = speed / speedOfSound;
|
||||||
|
float profile = FMath::Pow(Diameter / 200.0f, 2.0f)*3.141592f;
|
||||||
|
float drag = GetCurveValue(MachDragCurve, mach, 0.25f)*FMath::Pow(speed / 100.0f, 2.0f)*profile*air*FormFactor*50.0f;
|
||||||
|
NewVelocity -= relVel.GetSafeNormal() * drag / Mass * DeltaTime / WorldScale;
|
||||||
|
|
||||||
|
return NewVelocity;
|
||||||
|
}
|
||||||
@ -0,0 +1,118 @@
|
|||||||
|
// Copyright 2016 Mookie. All Rights Reserved.
|
||||||
|
|
||||||
|
#include "EBBarrel.h"
|
||||||
|
#include "Net/UnrealNetwork.h"
|
||||||
|
|
||||||
|
#define REPOWNERONLY false
|
||||||
|
|
||||||
|
void UEBBarrel::ShotFiredMulticast_Implementation() {
|
||||||
|
ShotFired.Broadcast();
|
||||||
|
}
|
||||||
|
|
||||||
|
void UEBBarrel::SpawnBulletEventMulticast_Implementation(FVector Start, FVector Velocity) {
|
||||||
|
SpawnBulletEvent.Broadcast(Start, Velocity);
|
||||||
|
}
|
||||||
|
|
||||||
|
void UEBBarrel::Shoot(bool Trigger, int nextFireID) {
|
||||||
|
if (ClientSideAim && GetOwner()->GetRemoteRole() == ROLE_Authority && Trigger) {
|
||||||
|
Aim = GetComponentTransform().GetUnitAxis(EAxis::X);
|
||||||
|
Location = GetComponentTransform().GetLocation();
|
||||||
|
nextFireEventID = nextFireID;
|
||||||
|
ShootRepCSA(Trigger, UGameplayStatics::RebaseLocalOriginOntoZero(GetWorld(), Location), Aim, nextFireID);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
nextFireEventID = nextFireID;
|
||||||
|
ShootRep(Trigger, nextFireID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void UEBBarrel::ShootRep_Implementation(bool Trigger, int nextFireID) {
|
||||||
|
if (Trigger) {
|
||||||
|
if (FireMode == EFireMode::FM_Burst || FireMode == EFireMode::FM_InterBurst) {
|
||||||
|
BurstRemaining = BurstCount;
|
||||||
|
};
|
||||||
|
Shooting = true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
//burst cannot be interrupted
|
||||||
|
if (FireMode != EFireMode::FM_Burst || BurstRemaining<=0) {
|
||||||
|
Shooting = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UEBBarrel::ShootRep_Validate(bool Trigger, int nextFireID) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void UEBBarrel::ShootRepCSA_Implementation(bool Trigger, FVector_NetQuantize NewLocation, FVector_NetQuantizeNormal NewAim, int nextFireID) {
|
||||||
|
Location = UGameplayStatics::RebaseZeroOriginOntoLocal(GetWorld(), NewLocation);
|
||||||
|
Aim = NewAim;
|
||||||
|
RemoteAimReceived = true;
|
||||||
|
|
||||||
|
if (Trigger) {
|
||||||
|
if (FireMode == EFireMode::FM_Burst || FireMode == EFireMode::FM_InterBurst) {
|
||||||
|
BurstRemaining = BurstCount;
|
||||||
|
};
|
||||||
|
Shooting = true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
//burst cannot be interrupted
|
||||||
|
if (FireMode != EFireMode::FM_Burst || BurstRemaining <= 0) {
|
||||||
|
Shooting = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UEBBarrel::ShootRepCSA_Validate(bool Trigger, FVector_NetQuantize NewLocation, FVector_NetQuantizeNormal NewAim, int nextFireID) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void UEBBarrel::GatlingSpool_Implementation(bool Spool) {
|
||||||
|
Spooling = Spool;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UEBBarrel::GatlingSpool_Validate(bool Spool) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void UEBBarrel::SwitchFireMode_Implementation(EFireMode NewFireMode) {
|
||||||
|
FireMode = NewFireMode;
|
||||||
|
}
|
||||||
|
bool UEBBarrel::SwitchFireMode_Validate(EFireMode NewFireMode) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void UEBBarrel::ClientAim_Implementation(FVector_NetQuantize NewLocation, FVector_NetQuantizeNormal NewAim) {
|
||||||
|
Location = UGameplayStatics::RebaseZeroOriginOntoLocal(GetWorld(),NewLocation);
|
||||||
|
Aim = NewAim;
|
||||||
|
RemoteAimReceived = true;
|
||||||
|
}
|
||||||
|
bool UEBBarrel::ClientAim_Validate(FVector_NetQuantize NewLocation, FVector_NetQuantizeNormal NewAim) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void UEBBarrel::GetLifetimeReplicatedProps(TArray< FLifetimeProperty > & OutLifetimeProps) const
|
||||||
|
{
|
||||||
|
Super::GetLifetimeReplicatedProps(OutLifetimeProps);
|
||||||
|
|
||||||
|
#if REPOWNERONLY
|
||||||
|
DOREPLIFETIME_CONDITION(UEBBarrel, FireMode, COND_OwnerOnly);
|
||||||
|
DOREPLIFETIME_CONDITION(UEBBarrel, CycleAmmoCount, COND_OwnerOnly);
|
||||||
|
DOREPLIFETIME_CONDITION(UEBBarrel, CycleAmmoPos, COND_OwnerOnly);
|
||||||
|
DOREPLIFETIME_CONDITION(UEBBarrel, Ammo, COND_OwnerOnly);
|
||||||
|
DOREPLIFETIME_CONDITION(UEBBarrel, ChamberedBullet, COND_OwnerOnly);
|
||||||
|
DOREPLIFETIME_CONDITION(UEBBarrel, Shooting, COND_OwnerOnly);
|
||||||
|
DOREPLIFETIME_CONDITION(UEBBarrel, ShootingBlocked, COND_OwnerOnly);
|
||||||
|
DOREPLIFETIME_CONDITION(UEBBarrel, Spooling, COND_OwnerOnly);
|
||||||
|
#else
|
||||||
|
DOREPLIFETIME(UEBBarrel, FireMode);
|
||||||
|
DOREPLIFETIME(UEBBarrel, CycleAmmoCount);
|
||||||
|
DOREPLIFETIME(UEBBarrel, CycleAmmoPos);
|
||||||
|
DOREPLIFETIME(UEBBarrel, Ammo);
|
||||||
|
DOREPLIFETIME(UEBBarrel, ChamberedBullet);
|
||||||
|
DOREPLIFETIME(UEBBarrel, Shooting);
|
||||||
|
DOREPLIFETIME(UEBBarrel, ShootingBlocked);
|
||||||
|
DOREPLIFETIME(UEBBarrel, Spooling);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
@ -0,0 +1,66 @@
|
|||||||
|
// Copyright 2019 Mookie. All Rights Reserved.
|
||||||
|
|
||||||
|
#if WITH_EDITOR
|
||||||
|
#include "EBBarrel.h"
|
||||||
|
#include "PrimitiveSceneProxy.h"
|
||||||
|
|
||||||
|
FPrimitiveSceneProxy* UEBBarrel::CreateSceneProxy() {
|
||||||
|
{
|
||||||
|
class FBarrelProxy : public FPrimitiveSceneProxy
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
FBarrelProxy(UEBBarrel* InComponent) : FPrimitiveSceneProxy(InComponent)
|
||||||
|
{
|
||||||
|
bWillEverBeLit = false;
|
||||||
|
Component = InComponent;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void GetDynamicMeshElements(const TArray<const FSceneView*>& Views, const FSceneViewFamily& ViewFamily, uint32 VisibilityMap, FMeshElementCollector& Collector) const override
|
||||||
|
{
|
||||||
|
QUICK_SCOPE_CYCLE_COUNTER(STAT_BarrelSceneProxy_GetDynamicMeshElements);
|
||||||
|
|
||||||
|
const FMatrix& Transform = GetLocalToWorld();
|
||||||
|
|
||||||
|
for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ViewIndex++)
|
||||||
|
{
|
||||||
|
if (VisibilityMap && ((1 << ViewIndex)!=0))
|
||||||
|
{
|
||||||
|
const FSceneView* View = Views[ViewIndex];
|
||||||
|
const FLinearColor DrawColor = GetViewSelectionColor(FColor::Green, *View, IsSelected(), IsHovered(), true, IsIndividuallySelected());
|
||||||
|
|
||||||
|
FPrimitiveDrawInterface* PDI = Collector.GetPDI(ViewIndex);
|
||||||
|
DrawDirectionalArrow(PDI, Transform, DrawColor, Component->DebugArrowSize, Component->DebugArrowSize*0.1f, 16, Component->DebugArrowSize*0.01f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual FPrimitiveViewRelevance GetViewRelevance(const FSceneView* View) const override
|
||||||
|
{
|
||||||
|
const bool bProxyVisible = IsSelected();
|
||||||
|
|
||||||
|
FPrimitiveViewRelevance Result;
|
||||||
|
Result.bDrawRelevance = (IsShown(View));
|
||||||
|
Result.bDynamicRelevance = true;
|
||||||
|
Result.bShadowRelevance = false;
|
||||||
|
Result.bEditorPrimitiveRelevance = UseEditorCompositing(View);
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
virtual uint32 GetMemoryFootprint(void) const override { return(sizeof(*this) + GetAllocatedSize()); }
|
||||||
|
uint32 GetAllocatedSize(void) const { return(FPrimitiveSceneProxy::GetAllocatedSize()); }
|
||||||
|
virtual SIZE_T GetTypeHash() const override { return 0; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
UEBBarrel* Component;
|
||||||
|
};
|
||||||
|
|
||||||
|
return new FBarrelProxy(this);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
FBoxSphereBounds UEBBarrel::CalcBounds(const FTransform& LocalToWorld) const
|
||||||
|
{
|
||||||
|
float SphereRadius = DebugArrowSize;
|
||||||
|
return FBoxSphereBounds(FVector::ZeroVector, FVector(SphereRadius), SphereRadius).TransformBy(LocalToWorld);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@ -0,0 +1,136 @@
|
|||||||
|
// Copyright 2016 Mookie. All Rights Reserved.
|
||||||
|
|
||||||
|
#include "EBBullet.h"
|
||||||
|
#include "EBMaterialResponseMap.h"
|
||||||
|
#include "Net/UnrealNetwork.h"
|
||||||
|
|
||||||
|
void AEBBullet::VelocityChangeBroadcast_Implementation(FVector_NetQuantize NewLocation, FVector NewVelocity) {
|
||||||
|
if (!HasAuthority()) {
|
||||||
|
FVector RebasedLocation = UGameplayStatics::RebaseZeroOriginOntoLocal(GetWorld(), NewLocation);
|
||||||
|
OnTrajectoryUpdateReceived(RebasedLocation, Velocity, NewVelocity);
|
||||||
|
SetActorLocation(RebasedLocation);
|
||||||
|
Velocity = NewVelocity;
|
||||||
|
CanRetrace = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AEBBullet::VelocityChangeBroadcastReliable_Implementation(FVector_NetQuantize NewLocation, FVector NewVelocity) {
|
||||||
|
if (!HasAuthority()) {
|
||||||
|
FVector RebasedLocation = UGameplayStatics::RebaseZeroOriginOntoLocal(GetWorld(), NewLocation);
|
||||||
|
OnTrajectoryUpdateReceived(RebasedLocation, Velocity, NewVelocity);
|
||||||
|
SetActorLocation(RebasedLocation);
|
||||||
|
Velocity = NewVelocity;
|
||||||
|
CanRetrace = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AEBBullet::SpawnWithExactVelocity(TSubclassOf<class AEBBullet> BulletClass, AActor* BulletOwner, APawn* BulletInstigator, FVector BulletLocation, FVector BulletVelocity, int nextEventFireID) {
|
||||||
|
|
||||||
|
if (BulletClass != nullptr && BulletOwner != nullptr) {
|
||||||
|
FActorSpawnParameters spawnParams;
|
||||||
|
spawnParams.Owner = BulletOwner;
|
||||||
|
spawnParams.Instigator = BulletInstigator;
|
||||||
|
|
||||||
|
AEBBullet* Default = Cast<AEBBullet>(BulletClass->GetDefaultObject());
|
||||||
|
Default->fireEventID = nextEventFireID;
|
||||||
|
|
||||||
|
FTransform Transform;
|
||||||
|
Transform.SetLocation(BulletLocation);
|
||||||
|
Transform.SetScale3D(Default->GetActorScale());
|
||||||
|
|
||||||
|
if (Default->RotateActor) {
|
||||||
|
FRotator Rotation = UKismetMathLibrary::MakeRotFromX(BulletVelocity);
|
||||||
|
if (Default->RotateRandomRoll) Rotation.Add(0, 0, Default->RandomStream.FRandRange(-180.0f, 180.0f));
|
||||||
|
Transform.SetRotation(Rotation.Quaternion());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Transform.SetRotation(FQuat(1, 0, 0, 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Default->Shotgun) {
|
||||||
|
AEBBullet* bullet = SpawnOrReactivate(BulletOwner->GetWorld(), BulletClass, Transform, BulletVelocity, BulletOwner, BulletInstigator, nextEventFireID);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
for (int i = 0; i < Default->ShotCount; i++) {
|
||||||
|
float Vel = BulletVelocity.Size()*Default->RandomStream.FRandRange(1.0 - Default->ShotVelocitySpread, 1.0 + Default->ShotVelocitySpread);
|
||||||
|
FVector SubmunitionVelocity = Default->RandomStream.VRandCone(BulletVelocity, Default->ShotSpread)*Vel;
|
||||||
|
AEBBullet* bullet = SpawnOrReactivate(BulletOwner->GetWorld(), BulletClass, Transform, SubmunitionVelocity, BulletOwner, BulletInstigator, nextEventFireID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
UE_LOG(LogTemp, Warning, TEXT("Cannot spawn bullet - invalid class or owner"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void AEBBullet::GetLifetimeReplicatedProps(TArray< FLifetimeProperty > & OutLifetimeProps) const
|
||||||
|
{
|
||||||
|
Super::GetLifetimeReplicatedProps(OutLifetimeProps);
|
||||||
|
DOREPLIFETIME_CONDITION(AEBBullet, Velocity, COND_InitialOnly);
|
||||||
|
DOREPLIFETIME_CONDITION(AEBBullet, RandomStream, COND_InitialOnly);
|
||||||
|
}
|
||||||
|
|
||||||
|
//alternative spawn
|
||||||
|
void AEBBullet::Spawn(TSubclassOf<class AEBBullet> BulletClass, AActor* BulletOwner, APawn* BulletInstigator, FVector BulletLocation, FVector BulletVelocity, int eventFireID) {
|
||||||
|
if (BulletClass != nullptr && BulletOwner != nullptr) {
|
||||||
|
|
||||||
|
FActorSpawnParameters spawnParams;
|
||||||
|
spawnParams.Owner = BulletOwner;
|
||||||
|
spawnParams.Instigator = BulletInstigator;
|
||||||
|
|
||||||
|
AEBBullet* Default = Cast<AEBBullet>(BulletClass->GetDefaultObject());
|
||||||
|
Default->fireEventID = eventFireID;
|
||||||
|
FTransform Transform;
|
||||||
|
Transform.SetLocation(BulletLocation);
|
||||||
|
Transform.SetScale3D(Default->GetActorScale());
|
||||||
|
|
||||||
|
if (Default->RotateActor) {
|
||||||
|
if (Default->RotateActor) {
|
||||||
|
FRotator Rotation = UKismetMathLibrary::MakeRotFromX(BulletVelocity);
|
||||||
|
if (Default->RotateRandomRoll) Rotation.Add(0, 0, Default->RandomStream.FRandRange(-180.0f, 180.0f));
|
||||||
|
Transform.SetRotation(Rotation.Quaternion());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Transform.SetRotation(FQuat(1, 0, 0, 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
//init velocity
|
||||||
|
float TotalSpread = Default->Spread;
|
||||||
|
if (Default->SpreadBias > 0.0f){
|
||||||
|
float SpreadMult = FMath::Pow(FMath::FRand(), Default->SpreadBias);
|
||||||
|
TotalSpread *= SpreadMult;
|
||||||
|
}
|
||||||
|
|
||||||
|
FVector BulletVelocityNew = Default->RandomStream.VRandCone(BulletVelocity, TotalSpread)*BulletVelocity.Size();
|
||||||
|
float VelocityMP = FMath::Lerp(Default->MuzzleVelocityMin, Default->MuzzleVelocityMax, Default->RandomStream.FRand());
|
||||||
|
BulletVelocityNew = BulletVelocityNew * VelocityMP;
|
||||||
|
|
||||||
|
if (!Default->Shotgun) {
|
||||||
|
AEBBullet* bullet = SpawnOrReactivate(BulletOwner->GetWorld(), BulletClass, Transform, BulletVelocityNew, BulletOwner, BulletInstigator, eventFireID);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
for (int i = 0; i < Default->ShotCount; i++) {
|
||||||
|
float Vel = BulletVelocityNew.Size()*Default->RandomStream.FRandRange(1.0 - Default->ShotVelocitySpread, 1.0 + Default->ShotVelocitySpread);
|
||||||
|
FVector SubmunitionVelocity = Default->RandomStream.VRandCone(BulletVelocityNew, Default->ShotSpread)*Vel;
|
||||||
|
AEBBullet* bullet = SpawnOrReactivate(BulletOwner->GetWorld(), BulletClass, Transform, SubmunitionVelocity, BulletOwner, BulletInstigator, eventFireID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
UE_LOG(LogTemp, Warning, TEXT("Cannot spawn bullet - invalid class or owner"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AEBBullet::OnImpact_Implementation(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, int FireEventID){
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
void AEBBullet::OnNetPredictedImpact_Implementation(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, int FireEventID) {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
void AEBBullet::OnDeactivated_Implementation() {
|
||||||
|
return;
|
||||||
|
};
|
||||||
@ -0,0 +1,4 @@
|
|||||||
|
// Copyright 2020 Mookie. All Rights Reserved.
|
||||||
|
|
||||||
|
#include "EBBullet.h"
|
||||||
|
|
||||||
@ -0,0 +1,65 @@
|
|||||||
|
#include "EBBarrel.h"
|
||||||
|
#include "EBBullet.h"
|
||||||
|
|
||||||
|
void UEBBarrel::CalculateAimDirection(TSubclassOf<class AEBBullet> BulletClass, FVector TargetLocation, FVector TargetVelocity, FVector& AimDirection, FVector& PredictedTargetLocation, FVector& PredictedIntersectionLocation, float& PredictedFlightTime, float& Error, float MaxTime, float Step, int NumIterations) const {
|
||||||
|
FVector StartLocation = GetComponentLocation();
|
||||||
|
CalculateAimDirectionFromLocation(BulletClass, StartLocation, TargetLocation, TargetVelocity, AimDirection, PredictedTargetLocation, PredictedIntersectionLocation, PredictedFlightTime, Error, MaxTime, Step, NumIterations);
|
||||||
|
}
|
||||||
|
|
||||||
|
void UEBBarrel::CalculateAimDirectionFromLocation(TSubclassOf<class AEBBullet> BulletClass, FVector StartLocation, FVector TargetLocation, FVector TargetVelocity, FVector& AimDirection, FVector& PredictedTargetLocation, FVector& PredictedIntersectionLocation, float& PredictedFlightTime, float& Error, float MaxTime, float Step, int NumIterations) const {
|
||||||
|
if (!BulletClass->IsValidLowLevel()) {
|
||||||
|
UE_LOG(LogTemp, Warning, TEXT("CalculateAimDirection - invalid bullet class"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
AEBBullet* bullet = Cast<AEBBullet>(BulletClass->GetDefaultObject());
|
||||||
|
|
||||||
|
FVector AddVelocity = AdditionalVelocity;
|
||||||
|
UPrimitiveComponent* parent = Cast<UPrimitiveComponent>(GetAttachParent());
|
||||||
|
if (parent != nullptr) {
|
||||||
|
if (parent->IsSimulatingPhysics()) {
|
||||||
|
AddVelocity += parent->GetPhysicsLinearVelocityAtPoint(StartLocation) * InheritVelocity;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
FVector InitialAimDirection = (TargetLocation - StartLocation).GetSafeNormal(); //initial prediction
|
||||||
|
AimDirection = InitialAimDirection;
|
||||||
|
FVector PreviousAimDirection = AimDirection;
|
||||||
|
|
||||||
|
for (int Iteration = 0; Iteration < NumIterations; Iteration++) {
|
||||||
|
FVector CurrentBulletLocation = StartLocation;
|
||||||
|
FVector Velocity = (AimDirection * (FMath::Lerp(MuzzleVelocityMultiplierMin, MuzzleVelocityMultiplierMax, 0.5) * FMath::Lerp(bullet->MuzzleVelocityMin, bullet->MuzzleVelocityMax, 0.5))) + AddVelocity;
|
||||||
|
bool hit = 0;
|
||||||
|
for (float time = 0; time <= MaxTime; time += Step) {
|
||||||
|
FVector PreviousVelocity = Velocity;
|
||||||
|
Velocity = bullet->UpdateVelocity(GetWorld(), CurrentBulletLocation, Velocity, Step);
|
||||||
|
|
||||||
|
FVector TraceVector = ((((PreviousVelocity + Velocity) * 0.5) - TargetVelocity) * Step);
|
||||||
|
FVector TraceEndLocation = CurrentBulletLocation + TraceVector;
|
||||||
|
FVector IntersectionPoint;
|
||||||
|
|
||||||
|
hit = FMath::SegmentPlaneIntersection(CurrentBulletLocation - TraceVector, TraceEndLocation, FPlane(TargetLocation, InitialAimDirection), IntersectionPoint); //actual hit test
|
||||||
|
|
||||||
|
if (hit) {
|
||||||
|
PredictedIntersectionLocation = IntersectionPoint;
|
||||||
|
FQuat AimCorrection = FQuat::FindBetween((IntersectionPoint - StartLocation), (TargetLocation - StartLocation));
|
||||||
|
AimDirection = AimCorrection.RotateVector(AimDirection).GetSafeNormal();
|
||||||
|
Error = (IntersectionPoint - TargetLocation).Size();
|
||||||
|
|
||||||
|
float AdditionalFlightTime = (FVector(CurrentBulletLocation - IntersectionPoint).Size() / TraceVector.Size()) * Step;
|
||||||
|
PredictedFlightTime = time + AdditionalFlightTime;
|
||||||
|
PredictedTargetLocation = TargetLocation + TargetVelocity * AdditionalFlightTime;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
//no hit, keep going
|
||||||
|
CurrentBulletLocation = TraceEndLocation;
|
||||||
|
}
|
||||||
|
if (!hit) {
|
||||||
|
Error = 99999999999999999.0f;
|
||||||
|
return; //no solution
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,25 @@
|
|||||||
|
#include "EBBullet.h"
|
||||||
|
|
||||||
|
bool AEBBullet::CollisionFilter_Implementation(FHitResult HitResult) const{
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
FHitResult AEBBullet::FilterHits(TArray<FHitResult> Results, bool &hit) const{
|
||||||
|
TArray<FHitResult> OutResults;
|
||||||
|
|
||||||
|
for (FHitResult Result : Results) {
|
||||||
|
if (Result.bBlockingHit) {
|
||||||
|
|
||||||
|
hit = true;
|
||||||
|
return Result;
|
||||||
|
}else{
|
||||||
|
if (CollisionFilter(Result)) {
|
||||||
|
hit = true;
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
hit = false;
|
||||||
|
return FHitResult(); //blank
|
||||||
|
};
|
||||||
@ -0,0 +1,303 @@
|
|||||||
|
// Copyright 2018 Mookie. All Rights Reserved.
|
||||||
|
#include "EBBarrel.h"
|
||||||
|
|
||||||
|
UEBBarrel::UEBBarrel() {
|
||||||
|
PrimaryComponentTick.bCanEverTick = true;
|
||||||
|
bHiddenInGame = true;
|
||||||
|
bAutoActivate = true;
|
||||||
|
SetIsReplicatedByDefault(ReplicateVariables);
|
||||||
|
|
||||||
|
RandomStream.GenerateNewSeed();
|
||||||
|
|
||||||
|
GatlingRPS = FireRateMin;
|
||||||
|
}
|
||||||
|
|
||||||
|
void UEBBarrel::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
|
||||||
|
{
|
||||||
|
Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
|
||||||
|
|
||||||
|
if (AntiRecoil)
|
||||||
|
{
|
||||||
|
if (previousAim.Num() > AntiRecoilPrevCount)
|
||||||
|
{
|
||||||
|
previousAim.RemoveAt(0);
|
||||||
|
}
|
||||||
|
if (previousLocation.Num() > AntiRecoilPrevCount)
|
||||||
|
{
|
||||||
|
previousLocation.RemoveAt(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ClientSideAim){
|
||||||
|
if (GetOwner()->GetRemoteRole()==ROLE_Authority){
|
||||||
|
TimeSinceAimUpdate += DeltaTime;
|
||||||
|
if (TimeSinceAimUpdate >= 1.0f / ClientAimUpdateFrequency) {
|
||||||
|
|
||||||
|
if (AntiRecoil)
|
||||||
|
{
|
||||||
|
// ForAntiRecoil
|
||||||
|
previousAim.Add(GetComponentTransform().GetUnitAxis(EAxis::X));
|
||||||
|
previousLocation.Add(GetComponentTransform().GetLocation());
|
||||||
|
|
||||||
|
Aim = previousAim[0];
|
||||||
|
Location = previousLocation[0];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Aim = GetComponentTransform().GetUnitAxis(EAxis::X);
|
||||||
|
Location = GetComponentTransform().GetLocation();
|
||||||
|
}
|
||||||
|
|
||||||
|
ClientAim(UGameplayStatics::RebaseLocalOriginOntoZero(GetWorld(),Location), Aim);
|
||||||
|
TimeSinceAimUpdate = FMath::Fmod(TimeSinceAimUpdate, 1.0f / ClientAimUpdateFrequency);
|
||||||
|
};
|
||||||
|
}else{
|
||||||
|
if (!RemoteAimReceived) {
|
||||||
|
if (AntiRecoil)
|
||||||
|
{
|
||||||
|
// ForAntiRecoil
|
||||||
|
previousAim.Add(GetComponentTransform().GetUnitAxis(EAxis::X));
|
||||||
|
previousLocation.Add(GetComponentTransform().GetLocation());
|
||||||
|
|
||||||
|
Aim = previousAim[0];
|
||||||
|
Location = previousLocation[0];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Aim = GetComponentTransform().GetUnitAxis(EAxis::X);
|
||||||
|
Location = GetComponentTransform().GetLocation();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
FVector LocOffset = (Location - GetComponentLocation());
|
||||||
|
if (LocOffset.Size() > ClientAimDistanceLimit) {
|
||||||
|
//lag or cheater???
|
||||||
|
Location = GetComponentLocation() + LocOffset.GetSafeNormal()*ClientAimDistanceLimit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (AntiRecoil)
|
||||||
|
{
|
||||||
|
// ForAntiRecoil
|
||||||
|
previousAim.Add(GetComponentTransform().GetUnitAxis(EAxis::X));
|
||||||
|
previousLocation.Add(GetComponentTransform().GetLocation());
|
||||||
|
|
||||||
|
Aim = previousAim[0];
|
||||||
|
Location = previousLocation[0];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Aim = GetComponentTransform().GetUnitAxis(EAxis::X);
|
||||||
|
Location = GetComponentTransform().GetLocation();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Only server can tick
|
||||||
|
if (GetOwner()->GetLocalRole() == ROLE_Authority){
|
||||||
|
|
||||||
|
float RemainingDelta;
|
||||||
|
|
||||||
|
if (FireMode == EFireMode::FM_Gatling) {
|
||||||
|
if (Spooling || (GatlingAutoSpool && Shooting)) {
|
||||||
|
GatlingRPS = FMath::Lerp(GatlingRPS, FireRateMax, FMath::Min(GatlingSpoolUpTime*DeltaTime, 1.0f));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
GatlingRPS = FMath::Lerp(GatlingRPS, FireRateMin, FMath::Min(GatlingSpoolUpTime*DeltaTime, 1.0f));
|
||||||
|
}
|
||||||
|
GatlingPhase += GatlingRPS*DeltaTime;
|
||||||
|
for (int i = 1; i <= GatlingPhase; i++) {
|
||||||
|
if (Cooldown <= 0.0f && LoadNext) {
|
||||||
|
NextBullet();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Shooting && ChamberedBullet != nullptr && (!ShootingBlocked)) {
|
||||||
|
SpawnBullet(GetOwner(), Location, Aim, nextFireEventID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
GatlingPhase = FMath::Fmod(GatlingPhase, 1.0f);
|
||||||
|
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
RemainingDelta = DeltaTime;
|
||||||
|
do {
|
||||||
|
float step = FMath::Min(Cooldown, RemainingDelta);
|
||||||
|
|
||||||
|
Cooldown -= step;
|
||||||
|
|
||||||
|
RemainingDelta -= step;
|
||||||
|
|
||||||
|
if (Cooldown <= 0.0f && LoadNext) {
|
||||||
|
NextBullet();
|
||||||
|
}
|
||||||
|
|
||||||
|
//shoot when ready
|
||||||
|
if (Shooting && ChamberedBullet != nullptr && (!ShootingBlocked)) {
|
||||||
|
if (BurstRemaining > 0 || (FireMode != EFireMode::FM_Burst && FireMode != EFireMode::FM_InterBurst)) {
|
||||||
|
SpawnBullet(GetOwner(), Location, Aim, nextFireEventID);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Shooting = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while (RemainingDelta > 0 && Cooldown > 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void UEBBarrel::NextBullet() {
|
||||||
|
if (ChamberedBullet == nullptr) {
|
||||||
|
if (Ammo.Num() > 0 && (CycleAmmoCount > 0 || CycleAmmoUnlimited || (!CycleAmmo))) {
|
||||||
|
|
||||||
|
//cycle ammo
|
||||||
|
if (CycleAmmo) {
|
||||||
|
if (CycleAmmoPos >= Ammo.Num()) { CycleAmmoPos = 0; }
|
||||||
|
ChamberedBullet = Ammo[CycleAmmoPos];
|
||||||
|
CycleAmmoPos++;
|
||||||
|
|
||||||
|
if (!CycleAmmoUnlimited) {
|
||||||
|
CycleAmmoCount--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ChamberedBullet = Ammo[0];
|
||||||
|
Ammo.RemoveAt(0, 1, EAllowShrinking::Yes);
|
||||||
|
}
|
||||||
|
|
||||||
|
ReadyToShoot.Broadcast();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
AmmoDepleted.Broadcast();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void UEBBarrel::SpawnBullet(AActor* Owner, FVector InLocation, FVector InAim, int fireEventID) {
|
||||||
|
TSubclassOf<class AEBBullet> BulletClass = ChamberedBullet;
|
||||||
|
|
||||||
|
if (BulletClass != nullptr) {
|
||||||
|
FVector OutLocation;
|
||||||
|
FVector OutAim;
|
||||||
|
|
||||||
|
InitialBulletTransform(InLocation, InAim, OutLocation, OutAim);
|
||||||
|
|
||||||
|
AEBBullet* Default = Cast<AEBBullet>(BulletClass->GetDefaultObject());
|
||||||
|
|
||||||
|
float BulletSpread = Default->Spread;
|
||||||
|
if (Default->SpreadBias > 0.0f) {
|
||||||
|
float SpreadMult = FMath::Pow(FMath::FRand(), Default->SpreadBias);
|
||||||
|
BulletSpread *= SpreadMult;
|
||||||
|
}
|
||||||
|
float BarrelSpread = Spread;
|
||||||
|
if (SpreadBias > 0.0f) {
|
||||||
|
float SpreadMult = FMath::Pow(FMath::FRand(), SpreadBias);
|
||||||
|
BarrelSpread *= SpreadMult;
|
||||||
|
}
|
||||||
|
|
||||||
|
float TotalSpread = BulletSpread+BarrelSpread;
|
||||||
|
|
||||||
|
OutAim = RandomStream.VRandCone(OutAim,TotalSpread);
|
||||||
|
float BulletVelocity = FMath::Lerp(MuzzleVelocityMultiplierMin* Default->MuzzleVelocityMin, MuzzleVelocityMultiplierMax*Default->MuzzleVelocityMax, RandomStream.FRand());
|
||||||
|
FVector Velocity = OutAim*BulletVelocity;
|
||||||
|
|
||||||
|
//get parent physics body
|
||||||
|
UPrimitiveComponent* parent = Cast<UPrimitiveComponent>(GetAttachParent());
|
||||||
|
Velocity += AdditionalVelocity;
|
||||||
|
|
||||||
|
if (parent != nullptr) {
|
||||||
|
|
||||||
|
if (parent->IsSimulatingPhysics()) {
|
||||||
|
Velocity += parent->GetPhysicsLinearVelocityAtPoint(OutLocation)*InheritVelocity;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Default->Shotgun) {
|
||||||
|
ApplyRecoil(parent, OutLocation, -Velocity*Default->Mass*RecoilMultiplier*Default->ShotCount);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
ApplyRecoil(parent, OutLocation, -Velocity*Default->Mass*RecoilMultiplier);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BeforeShotFired.Broadcast();
|
||||||
|
#ifdef WITH_EDITOR
|
||||||
|
if (shotTrace) {
|
||||||
|
DrawDebugLine(GetWorld(), OutLocation, Velocity, FColor(1, 0, 0, 1), false, 3, 0, 0);
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
if (ReplicateShotFiredEvents) {
|
||||||
|
SpawnBulletEventMulticast(OutLocation, Velocity);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
SpawnBulletEvent.Broadcast(OutLocation, Velocity);
|
||||||
|
}
|
||||||
|
|
||||||
|
AEBBullet::SpawnWithExactVelocity(BulletClass, Owner, Owner->GetInstigator(), OutLocation, Velocity, fireEventID);
|
||||||
|
|
||||||
|
//spend ammo
|
||||||
|
ChamberedBullet = nullptr;
|
||||||
|
if (FireMode != EFireMode::FM_Gatling) {
|
||||||
|
Cooldown = 1.0f / FMath::Lerp(FireRateMin, FireRateMax, RandomStream.FRand());
|
||||||
|
}
|
||||||
|
|
||||||
|
//fire modes
|
||||||
|
switch (FireMode) {
|
||||||
|
case EFireMode::FM_Auto:
|
||||||
|
LoadNext = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case EFireMode::FM_Burst:
|
||||||
|
LoadNext = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case EFireMode::FM_InterBurst:
|
||||||
|
LoadNext = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case EFireMode::FM_Semiauto:
|
||||||
|
Shooting = false;
|
||||||
|
LoadNext = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case EFireMode::FM_Manual:
|
||||||
|
Shooting = false;
|
||||||
|
LoadNext = false;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case EFireMode::FM_Slamfire:
|
||||||
|
LoadNext = false;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case EFireMode::FM_Gatling:
|
||||||
|
LoadNext = true;
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (BurstRemaining > 0) {
|
||||||
|
BurstRemaining--;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (FireMode == EFireMode::FM_Burst || FireMode == EFireMode::FM_InterBurst) {
|
||||||
|
Cooldown = FMath::Max(Cooldown, BurstCooldown);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ReplicateShotFiredEvents) {
|
||||||
|
ShotFiredMulticast();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ShotFired.Broadcast();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void UEBBarrel::InitialBulletTransform_Implementation(FVector InLocation, FVector InDirection, FVector& OutLocation, FVector& OutDirection) {
|
||||||
|
OutLocation = InLocation;
|
||||||
|
OutDirection = InDirection;
|
||||||
|
}
|
||||||
|
|
||||||
|
void UEBBarrel::ApplyRecoil_Implementation(UPrimitiveComponent* Component, FVector InLocation, FVector Impulse){
|
||||||
|
if (Component->IsSimulatingPhysics()) {
|
||||||
|
Component->AddImpulseAtLocation(Impulse, InLocation);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,141 @@
|
|||||||
|
// Copyright 2018 Mookie. All Rights Reserved.
|
||||||
|
#include "EBBullet.h"
|
||||||
|
|
||||||
|
// Sets default values
|
||||||
|
AEBBullet::AEBBullet() {
|
||||||
|
// Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it.
|
||||||
|
PrimaryActorTick.bCanEverTick = true;
|
||||||
|
SetTickGroup(ETickingGroup::TG_PrePhysics);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Called when the game starts or when spawned
|
||||||
|
void AEBBullet::BeginPlay() {
|
||||||
|
SetActorEnableCollision(AllowComponentCollisions);
|
||||||
|
|
||||||
|
if(!IsRecycled){
|
||||||
|
Super::BeginPlay();
|
||||||
|
IsRecycled = true;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
ReceiveBeginPlay();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SafeLaunch) {
|
||||||
|
OwnerSafe = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (DoFirstStepImmediately) {
|
||||||
|
float DeltaTime = GetWorld()->GetDeltaSeconds();
|
||||||
|
|
||||||
|
if (RandomFirstStepDelta) {
|
||||||
|
DeltaTime *= RandomStream.FRand();
|
||||||
|
};
|
||||||
|
|
||||||
|
if (FixedStep) {
|
||||||
|
Step(FixedStepSeconds);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Step(DeltaTime);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Called every frame
|
||||||
|
void AEBBullet::Tick(float DeltaTime) {
|
||||||
|
Super::Tick(DeltaTime);
|
||||||
|
|
||||||
|
if (FixedStep) {
|
||||||
|
AccumulatedDelta += DeltaTime;
|
||||||
|
|
||||||
|
while (AccumulatedDelta >= FixedStepSeconds) {
|
||||||
|
Step(FixedStepSeconds);
|
||||||
|
AccumulatedDelta -= FixedStepSeconds;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Step(DeltaTime);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AEBBullet::Step(float DeltaTime) {
|
||||||
|
FVector start = GetActorLocation();
|
||||||
|
bool sendUpdate = false;
|
||||||
|
|
||||||
|
if (Retrace && CanRetrace) {
|
||||||
|
//time travel
|
||||||
|
float remainingTime = LastTraceDelta;
|
||||||
|
int remainingSteps = MaxTracesPerStep;
|
||||||
|
FVector PreviousVelocity = LastTracePrevVelocity;
|
||||||
|
SetActorLocation(LastTraceStart);
|
||||||
|
Velocity = LastTraceVelocity;
|
||||||
|
|
||||||
|
do {
|
||||||
|
if (RetraceOnAnotherChannel) {
|
||||||
|
remainingTime = Trace(GetActorLocation(),
|
||||||
|
PreviousVelocity,
|
||||||
|
remainingTime,
|
||||||
|
RetraceChannel);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
remainingTime = Trace(GetActorLocation(),
|
||||||
|
PreviousVelocity,
|
||||||
|
remainingTime,
|
||||||
|
TraceChannel);
|
||||||
|
}
|
||||||
|
PreviousVelocity = Velocity;
|
||||||
|
remainingSteps -= 1;
|
||||||
|
if (remainingTime > 0.0f) { sendUpdate = true; };
|
||||||
|
} while (remainingTime > 0.0f && remainingSteps > 0);
|
||||||
|
}
|
||||||
|
CanRetrace = false;
|
||||||
|
|
||||||
|
FVector PreviousVelocity = Velocity;
|
||||||
|
Velocity = UpdateVelocity(GetWorld(), GetActorLocation(), Velocity, DeltaTime);
|
||||||
|
|
||||||
|
//trace
|
||||||
|
float remainingTime = DeltaTime;
|
||||||
|
int remainingSteps = MaxTracesPerStep;
|
||||||
|
do {
|
||||||
|
remainingTime = Trace(GetActorLocation(),
|
||||||
|
PreviousVelocity,
|
||||||
|
remainingTime,
|
||||||
|
TraceChannel
|
||||||
|
);
|
||||||
|
PreviousVelocity = Velocity;
|
||||||
|
remainingSteps -= 1;
|
||||||
|
if (remainingTime > 0.0f) { sendUpdate = true; };
|
||||||
|
} while (remainingTime > 0.0f && remainingSteps > 0);
|
||||||
|
|
||||||
|
if (sendUpdate) {
|
||||||
|
if (ReliableReplication) {
|
||||||
|
VelocityChangeBroadcastReliable(UGameplayStatics::RebaseLocalOriginOntoZero(GetWorld(),GetActorLocation()), Velocity);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
VelocityChangeBroadcast(UGameplayStatics::RebaseLocalOriginOntoZero(GetWorld(), GetActorLocation()), Velocity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(SafeDelay <= 0.0f){
|
||||||
|
OwnerSafe = false;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
SafeDelay -= DeltaTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (RotateActor) {
|
||||||
|
FRotator NewRot = UKismetMathLibrary::MakeRotFromX(Velocity);
|
||||||
|
NewRot.Roll = GetActorRotation().Roll;
|
||||||
|
SetActorRotation(NewRot);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float AEBBullet::GetCurveValue(const UCurveFloat* curve, float in, float deflt) const {
|
||||||
|
if (curve == nullptr) return deflt;
|
||||||
|
return curve->GetFloatValue(in);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AEBBullet::ApplyWorldOffset(const FVector& InOffset, bool bWorldShift) {
|
||||||
|
Super::ApplyWorldOffset(InOffset, bWorldShift);
|
||||||
|
LastTraceStart += InOffset;
|
||||||
|
}
|
||||||
@ -0,0 +1,21 @@
|
|||||||
|
// Copyright 1998-2016 Epic Games, Inc. All Rights Reserved.
|
||||||
|
// Copyright 2016 Mookie. All Rights Reserved.
|
||||||
|
|
||||||
|
#include "EasyBallistics.h"
|
||||||
|
|
||||||
|
#define LOCTEXT_NAMESPACE "FEasyBallisticsModule"
|
||||||
|
|
||||||
|
void FEasyBallisticsModule::StartupModule()
|
||||||
|
{
|
||||||
|
// This code will execute after your module is loaded into memory; the exact timing is specified in the .uplugin file per-module
|
||||||
|
}
|
||||||
|
|
||||||
|
void FEasyBallisticsModule::ShutdownModule()
|
||||||
|
{
|
||||||
|
// This function may be called during shutdown to clean up your module. For modules that support dynamic reloading,
|
||||||
|
// we call this function before unloading the module.
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef LOCTEXT_NAMESPACE
|
||||||
|
|
||||||
|
IMPLEMENT_MODULE(FEasyBallisticsModule, EasyBallistics)
|
||||||
@ -0,0 +1,58 @@
|
|||||||
|
// Copyright 2016 Mookie. All Rights Reserved.
|
||||||
|
|
||||||
|
#include "EBBullet.h"
|
||||||
|
|
||||||
|
FVector AEBBullet::GetWind_Implementation(UWorld* World, FVector Location) const{
|
||||||
|
return Wind;
|
||||||
|
}
|
||||||
|
|
||||||
|
float AEBBullet::GetAirDensity_Implementation(UWorld* World, FVector Location) const{
|
||||||
|
switch (AtmosphereType) {
|
||||||
|
case (EEBAtmosphereType::AT_Curve): {
|
||||||
|
float airmp = SeaLevelAirDensity / GetCurveValue(AirDensityCurve, 0, SeaLevelAirDensity);
|
||||||
|
return GetCurveValue(AirDensityCurve, GetAltitude(World, Location) / WorldScale, SeaLevelAirDensity)* airmp;
|
||||||
|
}
|
||||||
|
case (EEBAtmosphereType::AT_Earth): {
|
||||||
|
return GetAltitudeDensity(GetAltitude(World, Location) / WorldScale / 100.0f);
|
||||||
|
}
|
||||||
|
default:{
|
||||||
|
return SeaLevelAirDensity;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float AEBBullet::GetSpeedOfSound_Implementation(UWorld* World, FVector Location) const{
|
||||||
|
if (!SpeedOfSoundVariesWithAltitude) {
|
||||||
|
return SeaLevelSpeedOfSound * WorldScale;
|
||||||
|
}
|
||||||
|
|
||||||
|
float Altitude = GetAltitude(World, Location);
|
||||||
|
float soundvmp = SeaLevelSpeedOfSound / GetCurveValue(SpeedOfSoundCurve, 0, SeaLevelSpeedOfSound);
|
||||||
|
return GetCurveValue(SpeedOfSoundCurve, Altitude, SeaLevelSpeedOfSound)*WorldScale*soundvmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
float AEBBullet::GetAltitudePressure(float AltitudeMeter) const {
|
||||||
|
return FMath::Max(SeaLevelAirPressure * FMath::Pow((1 - (0.0000225577 * AltitudeMeter)), 5.25588), 0.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
float AEBBullet::GetAltitudeTemperature(float AltitudeMeter) const {
|
||||||
|
return SeaLevelAirTemperature - (TemperatureLapseRate * FMath::Min(AltitudeMeter, TropopauseAltitude));
|
||||||
|
}
|
||||||
|
|
||||||
|
float AEBBullet::GetAltitudeDensity(float AltitudeMeter) const {
|
||||||
|
float Temperature = GetAltitudeTemperature(AltitudeMeter);
|
||||||
|
float Pressure = GetAltitudePressure(AltitudeMeter);
|
||||||
|
return Pressure * 100.0f / ((Temperature + 273.15) * SpecificGasConstant);
|
||||||
|
}
|
||||||
|
|
||||||
|
float AEBBullet::GetAltitude(UWorld* World, FVector Location) const{
|
||||||
|
FVector DistanceFromOrigin = (Location - WorldCenterLocation + FVector(World->OriginLocation));
|
||||||
|
if (SphericalAltitude)
|
||||||
|
{
|
||||||
|
return (DistanceFromOrigin.Size() - SeaLevelRadius);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return DistanceFromOrigin.Z;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,40 @@
|
|||||||
|
// Copyright 2020 Mookie. All Rights Reserved.
|
||||||
|
|
||||||
|
#include "EBBullet.h"
|
||||||
|
|
||||||
|
float AEBBullet::PenetrationTrace(FVector StartLocation, FVector EndLocation, TWeakObjectPtr<UPrimitiveComponent, FWeakObjectPtr> Component, EPenTraceType PenTraceType, TEnumAsByte<ECollisionChannel> CollisionChannel, FVector &ExitLocation, FVector &ExitNormal) {
|
||||||
|
FCollisionQueryParams QueryParams;
|
||||||
|
QueryParams.bTraceComplex = TraceComplex;
|
||||||
|
QueryParams.bFindInitialOverlaps = true;
|
||||||
|
|
||||||
|
FHitResult Result;
|
||||||
|
|
||||||
|
switch (PenTraceType) {
|
||||||
|
case(EPenTraceType::PT_BackTrace): {
|
||||||
|
bool Hit = GetWorld()->LineTraceSingleByChannel(Result, EndLocation, StartLocation, CollisionChannel, QueryParams);
|
||||||
|
if (!Hit) return 1.0f;
|
||||||
|
ExitNormal = Result.Normal;
|
||||||
|
ExitLocation = Result.Location;
|
||||||
|
return (1.0f - Result.Time);
|
||||||
|
}
|
||||||
|
|
||||||
|
case(EPenTraceType::PT_ByComponent): {
|
||||||
|
bool Hit = Component->LineTraceComponent(Result, EndLocation, StartLocation, QueryParams);
|
||||||
|
if (!Hit) return 1.0f;
|
||||||
|
ExitNormal = Result.Normal;
|
||||||
|
ExitLocation = Result.Location;
|
||||||
|
return (1.0f - Result.Time);
|
||||||
|
}
|
||||||
|
|
||||||
|
case(EPenTraceType::PT_TwoSidedGeometry): {
|
||||||
|
bool Hit = GetWorld()->LineTraceSingleByChannel(Result, StartLocation, EndLocation, CollisionChannel, QueryParams);
|
||||||
|
if (!Hit) return 1.0f;
|
||||||
|
ExitLocation = Result.Location;
|
||||||
|
ExitNormal = -Result.Normal;
|
||||||
|
return Result.Time;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
return 1.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,169 @@
|
|||||||
|
#include "EBBullet.h"
|
||||||
|
|
||||||
|
void AEBBullet::Deactivate() {
|
||||||
|
//server only
|
||||||
|
if (!HasAuthority()) { return; }
|
||||||
|
OnDeactivated();
|
||||||
|
this->DeactivateToPool();
|
||||||
|
DeactivationBroadcast();
|
||||||
|
}
|
||||||
|
|
||||||
|
AEBBullet* AEBBullet::GetFromPool(UWorld* World, UClass* BulletClass) {
|
||||||
|
AEBBullet* Pool = Cast<AEBBullet>(BulletClass->GetDefaultObject());
|
||||||
|
|
||||||
|
if (Pool) {
|
||||||
|
//find first of correct class;
|
||||||
|
bool CleanupRequired=false;
|
||||||
|
|
||||||
|
int32 FoundIndex = Pool->Pooled.IndexOfByPredicate(
|
||||||
|
[&](auto InItem) {
|
||||||
|
if (InItem.IsValid() && InItem->GetWorld() == World) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
CleanupRequired = true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
TWeakObjectPtr<AEBBullet> Found = nullptr;
|
||||||
|
if (FoundIndex != INDEX_NONE) {
|
||||||
|
Found = Pool->Pooled[FoundIndex];
|
||||||
|
Pool->Pooled.RemoveAtSwap(FoundIndex,EAllowShrinking::Yes);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (CleanupRequired) {
|
||||||
|
#ifdef WITH_EDITOR
|
||||||
|
if (Pool->DebugPooling) {
|
||||||
|
GEngine->AddOnScreenDebugMessage(2, 2, FColor::White, TEXT("Invalid reference in pool, cleaning up"));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
Pool->Pooled.RemoveAll([&](auto InItem) {
|
||||||
|
if (InItem.IsValid() && InItem->GetWorld() == World) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return(Found.Get());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AEBBullet* AEBBullet::SpawnOrReactivate(UWorld* World, TSubclassOf<class AEBBullet> BulletClass, const FTransform& Transform, FVector BulletVelocity, AActor* BulletOwner, APawn* BulletInstigator, int nextEventFireID) {
|
||||||
|
AEBBullet* bullet;
|
||||||
|
|
||||||
|
AEBBullet* Recycled = GetFromPool(World, BulletClass);
|
||||||
|
|
||||||
|
if (Recycled) {
|
||||||
|
AEBBullet* Default = Cast<AEBBullet>(BulletClass->GetDefaultObject());
|
||||||
|
|
||||||
|
Recycled->Reset();
|
||||||
|
Recycled->fireEventID = nextEventFireID;
|
||||||
|
Recycled->SetOwner(BulletOwner);
|
||||||
|
Recycled->SetInstigator(BulletInstigator);
|
||||||
|
Recycled->SetActorTransform(Transform,false,nullptr,ETeleportType::TeleportPhysics);
|
||||||
|
Recycled->Velocity = BulletVelocity;
|
||||||
|
Recycled->SetActorHiddenInGame(Default->IsHidden());
|
||||||
|
Recycled->SetActorTickEnabled(true);
|
||||||
|
Recycled->CanRetrace = false;
|
||||||
|
Recycled->IgnoredActors = Default->IgnoredActors;
|
||||||
|
Recycled->SafeDelay = Default->SafeDelay;
|
||||||
|
Recycled->SetLifeSpan(Default->InitialLifeSpan);
|
||||||
|
Recycled->FinishSpawning(Transform);
|
||||||
|
//if (!Recycled->HasActorBegunPlay()){ Recycled->BeginPlay(); }
|
||||||
|
//Recycled->ReactivationBroadcast(UGameplayStatics::RebaseLocalOriginOntoZero(Recycled->GetWorld(), Transform.GetLocation()), BulletVelocity, BulletOwner, BulletInstigator);
|
||||||
|
#ifdef WITH_EDITOR
|
||||||
|
if (Recycled->DebugPooling) {
|
||||||
|
GEngine->AddOnScreenDebugMessage(0, 2, FColor::Green, TEXT("Recycling pooled bullet"));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return Recycled;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
bullet = Cast<AEBBullet>(World->SpawnActorDeferred<AEBBullet>(BulletClass, Transform, BulletOwner, BulletInstigator));
|
||||||
|
bullet->RandomStream.GenerateNewSeed();
|
||||||
|
bullet->Velocity = BulletVelocity;
|
||||||
|
bullet->fireEventID = nextEventFireID;
|
||||||
|
bullet->FinishSpawning(Transform);
|
||||||
|
//UGameplayStatics::FinishSpawningActor(bullet, Transform);
|
||||||
|
#ifdef WITH_EDITOR
|
||||||
|
if (bullet->DebugPooling) {
|
||||||
|
GEngine->AddOnScreenDebugMessage(0, 2, FColor::Orange, TEXT("Spawning new bullet"));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return bullet;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AEBBullet::FinishSpawning(FTransform Transform) {
|
||||||
|
if(IsRecycled){
|
||||||
|
if (!HasActorBegunPlay()){
|
||||||
|
BeginPlay();
|
||||||
|
}
|
||||||
|
ReactivationBroadcast(UGameplayStatics::RebaseLocalOriginOntoZero(this->GetWorld(), Transform.GetLocation()), this->Velocity, this->GetOwner(), this->GetInstigator(), fireEventID);
|
||||||
|
}else{
|
||||||
|
UGameplayStatics::FinishSpawningActor(this, Transform);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AEBBullet::ReactivationBroadcast_Implementation(FVector_NetQuantize NewLocation, FVector NewVelocity, AActor* BulletOwner, APawn* BulletInstigator, int nextEventFireID) {
|
||||||
|
if (!HasAuthority()) {
|
||||||
|
AEBBullet* Default = Cast<AEBBullet>(this->StaticClass()->GetDefaultObject());
|
||||||
|
|
||||||
|
SetOwner(BulletOwner);
|
||||||
|
SetInstigator(BulletInstigator);
|
||||||
|
fireEventID = nextEventFireID;
|
||||||
|
SetActorLocation(UGameplayStatics::RebaseZeroOriginOntoLocal(GetWorld(), NewLocation));
|
||||||
|
Velocity = NewVelocity;
|
||||||
|
CanRetrace = false;
|
||||||
|
|
||||||
|
SetActorHiddenInGame(Default->IsHidden());
|
||||||
|
SetActorTickEnabled(true);
|
||||||
|
SafeDelay = Default->SafeDelay;
|
||||||
|
OwnerSafe = Default->SafeLaunch;
|
||||||
|
BeginPlay();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AEBBullet::DeactivationBroadcast_Implementation() {
|
||||||
|
if (!HasAuthority()) {
|
||||||
|
OnDeactivated();
|
||||||
|
this->DeactivateToPool();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AEBBullet::LifeSpanExpired() {
|
||||||
|
Deactivate();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AEBBullet::DeactivateToPool() {
|
||||||
|
AEBBullet* Pool = Cast<AEBBullet>(GetClass()->GetDefaultObject());
|
||||||
|
|
||||||
|
if (Pool && EnablePooling) {
|
||||||
|
SetActorHiddenInGame(true);
|
||||||
|
SetActorTickEnabled(false);
|
||||||
|
Pool->Pooled.Add(this);
|
||||||
|
EndPlay(EEndPlayReason::RemovedFromWorld);
|
||||||
|
|
||||||
|
if (Pool->Pooled.Num() > MaxPoolSize) {
|
||||||
|
AEBBullet* Oldest = (Pool->Pooled[0].Get());
|
||||||
|
Pool->Pooled.RemoveAtSwap(0,EAllowShrinking::Yes);
|
||||||
|
if (Oldest) { Oldest->Destroy(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef WITH_EDITOR
|
||||||
|
if (DebugPooling) {
|
||||||
|
GEngine->AddOnScreenDebugMessage(2, 2, FColor::White, FString("Bullet pooled: ") + FString::FromInt(Pool->Pooled.Num()));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,74 @@
|
|||||||
|
// Copyright 2020 Mookie. All Rights Reserved.
|
||||||
|
|
||||||
|
#include "EBBarrel.h"
|
||||||
|
#include "EBBullet.h"
|
||||||
|
|
||||||
|
void UEBBarrel::PredictHit(bool& Hit, FHitResult& HitResult, FVector& HitLocation, float& HitTime, AActor*& HitActor, TArray<FVector>& Trajectory, TSubclassOf<class AEBBullet> BulletClass, TArray<AActor*> IgnoredActors, float MaxTime, float Step) const {
|
||||||
|
FVector StartLocation = GetComponentLocation();
|
||||||
|
FVector AimDirection = GetComponentQuat().GetForwardVector();
|
||||||
|
PredictHitFromLocation(Hit, HitResult, HitLocation, HitTime, HitActor, Trajectory, BulletClass, StartLocation, AimDirection, IgnoredActors, MaxTime, Step);
|
||||||
|
}
|
||||||
|
|
||||||
|
void UEBBarrel::PredictHitFromLocation(bool &Hit, FHitResult& HitResult, FVector& HitLocation, float& HitTime, AActor*& HitActor, TArray<FVector>& Trajectory, TSubclassOf<class AEBBullet> BulletClass, FVector StartLocation, FVector AimDirection, TArray<AActor*> IgnoredActors, float MaxTime, float Step) const{
|
||||||
|
if (!BulletClass->IsValidLowLevel()) {
|
||||||
|
UE_LOG(LogTemp, Warning, TEXT("PredictHit - invalid bullet class"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
float Time = 0;
|
||||||
|
Trajectory = TArray<FVector>();
|
||||||
|
|
||||||
|
FVector CurrentLocation = StartLocation;
|
||||||
|
AEBBullet* Bullet = Cast<AEBBullet>(BulletClass->GetDefaultObject());
|
||||||
|
FVector Velocity = AimDirection.GetSafeNormal()*(FMath::Lerp(MuzzleVelocityMultiplierMin, MuzzleVelocityMultiplierMax, 0.5)*FMath::Lerp(Bullet->MuzzleVelocityMin, Bullet->MuzzleVelocityMax, 0.5));
|
||||||
|
|
||||||
|
UPrimitiveComponent* Parent = Cast<UPrimitiveComponent>(GetAttachParent());
|
||||||
|
|
||||||
|
Velocity += AdditionalVelocity;
|
||||||
|
|
||||||
|
if (Parent != nullptr) {
|
||||||
|
if (Parent->IsSimulatingPhysics()) {
|
||||||
|
Velocity += Parent->GetPhysicsLinearVelocityAtPoint(CurrentLocation)*InheritVelocity;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while (Time < MaxTime) {
|
||||||
|
FVector PreviousVelocity = Velocity;
|
||||||
|
Velocity = Bullet->UpdateVelocity(GetWorld(), CurrentLocation, Velocity, Step);
|
||||||
|
Hit = UEBBarrel::PredictTrace(GetWorld(), Bullet, CurrentLocation, CurrentLocation + FMath::Lerp(PreviousVelocity, Velocity, 0.5f)*Step, HitResult, IgnoredActors);
|
||||||
|
if (Hit) {
|
||||||
|
Trajectory.Add(HitResult.Location);
|
||||||
|
HitTime = Time+(HitResult.Time*Step);
|
||||||
|
HitActor = HitResult.GetActor();
|
||||||
|
HitLocation = HitResult.Location;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Trajectory.Add(CurrentLocation);
|
||||||
|
CurrentLocation += FMath::Lerp(PreviousVelocity, Velocity, 0.5f)*Step;
|
||||||
|
Time += Step;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Hit = false;
|
||||||
|
HitTime = MaxTime;
|
||||||
|
HitLocation = CurrentLocation;
|
||||||
|
HitActor = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UEBBarrel::PredictTrace(UWorld* World, AEBBullet* Bullet, FVector Start, FVector End, FHitResult &HitResult, TArray<AActor*> IgnoredActors) const {
|
||||||
|
|
||||||
|
FCollisionResponseParams ResponseParams;
|
||||||
|
|
||||||
|
FCollisionQueryParams QueryParams;
|
||||||
|
QueryParams.bTraceComplex = Bullet->TraceComplex;
|
||||||
|
QueryParams.bReturnPhysicalMaterial = true;
|
||||||
|
|
||||||
|
if (Bullet->SafeLaunch) {
|
||||||
|
QueryParams.AddIgnoredActor(GetOwner());
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryParams.AddIgnoredActors(IgnoredActors);
|
||||||
|
|
||||||
|
return World->LineTraceSingleByChannel(HitResult, Start, End, Bullet->TraceChannel, QueryParams, ResponseParams);
|
||||||
|
}
|
||||||
@ -0,0 +1,74 @@
|
|||||||
|
// Copyright 2016 Mookie. All Rights Reserved.
|
||||||
|
|
||||||
|
#include "EBBarrel.h"
|
||||||
|
#include "EBBullet.h"
|
||||||
|
|
||||||
|
TArray<TSubclassOf<class AEBBullet>> UEBBarrel::GetAmmo(bool CountChambered) const {
|
||||||
|
if (!CountChambered || ChamberedBullet == nullptr) {
|
||||||
|
return Ammo;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
TArray<TSubclassOf<class AEBBullet>> RetAmmo;
|
||||||
|
RetAmmo.Add(ChamberedBullet);
|
||||||
|
RetAmmo.Append(Ammo);
|
||||||
|
return RetAmmo;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
int UEBBarrel::GetAmmoCount(bool CountChambered) const {
|
||||||
|
|
||||||
|
int remainingAmmo;
|
||||||
|
if (CycleAmmo) {
|
||||||
|
remainingAmmo = CycleAmmoCount;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
remainingAmmo = Ammo.Num();
|
||||||
|
};
|
||||||
|
|
||||||
|
if (CountChambered) {
|
||||||
|
if (ChamberedBullet != nullptr) {
|
||||||
|
remainingAmmo++;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
return remainingAmmo;
|
||||||
|
};
|
||||||
|
|
||||||
|
void UEBBarrel::SetAmmo(int Count, bool UnloadChambered, bool CancelShooting, bool ManualCharge, const TArray<TSubclassOf<class AEBBullet>>& NewAmmo) {
|
||||||
|
Ammo = NewAmmo;
|
||||||
|
|
||||||
|
CycleAmmoCount = Count;
|
||||||
|
|
||||||
|
if (UnloadChambered) {
|
||||||
|
ChamberedBullet = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (CancelShooting) {
|
||||||
|
BurstRemaining = 0;
|
||||||
|
Shooting = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (ManualCharge) {
|
||||||
|
LoadNext = false;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
void UEBBarrel::Charge_Implementation() {
|
||||||
|
LoadNext = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
bool UEBBarrel::Charge_Validate() {
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
void UEBBarrel::UnloadChambered_Implementation(bool ManualCharge) {
|
||||||
|
ChamberedBullet = nullptr;
|
||||||
|
|
||||||
|
if (ManualCharge) {
|
||||||
|
LoadNext = false;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
bool UEBBarrel::UnloadChambered_Validate(bool ManualCharge) {
|
||||||
|
return true;
|
||||||
|
};
|
||||||
@ -0,0 +1,28 @@
|
|||||||
|
// Copyright 2020 Mookie. All Rights Reserved.
|
||||||
|
|
||||||
|
#include "EBBullet.h"
|
||||||
|
|
||||||
|
TArray<AActor*>AEBBullet::GetSafeLaunchIgnoredActors(AActor* BulletOwner) const{
|
||||||
|
TArray<AActor*> Results = SafeLaunchIgnoredActors;
|
||||||
|
|
||||||
|
Results.Add(BulletOwner);
|
||||||
|
|
||||||
|
if (SafeLaunchIgnoreAttachParent && BulletOwner) {
|
||||||
|
AActor* AttachedRoot = BulletOwner;
|
||||||
|
|
||||||
|
while (true) { //find attachment root
|
||||||
|
AActor* AttachedTo;
|
||||||
|
AttachedTo = AttachedRoot->GetAttachParentActor();
|
||||||
|
|
||||||
|
if (AttachedTo) {
|
||||||
|
Results.Add(AttachedTo);
|
||||||
|
AttachedRoot = AttachedTo;
|
||||||
|
}
|
||||||
|
else break;
|
||||||
|
}
|
||||||
|
Results.Add(AttachedRoot);
|
||||||
|
if (SafeLaunchIgnoreAllAttached) Results.Append(GetAttachedActorsRecursive(AttachedRoot));
|
||||||
|
}
|
||||||
|
|
||||||
|
return Results;
|
||||||
|
}
|
||||||
@ -0,0 +1,216 @@
|
|||||||
|
// Copyright 2016 Mookie. All Rights Reserved.
|
||||||
|
|
||||||
|
#include "EBBullet.h"
|
||||||
|
|
||||||
|
float AEBBullet::Trace(FVector start, FVector PreviousVelocity, float delta, TEnumAsByte<ECollisionChannel> CollisionChannel) {
|
||||||
|
|
||||||
|
bool Hit;
|
||||||
|
FHitResult HitResult;
|
||||||
|
TArray<FHitResult> Results;
|
||||||
|
|
||||||
|
FCollisionResponseParams ResponseParameters;
|
||||||
|
|
||||||
|
FCollisionQueryParams CollisionParameters;
|
||||||
|
CollisionParameters.bTraceComplex = TraceComplex;
|
||||||
|
CollisionParameters.bReturnPhysicalMaterial = true;
|
||||||
|
CollisionParameters.AddIgnoredActor(this);
|
||||||
|
CollisionParameters.AddIgnoredActors(IgnoredActors);
|
||||||
|
CollisionParameters.bReturnFaceIndex = true;
|
||||||
|
|
||||||
|
if (OwnerSafe) {
|
||||||
|
CollisionParameters.AddIgnoredActors(GetSafeLaunchIgnoredActors(GetOwner()));
|
||||||
|
}
|
||||||
|
|
||||||
|
FVector TraceDistance = (PreviousVelocity + Velocity)*0.5*delta;
|
||||||
|
|
||||||
|
GetWorld()->LineTraceMultiByChannel(Results, start, start + TraceDistance, CollisionChannel, CollisionParameters, ResponseParameters);
|
||||||
|
if (Results.Num() > 0) {
|
||||||
|
HitResult = FilterHits(Results, Hit);
|
||||||
|
}
|
||||||
|
else { Hit = false; }
|
||||||
|
|
||||||
|
if (Hit) {
|
||||||
|
//Reduce velocity
|
||||||
|
Velocity = FMath::Lerp(PreviousVelocity, Velocity, HitResult.Time);
|
||||||
|
|
||||||
|
bool Ricochet = false;
|
||||||
|
bool Penetration = false;
|
||||||
|
FVector exitLoc;
|
||||||
|
FVector exitNormal;
|
||||||
|
FVector NewVelocity = Velocity;
|
||||||
|
|
||||||
|
//material mods
|
||||||
|
bool neverPenetrate = false;
|
||||||
|
bool neverRicochet = false;
|
||||||
|
float penDepthMultiplier = 1.0f;
|
||||||
|
float penNormalization = PenetrationNormalization;
|
||||||
|
float penNormalizationGrazing = PenetrationNormalizationGrazing;
|
||||||
|
float penEnterSpread = PenetrationEntryAngleSpread;
|
||||||
|
float penExitSpread = PenetrationExitAngleSpread;
|
||||||
|
float ricProbMultiplier = 1.0f;
|
||||||
|
float ricRestitution = RicochetRestitution;
|
||||||
|
float ricFriction = RicochetFriction;
|
||||||
|
float ricSpread = RicochetSpread;
|
||||||
|
EPenTraceType PenTraceType = DefaultPenTraceType;
|
||||||
|
|
||||||
|
UPhysicalMaterial* PhysMaterial = HitResult.PhysMaterial.Get();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if (PhysMaterial) {
|
||||||
|
//material response modifiers
|
||||||
|
if (MaterialResponseMap != nullptr) {
|
||||||
|
FEBMaterialResponseMapEntry* ResponseEntry = MaterialResponseMap->Map.Find(PhysMaterial);
|
||||||
|
if (ResponseEntry != nullptr) {
|
||||||
|
neverPenetrate = ResponseEntry->NeverPenetrate;
|
||||||
|
neverRicochet = ResponseEntry->NeverRicochet;
|
||||||
|
PenTraceType = ResponseEntry->PenTraceType;
|
||||||
|
|
||||||
|
penDepthMultiplier = ResponseEntry->PenetrationDepthMultiplier;
|
||||||
|
penNormalization = PenetrationNormalization + ResponseEntry->PenetrationNormalization;
|
||||||
|
penNormalizationGrazing = PenetrationNormalizationGrazing + ResponseEntry->PenetrationNormalizationGrazing;
|
||||||
|
penEnterSpread = PenetrationEntryAngleSpread + ResponseEntry->PenetrationEntryAngleSpread;
|
||||||
|
penExitSpread = PenetrationExitAngleSpread + ResponseEntry->PenetrationExitAngleSpread;
|
||||||
|
|
||||||
|
ricProbMultiplier = ResponseEntry->RicochetProbabilityMultiplier;
|
||||||
|
ricRestitution = FMath::Lerp(RicochetRestitution, ResponseEntry->RicochetRestitution, ResponseEntry->RicochetRestitutionInfluence);
|
||||||
|
ricFriction = FMath::Lerp(RicochetFriction, ResponseEntry->RicochetFriction, ResponseEntry->RicochetFrictionInfluence);
|
||||||
|
ricSpread = RicochetSpread + ResponseEntry->RicochetSpread;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (MaterialDensityControlsPenetrationDepth) {
|
||||||
|
penDepthMultiplier /= PhysMaterial->Density;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (MaterialRestitutionControlsRicochet) {
|
||||||
|
RicochetRestitution *= PhysMaterial->Restitution;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
float dot = FVector::DotProduct(Velocity.GetSafeNormal(), HitResult.Normal) + 1.0f;
|
||||||
|
FVector cross = FVector::CrossProduct(Velocity.GetSafeNormal(), HitResult.Normal);
|
||||||
|
FVector flat = HitResult.Normal.RotateAngleAxis(-90.0f, cross);
|
||||||
|
|
||||||
|
#ifdef WITH_EDITOR
|
||||||
|
if (DebugEnabled) {
|
||||||
|
FColor DebugColor = FColor::MakeRedToGreenColorFromScalar(Velocity.Size() / MuzzleVelocityMax);
|
||||||
|
DrawDebugLine(GetWorld(), start, HitResult.Location, DebugColor, false, DebugTrailTime, 0, DebugTrailWidth);
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
float GrazingAngle = FMath::Pow(dot, GrazingAngleExponent);
|
||||||
|
FVector PenetrationVector = RandomStream.VRandCone(Velocity, penEnterSpread);
|
||||||
|
PenetrationVector = FMath::Lerp(PenetrationVector, -HitResult.Normal, FMath::Lerp(penNormalization, penNormalizationGrazing, GrazingAngle));
|
||||||
|
float PenetrationDistance = FMath::Lerp(MinPenetration, MaxPenetration, RandomStream.FRand()) * FMath::Pow((Velocity.Size() / ((MuzzleVelocityMin + MuzzleVelocityMax) * 0.5f)), 2.0f) * penDepthMultiplier;
|
||||||
|
float PenetrationDepth = -FVector::DotProduct(PenetrationVector, HitResult.Normal) * PenetrationDistance;
|
||||||
|
|
||||||
|
float BlockTIme = 1.0f;
|
||||||
|
|
||||||
|
if (PenetrationDistance > 0.0f) {
|
||||||
|
if (!neverPenetrate) {
|
||||||
|
BlockTIme = PenetrationTrace(HitResult.Location - (HitResult.Normal * CollisionMargin), HitResult.Location + PenetrationVector * PenetrationDistance, HitResult.Component, PenTraceType, CollisionChannel, exitLoc, exitNormal);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (BlockTIme >= 0.999999f) {
|
||||||
|
|
||||||
|
//no pen
|
||||||
|
SetActorLocation(HitResult.Location + HitResult.Normal * CollisionMargin);
|
||||||
|
|
||||||
|
float ricThreshold = 1.0f;
|
||||||
|
if (SpeedControlsRicochetProbability) { ricThreshold *= Velocity.Size() / MuzzleVelocityMax; };
|
||||||
|
|
||||||
|
if (!neverRicochet && RandomStream.FRand() * ricThreshold < FMath::Lerp(RicochetProbability * ricProbMultiplier, RicochetProbabilityGrazing * ricProbMultiplier, GrazingAngle)) {
|
||||||
|
//bounce
|
||||||
|
FVector bounceAngle = flat * dot * (1.0f - ricFriction);
|
||||||
|
bounceAngle += HitResult.Normal * (1.0f - dot) * ricRestitution;
|
||||||
|
bounceAngle = RandomStream.VRandCone(bounceAngle, ricSpread) * bounceAngle.Size();
|
||||||
|
|
||||||
|
NewVelocity = bounceAngle * Velocity.Size();
|
||||||
|
Ricochet = true;
|
||||||
|
OwnerSafe = false;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
//stopped
|
||||||
|
NewVelocity = FVector(0, 0, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
//penetration
|
||||||
|
float RemainingEnergy = FMath::Pow(1.0f - BlockTIme, 2.0f);
|
||||||
|
SetActorLocation(exitLoc + exitNormal * CollisionMargin);
|
||||||
|
NewVelocity = RandomStream.VRandCone(PenetrationVector, penExitSpread * (1.0f - RemainingEnergy));
|
||||||
|
NewVelocity = FMath::Lerp(NewVelocity, Velocity.GetSafeNormal(), RemainingEnergy);
|
||||||
|
NewVelocity *= RemainingEnergy * Velocity.Size();
|
||||||
|
Penetration = true;
|
||||||
|
OwnerSafe = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//response
|
||||||
|
FVector Impulse = (Velocity - NewVelocity) * Mass * ImpulseMultiplier;
|
||||||
|
|
||||||
|
if (AddImpulse && HitResult.Component->IsSimulatingPhysics()) {
|
||||||
|
HitResult.Component->AddImpulseAtLocation(Impulse, HitResult.Location, HitResult.BoneName);
|
||||||
|
}
|
||||||
|
|
||||||
|
//impact actual
|
||||||
|
if (HasAuthority()) {
|
||||||
|
OnImpact(Ricochet, Penetration, HitResult.Location, Velocity, HitResult.Normal, GetActorLocation(), NewVelocity, Impulse, PenetrationDepth, HitResult.GetActor(), HitResult.Component.Get(), HitResult.BoneName, PhysMaterial, HitResult, fireEventID);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
OnNetPredictedImpact(Ricochet, Penetration, HitResult.Location, Velocity, HitResult.Normal, GetActorLocation(), NewVelocity, Impulse, PenetrationDepth, HitResult.GetActor(), HitResult.Component.Get(), HitResult.BoneName, PhysMaterial, HitResult, fireEventID);
|
||||||
|
}
|
||||||
|
|
||||||
|
Velocity = NewVelocity;
|
||||||
|
|
||||||
|
if ((Velocity.Size() < DespawnVelocity) || (!Ricochet && !Penetration && (DespawnVelocity>0.0f))){
|
||||||
|
Deactivate();
|
||||||
|
}
|
||||||
|
CanRetrace = false;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
//prepare for time travel
|
||||||
|
if (Retrace) {
|
||||||
|
CanRetrace = true;
|
||||||
|
LastTraceStart = start;
|
||||||
|
LastTraceDelta = delta;
|
||||||
|
LastTracePrevVelocity = PreviousVelocity;
|
||||||
|
LastTraceVelocity = Velocity;
|
||||||
|
}
|
||||||
|
|
||||||
|
SetActorLocation(start + TraceDistance);
|
||||||
|
HitResult.Time = 1.0f;
|
||||||
|
|
||||||
|
OnTrace(start, GetActorLocation());
|
||||||
|
|
||||||
|
#ifdef WITH_EDITOR
|
||||||
|
if (DebugEnabled) {
|
||||||
|
FLinearColor Color = GetDebugColor(Velocity.Size() / ((MuzzleVelocityMin + MuzzleVelocityMax)*0.5f));
|
||||||
|
DrawDebugLine(GetWorld(), start, start + TraceDistance, Color.ToFColor(true), false, DebugTrailTime, 0, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return delta*(1.0f - HitResult.Time);
|
||||||
|
}
|
||||||
|
|
||||||
|
TArray<AActor*> AEBBullet::GetAttachedActorsRecursive(AActor* Actor, uint16 Depth, TArray<AActor*> VisitedActors) const {
|
||||||
|
//TODO: limit depth
|
||||||
|
TArray<AActor*> Attached;
|
||||||
|
Actor->GetAttachedActors(Attached);
|
||||||
|
|
||||||
|
TArray<AActor*> AttachedRecursive;
|
||||||
|
for (AActor* ActorRecursive : Attached) { // Skip already visited actors to avoid infinite recursion
|
||||||
|
if (!VisitedActors.Contains(ActorRecursive)) {
|
||||||
|
VisitedActors.Add(ActorRecursive);
|
||||||
|
AttachedRecursive += GetAttachedActorsRecursive(ActorRecursive, Depth+1, VisitedActors);
|
||||||
|
VisitedActors.Remove(ActorRecursive); // Remove from visited actors to allow other branches to visit it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Attached += AttachedRecursive;
|
||||||
|
return Attached;
|
||||||
|
}
|
||||||
@ -0,0 +1,154 @@
|
|||||||
|
// Copyright 2020 Mookie. All Rights Reserved.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "CoreMinimal.h"
|
||||||
|
#include "Components/PrimitiveComponent.h"
|
||||||
|
#include "Kismet/GameplayStatics.h"
|
||||||
|
|
||||||
|
#include "EBBullet.h"
|
||||||
|
|
||||||
|
#include "EBBarrel.generated.h"
|
||||||
|
|
||||||
|
UENUM(BlueprintType)
|
||||||
|
enum class EFireMode : uint8
|
||||||
|
{
|
||||||
|
FM_Auto UMETA(DisplayName = "Full Auto"),
|
||||||
|
FM_Semiauto UMETA(DisplayName = "Semiauto"),
|
||||||
|
FM_Burst UMETA(DisplayName = "Burst"),
|
||||||
|
FM_InterBurst UMETA(DisplayName = "Interruptible Burst"),
|
||||||
|
FM_Manual UMETA(DisplayName = "Manual"),
|
||||||
|
FM_Slamfire UMETA(DisplayName = "Slam Fire"),
|
||||||
|
FM_Gatling UMETA(DisplayName = "Gatling")
|
||||||
|
};
|
||||||
|
|
||||||
|
UCLASS(Blueprintable, ClassGroup = (Custom), hidecategories = (Object, LOD, Physics, Lighting, TextureStreaming, Collision, HLOD, Mobile, VirtualTexture, ComponentReplication), editinlinenew, meta = (BlueprintSpawnableComponent))
|
||||||
|
class EASYBALLISTICS_API UEBBarrel : public UPrimitiveComponent
|
||||||
|
{
|
||||||
|
|
||||||
|
GENERATED_BODY()
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Sets default values for this component's properties
|
||||||
|
UEBBarrel();
|
||||||
|
|
||||||
|
// Called every frame
|
||||||
|
virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;
|
||||||
|
|
||||||
|
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "PROSERVE") int nextFireEventID = 100.0f;
|
||||||
|
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Debug") bool shotTrace = false;
|
||||||
|
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Debug") float DebugArrowSize = 100.0f;
|
||||||
|
|
||||||
|
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "AntiRecoil") bool AntiRecoil = true;
|
||||||
|
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "AntiRecoil") int AntiRecoilPrevCount = 5;
|
||||||
|
|
||||||
|
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Velocity", meta = (ToolTip = "Bullet inherits barrel velocity, only works with physics enabled or with additional velocity set")) float InheritVelocity = 1.0f;
|
||||||
|
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Velocity", meta = (ToolTip = "Amount of recoil applied to the barrel, only works with physics enabled")) float RecoilMultiplier = 1.0f;
|
||||||
|
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Velocity", meta = (ToolTip = "Additional velocity, for use with InheritVelocity")) FVector AdditionalVelocity = FVector(0,0,0);
|
||||||
|
|
||||||
|
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Weapon", meta = (ToolTip = "Additional maximum spread, in radians, applied on top of bullet spread", ClampMin = "0")) float Spread=0.0f;
|
||||||
|
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Weapon", meta = (ToolTip = "Additional Spread bias, higher is more accurate on average", ClampMin = "0")) float SpreadBias = 0.0f;
|
||||||
|
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Weapon", meta = (ToolTip = "Minimum of random multiplier applied to bullet muzzle velocity")) float MuzzleVelocityMultiplierMin = 1.0f;
|
||||||
|
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Weapon", meta = (ToolTip = "Maximum of random multiplier applied to bullet muzzle velocity")) float MuzzleVelocityMultiplierMax = 1.0f;
|
||||||
|
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Weapon", meta = (ToolTip = "Minimum fire rate, rounds per second")) float FireRateMin = 1.0f;
|
||||||
|
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Weapon", meta = (ToolTip = "Maximum fire rate, rounds per second, set to same number as FireRateMin to disable randomization")) float FireRateMax = 1.0f;
|
||||||
|
UPROPERTY(Replicated, BlueprintReadWrite, EditAnywhere, Category = "Weapon") EFireMode FireMode = EFireMode::FM_Auto;
|
||||||
|
UPROPERTY(Replicated, BlueprintReadWrite, EditAnywhere, Category = "Weapon") bool ShootingBlocked;
|
||||||
|
|
||||||
|
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Weapon", meta = (ToolTip = "Number of rounds auto fired in burst mode")) int BurstCount = 3;
|
||||||
|
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Weapon", meta = (ToolTip = "Minimum time between bursts")) float BurstCooldown = 0.0f;
|
||||||
|
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Weapon", meta = (ToolTip = "Automatically spin up gatling when trigger is being held down")) bool GatlingAutoSpool = true;
|
||||||
|
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Weapon") float GatlingSpoolUpTime = 1.0f;
|
||||||
|
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Weapon") float GatlingSpoolDownTime = 1.0f;
|
||||||
|
UPROPERTY(BlueprintReadWrite, Category = "Weapon") float GatlingPhase = 0.0f;
|
||||||
|
|
||||||
|
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Ammo") bool CycleAmmo = true;
|
||||||
|
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Ammo", meta = (EditCondition = "CycleAmmo")) bool CycleAmmoUnlimited = true;
|
||||||
|
UPROPERTY(Replicated, BlueprintReadWrite, EditAnywhere, Category = "Ammo") TArray<TSubclassOf<class AEBBullet>> Ammo;
|
||||||
|
UPROPERTY(Replicated, BlueprintReadWrite, EditAnywhere, Category = "Ammo", meta = (EditCondition = "CycleAmmo")) int CycleAmmoCount;
|
||||||
|
UPROPERTY(Replicated, BlueprintReadWrite, EditAnywhere, Category = "Ammo", meta = (EditCondition = "CycleAmmo")) int CycleAmmoPos;
|
||||||
|
|
||||||
|
UPROPERTY(Replicated, BlueprintReadWrite, Category = "WeaponState") TSubclassOf<class AEBBullet> ChamberedBullet;
|
||||||
|
UPROPERTY(Replicated, BlueprintReadWrite, Category = "WeaponState") bool Shooting;
|
||||||
|
UPROPERTY(Replicated, BlueprintReadWrite, Category = "WeaponState") bool Spooling = false;
|
||||||
|
UPROPERTY(BlueprintReadWrite, Category = "Weapon") float GatlingRPS = 0.0f;
|
||||||
|
|
||||||
|
UPROPERTY(BlueprintReadWrite, Category = "WeaponState") bool LoadNext=true;
|
||||||
|
UPROPERTY(BlueprintReadWrite, Category = "WeaponState") float Cooldown;
|
||||||
|
UPROPERTY(BlueprintReadWrite, Category = "WeaponState") int BurstRemaining;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
FRandomStream RandomStream;
|
||||||
|
|
||||||
|
UFUNCTION() void NextBullet();
|
||||||
|
UFUNCTION(BlueprintPure, Category = "Ammo") int GetAmmoCount(bool CountChambered) const;
|
||||||
|
UFUNCTION(BlueprintPure, Category = "Ammo") TArray<TSubclassOf<class AEBBullet>> GetAmmo(bool CountChambered) const;
|
||||||
|
UFUNCTION(BlueprintAuthorityOnly, BlueprintCallable, Category = "Ammo") void SetAmmo(int count, bool UnloadChambered, bool CancelShooting, bool ManualCharge, const TArray<TSubclassOf<class AEBBullet>>& NewAmmo);
|
||||||
|
UFUNCTION(Server, Reliable, WithValidation, BlueprintCallable, Category = "Ammo") void Charge();
|
||||||
|
UFUNCTION(Server, Reliable, WithValidation, BlueprintCallable, Category = "Ammo") void UnloadChambered(bool ManualCharge);
|
||||||
|
UFUNCTION(Server, Reliable, WithValidation, BlueprintCallable, Category = "Shooting") void SwitchFireMode(EFireMode NewFireMode);
|
||||||
|
UFUNCTION(Server, Reliable, WithValidation, BlueprintCallable, Category = "Shooting") void GatlingSpool(bool Spool);
|
||||||
|
UFUNCTION(BlueprintCallable, Category = "Shooting") void Shoot(bool Trigger, int nextEventFire);
|
||||||
|
|
||||||
|
UFUNCTION(BlueprintCallable, meta = (AutoCreateRefTerm = "IgnoredActors"), Category = "Prediction") void PredictHit(bool& Hit, FHitResult& TraceResult, FVector& HitLocation, float& HitTime, AActor*& HitActor, TArray<FVector>& Trajectory, TSubclassOf<class AEBBullet> BulletClass, TArray<AActor*>IgnoredActors, float MaxTime = 10.0f, float Step = 0.1f) const;
|
||||||
|
UFUNCTION(BlueprintCallable, meta = (AutoCreateRefTerm = "IgnoredActors"), Category = "Prediction") void PredictHitFromLocation(bool &Hit, FHitResult& TraceResult, FVector& HitLocation, float& HitTime, AActor*& HitActor, TArray<FVector>& Trajectory, TSubclassOf<class AEBBullet> BulletClass, FVector StartLocation, FVector AimDirection, TArray<AActor*>IgnoredActors, float MaxTime = 10.0f, float Step = 0.1f) const;
|
||||||
|
UFUNCTION(BlueprintCallable, Category = "Prediction") void CalculateAimDirection(TSubclassOf<class AEBBullet> BulletClass, FVector TargetLocation, FVector TargetVelocity, FVector& AimDirection, FVector& PredictedTargetLocation, FVector& PredictedIntersectionLocation, float& PredictedFlightTime, float& Error, float MaxTime = 10.0f, float Step = 0.1f, int NumIterations = 4) const;
|
||||||
|
UFUNCTION(BlueprintCallable, Category = "Prediction") void CalculateAimDirectionFromLocation(TSubclassOf<class AEBBullet> BulletClass, FVector StartLocation, FVector TargetLocation, FVector TargetVelocity, FVector& AimDirection, FVector& PredictedTargetLocation, FVector& PredictedIntersectionLocation, float& PredictedFlightTime, float& Error, float MaxTime = 10.0f, float Step=0.1f, int NumIterations = 4) const;
|
||||||
|
|
||||||
|
UFUNCTION(BlueprintNativeEvent, Category = "Events") void InitialBulletTransform(FVector InLocation, FVector InDirection, FVector& OutLocation, FVector& OutDirection);
|
||||||
|
UFUNCTION(BlueprintNativeEvent, Category = "Events") void ApplyRecoil(UPrimitiveComponent* Component, FVector InLocation, FVector Impulse);
|
||||||
|
|
||||||
|
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FBeforeShotFired);
|
||||||
|
UPROPERTY(BlueprintAssignable, Category = "Events")
|
||||||
|
FBeforeShotFired BeforeShotFired;
|
||||||
|
|
||||||
|
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FSpawnBulletEvent, FVector, Start, FVector, Velocity);
|
||||||
|
UPROPERTY(BlueprintAssignable, Category = "Events")
|
||||||
|
FSpawnBulletEvent SpawnBulletEvent;
|
||||||
|
|
||||||
|
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FShotFired);
|
||||||
|
UPROPERTY(BlueprintAssignable, Category = "Events")
|
||||||
|
FShotFired ShotFired;
|
||||||
|
|
||||||
|
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FAmmoDepleted);
|
||||||
|
UPROPERTY(BlueprintAssignable, Category = "Events")
|
||||||
|
FAmmoDepleted AmmoDepleted;
|
||||||
|
|
||||||
|
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FReadyToShoot);
|
||||||
|
UPROPERTY(BlueprintAssignable, Category = "Events")
|
||||||
|
FReadyToShoot ReadyToShoot;
|
||||||
|
|
||||||
|
#if WITH_EDITOR
|
||||||
|
virtual FPrimitiveSceneProxy* CreateSceneProxy() override;
|
||||||
|
virtual bool IsZeroExtent() const override { return false; };
|
||||||
|
virtual FBoxSphereBounds CalcBounds(const FTransform& LocalToWorld) const override;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
private:
|
||||||
|
void SpawnBullet(AActor* Owner, FVector LocalLocation, FVector LocalAim, int fireEventID);
|
||||||
|
|
||||||
|
UFUNCTION(Server, Unreliable, WithValidation) void ClientAim(FVector_NetQuantize NewLocation, FVector_NetQuantizeNormal NewAim);
|
||||||
|
UFUNCTION(Server, Reliable, WithValidation) void ShootRep(bool Trigger, int nextFireID);
|
||||||
|
UFUNCTION(Server, Reliable, WithValidation) void ShootRepCSA(bool Trigger, FVector_NetQuantize NewLocation, FVector_NetQuantizeNormal NewAim, int nextFireID);
|
||||||
|
|
||||||
|
UFUNCTION(NetMulticast, Reliable)
|
||||||
|
void ShotFiredMulticast();
|
||||||
|
|
||||||
|
UFUNCTION(NetMulticast, Reliable)
|
||||||
|
void SpawnBulletEventMulticast(FVector Start, FVector Velocity);
|
||||||
|
|
||||||
|
FVector Aim;
|
||||||
|
FVector Location;
|
||||||
|
|
||||||
|
TArray<FVector> previousAim;
|
||||||
|
TArray<FVector> previousLocation;
|
||||||
|
|
||||||
|
bool RemoteAimReceived;
|
||||||
|
float TimeSinceAimUpdate;
|
||||||
|
bool PredictTrace(UWorld* World, AEBBullet* Bullet, FVector Start, FVector End, FHitResult &HitResult, TArray<AActor*> IgnoredActors) const;
|
||||||
|
};
|
||||||
@ -0,0 +1,227 @@
|
|||||||
|
// Copyright 2016 Mookie. All Rights Reserved.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "CoreMinimal.h"
|
||||||
|
#include "GameFramework/Actor.h"
|
||||||
|
#include "Engine/Engine.h"
|
||||||
|
#include "Engine/World.h"
|
||||||
|
#include "Curves/CurveFloat.h"
|
||||||
|
#include "Kismet/KismetMathLibrary.h"
|
||||||
|
#include "Kismet/GameplayStatics.h"
|
||||||
|
#include "DrawDebugHelpers.h"
|
||||||
|
#include "Components/PrimitiveComponent.h"
|
||||||
|
|
||||||
|
#include "EBMaterialResponseMap.h"
|
||||||
|
|
||||||
|
#include "EBBullet.generated.h"
|
||||||
|
|
||||||
|
UENUM(BlueprintType)
|
||||||
|
enum class EEBAtmosphereType : uint8
|
||||||
|
{
|
||||||
|
AT_Constant UMETA(DisplayName = "Constant"),
|
||||||
|
AT_Curve UMETA(DisplayName = "Density Curve"),
|
||||||
|
AT_Earth UMETA(DisplayName = "Earth/IGL")
|
||||||
|
};
|
||||||
|
|
||||||
|
UCLASS(Blueprintable, BlueprintType)
|
||||||
|
class EASYBALLISTICS_API AEBBullet : public AActor
|
||||||
|
{
|
||||||
|
GENERATED_BODY()
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Sets default values for this actor's properties
|
||||||
|
AEBBullet();
|
||||||
|
|
||||||
|
UPROPERTY(Replicated, BlueprintReadWrite, Category = "State") FVector Velocity;
|
||||||
|
UPROPERTY(Replicated, BlueprintReadWrite, Category = "State") FRandomStream RandomStream;
|
||||||
|
|
||||||
|
UPROPERTY(BlueprintReadWrite, Category = "State") bool OwnerSafe=false;
|
||||||
|
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "PROSERVE") int fireEventID;
|
||||||
|
|
||||||
|
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Debug") bool DebugEnabled;
|
||||||
|
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Debug") float DebugTrailTime=1.0;
|
||||||
|
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Debug") float DebugTrailWidth=0;
|
||||||
|
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Debug") FLinearColor DebugTrailColorFast = FLinearColor(0, 1, 0, 1);
|
||||||
|
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Debug") FLinearColor DebugTrailColorSlow = FLinearColor(1, 0, 0, 1);
|
||||||
|
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Debug") bool DebugPooling;
|
||||||
|
|
||||||
|
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "World") FVector Wind;
|
||||||
|
UPROPERTY(BlueprintReadWrite, EditAnywhere, SaveGame, Category = "World", meta = (ToolTip = "Select atmosphere model")) EEBAtmosphereType AtmosphereType;
|
||||||
|
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "World", meta = (ToolTip = "Air Density at sea level - in KG/m^3", ClampMin = "0")) float SeaLevelAirDensity = 1.21;
|
||||||
|
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "World", meta = (ToolTip = "in cm/s", ClampMin = "0")) float SeaLevelSpeedOfSound = 34300;
|
||||||
|
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "World", meta = (ToolTip = "Used for Density Curve atmosphere model")) UCurveFloat* AirDensityCurve;
|
||||||
|
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "World") bool SpeedOfSoundVariesWithAltitude = false;
|
||||||
|
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "World") UCurveFloat* SpeedOfSoundCurve;
|
||||||
|
|
||||||
|
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "World") float WorldScale = 1.0;
|
||||||
|
UPROPERTY(BlueprintReadWrite, EditAnywhere, SaveGame, Category = "World", meta = (ToolTip = "Atmosphere pressure at 0,0,0 - in millibars", ClampMin = "0")) float SeaLevelAirPressure = 1012.5f;
|
||||||
|
UPROPERTY(BlueprintReadWrite, EditAnywhere, SaveGame, Category = "World", meta = (ToolTip = "Atmosphere Temperature at 0,0,0 - in degrees C")) float SeaLevelAirTemperature = 20.0f;
|
||||||
|
UPROPERTY(BlueprintReadWrite, EditAnywhere, SaveGame, Category = "World", meta = (ToolTip = "Temperature Decrease With Altitude, degrees per meter")) float TemperatureLapseRate = 0.00649f;
|
||||||
|
UPROPERTY(BlueprintReadWrite, EditAnywhere, SaveGame, Category = "World", meta = (ToolTip = "Altitude at which temperature stops decreasing, in meters")) float TropopauseAltitude = 11000.0f;
|
||||||
|
UPROPERTY(BlueprintReadWrite, EditAnywhere, SaveGame, Category = "World", meta = (ToolTip = "Specific Gas Constant, dry air = 287.058", ClampMin = "0")) float SpecificGasConstant = 287.058;
|
||||||
|
UPROPERTY(BlueprintReadWrite, EditAnywhere, SaveGame, Category = "World", meta = (ToolTip = "World Origin Location")) FVector WorldCenterLocation = FVector(0, 0, 0);
|
||||||
|
UPROPERTY(BlueprintReadWrite, EditAnywhere, SaveGame, Category = "World", meta = (ToolTip = "Use spherical planet model to get altitude")) bool SphericalAltitude = false;
|
||||||
|
UPROPERTY(BlueprintReadWrite, EditAnywhere, SaveGame, Category = "World", meta = (ToolTip = "Planet radius, in Unreal units", EditCondition = "SphericalAltitude", ClampMin = "0")) float SeaLevelRadius = 637100000.0f;
|
||||||
|
|
||||||
|
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "World") bool OverrideGravity = false;
|
||||||
|
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "World") FVector Gravity = FVector(0,0,-980);
|
||||||
|
|
||||||
|
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Safe launch") bool SafeLaunch = true;
|
||||||
|
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Safe launch", Meta = (EditCondition = "SafeLaunch")) bool SafeLaunchIgnoreAttachParent = true;
|
||||||
|
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Safe launch", Meta = (EditCondition = "SafeLaunchIgnoreAttachParent")) bool SafeLaunchIgnoreAllAttached = true;
|
||||||
|
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Safe launch", Meta = (EditCondition = "SafeLaunch", ClampMin = "0")) float SafeDelay = 1.0;
|
||||||
|
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Safe launch", Meta = (EditCondition = "SafeLaunch")) TArray<AActor*> SafeLaunchIgnoredActors;
|
||||||
|
|
||||||
|
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Shotgun") bool Shotgun=false;
|
||||||
|
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Shotgun", meta = (EditCondition = "Shotgun")) int ShotCount=10;
|
||||||
|
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Shotgun", meta = (EditCondition = "Shotgun")) float ShotSpread=0.01;
|
||||||
|
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Shotgun", meta = (EditCondition = "Shotgun")) float ShotVelocitySpread = 0.01;
|
||||||
|
|
||||||
|
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Flight") float MuzzleVelocityMin = 100000.0;
|
||||||
|
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Flight") float MuzzleVelocityMax = 100000.0;
|
||||||
|
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Flight", meta = (ToolTip = "Maximum bullet spread, in radians", ClampMin = "0")) float Spread = 0.0f;
|
||||||
|
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Flight", meta = (ToolTip = "Spread bias, higher is more accurate on average", ClampMin = "0")) float SpreadBias = 0.0f;
|
||||||
|
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Flight") float Mass = 0.005;
|
||||||
|
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Flight") float Diameter = 0.556;
|
||||||
|
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Flight") float FormFactor = 1.0;
|
||||||
|
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Flight") UCurveFloat* MachDragCurve;
|
||||||
|
|
||||||
|
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Impact") float GrazingAngleExponent = 2.0;
|
||||||
|
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Impact") float MinPenetration = 10.0;
|
||||||
|
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Impact") float MaxPenetration = 20.0;
|
||||||
|
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Impact") float PenetrationNormalization = 0.5;
|
||||||
|
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Impact") float PenetrationNormalizationGrazing = 0.0;
|
||||||
|
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Impact") float PenetrationEntryAngleSpread = 0.1;
|
||||||
|
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Impact") float PenetrationExitAngleSpread = 0.1;
|
||||||
|
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Impact") float RicochetProbability = 0.1;
|
||||||
|
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Impact") float RicochetProbabilityGrazing = 1;
|
||||||
|
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Impact") float RicochetRestitution = 0.1;
|
||||||
|
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Impact") float RicochetFriction = 0.0;
|
||||||
|
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Impact") float RicochetSpread = 0.1;
|
||||||
|
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Impact") bool SpeedControlsRicochetProbability = false;
|
||||||
|
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Impact") bool AddImpulse = true;
|
||||||
|
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Impact") float ImpulseMultiplier = 1.0;
|
||||||
|
|
||||||
|
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Impact") EPenTraceType DefaultPenTraceType = EPenTraceType::PT_BackTrace;
|
||||||
|
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Impact") UEBMaterialResponseMap* MaterialResponseMap;
|
||||||
|
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Impact") bool MaterialDensityControlsPenetrationDepth = true;
|
||||||
|
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Impact") bool MaterialRestitutionControlsRicochet = true;
|
||||||
|
|
||||||
|
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Replication") bool ReliableReplication = false;
|
||||||
|
|
||||||
|
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Collision", meta = (ToolTip = "Allow components to collide, intended for use with trigger volumes. Do not use for actual collisions.")) bool AllowComponentCollisions = false;
|
||||||
|
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Collision") TEnumAsByte<ECollisionChannel> TraceChannel;
|
||||||
|
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Collision") bool TraceComplex;
|
||||||
|
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Collision") float CollisionMargin=1.0;
|
||||||
|
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Collision", meta = (ToolTip = "Bullets with lower velocity will automatically despawn on impact, never despawn if set to zero or negative")) float DespawnVelocity=100.0f;
|
||||||
|
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Collision") TArray<AActor*> IgnoredActors;
|
||||||
|
|
||||||
|
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Simulation", meta = (ToolTip = "Spawned bullet performs first trace immediately, instead of waiting for next simulation step")) bool DoFirstStepImmediately = true;
|
||||||
|
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Simulation", meta = (EditCondition = "DoFirstStepImmediately")) bool RandomFirstStepDelta = true;
|
||||||
|
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Simulation") bool FixedStep = false;
|
||||||
|
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Simulation", meta = (EditCondition = "FixedStep", ClampMin = "0")) float FixedStepSeconds = 0.1;
|
||||||
|
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Simulation") int MaxTracesPerStep = 8;
|
||||||
|
|
||||||
|
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Retrace") bool Retrace = true;
|
||||||
|
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Retrace") bool RetraceOnAnotherChannel = false;
|
||||||
|
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Retrace", meta=(EditCondition="RetraceOnAnotherChannel")) TEnumAsByte<ECollisionChannel> RetraceChannel;
|
||||||
|
|
||||||
|
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Rotation") bool RotateActor = true;
|
||||||
|
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Rotation") bool RotateRandomRoll = true;
|
||||||
|
|
||||||
|
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Pooling") bool EnablePooling = false;
|
||||||
|
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Pooling", meta = (EditCondition = "EnablePooling")) int MaxPoolSize = 50;
|
||||||
|
|
||||||
|
//rebase
|
||||||
|
virtual void ApplyWorldOffset(const FVector& InOffset, bool bWorldShift) override;
|
||||||
|
|
||||||
|
// Called when the game starts or when spawned
|
||||||
|
virtual void BeginPlay() override;
|
||||||
|
|
||||||
|
// Called every frame
|
||||||
|
virtual void Tick(float DeltaSeconds) override;
|
||||||
|
|
||||||
|
virtual void LifeSpanExpired() override;
|
||||||
|
|
||||||
|
UFUNCTION(BlueprintCallable, Category = "EBBullet|Spawn")
|
||||||
|
static void SpawnWithExactVelocity(TSubclassOf<class AEBBullet> BulletClass, AActor* BulletOwner, APawn* BulletInstigator, FVector BulletLocation, FVector BulletVelocity, int EventFireID);
|
||||||
|
|
||||||
|
UFUNCTION(BlueprintCallable, Category = "EBBullet|Spawn")
|
||||||
|
static void Spawn(TSubclassOf<class AEBBullet> BulletClass, AActor* BulletOwner, APawn* BulletInstigator, FVector BulletLocation, FVector BulletVelocity, int EventFireID);
|
||||||
|
|
||||||
|
UFUNCTION(NetMulticast, Unreliable)
|
||||||
|
void VelocityChangeBroadcast(FVector_NetQuantize NewLocation, FVector NewVelocity);
|
||||||
|
UFUNCTION(NetMulticast, Reliable)
|
||||||
|
void VelocityChangeBroadcastReliable(FVector_NetQuantize NewLocation, FVector NewVelocity);
|
||||||
|
|
||||||
|
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, int EventFireID);
|
||||||
|
|
||||||
|
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, int EventFireID);
|
||||||
|
|
||||||
|
UFUNCTION(BlueprintImplementableEvent, Category = "EBBullet|Impact")
|
||||||
|
void OnTrace(FVector StartLocation, FVector EndLocation);
|
||||||
|
|
||||||
|
UFUNCTION(BlueprintImplementableEvent, Category = "EBBullet|Remote")
|
||||||
|
void OnTrajectoryUpdateReceived(FVector Location, FVector OldVelocity, FVector NewVelocity);
|
||||||
|
|
||||||
|
UFUNCTION(BlueprintNativeEvent, Category = "EBBullet|Activation")
|
||||||
|
void OnDeactivated();
|
||||||
|
|
||||||
|
UFUNCTION(BlueprintNativeEvent, Category = "EBBullet|Flight")FVector UpdateVelocity(UWorld* World, FVector Location, FVector PreviousVelocity, float DeltaTime) const;
|
||||||
|
UFUNCTION(BlueprintNativeEvent, Category = "EBBullet|World") FVector GetWind(UWorld* World, FVector Location) const;
|
||||||
|
UFUNCTION(BlueprintNativeEvent, Category = "EBBullet|World") float GetAirDensity(UWorld* World, FVector Location) const;
|
||||||
|
UFUNCTION(BlueprintNativeEvent, Category = "EBBullet|World") float GetSpeedOfSound(UWorld* World, FVector Location) const;
|
||||||
|
UFUNCTION(BlueprintNativeEvent, Category = "EBBullet|World") bool CollisionFilter(FHitResult HitResult) const;
|
||||||
|
|
||||||
|
//pooling
|
||||||
|
UFUNCTION(BlueprintAuthorityOnly, BlueprintCallable, Category = "EBBullet|Pooling")void Deactivate();
|
||||||
|
|
||||||
|
UFUNCTION(NetMulticast, Reliable)
|
||||||
|
void ReactivationBroadcast(FVector_NetQuantize NewLocation, FVector NewVelocity, AActor* BulletOwner, APawn* BulletInstigator, int nextFireEventID);
|
||||||
|
UFUNCTION(NetMulticast, Reliable)
|
||||||
|
void DeactivationBroadcast();
|
||||||
|
private:
|
||||||
|
UPROPERTY() TArray<TWeakObjectPtr<AEBBullet>> Pooled;
|
||||||
|
static AEBBullet* GetFromPool(UWorld* World, UClass* BulletClass);
|
||||||
|
static AEBBullet* SpawnOrReactivate(UWorld* World, TSubclassOf<class AEBBullet> BulletClass, const FTransform& Transform, FVector BulletVelocity, AActor* BulletOwner, APawn* BulletInstigator, int nextFireEventID);
|
||||||
|
void DeactivateToPool();
|
||||||
|
|
||||||
|
void FinishSpawning(FTransform Transform);
|
||||||
|
|
||||||
|
void Step(float DeltaTime);
|
||||||
|
|
||||||
|
float Trace(FVector start, FVector PreviousVelocity, float delta, TEnumAsByte<ECollisionChannel> channel);
|
||||||
|
|
||||||
|
TArray<AActor*> GetAttachedActorsRecursive(AActor* Actor, uint16 Depth = 0, TArray<AActor*> VisitedActors = TArray<AActor*>()) const;
|
||||||
|
|
||||||
|
float PenetrationTrace(FVector start, FVector end, TWeakObjectPtr<UPrimitiveComponent,FWeakObjectPtr> comp, EPenTraceType penType, TEnumAsByte<ECollisionChannel> channel, FVector &exitLoc, FVector &exitNormal);
|
||||||
|
|
||||||
|
float GetCurveValue(const UCurveFloat* curve, float in, float deflt) const;
|
||||||
|
|
||||||
|
float AccumulatedDelta;
|
||||||
|
|
||||||
|
bool CanRetrace = false;
|
||||||
|
FVector LastTraceStart;
|
||||||
|
float LastTraceDelta;
|
||||||
|
FVector LastTraceVelocity;
|
||||||
|
FVector LastTracePrevVelocity;
|
||||||
|
|
||||||
|
bool IsRecycled;
|
||||||
|
|
||||||
|
FHitResult FilterHits(TArray<FHitResult> Results, bool &hit) const;
|
||||||
|
TArray<AActor*>GetSafeLaunchIgnoredActors(AActor* Owner) const;
|
||||||
|
|
||||||
|
float GetAltitude(UWorld* World, FVector Location) const;
|
||||||
|
float GetAltitudePressure(float AltitudeMeter) const;
|
||||||
|
float GetAltitudeTemperature(float AltitudeMeter) const;
|
||||||
|
float GetAltitudeDensity(float AltitudeMeter) const;
|
||||||
|
|
||||||
|
#ifdef WITH_EDITOR
|
||||||
|
FLinearColor GetDebugColor(float In) const{
|
||||||
|
return FMath::Lerp(DebugTrailColorSlow, DebugTrailColorFast, In);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
};
|
||||||
@ -0,0 +1,45 @@
|
|||||||
|
// Copyright 2016 Mookie. All Rights Reserved.
|
||||||
|
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "CoreMinimal.h"
|
||||||
|
#include "Engine/DataAsset.h"
|
||||||
|
#include "PhysicalMaterials/PhysicalMaterial.h"
|
||||||
|
#include "EBMaterialResponseMap.generated.h"
|
||||||
|
|
||||||
|
UENUM(BlueprintType)
|
||||||
|
enum class EPenTraceType : uint8
|
||||||
|
{
|
||||||
|
PT_BackTrace UMETA(DisplayName = "Back Trace"),
|
||||||
|
PT_ByComponent UMETA(DisplayName = "By Component"),
|
||||||
|
PT_TwoSidedGeometry UMETA(DisplayName = "Double Sided Geometry"),
|
||||||
|
};
|
||||||
|
|
||||||
|
USTRUCT(BlueprintType)
|
||||||
|
struct FEBMaterialResponseMapEntry {
|
||||||
|
GENERATED_USTRUCT_BODY()
|
||||||
|
|
||||||
|
UPROPERTY(EditAnywhere, Category = "Material") EPenTraceType PenTraceType = EPenTraceType::PT_BackTrace;
|
||||||
|
UPROPERTY(EditAnywhere, Category = "Material") bool NeverPenetrate = false;
|
||||||
|
UPROPERTY(EditAnywhere, Category = "Material") float PenetrationDepthMultiplier = 1.0f;
|
||||||
|
UPROPERTY(EditAnywhere, Category = "Material") float PenetrationNormalization = 0.0f;
|
||||||
|
UPROPERTY(EditAnywhere, Category = "Material") float PenetrationNormalizationGrazing = 0.0f;
|
||||||
|
UPROPERTY(EditAnywhere, Category = "Material") float PenetrationEntryAngleSpread = 0.0f;
|
||||||
|
UPROPERTY(EditAnywhere, Category = "Material") float PenetrationExitAngleSpread = 0.0;
|
||||||
|
UPROPERTY(EditAnywhere, Category = "Material") bool NeverRicochet = false;
|
||||||
|
UPROPERTY(EditAnywhere, Category = "Material") float RicochetProbabilityMultiplier = 1.0f;
|
||||||
|
UPROPERTY(EditAnywhere, Category = "Material") float RicochetRestitution = 0.5f;
|
||||||
|
UPROPERTY(EditAnywhere, Category = "Material") float RicochetRestitutionInfluence = 0.0f;
|
||||||
|
UPROPERTY(EditAnywhere, Category = "Material") float RicochetFriction = 0.5f;
|
||||||
|
UPROPERTY(EditAnywhere, Category = "Material") float RicochetFrictionInfluence = 0.0f;
|
||||||
|
UPROPERTY(EditAnywhere, Category = "Material") float RicochetSpread = 0.0f;
|
||||||
|
};
|
||||||
|
|
||||||
|
UCLASS(BlueprintType)
|
||||||
|
class UEBMaterialResponseMap : public UDataAsset{
|
||||||
|
GENERATED_BODY()
|
||||||
|
|
||||||
|
public:
|
||||||
|
UPROPERTY(EditAnywhere, Category = "Responses") TMap<UPhysicalMaterial*, FEBMaterialResponseMapEntry> Map;
|
||||||
|
};
|
||||||
@ -0,0 +1,17 @@
|
|||||||
|
// Copyright 1998-2016 Epic Games, Inc. All Rights Reserved.
|
||||||
|
// Copyright 2018 Mookie. All Rights Reserved.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "CoreMinimal.h"
|
||||||
|
#include "Modules/ModuleInterface.h"
|
||||||
|
#include "Modules/ModuleManager.h"
|
||||||
|
|
||||||
|
class FEasyBallisticsModule : public IModuleInterface
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
/** IModuleInterface implementation */
|
||||||
|
virtual void StartupModule() override;
|
||||||
|
virtual void ShutdownModule() override;
|
||||||
|
};
|
||||||
15
Unreal/Source/PS_Ballistics.Target.cs
Normal file
15
Unreal/Source/PS_Ballistics.Target.cs
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||||
|
|
||||||
|
using UnrealBuildTool;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
public class PS_BallisticsTarget : TargetRules
|
||||||
|
{
|
||||||
|
public PS_BallisticsTarget(TargetInfo Target) : base(Target)
|
||||||
|
{
|
||||||
|
Type = TargetType.Game;
|
||||||
|
DefaultBuildSettings = BuildSettingsVersion.V5;
|
||||||
|
IncludeOrderVersion = EngineIncludeOrderVersion.Unreal5_5;
|
||||||
|
ExtraModuleNames.Add("PS_Ballistics");
|
||||||
|
}
|
||||||
|
}
|
||||||
23
Unreal/Source/PS_Ballistics/PS_Ballistics.Build.cs
Normal file
23
Unreal/Source/PS_Ballistics/PS_Ballistics.Build.cs
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||||
|
|
||||||
|
using UnrealBuildTool;
|
||||||
|
|
||||||
|
public class PS_Ballistics : ModuleRules
|
||||||
|
{
|
||||||
|
public PS_Ballistics(ReadOnlyTargetRules Target) : base(Target)
|
||||||
|
{
|
||||||
|
PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;
|
||||||
|
|
||||||
|
PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore", "EnhancedInput" });
|
||||||
|
|
||||||
|
PrivateDependencyModuleNames.AddRange(new string[] { });
|
||||||
|
|
||||||
|
// Uncomment if you are using Slate UI
|
||||||
|
// PrivateDependencyModuleNames.AddRange(new string[] { "Slate", "SlateCore" });
|
||||||
|
|
||||||
|
// Uncomment if you are using online features
|
||||||
|
// PrivateDependencyModuleNames.Add("OnlineSubsystem");
|
||||||
|
|
||||||
|
// To include OnlineSubsystemSteam, add it to the plugins section in your uproject file with the Enabled attribute set to true
|
||||||
|
}
|
||||||
|
}
|
||||||
6
Unreal/Source/PS_Ballistics/PS_Ballistics.cpp
Normal file
6
Unreal/Source/PS_Ballistics/PS_Ballistics.cpp
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||||
|
|
||||||
|
#include "PS_Ballistics.h"
|
||||||
|
#include "Modules/ModuleManager.h"
|
||||||
|
|
||||||
|
IMPLEMENT_PRIMARY_GAME_MODULE( FDefaultGameModuleImpl, PS_Ballistics, "PS_Ballistics" );
|
||||||
6
Unreal/Source/PS_Ballistics/PS_Ballistics.h
Normal file
6
Unreal/Source/PS_Ballistics/PS_Ballistics.h
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "CoreMinimal.h"
|
||||||
|
|
||||||
15
Unreal/Source/PS_BallisticsEditor.Target.cs
Normal file
15
Unreal/Source/PS_BallisticsEditor.Target.cs
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||||
|
|
||||||
|
using UnrealBuildTool;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
public class PS_BallisticsEditorTarget : TargetRules
|
||||||
|
{
|
||||||
|
public PS_BallisticsEditorTarget( TargetInfo Target) : base(Target)
|
||||||
|
{
|
||||||
|
Type = TargetType.Editor;
|
||||||
|
DefaultBuildSettings = BuildSettingsVersion.V5;
|
||||||
|
IncludeOrderVersion = EngineIncludeOrderVersion.Unreal5_5;
|
||||||
|
ExtraModuleNames.Add("PS_Ballistics");
|
||||||
|
}
|
||||||
|
}
|
||||||
335
Unreal/UpgradeLog.htm
Normal file
335
Unreal/UpgradeLog.htm
Normal file
File diff suppressed because one or more lines are too long
Loading…
x
Reference in New Issue
Block a user