diff --git a/Config/DefaultEngine.ini b/Config/DefaultEngine.ini index 32094fe..e3d5b06 100755 --- a/Config/DefaultEngine.ini +++ b/Config/DefaultEngine.ini @@ -51,6 +51,7 @@ bUseSplitscreen=False +Profiles=(Name="UI",CollisionEnabled=QueryOnly,bCanModify=False,ObjectTypeName="WorldDynamic",CustomResponses=((Channel="WorldStatic",Response=ECR_Overlap),(Channel="Pawn",Response=ECR_Overlap),(Channel="Visibility"),(Channel="WorldDynamic",Response=ECR_Overlap),(Channel="Camera",Response=ECR_Overlap),(Channel="PhysicsBody",Response=ECR_Overlap),(Channel="Vehicle",Response=ECR_Overlap),(Channel="Destructible",Response=ECR_Overlap)),HelpMessage="WorldStatic object that overlaps all actors by default. All new custom channels will use its own default response. ") +Profiles=(Name="Pickup",CollisionEnabled=QueryAndPhysics,bCanModify=True,ObjectTypeName="WorldStatic",CustomResponses=((Channel="WorldStatic",Response=ECR_Overlap),(Channel="WorldDynamic",Response=ECR_Overlap),(Channel="Pawn",Response=ECR_Overlap),(Channel="Visibility",Response=ECR_Overlap),(Channel="Camera",Response=ECR_Overlap),(Channel="PhysicsBody",Response=ECR_Overlap),(Channel="Vehicle",Response=ECR_Overlap),(Channel="Destructible",Response=ECR_Overlap),(Channel="Character",Response=ECR_Overlap)),HelpMessage="Item to pickup") +DefaultChannelResponses=(Channel=ECC_GameTraceChannel1,DefaultResponse=ECR_Block,bTraceType=False,bStaticObject=False,Name="Character") ++DefaultChannelResponses=(Channel=ECC_GameTraceChannel2,DefaultResponse=ECR_Ignore,bTraceType=True,bStaticObject=False,Name="Enemy") -ProfileRedirects=(OldName="BlockingVolume",NewName="InvisibleWall") -ProfileRedirects=(OldName="InterpActor",NewName="IgnoreOnlyPawn") -ProfileRedirects=(OldName="StaticMeshComponent",NewName="BlockAllDynamic") diff --git a/Content/EnemyAIController_BP.uasset b/Content/EnemyAIController_BP.uasset index badc6a8..ee11415 100755 Binary files a/Content/EnemyAIController_BP.uasset and b/Content/EnemyAIController_BP.uasset differ diff --git a/Content/EnemyPawn_BP.uasset b/Content/EnemyPawn_BP.uasset index e6228f7..4f94670 100755 Binary files a/Content/EnemyPawn_BP.uasset and b/Content/EnemyPawn_BP.uasset differ diff --git a/Content/GameModeBase_BP.uasset b/Content/GameModeBase_BP.uasset index 5f15a35..2b0ca84 100755 Binary files a/Content/GameModeBase_BP.uasset and b/Content/GameModeBase_BP.uasset differ diff --git a/Content/PlayerPawn_BP.uasset b/Content/PlayerPawn_BP.uasset index f292b6e..b014f4d 100755 Binary files a/Content/PlayerPawn_BP.uasset and b/Content/PlayerPawn_BP.uasset differ diff --git a/Content/PresidentPawn.uasset b/Content/PresidentPawn.uasset index df81884..cc74fa9 100755 Binary files a/Content/PresidentPawn.uasset and b/Content/PresidentPawn.uasset differ diff --git a/Content/TempBullet.uasset b/Content/TempBullet.uasset index bbff9b2..39a0f0b 100755 Binary files a/Content/TempBullet.uasset and b/Content/TempBullet.uasset differ diff --git a/Content/TestMap.umap b/Content/TestMap.umap index 864be60..e8db4a0 100755 Binary files a/Content/TestMap.umap and b/Content/TestMap.umap differ diff --git a/Content/TestMap_BuiltData.uasset b/Content/TestMap_BuiltData.uasset index fbbf49a..e2e1ebb 100755 Binary files a/Content/TestMap_BuiltData.uasset and b/Content/TestMap_BuiltData.uasset differ diff --git a/Source/PresidentsBrigade/BasePawn.cpp b/Source/PresidentsBrigade/BasePawn.cpp index 372387d..c29b3bf 100755 --- a/Source/PresidentsBrigade/BasePawn.cpp +++ b/Source/PresidentsBrigade/BasePawn.cpp @@ -4,9 +4,12 @@ #include "BasePawn.h" #include "Components/StaticMeshComponent.h" #include "GameFramework/FloatingPawnMovement.h" +#include "DrawDebugHelpers.h" +#include "Kismet/KismetSystemLibrary.h" #include "Util.h" #define LogInfo(Msg) Util::log_info(TEXT("ABasePawn"), Msg) +#define LogError(Msg) Util::log_error(TEXT("ABasePawn"), Msg) // Sets default values ABasePawn::ABasePawn(const FObjectInitializer &object_initializer): @@ -147,12 +150,30 @@ void ABasePawn::shoot() { if (current_ammo > 0) { - FVector player_location = player_mesh->GetComponentLocation(); - const float y = yaw.calculate_yaw(); - const FRotator rotator(0, y, 0); - FVector forward = FRotationMatrix(rotator).GetUnitAxis(EAxis::X) * 100; + const FVector player_location = get_location(); + FRotator rotator(0, yaw.calculate_yaw(), 0); + if (use_aim_assist) + { + LogInfo(FString::Printf(TEXT("Yaw %f"), rotator.Yaw)); + const float y_offset = aim_assist(player_location, rotator); + if (y_offset != 0) + { + rotator.Yaw = y_offset; + } + LogInfo(FString::Printf(TEXT("Offset %f"), y_offset)); + FVector line_end = FVector(5000, 0, 0); + FVector aim_line_end = rotator.RotateVector(line_end); +// DrawDebugLine( +// GetWorld(), +// player_location, +// aim_line_end + player_location, +// FColor::Red, +// true +// ); + } - FVector spawn_location = player_location + forward; + FVector forward = FRotationMatrix(rotator).GetUnitAxis(EAxis::X); + FVector spawn_location = player_location + (forward * 100); FActorSpawnParameters spawnParameters; spawnParameters.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn; spawnParameters.Owner = this; @@ -169,6 +190,81 @@ void ABasePawn::shoot() } } +/** + * Calculate the yaw angle needed to hit the nearest enemy target. + * + * @return Yaw angle offset. + */ +float ABasePawn::aim_assist(const FVector start, const FRotator rotator) +{ + /* + * Create trace end based on start location and given rotator. + */ + FVector trace = start + FVector(10000, 0, 0); + trace = rotator.RotateVector(trace); + + /* + * Run box trace for enemy targets. + */ + FHitResult out_hit; + const bool succeeded = UKismetSystemLibrary::SphereTraceSingle( + GetWorld(), + start, + trace, + aim_assist_distance, + ETraceTypeQuery::TraceTypeQuery3, // "Enemy" trace channel + false, + TArray(), + EDrawDebugTrace::Type::None, + out_hit, + true, + FLinearColor::Green, + FLinearColor::Green, + 0 + ); + + /* + * No enemies were within range. + */ + if (!succeeded) + { + return 0; + } + + ABasePawn* enemy_pawn = Cast(out_hit.Actor); + /* + * Bad setup. We should only be hitting pawns. + */ + if (!enemy_pawn) + { + LogError("Aim assist trace hit non-pawn"); + return 0; + } + + const FVector enemy_vector = enemy_pawn->get_location() - start; + const FRotator new_rotator = enemy_vector.Rotation(); + + //FVector target_vector = FVector(enemy_vector.X, enemy_vector.Y, 0); + //target_vector.Normalize(); + + //FVector actual_vector = FVector(trace.X, trace.Y, 0) - start; + //actual_vector.Normalize(); + + //const float angle_between = UKismetMathLibrary::DegAcos(FVector::DotProduct(actual_vector, target_vector)); + //const FVector cross = FVector::CrossProduct(actual_vector, target_vector); + //if (cross.Z > 0) + //{ + // return angle_between; + //} + //else if (cross.Z < 0) + //{ + // return angle_between * -1; + //} + + //return 0; + return new_rotator.Yaw; +} + void ABasePawn::handle_death() { /* diff --git a/Source/PresidentsBrigade/BasePawn.h b/Source/PresidentsBrigade/BasePawn.h index b73d6db..d278d3b 100755 --- a/Source/PresidentsBrigade/BasePawn.h +++ b/Source/PresidentsBrigade/BasePawn.h @@ -112,11 +112,20 @@ protected: float fire_rate_s; /** - * Max ammor. + * Max ammo. */ UPROPERTY(EditAnywhere, Category = "Attack") int32 max_ammo; + /** + * + */ + UPROPERTY(EditAnywhere, Category = "Attack") + float aim_assist_distance; + + UPROPERTY(EditAnywhere, Category = "Attack") + bool use_aim_assist; + /** * Shooting enabled; */ @@ -146,4 +155,7 @@ protected: * Spawned death effect actor. */ AActor* death_effect; + +private: + float aim_assist(const FVector start, const FRotator rotator); }; diff --git a/Source/PresidentsBrigade/EnemyAIController.cpp b/Source/PresidentsBrigade/EnemyAIController.cpp index 16c2d8e..c33eefa 100755 --- a/Source/PresidentsBrigade/EnemyAIController.cpp +++ b/Source/PresidentsBrigade/EnemyAIController.cpp @@ -38,14 +38,24 @@ void AEnemyAIController::Tick(float delta_time) else { FVector target_location = president->get_location(); - FVector current_location = Cast(GetPawn())->get_location(); - FVector between = target_location - current_location; - between = FVector(between.X, between.Y, 0); - between.Normalize(); - FVector extended = (between * overshoot_multiplier) + target_location; + const ABasePawn* local_pawn = Cast(GetPawn()); + if (local_pawn) + { + FVector current_location = local_pawn->get_location(); + FVector between = target_location - current_location; + between = FVector(between.X, between.Y, 0); + between.Normalize(); + FVector extended = (between * overshoot_multiplier) + target_location; + + MoveToLocation(extended); + current_state = state_t::moving; + } + else + { + // This will be cleaned up shortly. + current_state = state_t::dead; + } - MoveToLocation(extended); - current_state = state_t::moving; } break; case state_t::moving: @@ -95,7 +105,7 @@ ABasePawn* AEnemyAIController::get_president() const if (!found) { - LogError("No president found!"); + // LogError("No president found!"); } return found; diff --git a/Source/PresidentsBrigade/EnemyAIController.h b/Source/PresidentsBrigade/EnemyAIController.h index 8932b5d..b6d08b1 100755 --- a/Source/PresidentsBrigade/EnemyAIController.h +++ b/Source/PresidentsBrigade/EnemyAIController.h @@ -43,6 +43,7 @@ private: wait, target, moving, + dead }; ABasePawn* get_president() const; diff --git a/todo.txt b/todo.txt index 4c6e0d6..5d2d465 100644 --- a/todo.txt +++ b/todo.txt @@ -14,6 +14,10 @@ xShoot from any direction xShoot at continuous rate when holding shoot button xAdd player damage xAdd player ammo +xAdd auto aim +Add art + - Car models + - Street shader Add win condition - Time based. Keep president alive until he reaches destination. Add HUD UI @@ -21,9 +25,6 @@ Add menu Add local multiplayer x Blueprint - C++ -Add art - - Car models - - Street shader Add sounds Add juice Add muzzle on shoot