diff --git a/Config/DefaultEngine.ini b/Config/DefaultEngine.ini index 1b1c8ac..bb351c0 100644 --- a/Config/DefaultEngine.ini +++ b/Config/DefaultEngine.ini @@ -10,9 +10,9 @@ r.AllowStaticLighting=False r.GenerateMeshDistanceFields=True -r.DynamicGlobalIlluminationMethod=1 +r.DynamicGlobalIlluminationMethod=0 -r.ReflectionMethod=1 +r.ReflectionMethod=0 r.SkinCache.CompileShaders=True @@ -27,6 +27,12 @@ r.DefaultFeature.AutoExposure.ExtendDefaultLuminanceRange=True r.DefaultFeature.LocalExposure.HighlightContrastScale=0.8 r.DefaultFeature.LocalExposure.ShadowContrastScale=0.8 +r.Lumen.HardwareRayTracing=False +r.Lumen.Reflections.HardwareRayTracing.Translucent.Refraction.EnableForProject=False +r.Mobile.SupportsGen4TAA=False +r.CustomDepthTemporalAAJitter=False +r.AntiAliasingMethod=1 +r.DefaultFeature.MotionBlur=False [/Script/WindowsTargetPlatform.WindowsTargetSettings] DefaultGraphicsRHI=DefaultGraphicsRHI_DX12 @@ -94,3 +100,7 @@ ConnectionType=USBOnly bUseManualIPAddress=False ManualIPAddress= + +[CoreRedirects] ++ClassRedirects=(OldName="/Script/M4_CPP.M4_CentipedeController",NewName="/Script/M4_CPP.M4_CentipedeController") + diff --git a/Content/CTP/01_Level/L_Default.umap b/Content/CTP/01_Level/L_Default.umap index d006b8e..0bb66cf 100644 Binary files a/Content/CTP/01_Level/L_Default.umap and b/Content/CTP/01_Level/L_Default.umap differ diff --git a/Content/CTP/05_Material/MI_Body.uasset b/Content/CTP/05_Material/MI_Body.uasset new file mode 100644 index 0000000..092eb17 Binary files /dev/null and b/Content/CTP/05_Material/MI_Body.uasset differ diff --git a/Content/CTP/05_Material/MI_Head.uasset b/Content/CTP/05_Material/MI_Head.uasset new file mode 100644 index 0000000..636d773 Binary files /dev/null and b/Content/CTP/05_Material/MI_Head.uasset differ diff --git a/Source/M4_CPP/private/M4_CentipedeBody.cpp b/Source/M4_CPP/private/M4_CentipedeBody.cpp index f43d0b1..df0bdc3 100644 --- a/Source/M4_CPP/private/M4_CentipedeBody.cpp +++ b/Source/M4_CPP/private/M4_CentipedeBody.cpp @@ -10,21 +10,42 @@ AM4_CentipedeBody::AM4_CentipedeBody() GetStaticMeshComponent()->SetStaticMesh(MeshRef.Object); } + static ConstructorHelpers::FObjectFinder HeadMatRef(TEXT("/Game/CTP/05_Material/MI_Head.MI_Head")); + if (HeadMatRef.Succeeded()) + { + HeadMaterial = HeadMatRef.Object; + } + + static ConstructorHelpers::FObjectFinder BodyMatRef(TEXT("/Game/CTP/05_Material/MI_Body.MI_Body")); + if (BodyMatRef.Succeeded()) + { + BodyMaterial = BodyMatRef.Object; + } + GetStaticMeshComponent()->SetRelativeScale3D(FVector(1.f, 0.4f, 0.4f)); - GetStaticMeshComponent()->SetCollisionEnabled(ECollisionEnabled::QueryOnly); - GetStaticMeshComponent()->SetGenerateOverlapEvents(true); GetStaticMeshComponent()->SetMobility(EComponentMobility::Movable); + GetStaticMeshComponent()->SetCollisionObjectType(ECollisionChannel::ECC_WorldDynamic); + GetStaticMeshComponent()->SetGenerateOverlapEvents(true); + GetStaticMeshComponent()->SetCollisionEnabled(ECollisionEnabled::QueryOnly); + GetStaticMeshComponent()->SetCollisionProfileName(TEXT("OverlapAll")); } void AM4_CentipedeBody::SetAsHead(bool bHead) { - bIsHead = bHead; - if (bIsHead) - { - GetStaticMeshComponent()->SetDefaultCustomPrimitiveDataVector4(0, FVector4(1.0, 0.0, 0.0, 1.0)); - } - else - { - GetStaticMeshComponent()->SetDefaultCustomPrimitiveDataVector4(0, FVector4(0.0, 1.0, 0.0, 1.0)); - } -} + bIsHead = bHead; + + if (bIsHead) + { + if (HeadMaterial) + { + GetStaticMeshComponent()->SetMaterial(0, HeadMaterial); + } + } + else + { + if (BodyMaterial) + { + GetStaticMeshComponent()->SetMaterial(0, BodyMaterial); + } + } +} \ No newline at end of file diff --git a/Source/M4_CPP/private/M4_CentipedeController.cpp b/Source/M4_CPP/private/M4_CentipedeController.cpp index 445d7d8..39884d4 100644 --- a/Source/M4_CPP/private/M4_CentipedeController.cpp +++ b/Source/M4_CPP/private/M4_CentipedeController.cpp @@ -1,40 +1,110 @@ #include "M4_CentipedeController.h" +#include "M4_LOG.h" #include "M4_Gamemode.h" +#include "M4_Mushroom.h" +#include "Kismet/GameplayStatics.h" -AM4_CentipedeController::AM4_CentipedeController() +UM4_CentipedeController::UM4_CentipedeController() { - PrimaryActorTick.bCanEverTick = true; - Root = CreateDefaultSubobject(TEXT("RootComponent")); - RootComponent = Root; + } -void AM4_CentipedeController::BeginPlay() +void UM4_CentipedeController::Initialize(FSubsystemCollectionBase& Collection) { - Super::BeginPlay(); - SpawnCentipede(); + Super::Initialize(Collection); - PreviousPositions.SetNum(BodyCount); - for (int i = 0; i < BodyCount; ++i) + UE_LOG(M4_CPP, Warning, TEXT("Centipede Controller Initialized")); + +} + +void UM4_CentipedeController::Deinitialize() +{ + UE_LOG(M4_CPP, Warning, TEXT("Centipede Controller Deinitialized")); + + BodySegments.Empty(); + PreviousPositions.Empty(); + SegmentDirections.Empty(); + + Super::Deinitialize(); +} + +void UM4_CentipedeController::StartCentipede(FVector SpawnLocation) +{ + if (BodySegments.Num() > 0) { - PreviousPositions[i] = BodySegments[i]->GetActorLocation(); + UE_LOG(M4_CPP, Warning, TEXT("Centipede already spawned")); + return; + } + + for (int32 i = 0; i < BodyCount; ++i) + { + FVector SegmentLocation = SpawnLocation - FVector(0.f, i * CellSize, 0.f); + + AM4_CentipedeBody* Body = GetWorld()->SpawnActor( + AM4_CentipedeBody::StaticClass(), + SegmentLocation, + FRotator::ZeroRotator + ); + + if (Body) + { + BodySegments.Add(Body); + + if (i > 0) + { + Body->PreviousBody = BodySegments[i - 1]; + BodySegments[i - 1]->NextBody = Body; + } + + Body->SetAsHead(i == 0); + } } + SegmentHistory.SetNum(BodyCount); + for (int32 i = 0; i < BodyCount; ++i) + { + if (BodySegments.IsValidIndex(i) && BodySegments[i]) + { + FVector InitialPos = BodySegments[i]->GetActorLocation(); + + int32 InitialHistorySize = SegmentSpacing * (i + 1) + MaxHistorySize; + for (int32 j = 0; j < InitialHistorySize; ++j) + { + SegmentHistory[i].Add(InitialPos); + } + } + } + for (AM4_CentipedeBody* Segment : BodySegments) { SegmentDirections.Add(Segment, FVector2D(0.f, 1.f)); } + + UE_LOG(M4_CPP, Warning, TEXT("Centipede spawned with %d segments"), BodySegments.Num()); } -void AM4_CentipedeController::SpawnCentipede() +TStatId UM4_CentipedeController::GetStatId() const { - FVector SpawnLocation = GetActorLocation(); + RETURN_QUICK_DECLARE_CYCLE_STAT(UM4_CentipedeController, STATGROUP_Tickables); +} + +void UM4_CentipedeController::SpawnCentipede() +{ + AM4_Gamemode* GM = Cast(GetWorld()->GetAuthGameMode()); + if (!GM) return; - UE_LOG(LogTemp, Warning, TEXT("Controller spawn location: X=%.2f, Y=%.2f, Z=%.2f"), + FVector SpawnLocation = FVector( + GM->MushroomSpawnBounds.Max.X, + 0.f, + 0.f + ); + + UE_LOG(M4_CPP, Warning, TEXT("Controller spawn location: X=%.2f, Y=%.2f, Z=%.2f"), SpawnLocation.X, SpawnLocation.Y, SpawnLocation.Z); if (SpawnLocation.IsZero()) { - UE_LOG(LogTemp, Error, TEXT("Controller position is zero! Check spawn parameters.")); + UE_LOG(M4_CPP, Error, TEXT("Controller position is zero! Check spawn parameters.")); return; } @@ -63,80 +133,68 @@ void AM4_CentipedeController::SpawnCentipede() } } -void AM4_CentipedeController::Tick(float DeltaTime) +void UM4_CentipedeController::Tick(float DeltaTime) { Super::Tick(DeltaTime); if (BodySegments.Num() == 0) return; - - TimeSinceLastMove += DeltaTime; - - if (TimeSinceLastMove >= MoveInterval) + + AM4_CentipedeBody* Head = BodySegments[0]; + if (Head && Head->bIsHead) { - TimeSinceLastMove = 0.f; - - TArray TempPositions; - TempPositions.SetNum(BodySegments.Num()); - - for (int32 i = 0; i < BodySegments.Num(); ++i) - { - TempPositions[i] = BodySegments[i]->GetActorLocation(); - } - - for (int32 i = 0; i < BodySegments.Num(); ++i) - { - AM4_CentipedeBody* Segment = BodySegments[i]; - - if (!Segment) continue; - - if (Segment->bIsHead) - { - FVector CurrentPos = Segment->GetActorLocation(); - FVector2D SegmentDirection = GetSegmentDirection(Segment); - - bool bShouldDescend = CheckCollision(Segment, SegmentDirection); - - if (bShouldDescend) - { - FVector NewPos = CurrentPos - FVector(0.f, 0.f, CellSize); - Segment->SetActorLocation(NewPos); - - SegmentDirection.Y *= -1.f; - SetSegmentDirection(Segment, SegmentDirection); - - UE_LOG(LogTemp, Warning, TEXT("Head at index %d descending"), i); - } - else - { - FVector NewPos = CurrentPos + FVector(0.f, SegmentDirection.Y * CellSize, 0.f); - Segment->SetActorLocation(NewPos); - } - } - else - { - if (i > 0) - { - Segment->SetActorLocation(PreviousPositions[i - 1]); - - if (BodySegments[i - 1]) - { - FVector2D PrevDirection = GetSegmentDirection(BodySegments[i - 1]); - SetSegmentDirection(Segment, PrevDirection); - } - } - } - } - - for (int32 i = 0; i < BodySegments.Num(); ++i) - { - PreviousPositions[i] = BodySegments[i]->GetActorLocation(); - } + FVector CurrentPos = Head->GetActorLocation(); + FVector2D SegmentDirection = GetSegmentDirection(Head); - UpdateHeadStatus(); + bool bRowChanged = CheckCollision(Head, SegmentDirection); + + if (bRowChanged) + { + FVector NewPos = CurrentPos - FVector(0.f, 0.f, CellSize); + Head->SetActorLocation(NewPos); + + SegmentDirection.Y *= -1.f; + SetSegmentDirection(Head, SegmentDirection); + } + else + { + FVector NewPos = CurrentPos + FVector(0.f, SegmentDirection.Y * CentipedeSpeed * DeltaTime, 0.f); + Head->SetActorLocation(NewPos); + } + + SegmentHistory[0].Add(Head->GetActorLocation()); + if (SegmentHistory[0].Num() > MaxHistorySize) + { + SegmentHistory[0].RemoveAt(0); + } } + + for (int32 i = 1; i < BodySegments.Num(); ++i) + { + AM4_CentipedeBody* Segment = BodySegments[i]; + if (!Segment) continue; + + int32 PrevIndex = i - 1; + int32 HistoryLookback = SegmentSpacing; + + if (SegmentHistory[PrevIndex].Num() > HistoryLookback) + { + int32 HistoryIndex = SegmentHistory[PrevIndex].Num() - HistoryLookback - 1; + FVector TargetPos = SegmentHistory[PrevIndex][HistoryIndex]; + + Segment->SetActorLocation(TargetPos); + + SegmentHistory[i].Add(Segment->GetActorLocation()); + if (SegmentHistory[i].Num() > MaxHistorySize) + { + SegmentHistory[i].RemoveAt(0); + } + } + } + + UpdateHeadStatus(); } -bool AM4_CentipedeController::CheckCollision(AM4_CentipedeBody* Segment, FVector2D Direction) +bool UM4_CentipedeController::CheckCollision(AM4_CentipedeBody* Segment, FVector2D Direction) { if (!Segment) return false; @@ -148,19 +206,58 @@ bool AM4_CentipedeController::CheckCollision(AM4_CentipedeBody* Segment, FVector const float LeftBound = GM->MushroomSpawnBounds.Min.Y; const float RightBound = GM->MushroomSpawnBounds.Max.Y; + const float MinRows = GM->MushroomSpawnBounds.Min.X; + const float MaxRows = GM->MushroomSpawnBounds.Max.X; if (NextPos.Y <= LeftBound || NextPos.Y >= RightBound) { return true; } + + if (CurrentPos.Z > MinRows && NextPos.Z <= MinRows) + { + // On inverse la direction de descente pour remonter + FVector2D CurrentDirection = GetSegmentDirection(Segment); + CurrentDirection.Y *= -1.f; + SetSegmentDirection(Segment, CurrentDirection); + return true; // Collision détectée, le centipede descendra à la prochaine itération + } - // TODO: Ajouter vérification collision avec mushroom - // if (IsMushroomAt(NextPos)) return true; + // Vérification si on atteint la limite haute + if (CurrentPos.Z < MaxRows && NextPos.Z >= MaxRows) + { + // On inverse la direction de montée pour descendre + FVector2D CurrentDirection = GetSegmentDirection(Segment); + CurrentDirection.Y *= -1.f; + SetSegmentDirection(Segment, CurrentDirection); + return true; // Collision détectée, le centipede remontera à la prochaine itération + } + + int32 NextGridZ = FMath::RoundToInt(NextPos.Z / CellSize); + int32 NextGridY = FMath::RoundToInt(NextPos.Y / CellSize); + + TArray FoundMushrooms; + UGameplayStatics::GetAllActorsOfClass(GetWorld(), AM4_Mushroom::StaticClass(), FoundMushrooms); + + for (AActor* Actor : FoundMushrooms) + { + FVector MushroomPos = Actor->GetActorLocation(); + + // Conversion de la position du mushroom en coordonnées de grille (Z, Y) + int32 MushroomGridZ = FMath::RoundToInt(MushroomPos.Z / CellSize); + int32 MushroomGridY = FMath::RoundToInt(MushroomPos.Y / CellSize); + + // Vérification si c'est la même cellule de grille + if (NextGridZ == MushroomGridZ && NextGridY == MushroomGridY) + { + return true; + } + } return false; } -FVector2D AM4_CentipedeController::GetSegmentDirection(AM4_CentipedeBody* Segment) +FVector2D UM4_CentipedeController::GetSegmentDirection(AM4_CentipedeBody* Segment) { if (SegmentDirections.Contains(Segment)) { @@ -169,7 +266,7 @@ FVector2D AM4_CentipedeController::GetSegmentDirection(AM4_CentipedeBody* Segmen return FVector2D(0.f, 1.f); } -void AM4_CentipedeController::SetSegmentDirection(AM4_CentipedeBody* Segment, FVector2D Direction) +void UM4_CentipedeController::SetSegmentDirection(AM4_CentipedeBody* Segment, FVector2D Direction) { if (Segment) { @@ -177,7 +274,7 @@ void AM4_CentipedeController::SetSegmentDirection(AM4_CentipedeBody* Segment, FV } } -void AM4_CentipedeController::UpdateHeadStatus() +void UM4_CentipedeController::UpdateHeadStatus() { for (int32 i = 0; i < BodySegments.Num(); ++i) { @@ -193,37 +290,29 @@ void AM4_CentipedeController::UpdateHeadStatus() } } -void AM4_CentipedeController::OnSegmentDestroyed(AM4_CentipedeBody* DestroyedSegment) +void UM4_CentipedeController::OnSegmentDestroyed(AM4_CentipedeBody* DestroyedSegment) { if (!DestroyedSegment) return; int32 SegmentIndex = BodySegments.Find(DestroyedSegment); - if (SegmentIndex == INDEX_NONE) return; - UE_LOG(LogTemp, Warning, TEXT("Segment %d destroyed"), SegmentIndex); - if (SegmentIndex + 1 < BodySegments.Num()) { AM4_CentipedeBody* NewHead = BodySegments[SegmentIndex + 1]; if (NewHead) { NewHead->SetAsHead(true); - NewHead->PreviousBody = nullptr; - - UE_LOG(LogTemp, Warning, TEXT("New head created at index %d"), SegmentIndex + 1); + NewHead->PreviousBody = nullptr; } } - + if (SegmentIndex > 0 && BodySegments[SegmentIndex - 1]) { BodySegments[SegmentIndex - 1]->NextBody = nullptr; } - - BodySegments.RemoveAt(SegmentIndex); - PreviousPositions.RemoveAt(SegmentIndex); - SegmentDirections.Remove(DestroyedSegment); - // TODO: Spawner un mushroom à la position du segment détruit - // SpawnMushroomAt(DestroyedSegment->GetActorLocation()); + BodySegments.RemoveAt(SegmentIndex); + SegmentHistory.RemoveAt(SegmentIndex); + SegmentDirections.Remove(DestroyedSegment); } \ No newline at end of file diff --git a/Source/M4_CPP/private/M4_Gamemode.cpp b/Source/M4_CPP/private/M4_Gamemode.cpp index 27496e7..2d97557 100644 --- a/Source/M4_CPP/private/M4_Gamemode.cpp +++ b/Source/M4_CPP/private/M4_Gamemode.cpp @@ -85,8 +85,7 @@ void AM4_Gamemode::BeginPlay() ); } } - - // Spawn centipede controller + PRINT_SCREEN(TEXT("Spawning Centipede Controller"), FColor::Green); FVector CentipedeSpawnLocation = FVector( @@ -98,16 +97,13 @@ void AM4_Gamemode::BeginPlay() // PRINT SCREEN Max.X value PRINT_SCREEN(*FString::Printf(TEXT("Mushroom Spawn Bounds Max.X: %.2f"), MushroomSpawnBounds.Max.X), FColor::Green); - CentipedeController = GetWorld()->SpawnActor( - AM4_CentipedeController::StaticClass(), - CentipedeSpawnLocation, - FRotator::ZeroRotator - ); - - if (CentipedeController) + UM4_CentipedeController* Controller = GetWorld()->GetSubsystem(); + if (Controller) { - CentipedeController->BodyCount = CentipedeBodyCount; - CentipedeController->CellSize = CellSize; + Controller->BodyCount = CentipedeBodyCount; + Controller->CellSize = CellSize; + + Controller->StartCentipede(CentipedeSpawnLocation); } } diff --git a/Source/M4_CPP/private/M4_Mushroom.cpp b/Source/M4_CPP/private/M4_Mushroom.cpp index a315033..456a14f 100644 --- a/Source/M4_CPP/private/M4_Mushroom.cpp +++ b/Source/M4_CPP/private/M4_Mushroom.cpp @@ -31,9 +31,8 @@ AM4_Mushroom::AM4_Mushroom() const FVector2D MushroomScale = FVector2D(0.3f, 0.25f); GetStaticMeshComponent()->SetRelativeScale3D(FVector(1.f, 0.45f, 0.20f)); - // Custom preset for more advanced collision configuration - GetStaticMeshComponent()->SetCollisionProfileName(UCollisionProfile::CustomCollisionProfileName); - GetStaticMeshComponent()->SetCollisionResponseToChannel(ECC_Pawn, ECR_Overlap); + // Set collision profile to overlap all + GetStaticMeshComponent()->SetCollisionProfileName(TEXT("OverlapAll")); } diff --git a/Source/M4_CPP/public/M4_CentipedeBody.h b/Source/M4_CPP/public/M4_CentipedeBody.h index 14855b5..81a2416 100644 --- a/Source/M4_CPP/public/M4_CentipedeBody.h +++ b/Source/M4_CPP/public/M4_CentipedeBody.h @@ -22,4 +22,10 @@ public: bool bIsHead = false; void SetAsHead(bool bHead); + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Materials") + UMaterialInterface* HeadMaterial; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Materials") + UMaterialInterface* BodyMaterial; }; \ No newline at end of file diff --git a/Source/M4_CPP/public/M4_CentipedeController.h b/Source/M4_CPP/public/M4_CentipedeController.h index 325b994..53a98ca 100644 --- a/Source/M4_CPP/public/M4_CentipedeController.h +++ b/Source/M4_CPP/public/M4_CentipedeController.h @@ -1,50 +1,60 @@ #pragma once #include "CoreMinimal.h" -#include "GameFramework/Actor.h" #include "M4_CentipedeBody.h" +#include "Subsystems/WorldSubsystem.h" #include "M4_CentipedeController.generated.h" UCLASS() -class M4_CPP_API AM4_CentipedeController : public AActor +class M4_CPP_API UM4_CentipedeController : public UTickableWorldSubsystem { GENERATED_BODY() public: - AM4_CentipedeController(); + UM4_CentipedeController(); + + virtual void Initialize(FSubsystemCollectionBase& Collection) override; + virtual void Deinitialize() override; + void StartCentipede(FVector SpawnLocation); - virtual void BeginPlay() override; virtual void Tick(float DeltaTime) override; + + virtual TStatId GetStatId() const override; - UPROPERTY(EditAnywhere) + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Centipede") int32 BodyCount = 10; - UPROPERTY(EditAnywhere) + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Centipede") float CellSize = 50.f; - UPROPERTY(EditAnywhere) + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Centipede") float MoveInterval = 0.1f; - + + UFUNCTION(BlueprintCallable, Category = "Centipede") void OnSegmentDestroyed(AM4_CentipedeBody* DestroyedSegment); private: UPROPERTY() TArray BodySegments; - - UPROPERTY() - USceneComponent* Root; + TArray> SegmentHistory; // Historique pour chaque segment + int32 MaxHistorySize = 200; + + UPROPERTY(EditAnywhere, Category = "Centipede") + int32 SegmentSpacing = 15; // Distance en nombre de frames entre segments float TimeSinceLastMove = 0.f; - + float CentipedeSpeed = 400.f; + bool bFirstTick = true; + TArray PreviousPositions; - + TMap SegmentDirections; void SpawnCentipede(); void UpdateHeadStatus(); - + bool CheckCollision(AM4_CentipedeBody* Segment, FVector2D Direction); - + FVector2D GetSegmentDirection(AM4_CentipedeBody* Segment); void SetSegmentDirection(AM4_CentipedeBody* Segment, FVector2D Direction); -}; \ No newline at end of file +}; diff --git a/Source/M4_CPP/public/M4_Gamemode.h b/Source/M4_CPP/public/M4_Gamemode.h index 2271f9d..0f940fc 100644 --- a/Source/M4_CPP/public/M4_Gamemode.h +++ b/Source/M4_CPP/public/M4_Gamemode.h @@ -67,7 +67,7 @@ private: int32 CentipedeBodyCount = 10; UPROPERTY() - TObjectPtr CentipedeController; + TObjectPtr CentipedeController; int Score = 0; int Lives = 3;