Compare commits

...

2 Commits

Author SHA1 Message Date
kuzgoga
6e1a625102 feat: SFML 3.0, music, upscale, faster animations 2025-11-01 23:02:44 +07:00
kuzgoga
33acb24e20 upd: .gitignore 2025-11-01 23:02:15 +07:00
14 changed files with 383 additions and 0 deletions

2
.gitignore vendored
View File

@@ -2,3 +2,5 @@ cmake-build-debug
CandyCrush CandyCrush
*.data *.data
build build
.idea
*.zip

25
CMakeLists.txt Normal file
View File

@@ -0,0 +1,25 @@
cmake_minimum_required(VERSION 3.21)
project(CandyCrush LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 20)
set(BUILD_SHARED_LIBS OFF)
set(SFML_USE_STATIC_STD_LIBS ON)
set(SFML_BUILD_AUDIO ON)
set(SFML_BUILD_GRAPHICS ON)
set(SFML_BUILD_WINDOW OFF)
set(SFML_BUILD_NETWORK OFF)
set(SFML_USE_SYSTEM_DEPS OFF)
set(SFML_BUILD_EXAMPLES OFF)
include(FetchContent)
FetchContent_Declare(SFML
GIT_REPOSITORY https://github.com/SFML/SFML.git
GIT_TAG 3.0.2
)
FetchContent_MakeAvailable(SFML)
add_executable(CandyCrush src/main.cpp)
target_link_libraries(CandyCrush PRIVATE sfml-graphics sfml-audio)

BIN
fonts/Inter-Black.ttf Normal file

Binary file not shown.

BIN
fonts/Inter-Regular.ttf Normal file

Binary file not shown.

BIN
images/background.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 323 KiB

BIN
images/button_bg.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1022 B

BIN
images/candys.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 222 KiB

BIN
music/background.ogg Normal file

Binary file not shown.

54
src/checkCombinations.hpp Normal file
View File

@@ -0,0 +1,54 @@
#pragma once
#include "structCandy.hpp"
#include "move.hpp"
void check(candy map[][10])
{
for(int i = 1;i <= 8;i++)
for(int j = 1;j <= 8;j++)
{
if (map[i][j].kind == map[i+1][j].kind || map[i+1][j].kind > 4 || map[i][j].kind > 4)
if (map[i][j].kind == map[i-1][j].kind || map[i-1][j].kind > 4 || map[i][j].kind > 4)
if (map[i-1][j].kind == map[i+1][j].kind || map[i-1][j].kind > 4 || map[i+1][j].kind > 4)
for(int k = -1; k <= 1; k++)
{
if (map[i + k][j].kind == 6) for(int n = 0; n <= 8; n++) map[i + k][n].combination++;
if (map[i + k][j].kind == 5) for(int n = -1; n <= 1; n++) for(int m = -1; m <= 1; m++) if(i + k + n >= 0 && i + k + n <= 8 && j + m >= 0 && j + m <= 8) map[i + k + n][j + m].combination++;
map[i + k][j].combination++;
}
if (map[i][j].kind == map[i][j+1].kind || map[i][j+1].kind > 4 || map[i][j].kind > 4)
if (map[i][j].kind == map[i][j-1].kind || map[i][j-1].kind > 4 || map[i][j].kind > 4)
if (map[i][j-1].kind == map[i][j+1].kind || map[i][j-1].kind > 4 || map[i][j+1].kind > 4)
for(int k = -1; k <= 1; k++)
{
if (map[i][j + k].kind == 6) for(int n = 0; n <= 8; n++) map[i][n].combination++;
if (map[i][j + k].kind == 5) for(int n = -1; n <= 1; n++) for(int m = -1; m <= 1; m++) if(i + n >= 0 && i + n <= 8 && j + k + m >= 0 && j + k + m <= 8) map[i + n][j + k + m].combination++;
map[i][j + k].combination++;
}
}
}
void update(bool &isMoving, candy map[][10], int &points)
{
if (!isMoving)
{
for(int i = 8;i > 0; i--)
for(int j = 1;j <= 8;j++)
if (map[i][j].combination)
for(int n = i;n > 0; n--)
if (!map[n][j].combination) {swap(map[n][j], map[i][j], map); break;};
for(int j = 1; j <= 8;j++)
for(int i = 8,n = 0; i > 0; i--)
if (map[i][j].combination)
{
points++;
map[i][j].kind = rand() % 5;
if (rand() % 100 < 5) map[i][j].kind = 5 + rand() % 2;
map[i][j].y = -tile_size * n++;
map[i][j].combination=0;
map[i][j].alpha = 255;
}
}
}

14
src/generationCandys.hpp Normal file
View File

@@ -0,0 +1,14 @@
#pragma once
#include "structCandy.hpp"
void generation(candy map[][10])
{
for (int i = 1;i <= 8; i++)
for (int j = 1; j <= 8; j++)
{
map[i][j].kind = rand() % 5;
map[i][j].column = j;
map[i][j].row = i;
map[i][j].x = j * tile_size;
map[i][j].y = i * tile_size;
}
}

198
src/main.cpp Normal file
View File

@@ -0,0 +1,198 @@
#include <SFML/Graphics.hpp>
#include <ctime>
#include <iostream>
#include <fstream>
#include <filesystem>
#include <vector>
#include <algorithm>
#include "mouseClickHandler.hpp"
#include "structCandy.hpp"
#include "generationCandys.hpp"
#include "checkCombinations.hpp"
#include "move.hpp"
#include <SFML/Audio.hpp>
candy map[10][10];
void playMusic()
{
static sf::Music background_music;
if (!background_music.openFromFile("music/background.ogg"))
{
std::cerr << "Ошибка загрузки музыки" << std::endl;
}
background_music.setLooping(true);
background_music.setVolume(100);
background_music.play();
}
int main()
{
using namespace sf;
int seed;
srand(seed);
sf::RenderWindow window(sf::VideoMode({1280u, 720u}), "Candy Crush");
window.setFramerateLimit(120);
playMusic();
Texture bg_texture, candys_texture, button_texture;
if (!bg_texture.loadFromFile("images/background.png")) return -1;
if (!candys_texture.loadFromFile("images/candys.png")) return -1;
if (!button_texture.loadFromFile("images/button_bg.png")) return -1;
candys_texture.setSmooth(false);
Sprite background(bg_texture), candys(candys_texture), button_bg(button_texture);
button_bg.setPosition({490, 150});
Font font_regular, font_black;
if (!font_regular.openFromFile("fonts/Inter-Regular.ttf")) return -1;
if (!font_black.openFromFile("fonts/Inter-Black.ttf")) return -1;
Text points_text(font_regular, "0", 20);
points_text.setPosition({10, 5});
Text rating_text(font_regular, "", 28);
rating_text.setPosition({500, 260});
Text newgame_button_text(font_black, "NEW GAME", 48);
newgame_button_text.setPosition({500, 160});
Text endgame_button_text(font_black, "END GAME", 24);
endgame_button_text.setPosition({1110, 655});
generation(map);
int x0, y0, x, y;
int click = 0;
Vector2i position;
bool isSwap = false;
bool isMoving = false;
int points = 0;
int scene = 0;
if (std::filesystem::exists("last_game.data"))
{
std::ifstream points_file("last_game.data");
points_file >> points;
points_file.close();
}
std::vector<int> rating;
for(int i = 0; i < 5; i++) rating.push_back(0);
if (std::filesystem::exists("rating.data"))
{
std::ifstream rating_file("rating.data");
rating_file >> rating[0] >> rating[1] >> rating[2] >> rating[3] >> rating[4];
rating_file.close();
}
String rating_str;
for(int i = 0; i < 5; i++) rating_str += std::to_string(i + 1) + " - " + std::to_string(rating[i]) + " points\n";
rating_text.setString(rating_str);
if (points > 0) {
newgame_button_text.setString("CONTINUE");
newgame_button_text.setPosition({510, 160});
}
while (window.isOpen())
{
while (const std::optional event = window.pollEvent())
{
if (event->is<Event::Closed>())
{
std::ofstream points_file("last_game.data");
points_file << points;
points_file.close();
std::ofstream rating_file("rating.data");
rating_file << rating[0] << " " << rating[1] << " " << rating[2] << " " << rating[3] << " " << rating[4];
rating_file.close();
window.close();
}
if (const auto* mousePressed = event->getIf<Event::MouseButtonPressed>())
{
if (mousePressed->button == Mouse::Button::Left)
{
if (scene == 0)
{
position = Mouse::getPosition(window);
if (position.x >= 490 && position.x <= 790 && position.y >= 150 && position.y <= 230)
{
scene = 1;
button_bg.setScale({0.5f, 0.5f});
button_bg.setPosition({1100, 650});
}
}
else
{
position = Mouse::getPosition(window);
if (position.x >= 1100 && position.x <= 1250 && position.y >= 650 && position.y <= 690)
{
if (points > rating[4]) rating[4] = points;
std::sort(rating.begin(), rating.end(), std::greater<int>());
rating_str = "";
for(int i = 0; i < 5; i++) rating_str += std::to_string(i + 1) + " - " + std::to_string(rating[i]) + " points\n";
rating_text.setString(rating_str);
scene = 0;
points = 0;
newgame_button_text.setString("NEW GAME");
newgame_button_text.setPosition({500, 160});
button_bg.setScale({1, 1});
button_bg.setPosition({490, 150});
}
if (!isSwap && !isMoving) click++;
position -= offset;
}
}
}
}
if (scene == 0)
{
window.draw(background);
window.draw(button_bg);
window.draw(newgame_button_text);
window.draw(rating_text);
}
else if (scene == 1)
{
mouse_click(click, x0, y0, tile_size, position, isSwap, x, y, map);
check(map);
move(isMoving, map);
deleting(isMoving, map);
antiswap(isMoving, isSwap, map, y0, x0, y, x);
update(isMoving, map, points);
window.draw(background);
window.draw(button_bg);
window.draw(endgame_button_text);
points_text.setString("Points: " + std::to_string(points));
window.draw(points_text);
for (int i = 1; i <= 8; i++)
for (int j = 1; j <= 8; j++)
{
candy element = map[i][j];
candys.setTextureRect(IntRect({element.kind * 98*2, 0}, {98*2, 98*2}));
candys.setScale({70 / candys.getLocalBounds().size.y, 70 / candys.getLocalBounds().size.x});
candys.setColor(Color(255, 255, 255, element.alpha));
candys.setPosition({static_cast<float>(element.x), static_cast<float>(element.y)});
candys.move({static_cast<float>(offset.x - tile_size), static_cast<float>(offset.y - tile_size)});
window.draw(candys);
}
}
window.display();
}
return 0;
}

23
src/mouseClickHandler.hpp Normal file
View File

@@ -0,0 +1,23 @@
#pragma once
#include <math.h>
#include <SFML/Graphics.hpp>
#include "structCandy.hpp"
#include "move.hpp"
void mouse_click(int &click, int &x0, int &y0, int tile_size, sf::Vector2i pos, bool &isSwap, int &x, int &y, candy map[][10]){
if (click == 1)
{
x0 = pos.x / tile_size + 1;
y0 = pos.y / tile_size + 1;
}
if (click == 2)
{
x = pos.x / tile_size + 1;
y = pos.y / tile_size + 1;
if (abs(x - x0)+ abs(y - y0) == 1)
{
swap(map[y0][x0], map[y][x], map); isSwap = 1; click = 0;
}
else click = 1;
}
}

48
src/move.hpp Normal file
View File

@@ -0,0 +1,48 @@
#pragma once
#include <SFML/Graphics.hpp>
#include "structCandy.hpp"
void swap(candy first, candy second, candy map[][10])
{
std::swap(first.column,second.column);
std::swap(first.row,second.row);
map[first.row][first.column] = first;
map[second.row][second.column] = second;
}
void move(bool &isMoving, candy map[][10])
{
isMoving=false;
for (int i = 1;i <= 8;i++)
for (int j = 1;j <= 8;j++)
{
candy &element = map[i][j];
int dx, dy;
for(int n = 0; n < 4; n++)
{
dx = element.x - element.column * tile_size;
dy = element.y - element.row * tile_size;
if (dx) element.x -= dx/abs(dx);
if (dy) element.y -= dy/abs(dy);
}
if (dx||dy) isMoving = 1;
}
}
void deleting(bool &isMoving, candy map[][10])
{
if (!isMoving)
for (int i = 1; i <= 8; i++)
for (int j = 1;j <= 8; j++)
if (map[i][j].combination) if (map[i][j].alpha>10) {map[i][j].alpha -= 10; isMoving=true;}
}
void antiswap(bool &isMoving, bool &isSwap, candy map[][10], int y0, int x0, int y, int x)
{
int score = 0;
for (int i = 1;i <= 8;i++)
for (int j = 1;j <= 8;j++)
score += map[i][j].combination;
if (isSwap && !isMoving) {if (!score) swap(map[y0][x0], map[y][x], map); isSwap=0;}
}

19
src/structCandy.hpp Normal file
View File

@@ -0,0 +1,19 @@
#pragma once
#include <SFML/Graphics.hpp>
constexpr int tile_size = 80;
sf::Vector2i offset(320, 40);
struct candy
{
int x, y;
int column, row;
int kind;
int combination;
int alpha;
candy()
{
combination = 0;
alpha = 255;
}
};