Compare commits

...

27 Commits

Author SHA1 Message Date
72e9caf2c1 Minor - Implémente la collision joueur-centipede - V3.5.0
Implémente la détection de collision entre le joueur et le centipede.

Le joueur perd une vie lors de la collision et devient temporairement invincible.

Ajoute la logique de fin de niveau lorsque tous les segments du centipede sont détruits.
2025-11-06 20:47:26 +01:00
0da3851dde Minor - Gère la mort des segments - V3.4.0
Modifie la logique de destruction des segments de centipède.

Au lieu de détruire immédiatement le segment, désactive la collision et le rend invisible. Des champignons sont générés à l'endroit de sa mort et le score du joueur est augmenté.

L'événement OnSegmentDestroyed est renommé en OnSegmentHit pour refléter la nouvelle logique.
2025-11-05 14:19:08 +01:00
NisemonoQ
469451e491 Minor - Mushroom/Projectile interaction
Ok, le reste de la fonction ne marchait pas à cause d'un BlockAll qui s'était infiltré dans le code du Mushroom
Je vais passer à l'interaction avec le centipede
2025-11-04 23:34:15 +01:00
064d4cd576 Minor - Ajoute interaction projectile/champignon - V3.2.0
Implémente la détection de collision entre les projectiles et les champignons.

Le champignon est détruit après avoir été touché le nombre de fois défini par sa durée de vie.

Le projectile est détruit après avoir touché un champignon.
2025-11-04 18:29:30 +01:00
NisemonoQ
c8f3f53a8f Minor - Mushroom function
J'ai ajouté une fonction au Mushroom pour enregistrer le hit de la balle lorsqu'il la touche, mais on dirait que ça ne veut pas marcher.
2025-11-04 17:02:24 +01:00
NisemonoQ
6305198eda Major - Comportement de la Balle quasiment complet
Il ne reste plus qu'à associer le GameMode et la reconnaissance de la collision, j'ai déjà la fonction OnHit sur laquelle on peut commencer à bosser
2025-11-01 13:05:52 +01:00
NisemonoQ
9ddc2fdbed Minor - Ajustement sur la balle
Le sprite devrait apparaitre et se déplacer avec tout l'objet + la balle.
2025-10-31 17:54:49 +01:00
NisemonoQ
7a9a6d257a Merge branch 'main' into Bullet 2025-10-31 16:31:56 +01:00
NisemonoQ
49685ed167 Minor - Nouveau comportement pour la Balle
La Balle devrait pouvoir directement se déplacer et avoir son mesh qui spawne aussi
2025-10-31 16:16:53 +01:00
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
NisemonoQ
ed5475299e Revert "Minor - Petit changement pour le spawn des balles"
This reverts commit 406bafff0a.
2025-10-30 22:44:26 +01:00
NisemonoQ
406bafff0a Minor - Petit changement pour le spawn des balles 2025-10-30 22:00:07 +01:00
NisemonoQ
d2968f0d36 Minor - Sprite du Projectile
Le modèle 3D du projectile apparait enfin, maintenant, il faut que je puisse donner au modèle la bonne position de départ.
2025-10-28 16:20:39 +01:00
NisemonoQ
365727aa4c Minor - Apparition du projectile dans la scène à partir du joueur
Le joueur peut enfin faire apparaître le projectile dans la scène après avoir appuyé sur la touche "Espace".
Cependant le Mesh n'apparait toujours pas pour l'instant mais j'ai presque fini.
2025-10-27 11:31:52 +01:00
NisemonoQ
c7702b9f64 Minor - Apparition du sprite du tir
Normalement, le spirte apparait bien lors de l'appui sur la touche espace
2025-10-20 18:00:41 +02:00
NisemonoQ
5624625eda Minor - Projectile Spawning logic done
En passant par une méthode similaire à la génération de la caméra, j'ai pu faire spawner les projectiles, maintenant à partir de leur classe, je vais ajouter leur déplacement et physique dès leur initiation.
2025-10-19 18:08:05 +02: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
NisemonoQ
17c6475397 Minor - Bullet Spawning Method
La méthode est quasiment finie, il reste juste un pb au niveau de l'objet/la classe à appeler.
2025-10-17 17:13:48 +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
f57f6b8832 Minor - Ajout de la logique de Projectile au PlayerPawn
Le playerPawn possède une fonction qui pourra appeler le script de projectile.
Prochaine étape, complétion du système de Projectile.
2025-10-17 15:27:19 +02:00
NisemonoQ
8733dfd87f Merge branch 'main' into Bullet 2025-10-17 14:02:35 +02:00
NisemonoQ
df25b61b8f Merge branch 'Bullet' 2025-10-17 14:01:37 +02:00
NisemonoQ
c844a8a896 Initialize Projectile FrameWork
Ajout des bases (OnHit et Tir) du Projectile.

Commencement de la prise en compte des différentes collisions possibles dans le jeu.
2025-10-17 01:07:50 +02:00
NisemonoQ
f65171d5c2 Merge branch 'main' into Bullet 2025-10-17 00:17:22 +02:00
20 changed files with 654 additions and 157 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,65 @@ ConnectionType=USBOnly
bUseManualIPAddress=False
ManualIPAddress=
[CoreRedirects]
+ClassRedirects=(OldName="/Script/M4_CPP.M4_CentipedeController",NewName="/Script/M4_CPP.M4_CentipedeController")
+FunctionRedirects=(OldName="/Script/M4_CPP.M4_CentipedeController.OnSegmentDestroyed",NewName="/Script/M4_CPP.M4_CentipedeController.OnSegmentHit")
[/Script/Engine.CollisionProfile]
-Profiles=(Name="NoCollision",CollisionEnabled=NoCollision,ObjectTypeName="WorldStatic",CustomResponses=((Channel="Visibility",Response=ECR_Ignore),(Channel="Camera",Response=ECR_Ignore)),HelpMessage="No collision",bCanModify=False)
-Profiles=(Name="BlockAll",CollisionEnabled=QueryAndPhysics,ObjectTypeName="WorldStatic",CustomResponses=,HelpMessage="WorldStatic object that blocks all actors by default. All new custom channels will use its own default response. ",bCanModify=False)
-Profiles=(Name="OverlapAll",CollisionEnabled=QueryOnly,ObjectTypeName="WorldStatic",CustomResponses=((Channel="WorldStatic",Response=ECR_Overlap),(Channel="Pawn",Response=ECR_Overlap),(Channel="Visibility",Response=ECR_Overlap),(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. ",bCanModify=False)
-Profiles=(Name="BlockAllDynamic",CollisionEnabled=QueryAndPhysics,ObjectTypeName="WorldDynamic",CustomResponses=,HelpMessage="WorldDynamic object that blocks all actors by default. All new custom channels will use its own default response. ",bCanModify=False)
-Profiles=(Name="OverlapAllDynamic",CollisionEnabled=QueryOnly,ObjectTypeName="WorldDynamic",CustomResponses=((Channel="WorldStatic",Response=ECR_Overlap),(Channel="Pawn",Response=ECR_Overlap),(Channel="Visibility",Response=ECR_Overlap),(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="WorldDynamic object that overlaps all actors by default. All new custom channels will use its own default response. ",bCanModify=False)
-Profiles=(Name="IgnoreOnlyPawn",CollisionEnabled=QueryOnly,ObjectTypeName="WorldDynamic",CustomResponses=((Channel="Pawn",Response=ECR_Ignore),(Channel="Vehicle",Response=ECR_Ignore)),HelpMessage="WorldDynamic object that ignores Pawn and Vehicle. All other channels will be set to default.",bCanModify=False)
-Profiles=(Name="OverlapOnlyPawn",CollisionEnabled=QueryOnly,ObjectTypeName="WorldDynamic",CustomResponses=((Channel="Pawn",Response=ECR_Overlap),(Channel="Vehicle",Response=ECR_Overlap),(Channel="Camera",Response=ECR_Ignore)),HelpMessage="WorldDynamic object that overlaps Pawn, Camera, and Vehicle. All other channels will be set to default. ",bCanModify=False)
-Profiles=(Name="Pawn",CollisionEnabled=QueryAndPhysics,ObjectTypeName="Pawn",CustomResponses=((Channel="Visibility",Response=ECR_Ignore)),HelpMessage="Pawn object. Can be used for capsule of any playerable character or AI. ",bCanModify=False)
-Profiles=(Name="Spectator",CollisionEnabled=QueryOnly,ObjectTypeName="Pawn",CustomResponses=((Channel="WorldStatic",Response=ECR_Block),(Channel="Pawn",Response=ECR_Ignore),(Channel="Visibility",Response=ECR_Ignore),(Channel="WorldDynamic",Response=ECR_Ignore),(Channel="Camera",Response=ECR_Ignore),(Channel="PhysicsBody",Response=ECR_Ignore),(Channel="Vehicle",Response=ECR_Ignore),(Channel="Destructible",Response=ECR_Ignore)),HelpMessage="Pawn object that ignores all other actors except WorldStatic.",bCanModify=False)
-Profiles=(Name="CharacterMesh",CollisionEnabled=QueryOnly,ObjectTypeName="Pawn",CustomResponses=((Channel="Pawn",Response=ECR_Ignore),(Channel="Vehicle",Response=ECR_Ignore),(Channel="Visibility",Response=ECR_Ignore)),HelpMessage="Pawn object that is used for Character Mesh. All other channels will be set to default.",bCanModify=False)
-Profiles=(Name="PhysicsActor",CollisionEnabled=QueryAndPhysics,ObjectTypeName="PhysicsBody",CustomResponses=,HelpMessage="Simulating actors",bCanModify=False)
-Profiles=(Name="Destructible",CollisionEnabled=QueryAndPhysics,ObjectTypeName="Destructible",CustomResponses=,HelpMessage="Destructible actors",bCanModify=False)
-Profiles=(Name="InvisibleWall",CollisionEnabled=QueryAndPhysics,ObjectTypeName="WorldStatic",CustomResponses=((Channel="Visibility",Response=ECR_Ignore)),HelpMessage="WorldStatic object that is invisible.",bCanModify=False)
-Profiles=(Name="InvisibleWallDynamic",CollisionEnabled=QueryAndPhysics,ObjectTypeName="WorldDynamic",CustomResponses=((Channel="Visibility",Response=ECR_Ignore)),HelpMessage="WorldDynamic object that is invisible.",bCanModify=False)
-Profiles=(Name="Trigger",CollisionEnabled=QueryOnly,ObjectTypeName="WorldDynamic",CustomResponses=((Channel="WorldStatic",Response=ECR_Overlap),(Channel="Pawn",Response=ECR_Overlap),(Channel="Visibility",Response=ECR_Ignore),(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="WorldDynamic object that is used for trigger. All other channels will be set to default.",bCanModify=False)
-Profiles=(Name="Ragdoll",CollisionEnabled=QueryAndPhysics,ObjectTypeName="PhysicsBody",CustomResponses=((Channel="Pawn",Response=ECR_Ignore),(Channel="Visibility",Response=ECR_Ignore)),HelpMessage="Simulating Skeletal Mesh Component. All other channels will be set to default.",bCanModify=False)
-Profiles=(Name="Vehicle",CollisionEnabled=QueryAndPhysics,ObjectTypeName="Vehicle",CustomResponses=,HelpMessage="Vehicle object that blocks Vehicle, WorldStatic, and WorldDynamic. All other channels will be set to default.",bCanModify=False)
-Profiles=(Name="UI",CollisionEnabled=QueryOnly,ObjectTypeName="WorldDynamic",CustomResponses=((Channel="WorldStatic",Response=ECR_Overlap),(Channel="Pawn",Response=ECR_Overlap),(Channel="Visibility",Response=ECR_Block),(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. ",bCanModify=False)
+Profiles=(Name="NoCollision",CollisionEnabled=NoCollision,bCanModify=False,ObjectTypeName="WorldStatic",CustomResponses=((Channel="Visibility",Response=ECR_Ignore),(Channel="Camera",Response=ECR_Ignore)),HelpMessage="No collision")
+Profiles=(Name="BlockAll",CollisionEnabled=QueryAndPhysics,bCanModify=False,ObjectTypeName="WorldStatic",CustomResponses=,HelpMessage="WorldStatic object that blocks all actors by default. All new custom channels will use its own default response. ")
+Profiles=(Name="OverlapAll",CollisionEnabled=QueryOnly,bCanModify=False,ObjectTypeName="WorldStatic",CustomResponses=((Channel="WorldStatic",Response=ECR_Overlap),(Channel="Pawn",Response=ECR_Overlap),(Channel="Visibility",Response=ECR_Overlap),(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="BlockAllDynamic",CollisionEnabled=QueryAndPhysics,bCanModify=False,ObjectTypeName="WorldDynamic",CustomResponses=,HelpMessage="WorldDynamic object that blocks all actors by default. All new custom channels will use its own default response. ")
+Profiles=(Name="OverlapAllDynamic",CollisionEnabled=QueryOnly,bCanModify=False,ObjectTypeName="WorldDynamic",CustomResponses=((Channel="WorldStatic",Response=ECR_Overlap),(Channel="Pawn",Response=ECR_Overlap),(Channel="Visibility",Response=ECR_Overlap),(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="WorldDynamic object that overlaps all actors by default. All new custom channels will use its own default response. ")
+Profiles=(Name="IgnoreOnlyPawn",CollisionEnabled=QueryOnly,bCanModify=False,ObjectTypeName="WorldDynamic",CustomResponses=((Channel="Pawn",Response=ECR_Ignore),(Channel="Vehicle",Response=ECR_Ignore)),HelpMessage="WorldDynamic object that ignores Pawn and Vehicle. All other channels will be set to default.")
+Profiles=(Name="OverlapOnlyPawn",CollisionEnabled=QueryOnly,bCanModify=False,ObjectTypeName="WorldDynamic",CustomResponses=((Channel="Pawn",Response=ECR_Overlap),(Channel="Vehicle",Response=ECR_Overlap),(Channel="Camera",Response=ECR_Ignore)),HelpMessage="WorldDynamic object that overlaps Pawn, Camera, and Vehicle. All other channels will be set to default. ")
+Profiles=(Name="Pawn",CollisionEnabled=QueryAndPhysics,bCanModify=False,ObjectTypeName="Pawn",CustomResponses=((Channel="Visibility",Response=ECR_Ignore)),HelpMessage="Pawn object. Can be used for capsule of any playerable character or AI. ")
+Profiles=(Name="Spectator",CollisionEnabled=QueryOnly,bCanModify=False,ObjectTypeName="Pawn",CustomResponses=((Channel="WorldStatic"),(Channel="Pawn",Response=ECR_Ignore),(Channel="Visibility",Response=ECR_Ignore),(Channel="WorldDynamic",Response=ECR_Ignore),(Channel="Camera",Response=ECR_Ignore),(Channel="PhysicsBody",Response=ECR_Ignore),(Channel="Vehicle",Response=ECR_Ignore),(Channel="Destructible",Response=ECR_Ignore)),HelpMessage="Pawn object that ignores all other actors except WorldStatic.")
+Profiles=(Name="CharacterMesh",CollisionEnabled=QueryOnly,bCanModify=False,ObjectTypeName="Pawn",CustomResponses=((Channel="Pawn",Response=ECR_Ignore),(Channel="Vehicle",Response=ECR_Ignore),(Channel="Visibility",Response=ECR_Ignore)),HelpMessage="Pawn object that is used for Character Mesh. All other channels will be set to default.")
+Profiles=(Name="PhysicsActor",CollisionEnabled=QueryAndPhysics,bCanModify=False,ObjectTypeName="PhysicsBody",CustomResponses=,HelpMessage="Simulating actors")
+Profiles=(Name="Destructible",CollisionEnabled=QueryAndPhysics,bCanModify=False,ObjectTypeName="Destructible",CustomResponses=,HelpMessage="Destructible actors")
+Profiles=(Name="InvisibleWall",CollisionEnabled=QueryAndPhysics,bCanModify=False,ObjectTypeName="WorldStatic",CustomResponses=((Channel="Visibility",Response=ECR_Ignore)),HelpMessage="WorldStatic object that is invisible.")
+Profiles=(Name="InvisibleWallDynamic",CollisionEnabled=QueryAndPhysics,bCanModify=False,ObjectTypeName="WorldDynamic",CustomResponses=((Channel="Visibility",Response=ECR_Ignore)),HelpMessage="WorldDynamic object that is invisible.")
+Profiles=(Name="Trigger",CollisionEnabled=QueryOnly,bCanModify=False,ObjectTypeName="WorldDynamic",CustomResponses=((Channel="WorldStatic",Response=ECR_Overlap),(Channel="Pawn",Response=ECR_Overlap),(Channel="Visibility",Response=ECR_Ignore),(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="WorldDynamic object that is used for trigger. All other channels will be set to default.")
+Profiles=(Name="Ragdoll",CollisionEnabled=QueryAndPhysics,bCanModify=False,ObjectTypeName="PhysicsBody",CustomResponses=((Channel="Pawn",Response=ECR_Ignore),(Channel="Visibility",Response=ECR_Ignore)),HelpMessage="Simulating Skeletal Mesh Component. All other channels will be set to default.")
+Profiles=(Name="Vehicle",CollisionEnabled=QueryAndPhysics,bCanModify=False,ObjectTypeName="Vehicle",CustomResponses=,HelpMessage="Vehicle object that blocks Vehicle, WorldStatic, and WorldDynamic. All other channels will be set to default.")
+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. ")
+DefaultChannelResponses=(Channel=ECC_GameTraceChannel1,DefaultResponse=ECR_Block,bTraceType=False,bStaticObject=False,Name="Projectile")
-ProfileRedirects=(OldName="BlockingVolume",NewName="InvisibleWall")
-ProfileRedirects=(OldName="InterpActor",NewName="IgnoreOnlyPawn")
-ProfileRedirects=(OldName="StaticMeshComponent",NewName="BlockAllDynamic")
-ProfileRedirects=(OldName="SkeletalMeshActor",NewName="PhysicsActor")
-ProfileRedirects=(OldName="InvisibleActor",NewName="InvisibleWallDynamic")
+ProfileRedirects=(OldName="BlockingVolume",NewName="InvisibleWall")
+ProfileRedirects=(OldName="InterpActor",NewName="IgnoreOnlyPawn")
+ProfileRedirects=(OldName="StaticMeshComponent",NewName="BlockAllDynamic")
+ProfileRedirects=(OldName="SkeletalMeshActor",NewName="PhysicsActor")
+ProfileRedirects=(OldName="InvisibleActor",NewName="InvisibleWallDynamic")
-CollisionChannelRedirects=(OldName="Static",NewName="WorldStatic")
-CollisionChannelRedirects=(OldName="Dynamic",NewName="WorldDynamic")
-CollisionChannelRedirects=(OldName="VehicleMovement",NewName="Vehicle")
-CollisionChannelRedirects=(OldName="PawnMovement",NewName="Pawn")
+CollisionChannelRedirects=(OldName="Static",NewName="WorldStatic")
+CollisionChannelRedirects=(OldName="Dynamic",NewName="WorldDynamic")
+CollisionChannelRedirects=(OldName="VehicleMovement",NewName="Vehicle")
+CollisionChannelRedirects=(OldName="PawnMovement",NewName="Pawn")

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -10,21 +10,42 @@ AM4_CentipedeBody::AM4_CentipedeBody()
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()->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);
}
}
}

View File

@@ -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<USceneComponent>(TEXT("RootComponent"));
RootComponent = Root;
SegmentRemainingCount = BodyCount;
}
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>(
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()
{
GM_REF_PTR = Cast<AM4_Gamemode>(GetWorld()->GetAuthGameMode());
if (!GM_REF_PTR) return;
UE_LOG(LogTemp, Warning, TEXT("Controller spawn location: X=%.2f, Y=%.2f, Z=%.2f"),
FVector SpawnLocation = FVector(
GM_REF_PTR->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,104 +133,134 @@ 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<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();
}
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;
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;
if (!GM_REF_PTR)
{
GM_REF_PTR = Cast<AM4_Gamemode>(GetWorld()->GetAuthGameMode());
if (!GM_REF_PTR) return false;
}
const float LeftBound = GM->MushroomSpawnBounds.Min.Y;
const float RightBound = GM->MushroomSpawnBounds.Max.Y;
const float LeftBound = GM_REF_PTR->MushroomSpawnBounds.Min.Y;
const float RightBound = GM_REF_PTR->MushroomSpawnBounds.Max.Y;
const float MinRows = GM_REF_PTR->MushroomSpawnBounds.Min.X;
const float MaxRows = GM_REF_PTR->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<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 AM4_CentipedeController::GetSegmentDirection(AM4_CentipedeBody* Segment)
FVector2D UM4_CentipedeController::GetSegmentDirection(AM4_CentipedeBody* Segment)
{
if (SegmentDirections.Contains(Segment))
{
@@ -169,7 +269,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 +277,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 +293,55 @@ void AM4_CentipedeController::UpdateHeadStatus()
}
}
void AM4_CentipedeController::OnSegmentDestroyed(AM4_CentipedeBody* DestroyedSegment)
void UM4_CentipedeController::OnSegmentHit(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());
// disable collision and hide the destroyed segment
DestroyedSegment->GetStaticMeshComponent()->SetCollisionEnabled(ECollisionEnabled::NoCollision);
DestroyedSegment->SetActorHiddenInGame(true);
// Increase player score
if (!GM_REF_PTR)
{
GM_REF_PTR = Cast<AM4_Gamemode>(GetWorld()->GetAuthGameMode());
if (!GM_REF_PTR) return;
}
GM_REF_PTR->AddScore(100);
SpawnMushroomsAtSegmentDeathPos(DestroyedSegment->GetActorLocation());
// Decresase the remaining segment count and check if all segments are destroyed
SegmentRemainingCount--;
if (SegmentRemainingCount <= 0)
{
// TODO: Trigger level complete or respawn centipede
UE_LOG(M4_CPP, Warning, TEXT("All centipede segments destroyed!"));
}
}
void UM4_CentipedeController::SpawnMushroomsAtSegmentDeathPos(FVector Location)
{
FVector Offset = FVector(0.f, FMath::RandRange(-CellSize, CellSize), 0.f);
FVector SpawnLocation = Location + Offset;
GetWorld()->SpawnActor<AM4_Mushroom>(
AM4_Mushroom::StaticClass(),
SpawnLocation,
FRotator::ZeroRotator
);
}

View File

@@ -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>(
AM4_CentipedeController::StaticClass(),
CentipedeSpawnLocation,
FRotator::ZeroRotator
);
if (CentipedeController)
UM4_CentipedeController* Controller = GetWorld()->GetSubsystem<UM4_CentipedeController>();
if (Controller)
{
CentipedeController->BodyCount = CentipedeBodyCount;
CentipedeController->CellSize = CellSize;
Controller->BodyCount = CentipedeBodyCount;
Controller->CellSize = CellSize;
Controller->StartCentipede(CentipedeSpawnLocation);
}
}

View File

@@ -6,6 +6,7 @@
#include "M4_CTP_Macros.h"
#include "Kismet/GameplayStatics.h"
#include "M4_Gamemode.h"
#include "M4_Projectile.h"
// Sets default values
@@ -31,13 +32,29 @@ 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 block all
GetStaticMeshComponent()->SetCollisionProfileName(TEXT("OverlapAll"));
}
void AM4_Mushroom::BeginPlay()
{
MushLife = 2;
DestructionHit = 0;
Super::BeginPlay();
}
void AM4_Mushroom::OnHit(UPrimitiveComponent* HitComp,AActor* OtherActor,UPrimitiveComponent* OtherComp,FVector NormalImpulse,const FHitResult& Hit)
{
AM4_Projectile* Projectile = Cast<AM4_Projectile>(OtherActor);
if (!Projectile)
{
return;
}
if (DestructionHit++ == MushLife)
{
Destroy();
}
}

View File

@@ -1,8 +1,9 @@
#include "M4_PlayerPawn.h"
#include "EnhancedInputComponent.h"
#include "M4_Gamemode.h"
#include "M4_LOG.h"
#include "M4_Projectile.h"
#include "GameFramework/PlayerController.h"
#include "Camera/CameraComponent.h"
AM4_PlayerPawn::AM4_PlayerPawn()
{
@@ -16,10 +17,16 @@ AM4_PlayerPawn::AM4_PlayerPawn()
MeshComponent = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("MeshComponent"));
MeshComponent->SetupAttachment(RootComponent);
MeshComponent->SetMobility(EComponentMobility::Movable);
MeshComponent->SetCollisionEnabled(ECollisionEnabled::QueryAndPhysics);
MeshComponent->SetCollisionProfileName(UCollisionProfile::Pawn_ProfileName);
MeshComponent->SetRelativeScale3D(FVector(1.0f, MeshScale.Y, MeshScale.X));
MeshComponent->SetCollisionEnabled(ECollisionEnabled::QueryAndPhysics);
MeshComponent->SetCollisionObjectType(ECC_Pawn);
MeshComponent->SetCollisionResponseToAllChannels(ECR_Block);
MeshComponent->SetGenerateOverlapEvents(true);
MeshComponent->OnComponentBeginOverlap.AddDynamic(this,&AM4_PlayerPawn::OnPlayerOverlap);
MeshComponent->SetRelativeScale3D(FVector(1.0f, MeshScale.Y, MeshScale.X));
static ConstructorHelpers::FObjectFinder<UStaticMesh> DefaultMeshRef(TEXT("/Game/CTP/04_Mesh/SM_Cube.SM_Cube"));
if (DefaultMeshRef.Succeeded())
@@ -32,12 +39,18 @@ AM4_PlayerPawn::AM4_PlayerPawn()
{
MoveAction = MoveActionRef.Object;
}
static ConstructorHelpers::FObjectFinder<UInputAction> ShootActionRef(TEXT("/Game/CTP/03_Input/IA_Shoot.IA_Shoot"));
if (ShootActionRef.Succeeded())
{
ShootAction = ShootActionRef.Object;
}
}
void AM4_PlayerPawn::BeginPlay()
{
Super::BeginPlay();
SetActorLocation(FVector(0.0f, 0.0f, -400.0f));
SetActorLocation(FVector(-400.0f, 0.0f, -400.0f));
}
void AM4_PlayerPawn::Tick(float DeltaTime)
@@ -51,8 +64,6 @@ void AM4_PlayerPawn::Tick(float DeltaTime)
NewLocation.Y = FMath::Clamp(NewLocation.Y, GM->Bounds.Min.Y, GM->Bounds.Max.Y);
SetActorLocation(NewLocation);
}
}
void AM4_PlayerPawn::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
@@ -64,10 +75,71 @@ void AM4_PlayerPawn::SetupPlayerInputComponent(UInputComponent* PlayerInputCompo
{
Input->BindAction(MoveAction, ETriggerEvent::Triggered, this, &AM4_PlayerPawn::Move);
}
if (ShootAction)
{
Input->BindAction(ShootAction, ETriggerEvent::Triggered, this, &AM4_PlayerPawn::Shoot);
}
}
}
void AM4_PlayerPawn::Move(const FInputActionInstance& Instance)
{
LastMoveValue = Instance.GetValue().Get<FVector2D>().GetSafeNormal();
}
void AM4_PlayerPawn::Shoot(const FInputActionInstance& Inst)
{
if (Proj)
{
UWorld* World = GetWorld();
if (World)
{
FActorSpawnParameters SpawnParams;
SpawnParams.Owner = this;
const FVector InitialLocation = FVector(-400.f, GetActorLocation().Y, GetActorLocation().Z);
const FRotator InitialRotation = FRotator(0.f);
AM4_Projectile* Projectile = World->SpawnActor<AM4_Projectile>(Proj, InitialLocation, InitialRotation, SpawnParams);
if (Projectile)
{
Projectile->FireInDir(InitialLocation);
}
}
}
};
void AM4_PlayerPawn::OnPlayerOverlap(
UPrimitiveComponent* OverlappedComponent,
AActor* OtherActor,
UPrimitiveComponent* OtherComp,
int32 OtherBodyIndex,
bool bFromSweep,
const FHitResult& SweepResult)
{
if (!OtherActor || OtherActor == this || bIsInvincible)
{
return;
}
AM4_CentipedeBody* CentipedeSegment = Cast<AM4_CentipedeBody>(OtherActor);
if (CentipedeSegment)
{
UE_LOG(M4_CPP, Warning, TEXT("Player collided with Centipede Segment!"));
if (AM4_Gamemode* GM = Cast<AM4_Gamemode>(GetWorld()->GetAuthGameMode()))
{
GM->LoseLife();
UE_LOG(M4_CPP, Warning, TEXT("Player Lives Remaining: %d"), GM->GetLives());
bIsInvincible = true;
GetWorldTimerManager().SetTimer(InvincibleTimerHandle,this, &AM4_PlayerPawn::EndInvincibility, InvinciblityDuration, false);
}
}
}
void AM4_PlayerPawn::EndInvincibility()
{
bIsInvincible = false;
UE_LOG(M4_CPP, Warning, TEXT("Player invincibility ended."));
}

View File

@@ -0,0 +1,108 @@
#include "M4_Projectile.h"
#include "Components/MeshComponent.h"
#include "M4_Gamemode.h"
#include "M4_Mushroom.h"
#include "Components/SphereComponent.h"
// Sets default values
AM4_Projectile::AM4_Projectile()
{
PrimaryActorTick.bCanEverTick = true;
// Crée d'abord le composant de collision comme root
CollisionComp = CreateDefaultSubobject<USphereComponent>(TEXT("SphereComponent"));
CollisionComp->InitSphereRadius(15.0f);
CollisionComp->SetCollisionProfileName(TEXT("Projectile"));
CollisionComp->OnComponentBeginOverlap.AddDynamic(this, &AM4_Projectile::OnOverlap);
CollisionComp->SetGenerateOverlapEvents(true);
RootComponent = CollisionComp;
// Ensuite attache le mesh au composant de collision
ProjectileMeshComponent = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("ProjectileMeshComponent"));
ProjectileMeshComponent->SetupAttachment(RootComponent);
ProjectileMeshComponent->SetCollisionEnabled(ECollisionEnabled::NoCollision); // Le mesh ne gère pas la collision
static ConstructorHelpers::FObjectFinder<UStaticMesh> Mesh(TEXT("/Game/CTP/04_Mesh/SM_Projectile.SM_Projectile"));
if(Mesh.Succeeded())
{
ProjectileMeshComponent->SetStaticMesh(Mesh.Object);
}
static ConstructorHelpers::FObjectFinder<UMaterial> Material(TEXT("/Game/CTP/05_Material/M_Player.M_Player"));
if (Material.Succeeded())
{
ProjectileMat = UMaterialInstanceDynamic::Create(Material.Object, ProjectileMeshComponent);
}
ProjectileMeshComponent->SetMaterial(0, ProjectileMat);
ProjectileMeshComponent->SetRelativeScale3D(FVector(.3f, .3f, .35f));
ProjectileMeshComponent->SetMobility(EComponentMobility::Movable);
ProjectileMeshComponent->SetRelativeLocation(FVector::ZeroVector);
// Configure le ProjectileMovementComponent
ProjectileMovementComponent = CreateDefaultSubobject<UProjectileMovementComponent>(TEXT("ProjectileMovementComponent"));
ProjectileMovementComponent->SetUpdatedComponent(CollisionComp); // Maintenant CollisionComp existe
ProjectileMovementComponent->InitialSpeed = 380.f;
ProjectileMovementComponent->MaxSpeed = 380.f;
ProjectileMovementComponent->bRotationFollowsVelocity = false;
ProjectileMovementComponent->bShouldBounce = false;
ProjectileMovementComponent->ProjectileGravityScale = 0.0f;
InitialLifeSpan = 10.f;
}
///FAIRE SUPER GAFFE AUX INDENTATIONS ET LES FOR LOOPS sont à bien faire.
///Ce qui est critique dans notre code doit être vraiment bien mis en évidence sans être obscurci par la boucle.
///Gestion des pointeurs à revoir, lisibilité des fonctions critiques
void AM4_Projectile::BeginPlay()
{
Super::BeginPlay();
InitialLoc = GetActorLocation();
}
void AM4_Projectile::OnOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
{
UE_LOG(LogTemp, Warning, TEXT("Projectile OVERLAP: %s"), *OtherActor->GetName());
if (!OtherActor || OtherActor == this || !OtherComp)
{
return;
}
AM4_Mushroom* Mushroom = Cast<AM4_Mushroom>(OtherActor);
if (Mushroom)
{
UE_LOG(LogTemp, Warning, TEXT("OVERLAP MUSHROOM!"));
FVector NormalImpulse = FVector::ZeroVector;
Mushroom->OnHit(OverlappedComponent, this, OtherComp, NormalImpulse, SweepResult);
Destroy();
return;
}
AM4_CentipedeBody* CentipedeBody = Cast<AM4_CentipedeBody>(OtherActor);
if (CentipedeBody)
{
UE_LOG(LogTemp, Warning, TEXT("OVERLAP CENTIPEDE BODY!"));
UM4_CentipedeController* CentipedeController = GetWorld()->GetSubsystem<UM4_CentipedeController>();
if (CentipedeController)
{
CentipedeController->OnSegmentHit(CentipedeBody);
}
Destroy();
}
}
void AM4_Projectile::FireInDir(const FVector& ShootDir)
{
SetActorLocation(InitialLoc);
ProjectileMovementComponent->Velocity.Z = -1 * ((ShootDir.Z + 380.f) * ProjectileMovementComponent->InitialSpeed);
ProjectileMovementComponent->Velocity.X = 0.f;
}
// Called every frame
void AM4_Projectile::Tick(float DeltaTime)
{
Super::Tick( DeltaTime);
}

View File

@@ -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;
};

View File

@@ -1,50 +1,65 @@
#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;
void OnSegmentDestroyed(AM4_CentipedeBody* DestroyedSegment);
UFUNCTION(BlueprintCallable, Category = "Centipede")
void OnSegmentHit(AM4_CentipedeBody* DestroyedSegment);
private:
UPROPERTY()
TArray<AM4_CentipedeBody*> BodySegments;
UPROPERTY()
USceneComponent* Root;
TArray<TArray<FVector>> SegmentHistory; // Historique pour chaque segment
int32 MaxHistorySize = 200;
int8 SegmentRemainingCount = 0;
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();
void SpawnMushroomsAtSegmentDeathPos(FVector Location);
bool CheckCollision(AM4_CentipedeBody* Segment, FVector2D Direction);
FVector2D GetSegmentDirection(AM4_CentipedeBody* Segment);
void SetSegmentDirection(AM4_CentipedeBody* Segment, FVector2D Direction);
};
UPROPERTY()
class AM4_Gamemode* GM_REF_PTR;
};

View File

@@ -67,7 +67,7 @@ private:
int32 CentipedeBodyCount = 10;
UPROPERTY()
TObjectPtr<AM4_CentipedeController> CentipedeController;
TObjectPtr<UM4_CentipedeController> CentipedeController;
int Score = 0;
int Lives = 3;

View File

@@ -13,9 +13,14 @@ class M4_CPP_API AM4_Mushroom : public AStaticMeshActor
GENERATED_BODY()
public:
// Sets default values for this pawn's properties
AM4_Mushroom();
int MushLife;
int DestructionHit = 0;
UFUNCTION()
void OnHit(UPrimitiveComponent* HitComp,AActor* OtherActor, UPrimitiveComponent* OtherComp, FVector NormalImpulse,const FHitResult& Hit);
protected:
virtual void BeginPlay() override;
};

View File

@@ -1,5 +1,6 @@
#pragma once
#include "M4_Projectile.h"
#include "CoreMinimal.h"
#include "GameFramework/Pawn.h"
#include "InputAction.h"
@@ -11,6 +12,7 @@ UCLASS()
class AM4_PlayerPawn : public APawn
{
GENERATED_BODY()
public:
AM4_PlayerPawn();
@@ -18,6 +20,19 @@ public:
virtual void Tick(float DeltaTime) override;
virtual void SetupPlayerInputComponent(UInputComponent* PlayerInputComponent) override;
void Move(const FInputActionInstance& Instance);
void Shoot(const FInputActionInstance& Inst);
UPROPERTY(VisibleAnywhere)
TSubclassOf<AM4_Projectile> Proj = AM4_Projectile::StaticClass();
UFUNCTION()
void OnPlayerOverlap(
UPrimitiveComponent* OverlappedComponent,
AActor* OtherActor,
UPrimitiveComponent* OtherComp,
int32 OtherBodyIndex,
bool bFromSweep,
const FHitResult& SweepResult);
protected:
@@ -27,7 +42,19 @@ protected:
UPROPERTY()
UInputAction* MoveAction;
UPROPERTY()
UInputAction* ShootAction;
float MoveSpeed = 500.f;
FVector2D MeshScale = FVector2D(0.6f, 0.5f);
FVector2D LastMoveValue = FVector2D::ZeroVector;
UPROPERTY()
bool bIsInvincible = false;
UPROPERTY()
float InvinciblityDuration = 2.0f;
FTimerHandle InvincibleTimerHandle;
void EndInvincibility();
};

View File

@@ -0,0 +1,44 @@
#include "GameFramework/ProjectileMovementComponent.h"
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "M4_Projectile.generated.h"
class USphereComponent;
class UMeshComponent;
UCLASS()
class M4_CPP_API AM4_Projectile : public AActor
{
GENERATED_BODY()
public:
AM4_Projectile();
virtual void Tick( float DeltaTime ) override;
virtual void BeginPlay() override;
bool CollisionCheck = false;
FVector InitialLoc;
FVector NewLoc;
UPROPERTY(VisibleDefaultsOnly, Category = Projectile)
USphereComponent* CollisionComp;
UPROPERTY(VisibleAnywhere, Category = Movement)
UProjectileMovementComponent* ProjectileMovementComponent;
UPROPERTY(VisibleDefaultsOnly, Category = Projectile)
UStaticMeshComponent* ProjectileMeshComponent;
UPROPERTY(VisibleDefaultsOnly, Category = Projectile)
UMaterialInstanceDynamic* ProjectileMat;
UFUNCTION()
void OnOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult);
void FireInDir(const FVector& ShootDir);
};