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 spawning AMatch3Tile 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 calls GenerateNewTiles 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.

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다