├── .gitattributes ├── 1.png ├── 2.png ├── Config ├── DefaultEditor.ini ├── DefaultEditorPerProjectUserSettings.ini ├── DefaultEngine.ini ├── DefaultGame.ini └── DefaultInput.ini ├── Content ├── Geometry │ └── Meshes │ │ ├── 1M_Cube.uasset │ │ ├── 1M_Cube_Chamfer.uasset │ │ ├── CubeMaterial.uasset │ │ └── TemplateFloor.uasset ├── Mannequin │ ├── Animations │ │ ├── ThirdPersonIdle.uasset │ │ ├── ThirdPersonJump_End.uasset │ │ ├── ThirdPersonJump_Loop.uasset │ │ ├── ThirdPersonJump_Start.uasset │ │ ├── ThirdPersonRun.uasset │ │ ├── ThirdPersonWalk.uasset │ │ ├── ThirdPerson_AnimBP.uasset │ │ ├── ThirdPerson_IdleRun_2D.uasset │ │ └── ThirdPerson_Jump.uasset │ └── Character │ │ ├── Materials │ │ ├── M_UE4Man_Body.uasset │ │ ├── M_UE4Man_ChestLogo.uasset │ │ └── MaterialLayers │ │ │ ├── ML_GlossyBlack_Latex_UE4.uasset │ │ │ ├── ML_Plastic_Shiny_Beige.uasset │ │ │ ├── ML_Plastic_Shiny_Beige_LOGO.uasset │ │ │ ├── ML_SoftMetal_UE4.uasset │ │ │ ├── T_ML_Aluminum01.uasset │ │ │ ├── T_ML_Aluminum01_N.uasset │ │ │ ├── T_ML_Rubber_Blue_01_D.uasset │ │ │ └── T_ML_Rubber_Blue_01_N.uasset │ │ ├── Mesh │ │ ├── SK_Mannequin.uasset │ │ ├── SK_Mannequin_PhysicsAsset.uasset │ │ └── UE4_Mannequin_Skeleton.uasset │ │ └── Textures │ │ ├── UE4Man_Logo_N.uasset │ │ ├── UE4_LOGO_CARD.uasset │ │ ├── UE4_Mannequin_MAT_MASKA.uasset │ │ └── UE4_Mannequin__normals.uasset ├── ThirdPerson │ └── Meshes │ │ ├── Bump_StaticMesh.uasset │ │ ├── CubeMaterial.uasset │ │ ├── LeftArm_StaticMesh.uasset │ │ ├── Linear_Stair_StaticMesh.uasset │ │ ├── RampMaterial.uasset │ │ ├── Ramp_StaticMesh.uasset │ │ └── RightArm_StaticMesh.uasset └── ThirdPersonCPP │ ├── Blueprints │ └── ThirdPersonCharacter.uasset │ └── Maps │ ├── ThirdPersonExampleMap.umap │ └── ThirdPersonExampleMap_BuiltData.uasset ├── LICENSE ├── README.md ├── Source ├── TestMultiCollision.Target.cs ├── TestMultiCollision │ ├── MultiCollisionCapsuleComponent.cpp │ ├── MultiCollisionCapsuleComponent.h │ ├── MultiCollisionCharacter.cpp │ ├── MultiCollisionCharacter.h │ ├── MultiCollisionMovementComponent.cpp │ ├── MultiCollisionMovementComponent.h │ ├── TestMultiCollision.Build.cs │ ├── TestMultiCollision.cpp │ ├── TestMultiCollision.h │ ├── TestMultiCollisionCharacter.cpp │ ├── TestMultiCollisionCharacter.h │ ├── TestMultiCollisionGameMode.cpp │ └── TestMultiCollisionGameMode.h └── TestMultiCollisionEditor.Target.cs └── TestMultiCollision.uproject /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/h2ogit/UE4-MultiCollisionMovement/848f7d2b9762a019a3d2ec66b9d8abd40af25f49/1.png -------------------------------------------------------------------------------- /2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/h2ogit/UE4-MultiCollisionMovement/848f7d2b9762a019a3d2ec66b9d8abd40af25f49/2.png -------------------------------------------------------------------------------- /Config/DefaultEditor.ini: -------------------------------------------------------------------------------- 1 | [UnrealEd.SimpleMap] 2 | SimpleMapName=/Game/ThirdPersonCPP/Maps/ThirdPersonExampleMap 3 | 4 | [EditoronlyBP] 5 | bAllowClassAndBlueprintPinMatching=true 6 | bReplaceBlueprintWithClass= true 7 | bDontLoadBlueprintOutsideEditor= true 8 | bBlueprintIsNotBlueprintType= true -------------------------------------------------------------------------------- /Config/DefaultEditorPerProjectUserSettings.ini: -------------------------------------------------------------------------------- 1 | [ContentBrowser] 2 | ContentBrowserTab1.SelectedPaths=/Game/ThirdPersonCPP -------------------------------------------------------------------------------- /Config/DefaultEngine.ini: -------------------------------------------------------------------------------- 1 | [/Script/EngineSettings.GameMapsSettings] 2 | GameDefaultMap=/Game/ThirdPersonCPP/Maps/ThirdPersonExampleMap 3 | EditorStartupMap=/Game/ThirdPersonCPP/Maps/ThirdPersonExampleMap 4 | GlobalDefaultGameMode="/Script/TestMultiCollision.TestMultiCollisionGameMode" 5 | 6 | [/Script/Engine.Engine] 7 | +ActiveGameNameRedirects=(OldGameName="TP_ThirdPerson",NewGameName="/Script/TestMultiCollision") 8 | +ActiveGameNameRedirects=(OldGameName="/Script/TP_ThirdPerson",NewGameName="/Script/TestMultiCollision") 9 | +ActiveClassRedirects=(OldClassName="TP_ThirdPersonGameMode",NewClassName="TestMultiCollisionGameMode") 10 | +ActiveClassRedirects=(OldClassName="TP_ThirdPersonCharacter",NewClassName="TestMultiCollisionCharacter") 11 | 12 | [/Script/HardwareTargeting.HardwareTargetingSettings] 13 | TargetedHardwareClass=Desktop 14 | AppliedTargetedHardwareClass=Desktop 15 | DefaultGraphicsPerformance=Maximum 16 | AppliedDefaultGraphicsPerformance=Maximum 17 | 18 | [/Script/AndroidFileServerEditor.AndroidFileServerRuntimeSettings] 19 | bEnablePlugin=True 20 | bAllowNetworkConnection=True 21 | SecurityToken=17F7944D42EED5146C0BFFA0332197AB 22 | bIncludeInShipping=False 23 | bAllowExternalStartInShipping=False 24 | bCompileAFSProject=False 25 | bUseCompression=False 26 | bLogFiles=False 27 | bReportStats=False 28 | ConnectionType=USBOnly 29 | bUseManualIPAddress=False 30 | ManualIPAddress= 31 | 32 | -------------------------------------------------------------------------------- /Config/DefaultGame.ini: -------------------------------------------------------------------------------- 1 | [/Script/EngineSettings.GeneralProjectSettings] 2 | ProjectID=F26CEF1F461DAE8FF27238AFC692782E 3 | ProjectName=Third Person Game Template 4 | -------------------------------------------------------------------------------- /Config/DefaultInput.ini: -------------------------------------------------------------------------------- 1 | [/Script/Engine.InputSettings] 2 | -AxisConfig=(AxisKeyName="Gamepad_LeftX",AxisProperties=(DeadZone=0.25,Exponent=1.f,Sensitivity=1.f)) 3 | -AxisConfig=(AxisKeyName="Gamepad_LeftY",AxisProperties=(DeadZone=0.25,Exponent=1.f,Sensitivity=1.f)) 4 | -AxisConfig=(AxisKeyName="Gamepad_RightX",AxisProperties=(DeadZone=0.25,Exponent=1.f,Sensitivity=1.f)) 5 | -AxisConfig=(AxisKeyName="Gamepad_RightY",AxisProperties=(DeadZone=0.25,Exponent=1.f,Sensitivity=1.f)) 6 | -AxisConfig=(AxisKeyName="MouseX",AxisProperties=(DeadZone=0.f,Exponent=1.f,Sensitivity=0.07f)) 7 | -AxisConfig=(AxisKeyName="MouseY",AxisProperties=(DeadZone=0.f,Exponent=1.f,Sensitivity=0.07f)) 8 | -AxisConfig=(AxisKeyName="Mouse2D",AxisProperties=(DeadZone=0.f,Exponent=1.f,Sensitivity=0.07f)) 9 | +AxisConfig=(AxisKeyName="Gamepad_LeftX",AxisProperties=(DeadZone=0.250000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 10 | +AxisConfig=(AxisKeyName="Gamepad_LeftY",AxisProperties=(DeadZone=0.250000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 11 | +AxisConfig=(AxisKeyName="Gamepad_RightX",AxisProperties=(DeadZone=0.250000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 12 | +AxisConfig=(AxisKeyName="Gamepad_RightY",AxisProperties=(DeadZone=0.250000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 13 | +AxisConfig=(AxisKeyName="MouseX",AxisProperties=(DeadZone=0.000000,Sensitivity=0.070000,Exponent=1.000000,bInvert=False)) 14 | +AxisConfig=(AxisKeyName="MouseY",AxisProperties=(DeadZone=0.000000,Sensitivity=0.070000,Exponent=1.000000,bInvert=False)) 15 | +AxisConfig=(AxisKeyName="Mouse2D",AxisProperties=(DeadZone=0.000000,Sensitivity=0.070000,Exponent=1.000000,bInvert=False)) 16 | +AxisConfig=(AxisKeyName="MouseWheelAxis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 17 | +AxisConfig=(AxisKeyName="Gamepad_LeftTriggerAxis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 18 | +AxisConfig=(AxisKeyName="Gamepad_RightTriggerAxis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 19 | +AxisConfig=(AxisKeyName="Gamepad_Special_Left_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 20 | +AxisConfig=(AxisKeyName="Gamepad_Special_Left_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 21 | +AxisConfig=(AxisKeyName="Vive_Left_Trigger_Axis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 22 | +AxisConfig=(AxisKeyName="Vive_Left_Trackpad_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 23 | +AxisConfig=(AxisKeyName="Vive_Left_Trackpad_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 24 | +AxisConfig=(AxisKeyName="Vive_Right_Trigger_Axis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 25 | +AxisConfig=(AxisKeyName="Vive_Right_Trackpad_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 26 | +AxisConfig=(AxisKeyName="Vive_Right_Trackpad_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 27 | +AxisConfig=(AxisKeyName="MixedReality_Left_Trigger_Axis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 28 | +AxisConfig=(AxisKeyName="MixedReality_Left_Thumbstick_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 29 | +AxisConfig=(AxisKeyName="MixedReality_Left_Thumbstick_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 30 | +AxisConfig=(AxisKeyName="MixedReality_Left_Trackpad_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 31 | +AxisConfig=(AxisKeyName="MixedReality_Left_Trackpad_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 32 | +AxisConfig=(AxisKeyName="MixedReality_Right_Trigger_Axis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 33 | +AxisConfig=(AxisKeyName="MixedReality_Right_Thumbstick_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 34 | +AxisConfig=(AxisKeyName="MixedReality_Right_Thumbstick_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 35 | +AxisConfig=(AxisKeyName="MixedReality_Right_Trackpad_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 36 | +AxisConfig=(AxisKeyName="MixedReality_Right_Trackpad_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 37 | +AxisConfig=(AxisKeyName="OculusTouch_Left_Grip_Axis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 38 | +AxisConfig=(AxisKeyName="OculusTouch_Left_Trigger_Axis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 39 | +AxisConfig=(AxisKeyName="OculusTouch_Left_Thumbstick_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 40 | +AxisConfig=(AxisKeyName="OculusTouch_Left_Thumbstick_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 41 | +AxisConfig=(AxisKeyName="OculusTouch_Right_Grip_Axis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 42 | +AxisConfig=(AxisKeyName="OculusTouch_Right_Trigger_Axis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 43 | +AxisConfig=(AxisKeyName="OculusTouch_Right_Thumbstick_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 44 | +AxisConfig=(AxisKeyName="OculusTouch_Right_Thumbstick_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 45 | +AxisConfig=(AxisKeyName="ValveIndex_Left_Grip_Axis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 46 | +AxisConfig=(AxisKeyName="ValveIndex_Left_Grip_Force",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 47 | +AxisConfig=(AxisKeyName="ValveIndex_Left_Trigger_Axis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 48 | +AxisConfig=(AxisKeyName="ValveIndex_Left_Thumbstick_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 49 | +AxisConfig=(AxisKeyName="ValveIndex_Left_Thumbstick_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 50 | +AxisConfig=(AxisKeyName="ValveIndex_Left_Trackpad_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 51 | +AxisConfig=(AxisKeyName="ValveIndex_Left_Trackpad_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 52 | +AxisConfig=(AxisKeyName="ValveIndex_Left_Trackpad_Force",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 53 | +AxisConfig=(AxisKeyName="ValveIndex_Right_Grip_Axis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 54 | +AxisConfig=(AxisKeyName="ValveIndex_Right_Grip_Force",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 55 | +AxisConfig=(AxisKeyName="ValveIndex_Right_Trigger_Axis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 56 | +AxisConfig=(AxisKeyName="ValveIndex_Right_Thumbstick_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 57 | +AxisConfig=(AxisKeyName="ValveIndex_Right_Thumbstick_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 58 | +AxisConfig=(AxisKeyName="ValveIndex_Right_Trackpad_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 59 | +AxisConfig=(AxisKeyName="ValveIndex_Right_Trackpad_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 60 | +AxisConfig=(AxisKeyName="ValveIndex_Right_Trackpad_Force",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 61 | bAltEnterTogglesFullscreen=True 62 | bF11TogglesFullscreen=True 63 | bUseMouseForTouch=False 64 | bEnableMouseSmoothing=True 65 | bEnableFOVScaling=True 66 | bCaptureMouseOnLaunch=True 67 | bEnableLegacyInputScales=True 68 | bEnableMotionControls=True 69 | bFilterInputByPlatformUser=False 70 | bEnableInputDeviceSubsystem=True 71 | bShouldFlushPressedKeysOnViewportFocusLost=True 72 | bEnableDynamicComponentInputBinding=True 73 | bAlwaysShowTouchInterface=False 74 | bShowConsoleOnFourFingerTap=True 75 | bEnableGestureRecognizer=False 76 | bUseAutocorrect=False 77 | DefaultViewportMouseCaptureMode=CapturePermanently_IncludingInitialMouseDown 78 | DefaultViewportMouseLockMode=LockOnCapture 79 | FOVScale=0.011110 80 | DoubleClickTime=0.200000 81 | +ActionMappings=(ActionName="Jump",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=SpaceBar) 82 | +ActionMappings=(ActionName="Jump",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=Gamepad_FaceButton_Bottom) 83 | +ActionMappings=(ActionName="ResetVR",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=R) 84 | +ActionMappings=(ActionName="ResetVR",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=MotionController_Left_Grip1) 85 | +AxisMappings=(AxisName="MoveForward",Scale=1.000000,Key=W) 86 | +AxisMappings=(AxisName="MoveForward",Scale=-1.000000,Key=S) 87 | +AxisMappings=(AxisName="MoveForward",Scale=1.000000,Key=Up) 88 | +AxisMappings=(AxisName="MoveForward",Scale=-1.000000,Key=Down) 89 | +AxisMappings=(AxisName="MoveForward",Scale=1.000000,Key=Gamepad_LeftY) 90 | +AxisMappings=(AxisName="MoveRight",Scale=-1.000000,Key=A) 91 | +AxisMappings=(AxisName="MoveRight",Scale=1.000000,Key=D) 92 | +AxisMappings=(AxisName="MoveRight",Scale=1.000000,Key=Gamepad_LeftX) 93 | +AxisMappings=(AxisName="TurnRate",Scale=1.000000,Key=Gamepad_RightX) 94 | +AxisMappings=(AxisName="TurnRate",Scale=-1.000000,Key=Left) 95 | +AxisMappings=(AxisName="TurnRate",Scale=1.000000,Key=Right) 96 | +AxisMappings=(AxisName="Turn",Scale=1.000000,Key=MouseX) 97 | +AxisMappings=(AxisName="LookUpRate",Scale=1.000000,Key=Gamepad_RightY) 98 | +AxisMappings=(AxisName="LookUp",Scale=-1.000000,Key=MouseY) 99 | DefaultPlayerInputClass=/Script/EnhancedInput.EnhancedPlayerInput 100 | DefaultInputComponentClass=/Script/EnhancedInput.EnhancedInputComponent 101 | DefaultTouchInterface=/Engine/MobileResources/HUD/DefaultVirtualJoysticks.DefaultVirtualJoysticks 102 | -ConsoleKeys=Tilde 103 | +ConsoleKeys=Tilde 104 | 105 | -------------------------------------------------------------------------------- /Content/Geometry/Meshes/1M_Cube.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/h2ogit/UE4-MultiCollisionMovement/848f7d2b9762a019a3d2ec66b9d8abd40af25f49/Content/Geometry/Meshes/1M_Cube.uasset -------------------------------------------------------------------------------- /Content/Geometry/Meshes/1M_Cube_Chamfer.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/h2ogit/UE4-MultiCollisionMovement/848f7d2b9762a019a3d2ec66b9d8abd40af25f49/Content/Geometry/Meshes/1M_Cube_Chamfer.uasset -------------------------------------------------------------------------------- /Content/Geometry/Meshes/CubeMaterial.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/h2ogit/UE4-MultiCollisionMovement/848f7d2b9762a019a3d2ec66b9d8abd40af25f49/Content/Geometry/Meshes/CubeMaterial.uasset -------------------------------------------------------------------------------- /Content/Geometry/Meshes/TemplateFloor.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/h2ogit/UE4-MultiCollisionMovement/848f7d2b9762a019a3d2ec66b9d8abd40af25f49/Content/Geometry/Meshes/TemplateFloor.uasset -------------------------------------------------------------------------------- /Content/Mannequin/Animations/ThirdPersonIdle.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/h2ogit/UE4-MultiCollisionMovement/848f7d2b9762a019a3d2ec66b9d8abd40af25f49/Content/Mannequin/Animations/ThirdPersonIdle.uasset -------------------------------------------------------------------------------- /Content/Mannequin/Animations/ThirdPersonJump_End.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/h2ogit/UE4-MultiCollisionMovement/848f7d2b9762a019a3d2ec66b9d8abd40af25f49/Content/Mannequin/Animations/ThirdPersonJump_End.uasset -------------------------------------------------------------------------------- /Content/Mannequin/Animations/ThirdPersonJump_Loop.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/h2ogit/UE4-MultiCollisionMovement/848f7d2b9762a019a3d2ec66b9d8abd40af25f49/Content/Mannequin/Animations/ThirdPersonJump_Loop.uasset -------------------------------------------------------------------------------- /Content/Mannequin/Animations/ThirdPersonJump_Start.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/h2ogit/UE4-MultiCollisionMovement/848f7d2b9762a019a3d2ec66b9d8abd40af25f49/Content/Mannequin/Animations/ThirdPersonJump_Start.uasset -------------------------------------------------------------------------------- /Content/Mannequin/Animations/ThirdPersonRun.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/h2ogit/UE4-MultiCollisionMovement/848f7d2b9762a019a3d2ec66b9d8abd40af25f49/Content/Mannequin/Animations/ThirdPersonRun.uasset -------------------------------------------------------------------------------- /Content/Mannequin/Animations/ThirdPersonWalk.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/h2ogit/UE4-MultiCollisionMovement/848f7d2b9762a019a3d2ec66b9d8abd40af25f49/Content/Mannequin/Animations/ThirdPersonWalk.uasset -------------------------------------------------------------------------------- /Content/Mannequin/Animations/ThirdPerson_AnimBP.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/h2ogit/UE4-MultiCollisionMovement/848f7d2b9762a019a3d2ec66b9d8abd40af25f49/Content/Mannequin/Animations/ThirdPerson_AnimBP.uasset -------------------------------------------------------------------------------- /Content/Mannequin/Animations/ThirdPerson_IdleRun_2D.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/h2ogit/UE4-MultiCollisionMovement/848f7d2b9762a019a3d2ec66b9d8abd40af25f49/Content/Mannequin/Animations/ThirdPerson_IdleRun_2D.uasset -------------------------------------------------------------------------------- /Content/Mannequin/Animations/ThirdPerson_Jump.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/h2ogit/UE4-MultiCollisionMovement/848f7d2b9762a019a3d2ec66b9d8abd40af25f49/Content/Mannequin/Animations/ThirdPerson_Jump.uasset -------------------------------------------------------------------------------- /Content/Mannequin/Character/Materials/M_UE4Man_Body.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/h2ogit/UE4-MultiCollisionMovement/848f7d2b9762a019a3d2ec66b9d8abd40af25f49/Content/Mannequin/Character/Materials/M_UE4Man_Body.uasset -------------------------------------------------------------------------------- /Content/Mannequin/Character/Materials/M_UE4Man_ChestLogo.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/h2ogit/UE4-MultiCollisionMovement/848f7d2b9762a019a3d2ec66b9d8abd40af25f49/Content/Mannequin/Character/Materials/M_UE4Man_ChestLogo.uasset -------------------------------------------------------------------------------- /Content/Mannequin/Character/Materials/MaterialLayers/ML_GlossyBlack_Latex_UE4.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/h2ogit/UE4-MultiCollisionMovement/848f7d2b9762a019a3d2ec66b9d8abd40af25f49/Content/Mannequin/Character/Materials/MaterialLayers/ML_GlossyBlack_Latex_UE4.uasset -------------------------------------------------------------------------------- /Content/Mannequin/Character/Materials/MaterialLayers/ML_Plastic_Shiny_Beige.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/h2ogit/UE4-MultiCollisionMovement/848f7d2b9762a019a3d2ec66b9d8abd40af25f49/Content/Mannequin/Character/Materials/MaterialLayers/ML_Plastic_Shiny_Beige.uasset -------------------------------------------------------------------------------- /Content/Mannequin/Character/Materials/MaterialLayers/ML_Plastic_Shiny_Beige_LOGO.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/h2ogit/UE4-MultiCollisionMovement/848f7d2b9762a019a3d2ec66b9d8abd40af25f49/Content/Mannequin/Character/Materials/MaterialLayers/ML_Plastic_Shiny_Beige_LOGO.uasset -------------------------------------------------------------------------------- /Content/Mannequin/Character/Materials/MaterialLayers/ML_SoftMetal_UE4.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/h2ogit/UE4-MultiCollisionMovement/848f7d2b9762a019a3d2ec66b9d8abd40af25f49/Content/Mannequin/Character/Materials/MaterialLayers/ML_SoftMetal_UE4.uasset -------------------------------------------------------------------------------- /Content/Mannequin/Character/Materials/MaterialLayers/T_ML_Aluminum01.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/h2ogit/UE4-MultiCollisionMovement/848f7d2b9762a019a3d2ec66b9d8abd40af25f49/Content/Mannequin/Character/Materials/MaterialLayers/T_ML_Aluminum01.uasset -------------------------------------------------------------------------------- /Content/Mannequin/Character/Materials/MaterialLayers/T_ML_Aluminum01_N.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/h2ogit/UE4-MultiCollisionMovement/848f7d2b9762a019a3d2ec66b9d8abd40af25f49/Content/Mannequin/Character/Materials/MaterialLayers/T_ML_Aluminum01_N.uasset -------------------------------------------------------------------------------- /Content/Mannequin/Character/Materials/MaterialLayers/T_ML_Rubber_Blue_01_D.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/h2ogit/UE4-MultiCollisionMovement/848f7d2b9762a019a3d2ec66b9d8abd40af25f49/Content/Mannequin/Character/Materials/MaterialLayers/T_ML_Rubber_Blue_01_D.uasset -------------------------------------------------------------------------------- /Content/Mannequin/Character/Materials/MaterialLayers/T_ML_Rubber_Blue_01_N.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/h2ogit/UE4-MultiCollisionMovement/848f7d2b9762a019a3d2ec66b9d8abd40af25f49/Content/Mannequin/Character/Materials/MaterialLayers/T_ML_Rubber_Blue_01_N.uasset -------------------------------------------------------------------------------- /Content/Mannequin/Character/Mesh/SK_Mannequin.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/h2ogit/UE4-MultiCollisionMovement/848f7d2b9762a019a3d2ec66b9d8abd40af25f49/Content/Mannequin/Character/Mesh/SK_Mannequin.uasset -------------------------------------------------------------------------------- /Content/Mannequin/Character/Mesh/SK_Mannequin_PhysicsAsset.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/h2ogit/UE4-MultiCollisionMovement/848f7d2b9762a019a3d2ec66b9d8abd40af25f49/Content/Mannequin/Character/Mesh/SK_Mannequin_PhysicsAsset.uasset -------------------------------------------------------------------------------- /Content/Mannequin/Character/Mesh/UE4_Mannequin_Skeleton.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/h2ogit/UE4-MultiCollisionMovement/848f7d2b9762a019a3d2ec66b9d8abd40af25f49/Content/Mannequin/Character/Mesh/UE4_Mannequin_Skeleton.uasset -------------------------------------------------------------------------------- /Content/Mannequin/Character/Textures/UE4Man_Logo_N.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/h2ogit/UE4-MultiCollisionMovement/848f7d2b9762a019a3d2ec66b9d8abd40af25f49/Content/Mannequin/Character/Textures/UE4Man_Logo_N.uasset -------------------------------------------------------------------------------- /Content/Mannequin/Character/Textures/UE4_LOGO_CARD.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/h2ogit/UE4-MultiCollisionMovement/848f7d2b9762a019a3d2ec66b9d8abd40af25f49/Content/Mannequin/Character/Textures/UE4_LOGO_CARD.uasset -------------------------------------------------------------------------------- /Content/Mannequin/Character/Textures/UE4_Mannequin_MAT_MASKA.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/h2ogit/UE4-MultiCollisionMovement/848f7d2b9762a019a3d2ec66b9d8abd40af25f49/Content/Mannequin/Character/Textures/UE4_Mannequin_MAT_MASKA.uasset -------------------------------------------------------------------------------- /Content/Mannequin/Character/Textures/UE4_Mannequin__normals.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/h2ogit/UE4-MultiCollisionMovement/848f7d2b9762a019a3d2ec66b9d8abd40af25f49/Content/Mannequin/Character/Textures/UE4_Mannequin__normals.uasset -------------------------------------------------------------------------------- /Content/ThirdPerson/Meshes/Bump_StaticMesh.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/h2ogit/UE4-MultiCollisionMovement/848f7d2b9762a019a3d2ec66b9d8abd40af25f49/Content/ThirdPerson/Meshes/Bump_StaticMesh.uasset -------------------------------------------------------------------------------- /Content/ThirdPerson/Meshes/CubeMaterial.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/h2ogit/UE4-MultiCollisionMovement/848f7d2b9762a019a3d2ec66b9d8abd40af25f49/Content/ThirdPerson/Meshes/CubeMaterial.uasset -------------------------------------------------------------------------------- /Content/ThirdPerson/Meshes/LeftArm_StaticMesh.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/h2ogit/UE4-MultiCollisionMovement/848f7d2b9762a019a3d2ec66b9d8abd40af25f49/Content/ThirdPerson/Meshes/LeftArm_StaticMesh.uasset -------------------------------------------------------------------------------- /Content/ThirdPerson/Meshes/Linear_Stair_StaticMesh.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/h2ogit/UE4-MultiCollisionMovement/848f7d2b9762a019a3d2ec66b9d8abd40af25f49/Content/ThirdPerson/Meshes/Linear_Stair_StaticMesh.uasset -------------------------------------------------------------------------------- /Content/ThirdPerson/Meshes/RampMaterial.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/h2ogit/UE4-MultiCollisionMovement/848f7d2b9762a019a3d2ec66b9d8abd40af25f49/Content/ThirdPerson/Meshes/RampMaterial.uasset -------------------------------------------------------------------------------- /Content/ThirdPerson/Meshes/Ramp_StaticMesh.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/h2ogit/UE4-MultiCollisionMovement/848f7d2b9762a019a3d2ec66b9d8abd40af25f49/Content/ThirdPerson/Meshes/Ramp_StaticMesh.uasset -------------------------------------------------------------------------------- /Content/ThirdPerson/Meshes/RightArm_StaticMesh.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/h2ogit/UE4-MultiCollisionMovement/848f7d2b9762a019a3d2ec66b9d8abd40af25f49/Content/ThirdPerson/Meshes/RightArm_StaticMesh.uasset -------------------------------------------------------------------------------- /Content/ThirdPersonCPP/Blueprints/ThirdPersonCharacter.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/h2ogit/UE4-MultiCollisionMovement/848f7d2b9762a019a3d2ec66b9d8abd40af25f49/Content/ThirdPersonCPP/Blueprints/ThirdPersonCharacter.uasset -------------------------------------------------------------------------------- /Content/ThirdPersonCPP/Maps/ThirdPersonExampleMap.umap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/h2ogit/UE4-MultiCollisionMovement/848f7d2b9762a019a3d2ec66b9d8abd40af25f49/Content/ThirdPersonCPP/Maps/ThirdPersonExampleMap.umap -------------------------------------------------------------------------------- /Content/ThirdPersonCPP/Maps/ThirdPersonExampleMap_BuiltData.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/h2ogit/UE4-MultiCollisionMovement/848f7d2b9762a019a3d2ec66b9d8abd40af25f49/Content/ThirdPersonCPP/Maps/ThirdPersonExampleMap_BuiltData.uasset -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 h2ogit 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # UE4-MultiCollisionMovement 2 | 3 | Movement for character with complex collision shape 4 | 5 | Project example for UE 5.3.2 6 | 7 | When you need to have a character with complex collision shape like a vehicle or a space ship or something similar - you will have character capsule size be too much bigger than needed. This will come to some restriction in movement of the character – character will not be able to come close to objects, move in narrow places and etc. 8 | 9 | ![UE4-MultiCollisionMovement](https://github.com/h2ogit/UE4-MultiCollisionMovement/blob/master/1.png) 10 | 11 | The next solution is not a complete solution but just a one of the ways and example and can be used as entry point you can start from. It was used for flying objects mainly, but it also support other physics modes but I think other additional code changes will be required additionally. 12 | 13 | How to setup: 14 | 1. Character MC should have one of the following settings enabled: 15 | bOrientRotationToMovement or bUseControllerDesiredRotation 16 | 2. Change root collision size: 17 | 18 | • For flying physics you can drop root capsule size to unit and disable root capsule collision at all. 19 | 20 | • For walking physics root capsule size should be based on main walkable mesh 21 | 22 | 3. You add MultiCollisionCapsuleComponent to cover the mesh shape and you build with this additional components complex shape of the character. 23 | 24 | ![UE4-MultiCollisionMovement](https://github.com/h2ogit/UE4-MultiCollisionMovement/blob/master/2.png) 25 | 26 | How it works: 27 | 1. At character initialization movement component calls collect and update all MultiCollisionCapsuleComponent added to the character 28 | 2. At movement phase instead of moving and checking root capsule component – movement component simulates movement with sweeps on all additional components and checks the most first hit and stops on it not allowing to move far than possible. 29 | 3. The good move result is applied to root component as normal movement. 30 | 4. Rotation is also physics based and happens after movement is finished, when character turns – all collisions are also tested and checked. 31 | 32 | Optimization: 33 | 1. Many additional components can drop FPS when you have many characters which are moving/colliding/sliding at same time. It is important to have the quantity of additional components as less as possible. 34 | 2. Movement and Turning happens in different passes but it could be combined to one pass to decrease sweep checks. 35 | For example this could be done with next changes: 36 | Disabling PhysicsRotation function and enabling Character FaceRotation function which should calc new rotation for current frame. Then you need to override physics mode function so it will pass your new calculated rotation to movement code. 37 | 38 | This system can be used with modular characters with some changes. 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /Source/TestMultiCollision.Target.cs: -------------------------------------------------------------------------------- 1 | // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. 2 | 3 | using UnrealBuildTool; 4 | using System.Collections.Generic; 5 | 6 | public class TestMultiCollisionTarget : TargetRules 7 | { 8 | public TestMultiCollisionTarget(TargetInfo Target) : base(Target) 9 | { 10 | Type = TargetType.Game; 11 | DefaultBuildSettings = BuildSettingsVersion.Latest; 12 | IncludeOrderVersion = EngineIncludeOrderVersion.Latest; 13 | 14 | ExtraModuleNames.Add("TestMultiCollision"); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Source/TestMultiCollision/MultiCollisionCapsuleComponent.cpp: -------------------------------------------------------------------------------- 1 | //#include "TestMultiCollision.h" 2 | #include "MultiCollisionCapsuleComponent.h" 3 | 4 | UMultiCollisionCapsuleComponent::UMultiCollisionCapsuleComponent(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) 5 | { 6 | BodyInstance.SetCollisionProfileName(FName("Pawn")); 7 | SetShouldUpdatePhysicsVolume(true); 8 | CanCharacterStepUpOn = ECB_Yes; 9 | SetNotifyRigidBodyCollision(false); 10 | SetEnableGravity(false); 11 | } 12 | 13 | static float InitialOverlapToleranceCVar = 0.0f; 14 | static FAutoConsoleVariableRef CVarInitialOverlapTolerance( 15 | TEXT("p.InitialOverlapTolerance"), 16 | InitialOverlapToleranceCVar, 17 | TEXT("Tolerance for initial overlapping test in PrimitiveComponent movement.\n") 18 | TEXT("Normals within this tolerance are ignored if moving out of the object.\n") 19 | TEXT("Dot product of movement direction and surface normal."), 20 | ECVF_Default); 21 | 22 | static void PullBackHit(FHitResult& Hit, const FVector& Start, const FVector& End, const float Dist) 23 | { 24 | const float DesiredTimeBack = FMath::Clamp(0.1f, 0.1f / Dist, 1.f / Dist) + 0.001f; 25 | Hit.Time = FMath::Clamp(Hit.Time - DesiredTimeBack, 0.f, 1.f); 26 | } 27 | 28 | static bool ShouldIgnoreHitResult(const UWorld* InWorld, FHitResult const& TestHit, FVector const& MovementDirDenormalized, const AActor* MovingActor, EMoveComponentFlags MoveFlags) 29 | { 30 | if (TestHit.bBlockingHit) 31 | { 32 | // check "ignore bases" functionality 33 | if ((MoveFlags & MOVECOMP_IgnoreBases) && MovingActor) //we let overlap components go through because their overlap is still needed and will cause beginOverlap/endOverlap events 34 | { 35 | // ignore if there's a base relationship between moving actor and hit actor 36 | AActor const* const HitActor = TestHit.GetActor(); 37 | if (HitActor) 38 | { 39 | if (MovingActor->IsBasedOnActor(HitActor) || HitActor->IsBasedOnActor(MovingActor)) 40 | { 41 | return true; 42 | } 43 | } 44 | } 45 | 46 | // If we started penetrating, we may want to ignore it if we are moving out of penetration. 47 | // This helps prevent getting stuck in walls. 48 | if (TestHit.bStartPenetrating && !(MoveFlags & MOVECOMP_NeverIgnoreBlockingOverlaps)) 49 | { 50 | const float DotTolerance = InitialOverlapToleranceCVar; 51 | 52 | // Dot product of movement direction against 'exit' direction 53 | const FVector MovementDir = MovementDirDenormalized.GetSafeNormal(); 54 | const float MoveDot = (TestHit.ImpactNormal | MovementDir); 55 | 56 | const bool bMovingOut = MoveDot > DotTolerance; 57 | 58 | // If we are moving out, ignore this result! 59 | if (bMovingOut) 60 | { 61 | return true; 62 | } 63 | } 64 | } 65 | 66 | return false; 67 | } 68 | 69 | // this is a simitation of UPrimitiveComponent::MoveComponentImpl() without actual move, just sweep checks 70 | bool UMultiCollisionCapsuleComponent::SimulateMoveComponent(const class USceneComponent* CharacterRootComponent, const FVector& NewDelta, const FQuat& NewRotation, FHitResult* OutHit, EMoveComponentFlags MoveFlags) 71 | { 72 | // static things can move before they are registered (e.g. immediately after streaming), but not after. 73 | if (!IsValid(this) || !IsRegistered() || !GetWorld() || !GetAttachParent()) 74 | { 75 | if (OutHit) 76 | { 77 | OutHit->Init(); 78 | } 79 | 80 | return false; // skip simulation 81 | } 82 | 83 | ConditionalUpdateComponentToWorld(); 84 | 85 | // Additional component attached to te socket and has relative rotation, so the root rotation != additional component rotation 86 | // We need to find new additional component rotation which will be with NewRotationQuat applied to root component. 87 | const FQuat DeltaQuat = NewRotation * CharacterRootComponent->GetComponentQuat().Inverse(); // find delta rotation of the root component 88 | const FQuat NewCompQuat = DeltaQuat * GetComponentQuat(); // calc new rotation for this component 89 | 90 | // debug 91 | // UE_LOG(LogClass, Log, TEXT(" SimulateMoveComponent %s ROT Current %s New = %s"), *GetNameSafe(GetOwner()), *GetComponentQuat().Rotator().ToString(), *NewCompQuat.Rotator().ToString()); 92 | // debug 93 | 94 | // Additional component has translation from the root component. That means any turn of the root is also the location change for additional component 95 | const FVector RootComponentLocation = CharacterRootComponent->GetComponentLocation(); 96 | 97 | const FVector TraceStart = GetComponentLocation(); 98 | 99 | // In modular system component can not be attached directly to the root component, and can be attached to the child of the child of the child 100 | // This means we can not find relative translation directly from transform 101 | // For this component we need to find translation from the root center and calc new location on new root rotation 102 | const FVector DeltaLocation = TraceStart - RootComponentLocation; 103 | const FVector DeltaDir = DeltaLocation.GetSafeNormal(); 104 | const float DeltaSize = DeltaLocation.Size(); 105 | const FVector NewDir = DeltaQuat.RotateVector(DeltaDir); // turn direction vector on delta rotation 106 | const FVector NewComponentLocation = RootComponentLocation + NewDir * DeltaSize; 107 | 108 | const FVector TraceEnd = NewComponentLocation + NewDelta; 109 | 110 | // debug 111 | // UE_LOG(LogClass, Log, TEXT(" SimulateMoveComponent %s Loc Current %s New = %s"), *GetNameSafe(GetOwner()), *TraceStart.ToString(), *TraceEnd.ToString()); 112 | // debug 113 | 114 | TArray Hits; 115 | Hits.Empty(); 116 | 117 | FComponentQueryParams QueryParams(TEXT("SimulateMoveComponent"), GetOwner()); 118 | FCollisionResponseParams ResponseParam; 119 | InitSweepCollisionParams(QueryParams, ResponseParam); 120 | 121 | const bool bHadBlockingHit = GetWorld()->ComponentSweepMulti(Hits, this, TraceStart, TraceEnd, NewCompQuat, QueryParams); 122 | 123 | if (Hits.Num() > 0) 124 | { 125 | const float NewDeltaSize = NewDelta.Size(); 126 | for (int32 HitIdx = 0; HitIdx < Hits.Num(); HitIdx++) 127 | { 128 | PullBackHit(Hits[HitIdx], TraceStart, TraceEnd, NewDeltaSize); 129 | } 130 | } 131 | 132 | if (bHadBlockingHit) 133 | { 134 | FHitResult BlockingHit(NoInit); 135 | BlockingHit.bBlockingHit = false; 136 | BlockingHit.Time = 1.f; 137 | 138 | int32 BlockingHitIndex = INDEX_NONE; 139 | float BlockingHitNormalDotDelta = BIG_NUMBER; 140 | for (int32 HitIdx = 0; HitIdx < Hits.Num(); HitIdx++) 141 | { 142 | const FHitResult& TestHit = Hits[HitIdx]; 143 | 144 | if (TestHit.bBlockingHit) 145 | { 146 | if (!ShouldIgnoreHitResult(GetWorld(), TestHit, NewDelta, GetOwner(), MoveFlags)) 147 | { 148 | if (TestHit.Time == 0.f) 149 | { 150 | // We may have multiple initial hits, and want to choose the one with the normal most opposed to our movement. 151 | const float NormalDotDelta = (TestHit.ImpactNormal | NewDelta); 152 | if (NormalDotDelta < BlockingHitNormalDotDelta) 153 | { 154 | BlockingHitNormalDotDelta = NormalDotDelta; 155 | BlockingHitIndex = HitIdx; 156 | } 157 | } 158 | else if (BlockingHitIndex == INDEX_NONE) 159 | { 160 | // First non-overlapping blocking hit should be used, if an overlapping hit was not. 161 | // This should be the only non-overlapping blocking hit, and last in the results. 162 | BlockingHitIndex = HitIdx; 163 | break; 164 | } 165 | } 166 | } 167 | } 168 | 169 | // Update blocking hit, if there was a valid one. 170 | if (BlockingHitIndex >= 0) 171 | { 172 | BlockingHit = Hits[BlockingHitIndex]; 173 | 174 | if (OutHit) 175 | { 176 | *OutHit = BlockingHit; 177 | } 178 | 179 | return false; 180 | } 181 | else 182 | { 183 | return true; 184 | } 185 | } 186 | 187 | return true; 188 | } -------------------------------------------------------------------------------- /Source/TestMultiCollision/MultiCollisionCapsuleComponent.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Runtime/Engine/Classes/Components/CapsuleComponent.h" 3 | #include "MultiCollisionCapsuleComponent.generated.h" 4 | 5 | /** Implements the additional capsule component for movement sweep */ 6 | UCLASS(NotBlueprintable, NotBlueprintType, ClassGroup = "Collision", editinlinenew, meta = (BlueprintSpawnableComponent)) 7 | class UMultiCollisionCapsuleComponent : public UCapsuleComponent 8 | { 9 | GENERATED_BODY() 10 | UMultiCollisionCapsuleComponent(const FObjectInitializer& ObjectInitializer); 11 | 12 | public: 13 | bool SimulateMoveComponent(const class USceneComponent* CharacterRootComponent, const FVector& NewDelta, const FQuat& NewRotation, FHitResult* OutHit = nullptr, EMoveComponentFlags MoveFlags = MOVECOMP_NoFlags); 14 | protected: 15 | 16 | 17 | private: 18 | 19 | 20 | }; 21 | -------------------------------------------------------------------------------- /Source/TestMultiCollision/MultiCollisionCharacter.cpp: -------------------------------------------------------------------------------- 1 | #include "MultiCollisionCharacter.h" 2 | #include "MultiCollisionMovementComponent.h" 3 | 4 | AMultiCollisionCharacter::AMultiCollisionCharacter(const FObjectInitializer& ObjectInitializer) : 5 | Super(ObjectInitializer.SetDefaultSubobjectClass(ACharacter::CharacterMovementComponentName)) 6 | { 7 | 8 | } 9 | 10 | void AMultiCollisionCharacter::PostInitializeComponents() 11 | { 12 | Super::PostInitializeComponents(); 13 | 14 | MultiCollisionMovementComponent = Cast(GetCharacterMovement()); 15 | if (MultiCollisionMovementComponent) 16 | { 17 | MultiCollisionMovementComponent->UpdateAdditionalUpdatedComponents(); 18 | } 19 | } 20 | 21 | void AMultiCollisionCharacter::FaceRotation(FRotator ControlRotation, float DeltaTime) 22 | { 23 | // No super call. No character rotation set 24 | } -------------------------------------------------------------------------------- /Source/TestMultiCollision/MultiCollisionCharacter.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "GameFramework/Character.h" 3 | #include "MultiCollisionCharacter.generated.h" 4 | 5 | UCLASS(config=Game) 6 | class AMultiCollisionCharacter : public ACharacter 7 | { 8 | GENERATED_BODY() 9 | 10 | 11 | public: 12 | 13 | virtual void PostInitializeComponents() override; 14 | 15 | virtual void FaceRotation(FRotator ControlRotation, float DeltaTime) override; 16 | 17 | protected: 18 | AMultiCollisionCharacter(const FObjectInitializer& ObjectInitializer); 19 | 20 | private: 21 | class UMultiCollisionMovementComponent* MultiCollisionMovementComponent; 22 | }; 23 | 24 | -------------------------------------------------------------------------------- /Source/TestMultiCollision/MultiCollisionMovementComponent.cpp: -------------------------------------------------------------------------------- 1 | #include "MultiCollisionMovementComponent.h" 2 | #include "MultiCollisionCapsuleComponent.h" 3 | #include "MultiCollisionCharacter.h" 4 | 5 | #include "Runtime/Engine/Classes/GameFramework/PhysicsVolume.h" 6 | 7 | 8 | UMultiCollisionMovementComponent::UMultiCollisionMovementComponent(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) 9 | { 10 | PenetrationOverlapCheckInflation = 0.1f; 11 | 12 | } 13 | 14 | void UMultiCollisionMovementComponent::InitializeComponent() 15 | { 16 | Super::InitializeComponent(); 17 | } 18 | 19 | void UMultiCollisionMovementComponent::UpdateAdditionalUpdatedComponents() 20 | { 21 | class AMultiCollisionCharacter* MultiCollisionOwner = Cast(GetCharacterOwner()); 22 | if (!MultiCollisionOwner) 23 | { 24 | return; 25 | } 26 | 27 | // 1. Remove old if exist (for runtime character reconfiguration/changes) 28 | for (int32 i = 0; i < AdditionalUpdatedComponents.Num(); i++) 29 | { 30 | if (auto AdditionalComponent = Cast(AdditionalUpdatedComponents[i])) 31 | { 32 | AdditionalComponent->MoveIgnoreActors.Empty(); 33 | 34 | if (bEnablePhysicsInteraction) 35 | { 36 | AdditionalComponent->OnComponentBeginOverlap.RemoveAll(this); 37 | } 38 | } 39 | } 40 | 41 | AdditionalUpdatedComponents.Empty(); 42 | 43 | // SHOULD WE REUPDATE IGNORE ACTORS? 44 | //UpdatedPrimitive->MoveIgnoreActors = get ignore actors from character owner 45 | 46 | // 2. Collect all additional collisions 47 | 48 | auto CollisionComponents = MultiCollisionOwner->GetComponents().Array(); 49 | for (int32 i = 0; i < CollisionComponents.Num(); i++) 50 | { 51 | if (auto AdditionalComponent = Cast(CollisionComponents[i])) 52 | { 53 | AdditionalComponent->MoveIgnoreActors.Add(MultiCollisionOwner); 54 | AdditionalComponent->MoveIgnoreActors += UpdatedPrimitive->MoveIgnoreActors; 55 | 56 | if (bEnablePhysicsInteraction) 57 | { 58 | AdditionalComponent->OnComponentBeginOverlap.AddUniqueDynamic(this, &UMultiCollisionMovementComponent::CapsuleTouched); 59 | } 60 | 61 | AdditionalUpdatedComponents.Add(AdditionalComponent); 62 | } 63 | } 64 | } 65 | 66 | bool UMultiCollisionMovementComponent::MoveUpdatedComponentImpl(const FVector& Delta, const FQuat& Rotation, bool bSweep, FHitResult* OutHit, ETeleportType Teleport) 67 | { 68 | if (!UpdatedComponent) 69 | { 70 | return false; 71 | } 72 | 73 | FQuat NewRotation = Rotation; 74 | 75 | FVector NewDelta = ConstrainDirectionToPlane(Delta); 76 | 77 | // Delta move and delta rot check - are they much enough for physics sweep 78 | // ComponentSweepMulti does nothing if moving < KINDA_SMALL_NUMBER in distance, so it's important to not try to sweep distances smaller than that. 79 | const float DeltaMoveSizeSq = NewDelta.SizeSquared(); 80 | const float MinMovementDistSq = FMath::Square(4.f * KINDA_SMALL_NUMBER); 81 | if (DeltaMoveSizeSq <= MinMovementDistSq) 82 | { 83 | if (NewRotation.Equals(UpdatedComponent->GetComponentQuat(), SCENECOMPONENT_QUAT_TOLERANCE)) 84 | { 85 | if (OutHit) 86 | { 87 | OutHit->Reset(1.f); 88 | } 89 | return true; 90 | } 91 | else 92 | { 93 | NewDelta = FVector::ZeroVector; 94 | } 95 | } 96 | 97 | // test if our move will not hit something with additional collisions 98 | const bool bMoved = bSweep ? MoveAdditionalUpdatedComponents(NewDelta, NewRotation, OutHit) : true; 99 | 100 | if (!bMoved) 101 | { 102 | NewDelta *= OutHit->Time; // adjust delta to move as much as possible to location before the hit based on hit time 103 | NewRotation = FQuat::Slerp(UpdatedComponent->GetComponentQuat(), Rotation, OutHit->Time); // adjust rotation 104 | } 105 | 106 | // We move updated component without sweep because sweep is used on additional collisions only 107 | UpdatedComponent->MoveComponent(NewDelta, NewRotation, false, nullptr, MoveComponentFlags, ETeleportType::TeleportPhysics); 108 | 109 | // Force transform update of AdditionalUpdatedComponents after any move/turn happened 110 | UpdatedComponent->UpdateChildTransforms(EUpdateTransformFlags::PropagateFromParent, ETeleportType::TeleportPhysics); 111 | 112 | return bMoved; 113 | } 114 | 115 | bool UMultiCollisionMovementComponent::MoveAdditionalUpdatedComponents(const FVector& Delta, const FQuat& NewRotation, FHitResult* OutHit) 116 | { 117 | // init array of blocking hits 118 | TArray BlockedHits; 119 | BlockedHits.Empty(); 120 | 121 | // init array of blocked components related to blocked hits 122 | TArray BlockedComponents; 123 | BlockedComponents.Empty(); 124 | 125 | // init current movement blocked component 126 | LastBlockedComponent = nullptr; 127 | 128 | // we are checking if any of the additional components goes in block of another object and saving the results of every component test 129 | for (int32 i = 0; i < AdditionalUpdatedComponents.Num(); i++) 130 | { 131 | if (AdditionalUpdatedComponents[i]) 132 | { 133 | FHitResult BlockedHit = FHitResult(1.f); 134 | const bool bMoveResult = AdditionalUpdatedComponents[i]->SimulateMoveComponent(UpdatedComponent, Delta, NewRotation, &BlockedHit, MoveComponentFlags); 135 | 136 | if (!bMoveResult) 137 | { 138 | BlockedHits.Add(BlockedHit); 139 | BlockedComponents.Add(AdditionalUpdatedComponents[i]); 140 | } 141 | } 142 | } 143 | 144 | if (BlockedHits.Num() > 0) 145 | { 146 | // there is situation when we move forward and ship wings can be larger in front of the trunk. but the move delta can very high especially when boosting or dodging 147 | // large move delta can cause that several components will penetrate another object. we need to find the one which is the most far penetrated the object. 148 | // if we just use the order of AdditionalUpdatedComponents then trunk will ever be first which can get wrong result on large delta. 149 | 150 | // select hit by the most small hit time to find the most first colision hit 151 | int32 BadIndex = 0; 152 | float BadTime = 1.f; 153 | 154 | for (int32 i = 0; i < BlockedHits.Num(); i++) 155 | { 156 | const float TestTime = BlockedHits[i].Time; 157 | if (TestTime < BadTime) 158 | { 159 | BadTime = TestTime; 160 | BadIndex = i; 161 | } 162 | } 163 | 164 | *OutHit = BlockedHits[BadIndex]; // save the most bad hit result 165 | LastBlockedComponent = BlockedComponents[BadIndex]; // save component which caused the most bad hit 166 | 167 | return false; // our move was blocked. the performed move failed and requires a correction. 168 | } 169 | else 170 | { 171 | OutHit->Reset(1.f); // zero out hit on success move 172 | return true; // there was nothing blocked on move and turn - we get successful move. no correction needed. 173 | } 174 | } 175 | 176 | bool UMultiCollisionMovementComponent::ResolvePenetrationImpl(const FVector& ProposedAdjustment, const FHitResult& Hit, const FQuat& Rotation) 177 | { 178 | if (!LastBlockedComponent) 179 | { 180 | return false; // process only with valid last blocked component. 181 | } 182 | 183 | bool bMoved = false; 184 | 185 | // SceneComponent can't be in penetration, so this function really only applies to PrimitiveComponent. 186 | const FVector Adjustment = ConstrainDirectionToPlane(ProposedAdjustment); 187 | 188 | // Set rotation to use 189 | const FQuat MoveRotation = Rotation; // use new rotation when resolving penetration 190 | //const FQuat MoveRotation = UpdatedComponent->GetComponentQuat(); // use current rotation when resolving penetration - means no rotation change if resolving penetration 191 | 192 | if (!Adjustment.IsZero()) 193 | { 194 | // We really want to make sure that precision differences or differences between the overlap test and sweep tests don't put us into another overlap, 195 | // so make the overlap test a bit more restrictive. 196 | 197 | bool bEncroached = false; 198 | bEncroached = OverlapTest(Hit.TraceStart + Adjustment, LastBlockedComponent->GetComponentQuat(), LastBlockedComponent->GetCollisionObjectType(), LastBlockedComponent->GetCollisionShape(PenetrationOverlapCheckInflation), LastBlockedComponent->GetOwner()); 199 | 200 | if (!bEncroached) 201 | { 202 | // Move without sweeping. 203 | FHitResult EncroachHit(1.f); 204 | bMoved = MoveUpdatedComponent(Adjustment, MoveRotation, false, &EncroachHit, ETeleportType::TeleportPhysics); 205 | } 206 | else 207 | { 208 | // Disable MOVECOMP_NeverIgnoreBlockingOverlaps if it is enabled, otherwise we wouldn't be able to sweep out of the object to fix the penetration. 209 | TGuardValue ScopedFlagRestore(MoveComponentFlags, EMoveComponentFlags(MoveComponentFlags & (~MOVECOMP_NeverIgnoreBlockingOverlaps))); 210 | 211 | // Try sweeping as far as possible... 212 | FHitResult SweepOutHit(1.f); 213 | 214 | bMoved = MoveUpdatedComponent(Adjustment, MoveRotation, true, &SweepOutHit, ETeleportType::TeleportPhysics); 215 | 216 | // Still stuck? 217 | if (!bMoved && SweepOutHit.bStartPenetrating) 218 | { 219 | // Combine two MTD results to get a new direction that gets out of multiple surfaces. 220 | const FVector SecondMTD = GetPenetrationAdjustment(SweepOutHit); 221 | const FVector CombinedMTD = Adjustment + SecondMTD; 222 | if (SecondMTD != Adjustment && !CombinedMTD.IsZero()) 223 | { 224 | bMoved = MoveUpdatedComponent(CombinedMTD, MoveRotation, true, &SweepOutHit, ETeleportType::TeleportPhysics); 225 | } 226 | } 227 | 228 | // Still stuck? 229 | if (!bMoved) 230 | { 231 | // Try moving the proposed adjustment plus the attempted move direction. This can sometimes get out of penetrations with multiple objects 232 | const FVector MoveDelta = ConstrainDirectionToPlane(Hit.TraceEnd - Hit.TraceStart); 233 | if (!MoveDelta.IsZero()) 234 | { 235 | FHitResult FallBacktHit(1.f); 236 | bMoved = MoveUpdatedComponent(Adjustment + MoveDelta, MoveRotation, true, &FallBacktHit, ETeleportType::TeleportPhysics); 237 | } 238 | } 239 | } 240 | } 241 | 242 | bJustTeleported |= bMoved; 243 | return bJustTeleported; 244 | } 245 | 246 | void UMultiCollisionMovementComponent::PhysicsRotation(float DeltaTime) 247 | { 248 | if (!(bOrientRotationToMovement || bUseControllerDesiredRotation)) 249 | { 250 | return; 251 | } 252 | 253 | if (!HasValidData() || (!CharacterOwner->Controller && !bRunPhysicsWithNoController)) 254 | { 255 | return; 256 | } 257 | 258 | FRotator CurrentRotation = UpdatedComponent->GetComponentRotation(); // Normalized 259 | CurrentRotation.DiagnosticCheckNaN(TEXT("CharacterMovementComponent::PhysicsRotation(): CurrentRotation")); 260 | 261 | FRotator DeltaRot = GetDeltaRotation(DeltaTime); 262 | DeltaRot.DiagnosticCheckNaN(TEXT("CharacterMovementComponent::PhysicsRotation(): GetDeltaRotation")); 263 | 264 | FRotator DesiredRotation = CurrentRotation; 265 | if (bOrientRotationToMovement) 266 | { 267 | DesiredRotation = ComputeOrientToMovementRotation(CurrentRotation, DeltaTime, DeltaRot); 268 | } 269 | else if (CharacterOwner->Controller && bUseControllerDesiredRotation) 270 | { 271 | DesiredRotation = CharacterOwner->Controller->GetDesiredRotation(); 272 | } 273 | else 274 | { 275 | return; 276 | } 277 | 278 | if (ShouldRemainVertical()) 279 | { 280 | DesiredRotation.Pitch = 0.f; 281 | DesiredRotation.Yaw = FRotator::NormalizeAxis(DesiredRotation.Yaw); 282 | DesiredRotation.Roll = 0.f; 283 | } 284 | else 285 | { 286 | DesiredRotation.Normalize(); 287 | } 288 | 289 | // Accumulate a desired new rotation. 290 | const float AngleTolerance = 1e-3f; 291 | 292 | if (!CurrentRotation.Equals(DesiredRotation, AngleTolerance)) 293 | { 294 | // PITCH 295 | if (!FMath::IsNearlyEqual(CurrentRotation.Pitch, DesiredRotation.Pitch, AngleTolerance)) 296 | { 297 | DesiredRotation.Pitch = FMath::FixedTurn(CurrentRotation.Pitch, DesiredRotation.Pitch, DeltaRot.Pitch); 298 | } 299 | 300 | // YAW 301 | if (!FMath::IsNearlyEqual(CurrentRotation.Yaw, DesiredRotation.Yaw, AngleTolerance)) 302 | { 303 | DesiredRotation.Yaw = FMath::FixedTurn(CurrentRotation.Yaw, DesiredRotation.Yaw, DeltaRot.Yaw); 304 | } 305 | 306 | // ROLL 307 | if (!FMath::IsNearlyEqual(CurrentRotation.Roll, DesiredRotation.Roll, AngleTolerance)) 308 | { 309 | DesiredRotation.Roll = FMath::FixedTurn(CurrentRotation.Roll, DesiredRotation.Roll, DeltaRot.Roll); 310 | } 311 | 312 | // Set the new rotation. 313 | DesiredRotation.DiagnosticCheckNaN(TEXT("CharacterMovementComponent::PhysicsRotation(): DesiredRotation")); 314 | 315 | FHitResult RotationHit(1.f); 316 | MoveUpdatedComponent(FVector::ZeroVector, DesiredRotation, true, &RotationHit); 317 | } 318 | } 319 | 320 | void UMultiCollisionMovementComponent::OnMovementUpdated(float DeltaSeconds, const FVector& OldLocation, const FVector& OldVelocity) 321 | { 322 | Super::OnMovementUpdated(DeltaSeconds, OldLocation, OldVelocity); 323 | 324 | // If character was moved we need to notify all world objects about overlaps of additional collisions. 325 | // Update overlaps for additional components after they were teleported with root capsule component 326 | for (int32 i = 0; i < AdditionalUpdatedComponents.Num(); i++) 327 | { 328 | if (AdditionalUpdatedComponents[i]) 329 | { 330 | AdditionalUpdatedComponents[i]->UpdateOverlaps(); 331 | AdditionalUpdatedComponents[i]->UpdatePhysicsVolume(true); 332 | } 333 | } 334 | 335 | LastBlockedComponent = nullptr; // zero 336 | } 337 | -------------------------------------------------------------------------------- /Source/TestMultiCollision/MultiCollisionMovementComponent.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Runtime/Engine/Classes/GameFramework/CharacterMovementComponent.h" 3 | #include "MultiCollisionMovementComponent.generated.h" 4 | 5 | UCLASS() 6 | class UMultiCollisionMovementComponent : public UCharacterMovementComponent 7 | { 8 | GENERATED_BODY() 9 | UMultiCollisionMovementComponent(const FObjectInitializer& ObjectInitializer); 10 | 11 | public: 12 | 13 | virtual void InitializeComponent() override; 14 | 15 | void UpdateAdditionalUpdatedComponents(); 16 | 17 | virtual void PhysicsRotation(float DeltaTime) override; 18 | 19 | void SetPendingRotation(const FQuat NewPendingRotation); 20 | 21 | protected: 22 | 23 | virtual void OnMovementUpdated(float DeltaSeconds, const FVector & OldLocation, const FVector & OldVelocity) override; 24 | 25 | //virtual void PhysFlying(float deltaTime, int32 Iterations) override; 26 | //virtual void PhysWalking(float deltaTime, int32 Iterations) override; 27 | 28 | virtual bool MoveUpdatedComponentImpl(const FVector& Delta, const FQuat& Rotation, bool bSweep, FHitResult* OutHit = NULL, ETeleportType Teleport = ETeleportType::None); 29 | 30 | virtual bool ResolvePenetrationImpl(const FVector& Adjustment, const FHitResult& Hit, const FQuat& Rotation) override; 31 | 32 | // this is a movement component CVarPenetrationOverlapCheckInflation copy 33 | UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Movement") 34 | /** Inflation added to object when checking if a location is free of blocking collision. Distance added to inflation in penetration overlap check. */ 35 | float PenetrationOverlapCheckInflation; 36 | 37 | 38 | private: 39 | 40 | UPROPERTY() 41 | TArray AdditionalUpdatedComponents; 42 | 43 | UPROPERTY() 44 | class UPrimitiveComponent* LastBlockedComponent; 45 | 46 | bool MoveAdditionalUpdatedComponents(const FVector& Delta, const FQuat& NewRotation, FHitResult* OutHit); 47 | 48 | }; 49 | -------------------------------------------------------------------------------- /Source/TestMultiCollision/TestMultiCollision.Build.cs: -------------------------------------------------------------------------------- 1 | // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. 2 | 3 | using UnrealBuildTool; 4 | 5 | public class TestMultiCollision : ModuleRules 6 | { 7 | public TestMultiCollision(ReadOnlyTargetRules Target) : base(Target) 8 | { 9 | PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs; 10 | 11 | PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore"}); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Source/TestMultiCollision/TestMultiCollision.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. 2 | 3 | #include "TestMultiCollision.h" 4 | #include "Modules/ModuleManager.h" 5 | 6 | IMPLEMENT_PRIMARY_GAME_MODULE( FDefaultGameModuleImpl, TestMultiCollision, "TestMultiCollision" ); 7 | -------------------------------------------------------------------------------- /Source/TestMultiCollision/TestMultiCollision.h: -------------------------------------------------------------------------------- 1 | // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. 2 | 3 | #pragma once 4 | 5 | #include "CoreMinimal.h" 6 | -------------------------------------------------------------------------------- /Source/TestMultiCollision/TestMultiCollisionCharacter.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. 2 | 3 | #include "TestMultiCollisionCharacter.h" 4 | #include "Camera/CameraComponent.h" 5 | #include "Components/CapsuleComponent.h" 6 | #include "Components/InputComponent.h" 7 | #include "GameFramework/CharacterMovementComponent.h" 8 | #include "GameFramework/Controller.h" 9 | #include "GameFramework/SpringArmComponent.h" 10 | 11 | ////////////////////////////////////////////////////////////////////////// 12 | // ATestMultiCollisionCharacter 13 | 14 | ATestMultiCollisionCharacter::ATestMultiCollisionCharacter(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) 15 | { 16 | // Set size for collision capsule 17 | GetCapsuleComponent()->InitCapsuleSize(42.f, 96.0f); 18 | 19 | // set our turn rates for input 20 | BaseTurnRate = 45.f; 21 | BaseLookUpRate = 45.f; 22 | 23 | // Don't rotate when the controller rotates. Let that just affect the camera. 24 | bUseControllerRotationPitch = false; 25 | bUseControllerRotationYaw = false; 26 | bUseControllerRotationRoll = false; 27 | 28 | // Configure character movement 29 | GetCharacterMovement()->bOrientRotationToMovement = true; // Character moves in the direction of input... 30 | GetCharacterMovement()->RotationRate = FRotator(0.0f, 540.0f, 0.0f); // ...at this rotation rate 31 | GetCharacterMovement()->JumpZVelocity = 600.f; 32 | GetCharacterMovement()->AirControl = 0.2f; 33 | 34 | // Create a camera boom (pulls in towards the player if there is a collision) 35 | CameraBoom = CreateDefaultSubobject(TEXT("CameraBoom")); 36 | CameraBoom->SetupAttachment(RootComponent); 37 | CameraBoom->TargetArmLength = 300.0f; // The camera follows at this distance behind the character 38 | CameraBoom->bUsePawnControlRotation = true; // Rotate the arm based on the controller 39 | 40 | // Create a follow camera 41 | FollowCamera = CreateDefaultSubobject(TEXT("FollowCamera")); 42 | FollowCamera->SetupAttachment(CameraBoom, USpringArmComponent::SocketName); // Attach the camera to the end of the boom and let the boom adjust to match the controller orientation 43 | FollowCamera->bUsePawnControlRotation = false; // Camera does not rotate relative to arm 44 | 45 | // Note: The skeletal mesh and anim blueprint references on the Mesh component (inherited from Character) 46 | // are set in the derived blueprint asset named MyCharacter (to avoid direct content references in C++) 47 | } 48 | 49 | ////////////////////////////////////////////////////////////////////////// 50 | // Input 51 | 52 | void ATestMultiCollisionCharacter::SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) 53 | { 54 | // Set up gameplay key bindings 55 | check(PlayerInputComponent); 56 | PlayerInputComponent->BindAction("Jump", IE_Pressed, this, &ACharacter::Jump); 57 | PlayerInputComponent->BindAction("Jump", IE_Released, this, &ACharacter::StopJumping); 58 | 59 | PlayerInputComponent->BindAxis("MoveForward", this, &ATestMultiCollisionCharacter::MoveForward); 60 | PlayerInputComponent->BindAxis("MoveRight", this, &ATestMultiCollisionCharacter::MoveRight); 61 | 62 | // We have 2 versions of the rotation bindings to handle different kinds of devices differently 63 | // "turn" handles devices that provide an absolute delta, such as a mouse. 64 | // "turnrate" is for devices that we choose to treat as a rate of change, such as an analog joystick 65 | PlayerInputComponent->BindAxis("Turn", this, &APawn::AddControllerYawInput); 66 | PlayerInputComponent->BindAxis("TurnRate", this, &ATestMultiCollisionCharacter::TurnAtRate); 67 | PlayerInputComponent->BindAxis("LookUp", this, &APawn::AddControllerPitchInput); 68 | PlayerInputComponent->BindAxis("LookUpRate", this, &ATestMultiCollisionCharacter::LookUpAtRate); 69 | 70 | // handle touch devices 71 | PlayerInputComponent->BindTouch(IE_Pressed, this, &ATestMultiCollisionCharacter::TouchStarted); 72 | PlayerInputComponent->BindTouch(IE_Released, this, &ATestMultiCollisionCharacter::TouchStopped); 73 | } 74 | 75 | void ATestMultiCollisionCharacter::TouchStarted(ETouchIndex::Type FingerIndex, FVector Location) 76 | { 77 | Jump(); 78 | } 79 | 80 | void ATestMultiCollisionCharacter::TouchStopped(ETouchIndex::Type FingerIndex, FVector Location) 81 | { 82 | StopJumping(); 83 | } 84 | 85 | void ATestMultiCollisionCharacter::TurnAtRate(float Rate) 86 | { 87 | // calculate delta for this frame from the rate information 88 | AddControllerYawInput(Rate * BaseTurnRate * GetWorld()->GetDeltaSeconds()); 89 | } 90 | 91 | void ATestMultiCollisionCharacter::LookUpAtRate(float Rate) 92 | { 93 | // calculate delta for this frame from the rate information 94 | AddControllerPitchInput(Rate * BaseLookUpRate * GetWorld()->GetDeltaSeconds()); 95 | } 96 | 97 | void ATestMultiCollisionCharacter::MoveForward(float Value) 98 | { 99 | if ((Controller != NULL) && (Value != 0.0f)) 100 | { 101 | // find out which way is forward 102 | const FRotator Rotation = Controller->GetControlRotation(); 103 | const FRotator YawRotation(0, Rotation.Yaw, 0); 104 | 105 | // get forward vector 106 | const FVector Direction = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::X); 107 | AddMovementInput(Direction, Value); 108 | } 109 | } 110 | 111 | void ATestMultiCollisionCharacter::MoveRight(float Value) 112 | { 113 | if ( (Controller != NULL) && (Value != 0.0f) ) 114 | { 115 | // find out which way is right 116 | const FRotator Rotation = Controller->GetControlRotation(); 117 | const FRotator YawRotation(0, Rotation.Yaw, 0); 118 | 119 | // get right vector 120 | const FVector Direction = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::Y); 121 | // add movement in that direction 122 | AddMovementInput(Direction, Value); 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /Source/TestMultiCollision/TestMultiCollisionCharacter.h: -------------------------------------------------------------------------------- 1 | // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. 2 | 3 | #pragma once 4 | 5 | #include "CoreMinimal.h" 6 | #include "MultiCollisionCharacter.h" 7 | #include "TestMultiCollisionCharacter.generated.h" 8 | 9 | UCLASS(config=Game) 10 | class ATestMultiCollisionCharacter : public AMultiCollisionCharacter 11 | { 12 | GENERATED_BODY() 13 | 14 | /** Camera boom positioning the camera behind the character */ 15 | UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Camera, meta = (AllowPrivateAccess = "true")) 16 | class USpringArmComponent* CameraBoom; 17 | 18 | /** Follow camera */ 19 | UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Camera, meta = (AllowPrivateAccess = "true")) 20 | class UCameraComponent* FollowCamera; 21 | public: 22 | 23 | /** Base turn rate, in deg/sec. Other scaling may affect final turn rate. */ 24 | UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category=Camera) 25 | float BaseTurnRate; 26 | 27 | /** Base look up/down rate, in deg/sec. Other scaling may affect final rate. */ 28 | UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category=Camera) 29 | float BaseLookUpRate; 30 | 31 | protected: 32 | ATestMultiCollisionCharacter(const FObjectInitializer& ObjectInitializer); 33 | 34 | /** Called for forwards/backward input */ 35 | void MoveForward(float Value); 36 | 37 | /** Called for side to side input */ 38 | void MoveRight(float Value); 39 | 40 | /** 41 | * Called via input to turn at a given rate. 42 | * @param Rate This is a normalized rate, i.e. 1.0 means 100% of desired turn rate 43 | */ 44 | void TurnAtRate(float Rate); 45 | 46 | /** 47 | * Called via input to turn look up/down at a given rate. 48 | * @param Rate This is a normalized rate, i.e. 1.0 means 100% of desired turn rate 49 | */ 50 | void LookUpAtRate(float Rate); 51 | 52 | /** Handler for when a touch input begins. */ 53 | void TouchStarted(ETouchIndex::Type FingerIndex, FVector Location); 54 | 55 | /** Handler for when a touch input stops. */ 56 | void TouchStopped(ETouchIndex::Type FingerIndex, FVector Location); 57 | 58 | protected: 59 | // APawn interface 60 | virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override; 61 | // End of APawn interface 62 | 63 | public: 64 | /** Returns CameraBoom subobject **/ 65 | FORCEINLINE class USpringArmComponent* GetCameraBoom() const { return CameraBoom; } 66 | /** Returns FollowCamera subobject **/ 67 | FORCEINLINE class UCameraComponent* GetFollowCamera() const { return FollowCamera; } 68 | }; 69 | 70 | -------------------------------------------------------------------------------- /Source/TestMultiCollision/TestMultiCollisionGameMode.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. 2 | 3 | #include "TestMultiCollisionGameMode.h" 4 | #include "TestMultiCollisionCharacter.h" 5 | #include "UObject/ConstructorHelpers.h" 6 | 7 | ATestMultiCollisionGameMode::ATestMultiCollisionGameMode() 8 | { 9 | // set default pawn class to our Blueprinted character 10 | static ConstructorHelpers::FClassFinder PlayerPawnBPClass(TEXT("/Game/ThirdPersonCPP/Blueprints/ThirdPersonCharacter")); 11 | if (PlayerPawnBPClass.Class != NULL) 12 | { 13 | DefaultPawnClass = PlayerPawnBPClass.Class; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Source/TestMultiCollision/TestMultiCollisionGameMode.h: -------------------------------------------------------------------------------- 1 | // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. 2 | 3 | #pragma once 4 | 5 | #include "CoreMinimal.h" 6 | #include "GameFramework/GameModeBase.h" 7 | #include "TestMultiCollisionGameMode.generated.h" 8 | 9 | UCLASS(minimalapi) 10 | class ATestMultiCollisionGameMode : public AGameModeBase 11 | { 12 | GENERATED_BODY() 13 | 14 | public: 15 | ATestMultiCollisionGameMode(); 16 | }; 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /Source/TestMultiCollisionEditor.Target.cs: -------------------------------------------------------------------------------- 1 | // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. 2 | 3 | using UnrealBuildTool; 4 | using System.Collections.Generic; 5 | 6 | public class TestMultiCollisionEditorTarget : TargetRules 7 | { 8 | public TestMultiCollisionEditorTarget(TargetInfo Target) : base(Target) 9 | { 10 | Type = TargetType.Editor; 11 | DefaultBuildSettings = BuildSettingsVersion.Latest; 12 | IncludeOrderVersion = EngineIncludeOrderVersion.Latest; 13 | 14 | ExtraModuleNames.Add("TestMultiCollision"); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /TestMultiCollision.uproject: -------------------------------------------------------------------------------- 1 | { 2 | "FileVersion": 3, 3 | "EngineAssociation": "5.3", 4 | "Category": "", 5 | "Description": "", 6 | "Modules": [ 7 | { 8 | "Name": "TestMultiCollision", 9 | "Type": "Runtime", 10 | "LoadingPhase": "Default" 11 | } 12 | ] 13 | } --------------------------------------------------------------------------------