feat: SFML 3.0, music, upscale, faster animations
This commit is contained in:
25
CMakeLists.txt
Normal file
25
CMakeLists.txt
Normal 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
BIN
fonts/Inter-Black.ttf
Normal file
Binary file not shown.
BIN
fonts/Inter-Regular.ttf
Normal file
BIN
fonts/Inter-Regular.ttf
Normal file
Binary file not shown.
BIN
images/background.png
Normal file
BIN
images/background.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 323 KiB |
BIN
images/button_bg.png
Normal file
BIN
images/button_bg.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1022 B |
BIN
images/candys.png
Normal file
BIN
images/candys.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 222 KiB |
BIN
music/background.ogg
Normal file
BIN
music/background.ogg
Normal file
Binary file not shown.
54
src/checkCombinations.hpp
Normal file
54
src/checkCombinations.hpp
Normal 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
14
src/generationCandys.hpp
Normal 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
198
src/main.cpp
Normal 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
23
src/mouseClickHandler.hpp
Normal 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
48
src/move.hpp
Normal 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
19
src/structCandy.hpp
Normal 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;
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user