Merge branch 'main' into Bullet

This commit is contained in:
NisemonoQ
2025-10-17 14:02:35 +02:00
7 changed files with 394 additions and 2 deletions

View File

@@ -0,0 +1,30 @@
#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);
}
GetStaticMeshComponent()->SetRelativeScale3D(FVector(1.f, 0.4f, 0.4f));
GetStaticMeshComponent()->SetCollisionEnabled(ECollisionEnabled::QueryOnly);
GetStaticMeshComponent()->SetGenerateOverlapEvents(true);
GetStaticMeshComponent()->SetMobility(EComponentMobility::Movable);
}
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));
}
}

View File

@@ -0,0 +1,229 @@
#include "M4_CentipedeController.h"
#include "M4_Gamemode.h"
AM4_CentipedeController::AM4_CentipedeController()
{
PrimaryActorTick.bCanEverTick = true;
Root = CreateDefaultSubobject<USceneComponent>(TEXT("RootComponent"));
RootComponent = Root;
}
void AM4_CentipedeController::BeginPlay()
{
Super::BeginPlay();
SpawnCentipede();
PreviousPositions.SetNum(BodyCount);
for (int i = 0; i < BodyCount; ++i)
{
PreviousPositions[i] = BodySegments[i]->GetActorLocation();
}
for (AM4_CentipedeBody* Segment : BodySegments)
{
SegmentDirections.Add(Segment, FVector2D(0.f, 1.f));
}
}
void AM4_CentipedeController::SpawnCentipede()
{
FVector SpawnLocation = GetActorLocation();
UE_LOG(LogTemp, 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."));
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 AM4_CentipedeController::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
if (BodySegments.Num() == 0) return;
TimeSinceLastMove += DeltaTime;
if (TimeSinceLastMove >= MoveInterval)
{
TimeSinceLastMove = 0.f;
TArray<FVector> 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();
}
UpdateHeadStatus();
}
}
bool AM4_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;
if (NextPos.Y <= LeftBound || NextPos.Y >= RightBound)
{
return true;
}
// TODO: Ajouter vérification collision avec mushroom
// if (IsMushroomAt(NextPos)) return true;
return false;
}
FVector2D AM4_CentipedeController::GetSegmentDirection(AM4_CentipedeBody* Segment)
{
if (SegmentDirections.Contains(Segment))
{
return SegmentDirections[Segment];
}
return FVector2D(0.f, 1.f);
}
void AM4_CentipedeController::SetSegmentDirection(AM4_CentipedeBody* Segment, FVector2D Direction)
{
if (Segment)
{
SegmentDirections.Add(Segment, Direction);
}
}
void AM4_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 AM4_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);
}
}
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());
}

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,36 @@ 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
);
}
}
// Spawn centipede controller
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);
CentipedeController = GetWorld()->SpawnActor<AM4_CentipedeController>(
AM4_CentipedeController::StaticClass(),
CentipedeSpawnLocation,
FRotator::ZeroRotator
);
if (CentipedeController)
{
CentipedeController->BodyCount = CentipedeBodyCount;
CentipedeController->CellSize = CellSize;
}
}

View File

@@ -34,6 +34,7 @@ AM4_Mushroom::AM4_Mushroom()
// Custom preset for more advanced collision configuration
GetStaticMeshComponent()->SetCollisionProfileName(UCollisionProfile::CustomCollisionProfileName);
GetStaticMeshComponent()->SetCollisionResponseToChannel(ECC_Pawn, ECR_Overlap);
}
void AM4_Mushroom::BeginPlay()

View File

@@ -0,0 +1,25 @@
#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);
};

View File

@@ -0,0 +1,50 @@
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "M4_CentipedeBody.h"
#include "M4_CentipedeController.generated.h"
UCLASS()
class M4_CPP_API AM4_CentipedeController : public AActor
{
GENERATED_BODY()
public:
AM4_CentipedeController();
virtual void BeginPlay() override;
virtual void Tick(float DeltaTime) override;
UPROPERTY(EditAnywhere)
int32 BodyCount = 10;
UPROPERTY(EditAnywhere)
float CellSize = 50.f;
UPROPERTY(EditAnywhere)
float MoveInterval = 0.1f;
void OnSegmentDestroyed(AM4_CentipedeBody* DestroyedSegment);
private:
UPROPERTY()
TArray<AM4_CentipedeBody*> BodySegments;
UPROPERTY()
USceneComponent* Root;
float TimeSinceLastMove = 0.f;
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<AM4_CentipedeController> CentipedeController;
int Score = 0;
int Lives = 3;