Beau résultat, félicitations...
Il l'a fait...
Tetris sur Unreal avec une statue de Poutine
Génie !
au fait je savais pas que t'étais une brute du modeling Oo
Merci pour tes compliments. Au fait ton projet impossible à finir, ça avance ?
Je m'y suis jamais mis au projet impossible j'ai juste pris la température pour avoir vos avis (j'en ai conclu que ça valait pas le coup).
Je remate tes vidéos du tetris unreal et... bordel tu gères y'a de l'algo là dessous bravo.
Ci jontil cousin. Wallah sur li coran ti mi fi plisir.
Non c'est assez simple, par conte c'est un peu de boulot. Surtout la partie détection de collision avec avec cubes + animation ou non d'effacement de ligne(s) et effondrement des cubes du dessus.
La fonction de déplacement de shape :
Si collision et forme posée au sol :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65 void ACubesManager::MoveCubes(Direction Dir) { int32 right_boundary, left_boundary, factor_y = 0, factor_z = 0; ACube* cube_movement[4]; right_boundary = RightBoundary - CubeWidth / 4; left_boundary = LeftBoundary + CubeWidth / 4; switch (Dir) //TODO utiliser ENUM { case Direction::LEFT: factor_y = -1; factor_z = 0; break; case Direction::RIGHT: factor_y = 1; factor_z = 0; break; case Direction::DOWN: factor_y = 0; factor_z = -1; break; } for (int32 i = 0; i <= 3; i++) { CubesCurrentShapeArrayTest[i] = CubesCurrentShapeArray[i]; if (!CubesNextShapeArray[i]) { return; }; cube_movement[i] = CubesNextShapeArray[i]; // doit stocker un pointeur sur cube, alors pour ne pas avoir de bug on stocke chaque cube de CubesNextShapeArray[] cube_movement[i]->y = factor_y * (CubeWidth + SpaceInterCubes); cube_movement[i]->z = factor_z * (CubeWidth + SpaceInterCubes); CubesCurrentShapeArrayTest[i]->y = CubesCurrentShapeArrayTest[i]->GetActorLocation().Y + factor_y * (CubeWidth + SpaceInterCubes); CubesCurrentShapeArrayTest[i]->z = CubesCurrentShapeArrayTest[i]->GetActorLocation().Z + factor_z * (CubeWidth + SpaceInterCubes); } if (!ShapeCollidesWithMatrix(CubesCurrentShapeArrayTest, Dir)) { // si non collision for (int32 i = 0; i <= 3; i++) { if (Dir == Direction::DOWN) { CubesHaveJustSpawned = false; } CubesCurrentShapeArray[i]->SetActorLocation(CubesCurrentShapeArray[i]->GetActorLocation() + FVector(0.f, cube_movement[i]->y, cube_movement[i]->z)); } } else { // si collision if (Dir == Direction::DOWN) { // Si une forme est posée au sol if (CubesHaveJustSpawned) { //Partie perdue ! GameOver(); return; } if (UpdateMatrix(CubesCurrentShapeArrayTest)) { ClearMatrixRows(); } } } }
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36 bool ACubesManager::UpdateMatrix(ACube* ShapeArr[]) { // intégre les 4 nouveaux cubes dans la matrices après collision au sol int32 top_cube_index = TopCubeIndex; int32 far_left_cube_index = 10; int32 far_right_cube_index = 1; for (int32 k = 0; k < 4; k++) { ShapeArr[k]->SetTrailParticleInactive.Broadcast(); CubesMatrix[ShapeArr[k]->YMat][ShapeArr[k]->ZMat].IsACube = true; CubesMatrix[ShapeArr[k]->YMat][ShapeArr[k]->ZMat].Cube = ShapeArr[k]; if (ShapeArr[k]->ZMat > top_cube_index) { //on detecte la position Z du cube la plus grande top_cube_index = ShapeArr[k]->ZMat; } if (ShapeArr[k]->YMat > far_right_cube_index) { far_right_cube_index = ShapeArr[k]->YMat; } if (ShapeArr[k]->YMat < far_left_cube_index) { far_left_cube_index = ShapeArr[k]->YMat; } } TopCubeIndex = top_cube_index; if (TopCubeIndex >= 19 && far_right_cube_index > 3 && far_left_cube_index < 8) { GameOver(); return false; } NumCubesInMatrix += 4; //UE_LOG(LogTemp, Warning, TEXT("top cube index : %d"), TopCubeIndex); return true; }
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66 bool ACubesManager::ClearMatrixRows() { int32 cubes_compteur = 0, row_to_clear_start_index = 0; bool rows_indexes_to_clear_arr[4] = { false }; if (TopCubeIndex == 0) { return false; } for (int32 j = 1; j < TopCubeIndex + 1; j++) { for (int32 i = 1; i < NumCubesPerRow + 1; i++) { cubes_compteur += CubesMatrix[i][j].IsACube; } if (cubes_compteur == NumCubesPerRow) { if (row_to_clear_start_index == 0) { //si on en est à la premiere rangée pleine row_to_clear_start_index = j; // on indique l'index de la première rangée à vider } rows_indexes_to_clear_arr[j - row_to_clear_start_index] = true; if (j == row_to_clear_start_index + 3) { break; } } cubes_compteur = 0; } if (row_to_clear_start_index > 0) { //Si on a au moins une rangée à éliminer for (int32 j = row_to_clear_start_index; j < row_to_clear_start_index + 4; j++) { for (int32 i = 1; i < NumCubesPerRow + 1; i++) { if (rows_indexes_to_clear_arr[j - row_to_clear_start_index]) { CubesMatrix[i][j].Cube->MovementZTick = 1; CubesArray.Add(CubesMatrix[i][j].Cube); CubesToRemoveArray.Add(CubesMatrix[i][j].Cube);// va être utile pour l'animation dans le SetTimer() CubesToRemoveArray[CubesToRemoveArray.Num() - 1]->InitX = CubesMatrix[i][j].Cube->GetActorLocation().X; CubesToRemoveArray[CubesToRemoveArray.Num() - 1]->InitZ = CubesMatrix[i][j].Cube->GetActorLocation().Z; CubesMatrix[i][j].Cube = nullptr; CubesMatrix[i][j].IsACube = false; } } } } if (row_to_clear_start_index > 0) { return CollapseMatrix(row_to_clear_start_index, rows_indexes_to_clear_arr); }else { CubesCanBeMoved = true; SpawnCurrentShape(); SetRandNextShape(); SpawnNextShape(); return false; } }
L'animation d'effondrement de cubes après que une ou plusieurs lignes aient disparu :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83 bool ACubesManager::CollapseMatrix(int32 RowToClearStartIndex, bool RowsIndexesToClear[]) { GetWorld()->GetTimerManager().ClearTimer(MovingDownCubesHandle); int32 num_rows_to_collapse = 0; //utile pour savoir de combien chaque rangée de cube chute for (int32 j = RowToClearStartIndex; j < TopCubeIndex + 1; j++) { if (RowsIndexesToClear[j - RowToClearStartIndex] && j - RowToClearStartIndex < 4) { num_rows_to_collapse++; } else { for (int32 i = 1; i <= NumCubesPerRow; i++) { if (CubesMatrix[i][j].IsACube && num_rows_to_collapse > 0) { CubesMatrix[i][j].Cube->MovementZTick = 1; CubesMatrix[i][j - num_rows_to_collapse].Cube = CubesMatrix[i][j].Cube; CubesMatrix[i][j - num_rows_to_collapse].IsACube = true; CubesToCollapseArray.Add(CubesMatrix[i][j].Cube);// va être utile pour l'animation dans le SetTimer() CubesToCollapseArray[CubesToCollapseArray.Num() - 1]->NumRowsToCollapse = num_rows_to_collapse; CubesToCollapseArray[CubesToCollapseArray.Num() - 1]->InitZ = CubesMatrix[i][j].Cube->GetActorLocation().Z; CubesToCollapseArray[CubesToCollapseArray.Num() - 1]->InitX = CubesMatrix[i][j].Cube->GetActorLocation().X; //CubesMatrix[i][j].Cube->SetActorLocation(CubesMatrix[i][j].Cube->GetActorLocation() + FVector(0.f, 0.f, -(CubeWidth + SpaceInterCubes)*num_rows_to_collapse)); CubesMatrix[i][j].Cube = nullptr; CubesMatrix[i][j].IsACube = false; } } } } TopCubeIndex -= num_rows_to_collapse; NumCubesInMatrix -= NumCubesPerRow * num_rows_to_collapse; GameUILines += num_rows_to_collapse; switch (num_rows_to_collapse) { case 1: GameUIScore += (0.5*CubesHaveJustSpined * 100 + 100) * GameUILevel; break; case 2: GameUIScore += (0.5*CubesHaveJustSpined * 250 + 250) * GameUILevel; break; case 3: GameUIScore += (0.5*CubesHaveJustSpined * 500 + 500) * GameUILevel; break; case 4: GameUIScore += (0.5*CubesHaveJustSpined * 1000 + 1000) * GameUILevel; break; } UpdateBPScoreAndLines.Broadcast(); CubesCanBeMoved = false; if (CubesToCollapseArray.Num() < 40) { Delay = 3; }else if (CubesToCollapseArray.Num() >= 30 && CubesToCollapseArray.Num() < 70) { Delay = 2; }else { Delay = 1; } if (CubesToCollapseArray.Num() != 0) { GetWorld()->GetTimerManager().SetTimer(CollapseCubesRowsHandle, this, &ACubesManager::EaseCollapseCubesRows, DeltaTime, true); }else { SpawnCurrentShape(); SetRandNextShape(); SpawnNextShape(); SetMovingDownCubesTimer(DeltaTimeMoveCubesDown); CubesCanBeMoved = true; } GetWorld()->GetTimerManager().SetTimer(RemoveCubesRowsHandle, this, &ACubesManager::EaseRemoveCubesRows, DeltaTime, true); return true; }
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44 void ACubesManager::EaseCollapseCubesRows() { FVector actor_location; for (int32 i = 0; i < CubesToCollapseArray.Num(); i++) { if (CubesToCollapseArray[CubesToCollapseArray.Num() - 1]->MovementZTick > CollapseCubesRowsDuration) { if (i == CubesToCollapseArray.Num() - 1) { GlobalTick1 = 1; CubesToCollapseArray.Empty(); SpawnCurrentShape(); SetRandNextShape(); SpawnNextShape(); SetMovingDownCubesTimer(DeltaTimeMoveCubesDown); CubesCanBeMoved = true; Delay = 3; GetWorld()->GetTimerManager().ClearTimer(CollapseCubesRowsHandle); return; } }else { if (i * Delay <= GlobalTick1 - 1) { //mise en place d'un delay entre chaque animation de cube if (CubesToCollapseArray[i]->MovementZTick <= CollapseCubesRowsDuration) { actor_location = CubesToCollapseArray[i]->GetActorLocation(); actor_location.Z = EasePennerObject->EaseOutBounce(float(CubesToCollapseArray[i]->MovementZTick), CubesToCollapseArray[i]->InitZ, -(CubeWidth + SpaceInterCubes)*CubesToCollapseArray[i]->NumRowsToCollapse, (float)CollapseCubesRowsDuration); //TODO rendre CubeWidth et SpaceInterCubes Globales CubesToCollapseArray[i]->SetActorLocation(actor_location); CubesToCollapseArray[i]->MovementZTick++; } else { CubesToCollapseArray[i]->SetDustParticleActive.Broadcast(); } } } } GlobalTick1++; }
La fonction de spin n'est pas des plus rapides à programmer non plus :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39 void ATetrisPlayerController::SpinCubes() { // Fait rapidement descendre les cubes if (!CubesManager->CubesCanBeMoved) { return; } CubesManager->SpinSteps = 0; CubesManager->CubesCanBeMoved = false; for (int32 i = 0; i <= 3; i++) { CubesManager->CubesCurrentShapeArray[i]->MovementZTick = 1; CubesManager->CubesCurrentShapeArray[i]->InitZ = CubesManager->CubesCurrentShapeArray[i]->GetActorLocation().Z; CubesManager->CubesCurrentShapeArrayTest[i] = CubesManager->CubesCurrentShapeArray[i]; CubesManager->CubesCurrentShapeArrayTest[i]->y = CubesManager->CubesCurrentShapeArrayTest[i]->GetActorLocation().Y; CubesManager->CubesCurrentShapeArrayTest[i]->z = CubesManager->CubesCurrentShapeArrayTest[i]->GetActorLocation().Z - (CubesManager->SpinSteps + 1) * (CubesManager->CubeWidth + CubesManager->SpaceInterCubes); } while (!CubesManager->ShapeCollidesWithMatrix(CubesManager->CubesCurrentShapeArrayTest, Direction::NONE)){ CubesManager->SpinSteps++; for (int32 i = 0; i <= 3; i++) { CubesManager->CubesCurrentShapeArrayTest[i]->z = CubesManager->CubesCurrentShapeArrayTest[i]->GetActorLocation().Z - (CubesManager->SpinSteps + 1) * (CubesManager->CubeWidth + CubesManager->SpaceInterCubes); } } if (CubesManager->SpinSteps > 0) { GetWorld()->GetTimerManager().ClearTimer(CubesManager->MovingDownCubesHandle); for (int32 i = 0; i <= 3; i++) { CubesManager->CubesCurrentShapeArray[i]->SetSpinTrailParticleActive.Broadcast(); CubesManager->SetSpinningCubesTimer(); } } }
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40 void ACubesManager::EaseSpinCubes() { FVector actor_location; FRotator actor_rotator; for (int32 i = 0; i <= 3; i++) { if (CubesCurrentShapeArray[i]->MovementZTick > CollapseCubesRowsDuration) { CubesCurrentShapeArray[i]->SetDustParticleActive.Broadcast(); CubesHaveJustSpined = true; if (i == 3) { SetMovingDownCubesTimer(DeltaTimeMoveCubesDown); if (UpdateMatrix(CubesCurrentShapeArrayTest)) { ClearMatrixRows(); } GetWorld()->GetTimerManager().ClearTimer(SpinCubesHandle); return; } } else { actor_location = CubesCurrentShapeArray[i]->GetActorLocation(); EasePennerObject->EaseOutExpo(float(CubesCurrentShapeArray[i]->MovementZTick), CubesCurrentShapeArray[i]->InitX, -SpinSteps * (CubeWidth + SpaceInterCubes), (float)CollapseCubesRowsDuration); //TODO rendre CubeWidth et SpaceInterCubes Globales actor_location.Z = EasePennerObject->EaseOutExpo(float(CubesCurrentShapeArray[i]->MovementZTick), CubesCurrentShapeArray[i]->InitZ, - SpinSteps * (CubeWidth + SpaceInterCubes), (float)CollapseCubesRowsDuration); //TODO rendre CubeWidth et SpaceInterCubes Globales CubesCurrentShapeArray[i]->SetActorLocation(actor_location); CubesCurrentShapeArray[i]->MovementZTick++; } } }
Bonjour,
Mon modeste projet est terminé :
Pensez à augmenter le volume, car le signal audio est assez faible.
Bien à vous
modeste... c'est toi qui es modeste...
vraiment balaise, respect man...
Merci c'est gentil, mais ça reste un "petit" projet pour débuter.
Mets-nous le .exe sur sourceforge stp. On veut jouer !
Trop peu de gens sont intéressés à l'idée de jouer à un tetris au gameplay classique, en revanche je compte faire un .exe pour mon pinball.
Pour le Tetris c'était juste une démo technique.
Vous avez un bloqueur de publicités installé.
Le Club Developpez.com n'affiche que des publicités IT, discrètes et non intrusives.
Afin que nous puissions continuer à vous fournir gratuitement du contenu de qualité, merci de nous soutenir en désactivant votre bloqueur de publicités sur Developpez.com.
Partager