목차
1. Grid Generation and Initialization
In Unreal Engine, we use an array to store the grid’s tiles and spawn Actor
objects that represent each tile. Each tile is assigned a unique sprite or mesh representing a gem or collectible item. The grid will be 2D, and we need to initialize it with random gem types.
Grid Generation in Unreal Engine
#include "Match3GameMode.h"
#include "Engine/World.h"
#include "GameFramework/Actor.h"
#include "Match3Tile.h"
#include "UObject/ConstructorHelpers.h"
AMatch3GameMode::AMatch3GameMode()
{
// Set default values
GridWidth = 8;
GridHeight = 8;
// Load the tile mesh or sprite
static ConstructorHelpers::FObjectFinder<UStaticMesh> TileMesh(TEXT("/Game/PathToYourTileMesh"));
if (TileMesh.Succeeded())
{
TileMeshAsset = TileMesh.Object;
}
}
void AMatch3GameMode::GenerateGrid()
{
// Create a 2D array for storing tile references
Grid.Empty();
Grid.SetNumZeroed(GridWidth);
for (int32 X = 0; X < GridWidth; X++)
{
Grid[X].SetNumZeroed(GridHeight);
for (int32 Y = 0; Y < GridHeight; Y++)
{
FVector Position(X * TileSize, Y * TileSize, 0.0f);
AMatch3Tile* NewTile = GetWorld()->SpawnActor<AMatch3Tile>(TileClass, Position, FRotator::ZeroRotator);
NewTile->SetTileType(FMath::RandRange(0, NumGemTypes - 1)); // Random gem type
Grid[X][Y] = NewTile;
}
}
}
Explanation:
AMatch3GameMode
initializes the grid size and tile meshes (or sprites).- The
GenerateGrid
method generates the grid of tiles by spawningAMatch3Tile
actors at appropriate positions, with each tile assigned a random gem type from the predefined set.
2. Tile Selection and Swapping
In Unreal Engine, players interact with the grid using mouse clicks or touch input. This logic includes selecting two adjacent tiles and swapping their positions.
Tile Selection and Swapping
#include "Match3Tile.h"
#include "Engine/World.h"
#include "GameFramework/Actor.h"
AMatch3Tile* SelectedTile = nullptr;
void AMatch3GameMode::OnTileSelected(AMatch3Tile* Tile)
{
if (!SelectedTile)
{
SelectedTile = Tile;
}
else
{
SwapTiles(SelectedTile, Tile);
SelectedTile = nullptr; // Reset selection
}
}
void AMatch3GameMode::SwapTiles(AMatch3Tile* Tile1, AMatch3Tile* Tile2)
{
FVector TempPosition = Tile1->GetActorLocation();
Tile1->SetActorLocation(Tile2->GetActorLocation());
Tile2->SetActorLocation(TempPosition);
// Swap the tiles' references in the grid
int32 X1, Y1, X2, Y2;
Tile1->GetGridCoordinates(X1, Y1);
Tile2->GetGridCoordinates(X2, Y2);
Grid[X1][Y1] = Tile2;
Grid[X2][Y2] = Tile1;
}
Explanation:
- The
OnTileSelected
method captures player input and swaps the positions of two selected tiles. SwapTiles
swaps the tiles both visually (by changing their actor locations) and in the grid data structure.
3. Matching Logic
The core of any match-3 game is detecting matches, where tiles of the same type align horizontally or vertically. This is achieved by checking the neighboring tiles for the same type and ensuring at least three consecutive tiles are aligned.
Tile Matching Logic
#include "Match3Tile.h"
#include "Engine/World.h"
TArray<AMatch3Tile*> AMatch3GameMode::FindMatches()
{
TArray<AMatch3Tile*> MatchedTiles;
for (int32 X = 0; X < GridWidth; X++)
{
for (int32 Y = 0; Y < GridHeight; Y++)
{
AMatch3Tile* Tile = Grid[X][Y];
if (!Tile) continue;
// Check horizontal and vertical matches
TArray<AMatch3Tile*> HorizontalMatch = CheckDirection(X, Y, 1, 0, Tile->GetTileType());
TArray<AMatch3Tile*> VerticalMatch = CheckDirection(X, Y, 0, 1, Tile->GetTileType());
if (HorizontalMatch.Num() >= 3) MatchedTiles.Append(HorizontalMatch);
if (VerticalMatch.Num() >= 3) MatchedTiles.Append(VerticalMatch);
}
}
return MatchedTiles;
}
TArray<AMatch3Tile*> AMatch3GameMode::CheckDirection(int32 StartX, int32 StartY, int32 DirX, int32 DirY, int32 TileType)
{
TArray<AMatch3Tile*> MatchedTiles;
int32 X = StartX;
int32 Y = StartY;
while (X >= 0 && X < GridWidth && Y >= 0 && Y < GridHeight && Grid[X][Y] && Grid[X][Y]->GetTileType() == TileType)
{
MatchedTiles.Add(Grid[X][Y]);
X += DirX;
Y += DirY;
}
return MatchedTiles;
}
Explanation:
- The
FindMatches
method loops through the grid and checks both horizontally and vertically for consecutive tiles of the same type. CheckDirection
checks a specified direction (either horizontal or vertical) to find consecutive matching tiles of the same type.
4. Removing Matched Tiles
Once matches are found, the matched tiles must be removed, and new tiles should be generated to fill the empty spaces. In Unreal Engine, this can be done by destroying the matched tiles and then generating new ones to fill the gaps.
Removing Matched Tiles
#include "Match3Tile.h"
#include "Engine/World.h"
void AMatch3GameMode::RemoveMatchedTiles(TArray<AMatch3Tile*> MatchedTiles)
{
for (AMatch3Tile* Tile : MatchedTiles)
{
Tile->Destroy(); // Remove the matched tile
}
// Generate new tiles
GenerateNewTiles();
}
void AMatch3GameMode::GenerateNewTiles()
{
for (int32 X = 0; X < GridWidth; X++)
{
for (int32 Y = 0; Y < GridHeight; Y++)
{
if (!Grid[X][Y]) // If the tile is empty, generate a new tile
{
FVector Position(X * TileSize, Y * TileSize, 0.0f);
AMatch3Tile* NewTile = GetWorld()->SpawnActor<AMatch3Tile>(TileClass, Position, FRotator::ZeroRotator);
NewTile->SetTileType(FMath::RandRange(0, NumGemTypes - 1)); // Random new tile type
Grid[X][Y] = NewTile;
}
}
}
}
Explanation:
- The
RemoveMatchedTiles
function destroys the matched tiles and callsGenerateNewTiles
to fill the gaps with new tiles. New tiles are randomly assigned a gem type.
5. Cascading Effects
In many match-3 games, tiles above the destroyed ones “fall” to fill the empty spaces, potentially creating new matches in the process. This cascading effect is handled by shifting tiles downward and checking for new matches after each cascade.
Cascading Effect
void AMatch3GameMode::CascadeTiles()
{
for (int32 X = 0; X < GridWidth; X++)
{
for (int32 Y = GridHeight - 1; Y >= 0; Y--)
{
if (!Grid[X][Y]) // If there's no tile in this spot, move tiles down
{
MoveTilesDown(X, Y);
}
}
}
}
void AMatch3GameMode::MoveTilesDown(int32 X, int32 EmptyY)
{
for (int32 Y = EmptyY - 1; Y >= 0; Y--)
{
if (Grid[X][Y])
{
FVector NewPosition(X * TileSize, EmptyY * TileSize, 0.0f);
Grid[X][EmptyY] = Grid[X][Y];
Grid[X][Y]->SetActorLocation(NewPosition);
Grid[X][Y] = nullptr;
EmptyY++;
}
}
}
Explanation:
- The
CascadeTiles
function moves tiles downward to fill gaps created by removed tiles. MoveTilesDown
shifts tiles from above to fill the empty spaces, cascading the remaining tiles down the grid.
6. Scoring System
A simple scoring system can be implemented
to track the player’s score based on the number of matched tiles.
Scoring System
#include "Match3GameMode.h"
int32 AMatch3GameMode::CalculateScore(TArray<AMatch3Tile*> MatchedTiles)
{
return MatchedTiles.Num() * 10; // 10 points per matched tile
}
void AMatch3GameMode::UpdateScore(int32 Points)
{
CurrentScore += Points;
// Optionally update the UI with the new score
}
Explanation:
CalculateScore
calculates the score based on the number of tiles matched.UpdateScore
updates the player’s score.
Conclusion
This implementation covers the core mechanics of a match-3 game in Unreal Engine. It includes grid generation, tile selection and swapping, match detection, tile removal, cascading, and scoring. You can extend this system by adding more advanced features such as special tiles, power-ups, animations, and sound effects for a more polished gameplay experience.