Compare commits

...

8 Commits

Author SHA1 Message Date
fc97901cdc Minor - Change le comportement du mille-pattes - V2.2.0
Améliore la logique de collision du mille-pattes avec les bords et les champignons.

Le mille-pattes change de direction lorsqu'il atteint les limites de la zone de jeu ou rencontre un champignon.
2025-10-30 23:44:26 +01:00
600897b905 Merge remote-tracking branch 'origin/main' 2025-10-18 22:26:02 +02:00
17c60a72e3 Patch - Optimise les paramètres graphiques - V2.1.0
Reduit les paramètres graphiques par défaut pour une meilleure performance.

Desactive le ray tracing matériel et d'autres fonctionnalités gourmandes en ressources.
2025-10-18 22:25:47 +02:00
a85c596e23 Minor - Optimise les paramètres graphiques - V
Reduit les paramètres graphiques par défaut pour une meilleure performance.

Desactive le ray tracing matériel et d'autres fonctionnalités gourmandes en ressources.
2025-10-18 22:25:27 +02:00
7e3424d0f6 Minor - Modifie la trajectoire de la centipede - V2.1.0
Ajuste le déplacement de la centipede en modifiant le calcul de sa trajectoire.
La centipede se déplace désormais horizontalement, ce qui améliore sa visibilité.
2025-10-17 16:51:24 +02:00
987856ca09 Major - Implémente le contrôleur de mille-pattes - V2.0.0
This commit introduces a centipede controller subsystem, managing centipede spawning, movement, and segment behavior.

It adds centipede body materials, movement logic, collision detection, and head assignment.
The controller handles segment following, direction changes at boundaries, and dynamic head updates upon segment destruction.
2025-10-17 16:32:27 +02:00
NisemonoQ
df25b61b8f Merge branch 'Bullet' 2025-10-17 14:01:37 +02:00
d20171032f Minor - Implémente le comportement de la centipede - V01.11.00
Implémente la logique de base du mouvement de la centipede,
la gestion des collisions et l'ajustement de la direction.

Ajoute les classes CentipedeBody et CentipedeController
pour gérer les segments et le mouvement.

Gère la destruction des segments et la création d'un nouveau
segment de tête.
2025-10-17 00:23:09 +02:00
11 changed files with 530 additions and 7 deletions

View File

@@ -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")

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,51 @@
#include "M4_CentipedeBody.h"
AM4_CentipedeBody::AM4_CentipedeBody()
{
PrimaryActorTick.bCanEverTick = false;
static ConstructorHelpers::FObjectFinder<UStaticMesh> MeshRef(TEXT("/Game/CTP/04_Mesh/SM_Cube.SM_Cube"));
if (MeshRef.Succeeded())
{
GetStaticMeshComponent()->SetStaticMesh(MeshRef.Object);
}
static ConstructorHelpers::FObjectFinder<UMaterialInterface> HeadMatRef(TEXT("/Game/CTP/05_Material/MI_Head.MI_Head"));
if (HeadMatRef.Succeeded())
{
HeadMaterial = HeadMatRef.Object;
}
static ConstructorHelpers::FObjectFinder<UMaterialInterface> 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()->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)
{
if (HeadMaterial)
{
GetStaticMeshComponent()->SetMaterial(0, HeadMaterial);
}
}
else
{
if (BodyMaterial)
{
GetStaticMeshComponent()->SetMaterial(0, BodyMaterial);
}
}
}

View File

@@ -0,0 +1,318 @@
#include "M4_CentipedeController.h"
#include "M4_LOG.h"
#include "M4_Gamemode.h"
#include "M4_Mushroom.h"
#include "Kismet/GameplayStatics.h"
UM4_CentipedeController::UM4_CentipedeController()
{
}
void UM4_CentipedeController::Initialize(FSubsystemCollectionBase& Collection)
{
Super::Initialize(Collection);
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)
{
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>(
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());
}
TStatId UM4_CentipedeController::GetStatId() const
{
RETURN_QUICK_DECLARE_CYCLE_STAT(UM4_CentipedeController, STATGROUP_Tickables);
}
void UM4_CentipedeController::SpawnCentipede()
{
AM4_Gamemode* GM = Cast<AM4_Gamemode>(GetWorld()->GetAuthGameMode());
if (!GM) return;
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(M4_CPP, Error, TEXT("Controller position is zero! Check spawn parameters."));
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>(
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);
}
}
}
void UM4_CentipedeController::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
if (BodySegments.Num() == 0) return;
AM4_CentipedeBody* Head = BodySegments[0];
if (Head && Head->bIsHead)
{
FVector CurrentPos = Head->GetActorLocation();
FVector2D SegmentDirection = GetSegmentDirection(Head);
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 UM4_CentipedeController::CheckCollision(AM4_CentipedeBody* Segment, FVector2D Direction)
{
if (!Segment) return false;
FVector CurrentPos = Segment->GetActorLocation();
FVector NextPos = CurrentPos + FVector(0.f, Direction.Y * CellSize, 0.f);
AM4_Gamemode* GM = Cast<AM4_Gamemode>(GetWorld()->GetAuthGameMode());
if (!GM) return false;
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
}
// 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<AActor*> 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 UM4_CentipedeController::GetSegmentDirection(AM4_CentipedeBody* Segment)
{
if (SegmentDirections.Contains(Segment))
{
return SegmentDirections[Segment];
}
return FVector2D(0.f, 1.f);
}
void UM4_CentipedeController::SetSegmentDirection(AM4_CentipedeBody* Segment, FVector2D Direction)
{
if (Segment)
{
SegmentDirections.Add(Segment, Direction);
}
}
void UM4_CentipedeController::UpdateHeadStatus()
{
for (int32 i = 0; i < BodySegments.Num(); ++i)
{
AM4_CentipedeBody* Body = BodySegments[i];
if (!Body) continue;
bool bShouldBeHead = (i == 0) || (Body->PreviousBody == nullptr);
if (Body->bIsHead != bShouldBeHead)
{
Body->SetAsHead(bShouldBeHead);
}
}
}
void UM4_CentipedeController::OnSegmentDestroyed(AM4_CentipedeBody* DestroyedSegment)
{
if (!DestroyedSegment) return;
int32 SegmentIndex = BodySegments.Find(DestroyedSegment);
if (SegmentIndex == INDEX_NONE) return;
if (SegmentIndex + 1 < BodySegments.Num())
{
AM4_CentipedeBody* NewHead = BodySegments[SegmentIndex + 1];
if (NewHead)
{
NewHead->SetAsHead(true);
NewHead->PreviousBody = nullptr;
}
}
if (SegmentIndex > 0 && BodySegments[SegmentIndex - 1])
{
BodySegments[SegmentIndex - 1]->NextBody = nullptr;
}
BodySegments.RemoveAt(SegmentIndex);
SegmentHistory.RemoveAt(SegmentIndex);
SegmentDirections.Remove(DestroyedSegment);
}

View File

@@ -1,6 +1,7 @@
// Fill out your copyright notice in the Description page of Project Settings.
#include "M4_Gamemode.h"
#include "M4_CTP_Macros.h"
#include "M4_Mushroom.h"
#include "M4_PlayerController.h"
#include "M4_PlayerPawn.h"
@@ -45,11 +46,30 @@ void AM4_Gamemode::BeginPlay()
for (int32 i = 0; i < MushroomCount; ++i)
{
FIntPoint Cell;
bool bValidCell;
int32 MaxAttempts = 100;
int32 Attempts = 0;
do
{
Cell.X = FMath::RandRange(0, GridRows - 1);
Cell.Y = FMath::RandRange(0, GridCols - 1);
} while (OccupiedCells.Contains(Cell));
// Check if cell and adjacent cells are free
bValidCell = !OccupiedCells.Contains(Cell) &&
!OccupiedCells.Contains(FIntPoint(Cell.X - 1, Cell.Y)) &&
!OccupiedCells.Contains(FIntPoint(Cell.X + 1, Cell.Y)) &&
!OccupiedCells.Contains(FIntPoint(Cell.X, Cell.Y - 1)) &&
!OccupiedCells.Contains(FIntPoint(Cell.X, Cell.Y + 1));
Attempts++;
} while (!bValidCell && Attempts < MaxAttempts);
if (!bValidCell)
{
PRINT_SCREEN(TEXT("Could not find valid cell for mushroom"), FColor::Yellow);
continue;
}
OccupiedCells.Add(Cell);
@@ -58,7 +78,32 @@ void AM4_Gamemode::BeginPlay()
SpawnLocation.Y = MushroomSpawnBounds.Min.Y + Cell.Y * CellSize + CellSize / 2.0f;
SpawnLocation.X = -400.0f;
GetWorld()->SpawnActor<AM4_Mushroom>(AM4_Mushroom::StaticClass(), SpawnLocation, FRotator::ZeroRotator);
GetWorld()->SpawnActor<AM4_Mushroom>(
AM4_Mushroom::StaticClass(),
SpawnLocation,
FRotator::ZeroRotator
);
}
}
PRINT_SCREEN(TEXT("Spawning Centipede Controller"), FColor::Green);
FVector CentipedeSpawnLocation = FVector(
-400.0f,
0.0f,
MushroomSpawnBounds.Max.X + CellSize
);
// PRINT SCREEN Max.X value
PRINT_SCREEN(*FString::Printf(TEXT("Mushroom Spawn Bounds Max.X: %.2f"), MushroomSpawnBounds.Max.X), FColor::Green);
UM4_CentipedeController* Controller = GetWorld()->GetSubsystem<UM4_CentipedeController>();
if (Controller)
{
Controller->BodyCount = CentipedeBodyCount;
Controller->CellSize = CellSize;
Controller->StartCentipede(CentipedeSpawnLocation);
}
}

View File

@@ -31,9 +31,9 @@ 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"));
}
void AM4_Mushroom::BeginPlay()

View File

@@ -0,0 +1,31 @@
#pragma once
#include "CoreMinimal.h"
#include "Engine/StaticMeshActor.h"
#include "M4_CentipedeBody.generated.h"
UCLASS()
class M4_CPP_API AM4_CentipedeBody : public AStaticMeshActor
{
GENERATED_BODY()
public:
AM4_CentipedeBody();
UPROPERTY()
AM4_CentipedeBody* NextBody;
UPROPERTY()
AM4_CentipedeBody* PreviousBody;
UPROPERTY(EditAnywhere)
bool bIsHead = false;
void SetAsHead(bool bHead);
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Materials")
UMaterialInterface* HeadMaterial;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Materials")
UMaterialInterface* BodyMaterial;
};

View File

@@ -0,0 +1,60 @@
#pragma once
#include "CoreMinimal.h"
#include "M4_CentipedeBody.h"
#include "Subsystems/WorldSubsystem.h"
#include "M4_CentipedeController.generated.h"
UCLASS()
class M4_CPP_API UM4_CentipedeController : public UTickableWorldSubsystem
{
GENERATED_BODY()
public:
UM4_CentipedeController();
virtual void Initialize(FSubsystemCollectionBase& Collection) override;
virtual void Deinitialize() override;
void StartCentipede(FVector SpawnLocation);
virtual void Tick(float DeltaTime) override;
virtual TStatId GetStatId() const override;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Centipede")
int32 BodyCount = 10;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Centipede")
float CellSize = 50.f;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Centipede")
float MoveInterval = 0.1f;
UFUNCTION(BlueprintCallable, Category = "Centipede")
void OnSegmentDestroyed(AM4_CentipedeBody* DestroyedSegment);
private:
UPROPERTY()
TArray<AM4_CentipedeBody*> BodySegments;
TArray<TArray<FVector>> 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<FVector> PreviousPositions;
TMap<AM4_CentipedeBody*, FVector2D> SegmentDirections;
void SpawnCentipede();
void UpdateHeadStatus();
bool CheckCollision(AM4_CentipedeBody* Segment, FVector2D Direction);
FVector2D GetSegmentDirection(AM4_CentipedeBody* Segment);
void SetSegmentDirection(AM4_CentipedeBody* Segment, FVector2D Direction);
};

View File

@@ -4,6 +4,7 @@
#include "CoreMinimal.h"
#include "GameFramework/GameModeBase.h"
#include "M4_CentipedeController.h"
#include "M4_Gamemode.generated.h"
/**
@@ -61,6 +62,13 @@ public:
private:
UPROPERTY(EditAnywhere, Category="Centipede")
int32 CentipedeBodyCount = 10;
UPROPERTY()
TObjectPtr<UM4_CentipedeController> CentipedeController;
int Score = 0;
int Lives = 3;