parent
efa898ebaa
commit
7df31f6b5c
@ -1 +1,6 @@
|
|||||||
.cache
|
# Generated by Cargo
|
||||||
|
# will have compiled files and executables
|
||||||
|
/target/
|
||||||
|
|
||||||
|
# These are backup files generated by rustfmt
|
||||||
|
**/*.rs.bk
|
@ -1,14 +0,0 @@
|
|||||||
set(ProjectName "septadrop")
|
|
||||||
|
|
||||||
cmake_minimum_required(VERSION 3.10)
|
|
||||||
set(CMAKE_CXX_STANDARD 20)
|
|
||||||
set(CMAKE_CXX_STANDARD_REQUIRED 20)
|
|
||||||
|
|
||||||
project(${ProjectName} VERSION 1.0)
|
|
||||||
|
|
||||||
file (GLOB_RECURSE SRC_FILES src/*.cpp)
|
|
||||||
add_executable(${ProjectName} ${SRC_FILES})
|
|
||||||
target_include_directories(${ProjectName} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
|
|
||||||
|
|
||||||
find_package(SFML 2.5 COMPONENTS system window graphics network audio REQUIRED)
|
|
||||||
target_link_libraries(${ProjectName} sfml-graphics sfml-audio)
|
|
@ -0,0 +1,155 @@
|
|||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bitflags"
|
||||||
|
version = "1.3.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cfg-if"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "csfml-audio-sys"
|
||||||
|
version = "0.6.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f4e20d25b6f2c582dff0b82440dd2b6b6a3ae78eb07096ca226a64f02779da96"
|
||||||
|
dependencies = [
|
||||||
|
"csfml-system-sys",
|
||||||
|
"sfml-build",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "csfml-graphics-sys"
|
||||||
|
version = "0.6.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b592b4e5f26de6d46b53f762a2a46e80826f69e008272d302a49e87c27a6c996"
|
||||||
|
dependencies = [
|
||||||
|
"csfml-system-sys",
|
||||||
|
"csfml-window-sys",
|
||||||
|
"sfml-build",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "csfml-system-sys"
|
||||||
|
version = "0.6.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4019b7cb9ece70481603aaadb9a0094c9a6455d1a71d82d24c5a0b47c037cfaf"
|
||||||
|
dependencies = [
|
||||||
|
"sfml-build",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "csfml-window-sys"
|
||||||
|
version = "0.6.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e27076c2b6aafd377d396700f25bbf5020c695781d20aed6a399bef7ea351a17"
|
||||||
|
dependencies = [
|
||||||
|
"csfml-system-sys",
|
||||||
|
"sfml-build",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "getrandom"
|
||||||
|
version = "0.2.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d39cd93900197114fa1fcb7ae84ca742095eed9442088988ae74fa744e930e77"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"libc",
|
||||||
|
"wasi",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libc"
|
||||||
|
version = "0.2.120"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ad5c14e80759d0939d013e6ca49930e59fc53dd8e5009132f76240c179380c09"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "once_cell"
|
||||||
|
version = "1.10.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "87f3e037eac156d1775da914196f0f37741a274155e34a0b7e427c35d2a2ecb9"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ppv-lite86"
|
||||||
|
version = "0.2.16"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand"
|
||||||
|
version = "0.8.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"rand_chacha",
|
||||||
|
"rand_core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand_chacha"
|
||||||
|
version = "0.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
|
||||||
|
dependencies = [
|
||||||
|
"ppv-lite86",
|
||||||
|
"rand_core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand_core"
|
||||||
|
version = "0.6.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7"
|
||||||
|
dependencies = [
|
||||||
|
"getrandom",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "septadrop"
|
||||||
|
version = "1.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"rand",
|
||||||
|
"sfml",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sfml"
|
||||||
|
version = "0.16.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e4c72108133019d399b24d0c0bd179cc26aa2909b0001e4202d756e4c90c21b4"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags",
|
||||||
|
"csfml-audio-sys",
|
||||||
|
"csfml-graphics-sys",
|
||||||
|
"csfml-system-sys",
|
||||||
|
"csfml-window-sys",
|
||||||
|
"once_cell",
|
||||||
|
"widestring",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sfml-build"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "53e0893aaf18583de27202b17007258377d5c4be16e1d0b601fd6943bc36c98b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasi"
|
||||||
|
version = "0.10.2+wasi-snapshot-preview1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "widestring"
|
||||||
|
version = "0.4.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c168940144dd21fd8046987c16a46a33d5fc84eec29ef9dcddc2ac9e31526b7c"
|
@ -0,0 +1,10 @@
|
|||||||
|
[package]
|
||||||
|
name = "septadrop"
|
||||||
|
version = "1.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
sfml = "0.16.0"
|
||||||
|
rand = "0.8.5"
|
@ -1,9 +1,2 @@
|
|||||||
CMakeFiles
|
|
||||||
cmake_install.cmake
|
|
||||||
CMakeCache.txt
|
|
||||||
compile_commands.json
|
|
||||||
Makefile
|
|
||||||
septadrop
|
septadrop
|
||||||
septadrop_1.0_amd64/usr/bin/septadrop
|
*.deb
|
||||||
septadrop_1.0_amd64.deb
|
|
||||||
.cmake
|
|
@ -1,6 +0,0 @@
|
|||||||
# DCMAKE_EXPORT_COMPILE_COMMANDS=ON generates compile_commands.json in build folder,
|
|
||||||
# which clangd will pick up
|
|
||||||
# Without this, clangd might assume the wrong C++ version
|
|
||||||
cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=ON ..
|
|
||||||
python3 packer.py
|
|
||||||
cmake --build .
|
|
@ -1,5 +1,7 @@
|
|||||||
TARGET=septadrop_1.0_amd64
|
TARGET=septadrop_1.0_amd64
|
||||||
./build.sh
|
|
||||||
mkdir -p ${TARGET}/usr/bin/
|
mkdir -p ${TARGET}/usr/bin/
|
||||||
cp septadrop ${TARGET}/usr/bin/
|
cd ..
|
||||||
|
cargo build --release
|
||||||
|
cp target/release/septadrop build/${TARGET}/usr/bin/
|
||||||
|
cd build
|
||||||
dpkg-deb --build ${TARGET}
|
dpkg-deb --build ${TARGET}
|
@ -1,57 +0,0 @@
|
|||||||
import os, shutil
|
|
||||||
|
|
||||||
RES_DIR = "../res/"
|
|
||||||
PACKED_DIR = "../include/packed/"
|
|
||||||
SHARED_HEADER_PATH = f"{PACKED_DIR}/SharedResources.hpp"
|
|
||||||
|
|
||||||
resources = os.fsencode(RES_DIR)
|
|
||||||
os.makedirs(PACKED_DIR, exist_ok=True)
|
|
||||||
packed_dir = os.fsencode(PACKED_DIR)
|
|
||||||
|
|
||||||
for filename in os.listdir(packed_dir):
|
|
||||||
file_path = os.path.join(packed_dir, filename)
|
|
||||||
if os.path.isfile(file_path) or os.path.islink(file_path):
|
|
||||||
os.unlink(file_path)
|
|
||||||
elif os.path.isdir(file_path):
|
|
||||||
shutil.rmtree(file_path)
|
|
||||||
|
|
||||||
shared_header = "#pragma once\n\n"
|
|
||||||
|
|
||||||
for folder in os.listdir(resources):
|
|
||||||
folder_path = os.path.join(resources, folder)
|
|
||||||
if os.path.isfile(folder_path):
|
|
||||||
continue
|
|
||||||
packed_path = os.path.join(packed_dir, folder)
|
|
||||||
os.makedirs(packed_path, exist_ok=True)
|
|
||||||
for resource in os.listdir(folder_path):
|
|
||||||
resource_path = os.path.join(folder_path, resource)
|
|
||||||
|
|
||||||
res = "#pragma once\n\n"
|
|
||||||
|
|
||||||
splitext = os.path.splitext(resource)
|
|
||||||
name = splitext[0].decode()
|
|
||||||
ext = splitext[1].decode()
|
|
||||||
|
|
||||||
if ext == ".png":
|
|
||||||
name += "_texture"
|
|
||||||
elif ext == ".wav":
|
|
||||||
name += "_audio"
|
|
||||||
name += "_data"
|
|
||||||
|
|
||||||
encoded = f"const unsigned char {name.upper()}[] = {'{'}"
|
|
||||||
file = open(resource_path, "rb") # read binary
|
|
||||||
bytes_processed = 0
|
|
||||||
for byte in file.read():
|
|
||||||
if bytes_processed % 16 == 0:
|
|
||||||
encoded += "\n\t"
|
|
||||||
encoded += f"0x{byte.to_bytes(1, byteorder='little').hex()}, "
|
|
||||||
bytes_processed += 1
|
|
||||||
encoded = encoded[:-2] + "\n};"
|
|
||||||
res += encoded + "\n"
|
|
||||||
header_name = f"{name}.hpp"
|
|
||||||
with open(os.path.join(packed_path.decode(), header_name), "w") as f:
|
|
||||||
f.write(res)
|
|
||||||
shared_header += f'#include "{folder.decode()}/{header_name}"\n'
|
|
||||||
|
|
||||||
with open(SHARED_HEADER_PATH, "w") as f:
|
|
||||||
f.write(shared_header)
|
|
@ -1,2 +0,0 @@
|
|||||||
./build.sh
|
|
||||||
./septadrop
|
|
@ -1,10 +1,10 @@
|
|||||||
Package: septadrop
|
Package: septadrop
|
||||||
Version: 1.0
|
Version: 1.1
|
||||||
Architecture: amd64
|
Architecture: amd64
|
||||||
Essential: no
|
Essential: no
|
||||||
Priority: optional
|
Priority: optional
|
||||||
Maintainer: ElnuDev <elnu@elnu.com>
|
Maintainer: ElnuDev <elnu@elnu.com>
|
||||||
Description: A block game made in C++ and SFML.
|
Description: A block game made in Rust and SFML.
|
||||||
Homepage: https://github.com/ElnuDev/septadrop
|
Homepage: https://github.com/ElnuDev/septadrop
|
||||||
Vcs-Browser: https://github.com/ElnuDev/septadrop
|
Vcs-Browser: https://github.com/ElnuDev/septadrop
|
||||||
Vcs-Git: https://github.com/ElnuDev/septadrop.git
|
Vcs-Git: https://github.com/ElnuDev/septadrop.git
|
@ -1 +0,0 @@
|
|||||||
packed
|
|
@ -1,12 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "BlockType.hpp"
|
|
||||||
|
|
||||||
class Block {
|
|
||||||
public:
|
|
||||||
BlockType* type;
|
|
||||||
sf::Vector2i position;
|
|
||||||
int rotation_state;
|
|
||||||
Block();
|
|
||||||
std::vector<sf::Vector2i> get_tiles();
|
|
||||||
};
|
|
@ -1,19 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "TileType.hpp"
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
class BlockType {
|
|
||||||
public:
|
|
||||||
TileType* tile_type;
|
|
||||||
std::vector<std::vector<bool>> grid;
|
|
||||||
uint width, height, starting_line;
|
|
||||||
bool rotate;
|
|
||||||
BlockType(TileType* _tile_type, const std::vector<std::vector<bool>> _grid, bool _rotate = true);
|
|
||||||
|
|
||||||
static BlockType* random();
|
|
||||||
static void init();
|
|
||||||
private:
|
|
||||||
inline static std::vector<BlockType> list = {};
|
|
||||||
inline static bool inited = false;
|
|
||||||
};
|
|
@ -1,24 +0,0 @@
|
|||||||
#define TILE_SIZE 20
|
|
||||||
|
|
||||||
#define GRID_WIDTH 14
|
|
||||||
#define GRID_HEIGHT 20
|
|
||||||
|
|
||||||
#define WINDOW_WIDTH 500
|
|
||||||
#define WINDOW_HEIGHT 440
|
|
||||||
|
|
||||||
#define PLAYFIELD_X 20
|
|
||||||
#define PLAYFIELD_Y 20
|
|
||||||
|
|
||||||
#define NEXT_X 370
|
|
||||||
#define NEXT_Y 70
|
|
||||||
#define NEXT_WIDTH 5
|
|
||||||
#define NEXT_HEIGHT 5
|
|
||||||
|
|
||||||
#define LINES_PER_LEVEL 5
|
|
||||||
#define POINTS_1_LINE 40
|
|
||||||
#define POINTS_2_LINES 100
|
|
||||||
#define POINTS_3_LINES 300
|
|
||||||
#define POINTS_4_LINES 1200
|
|
||||||
|
|
||||||
#define MOVE_FRAME_INTERVAL 125
|
|
||||||
#define MAX_FAST_FORWARD_INTERVAL 125
|
|
@ -1,18 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <SFML/Graphics.hpp>
|
|
||||||
|
|
||||||
class NumberRenderer {
|
|
||||||
public:
|
|
||||||
sf::Texture texture;
|
|
||||||
sf::IntRect comma_rect;
|
|
||||||
sf::IntRect numeral_rects[10];
|
|
||||||
NumberRenderer(
|
|
||||||
sf::Texture _texture,
|
|
||||||
sf::IntRect _comma_rect,
|
|
||||||
std::initializer_list<sf::IntRect> _numeral_rects
|
|
||||||
);
|
|
||||||
void render(sf::RenderWindow* window, uint number, int x, int y);
|
|
||||||
private:
|
|
||||||
sf::Sprite sprite;
|
|
||||||
};
|
|
@ -1,12 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <SFML/Graphics/Rect.hpp>
|
|
||||||
|
|
||||||
#include "Config.hpp"
|
|
||||||
|
|
||||||
class TileType {
|
|
||||||
public:
|
|
||||||
sf::IntRect texture_rect;
|
|
||||||
sf::IntRect ghost_texture_rect;
|
|
||||||
TileType(sf::IntRect _texture_rect, sf::IntRect _ghost_texture_rect);
|
|
||||||
};
|
|
@ -1,52 +0,0 @@
|
|||||||
#include <Block.hpp>
|
|
||||||
#include <BlockType.hpp>
|
|
||||||
#include <Config.hpp>
|
|
||||||
|
|
||||||
Block::Block() {
|
|
||||||
type = BlockType::random();
|
|
||||||
position = sf::Vector2i(GRID_WIDTH / 2 - type->grid[0].size() / 2, 0);
|
|
||||||
rotation_state = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<sf::Vector2i> Block::get_tiles() {
|
|
||||||
std::vector<sf::Vector2i>tiles = {};
|
|
||||||
for (int y = 0; y < type->grid.size(); y++) {
|
|
||||||
for (int x = 0; x < type->grid[y].size(); x++) {
|
|
||||||
if (!type->grid[y][x]) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
int rotated_x = x;
|
|
||||||
int rotated_y = y;
|
|
||||||
if (type->rotate) {
|
|
||||||
int center_x = type->grid[0].size() / 2;
|
|
||||||
int center_y = type->grid.size() / 2;
|
|
||||||
int offset_x = x - center_x;
|
|
||||||
int offset_y = y - center_y;
|
|
||||||
switch (rotation_state) {
|
|
||||||
case 0:
|
|
||||||
rotated_x = x;
|
|
||||||
rotated_y = y;
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
rotated_x = center_x + offset_y;
|
|
||||||
rotated_y = center_y - offset_x;
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
rotated_x = center_x - offset_x;
|
|
||||||
rotated_y = center_y - offset_y;
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
rotated_x = center_x - offset_y;
|
|
||||||
rotated_y = center_y + offset_x;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
rotation_state %= 4;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
int global_x = rotated_x + position.x;
|
|
||||||
int global_y = rotated_y + position.y;
|
|
||||||
tiles.push_back(sf::Vector2i(global_x, global_y));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return tiles;
|
|
||||||
}
|
|
@ -1,115 +0,0 @@
|
|||||||
#include <BlockType.hpp>
|
|
||||||
|
|
||||||
BlockType::BlockType(TileType* _tile_type, const std::vector<std::vector<bool>> _grid, bool _rotate) {
|
|
||||||
tile_type = _tile_type;
|
|
||||||
grid = _grid;
|
|
||||||
rotate = _rotate;
|
|
||||||
// Used for alignment in "next block" area
|
|
||||||
width = 0;
|
|
||||||
starting_line = 0;
|
|
||||||
for (uint y = 0; y < grid.size(); y++) {
|
|
||||||
bool has_content = false;
|
|
||||||
for (uint x = 0; x < grid[y].size(); x++) {
|
|
||||||
if (grid[y][x]) {
|
|
||||||
width = std::max({width, x + 1});
|
|
||||||
has_content = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (has_content) {
|
|
||||||
if (height == 0) {
|
|
||||||
starting_line = y;
|
|
||||||
}
|
|
||||||
height = y + 1 - starting_line;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
BlockType* BlockType::random() {
|
|
||||||
init();
|
|
||||||
return &list[rand() % list.size()];
|
|
||||||
}
|
|
||||||
|
|
||||||
void BlockType::init() {
|
|
||||||
if (inited) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// I block
|
|
||||||
list.push_back(BlockType(new TileType(
|
|
||||||
sf::IntRect(0, 0, TILE_SIZE, TILE_SIZE),
|
|
||||||
sf::IntRect(0, TILE_SIZE, TILE_SIZE, TILE_SIZE)
|
|
||||||
), {
|
|
||||||
{0, 0, 0, 0},
|
|
||||||
{1, 1, 1, 1},
|
|
||||||
{0, 0, 0, 0},
|
|
||||||
{0, 0, 0, 0}
|
|
||||||
}
|
|
||||||
));
|
|
||||||
|
|
||||||
// J Block
|
|
||||||
list.push_back(BlockType(new TileType(
|
|
||||||
sf::IntRect(TILE_SIZE, 0, TILE_SIZE, TILE_SIZE),
|
|
||||||
sf::IntRect(TILE_SIZE, TILE_SIZE, TILE_SIZE, TILE_SIZE)
|
|
||||||
), {
|
|
||||||
{1, 0, 0},
|
|
||||||
{1, 1, 1},
|
|
||||||
{0, 0, 0}
|
|
||||||
}
|
|
||||||
));
|
|
||||||
|
|
||||||
// L Block
|
|
||||||
list.push_back(BlockType(new TileType(
|
|
||||||
sf::IntRect(TILE_SIZE * 2, 0, TILE_SIZE, TILE_SIZE),
|
|
||||||
sf::IntRect(TILE_SIZE * 2, TILE_SIZE, TILE_SIZE, TILE_SIZE)
|
|
||||||
), {
|
|
||||||
{0, 0, 1},
|
|
||||||
{1, 1, 1},
|
|
||||||
{0, 0, 0}
|
|
||||||
}
|
|
||||||
));
|
|
||||||
|
|
||||||
// O Block
|
|
||||||
list.push_back(BlockType(new TileType(
|
|
||||||
sf::IntRect(TILE_SIZE * 3, 0, TILE_SIZE, TILE_SIZE),
|
|
||||||
sf::IntRect(TILE_SIZE * 3, TILE_SIZE, TILE_SIZE, TILE_SIZE)
|
|
||||||
), {
|
|
||||||
{1, 1},
|
|
||||||
{1, 1}
|
|
||||||
}, false
|
|
||||||
));
|
|
||||||
|
|
||||||
// S Block
|
|
||||||
list.push_back(BlockType(new TileType(
|
|
||||||
sf::IntRect(TILE_SIZE * 4, 0, TILE_SIZE, TILE_SIZE),
|
|
||||||
sf::IntRect(TILE_SIZE * 4, TILE_SIZE, TILE_SIZE, TILE_SIZE)
|
|
||||||
), {
|
|
||||||
{0, 1, 1},
|
|
||||||
{1, 1, 0},
|
|
||||||
{0, 0, 0}
|
|
||||||
}
|
|
||||||
));
|
|
||||||
|
|
||||||
// T Block
|
|
||||||
list.push_back(BlockType(new TileType(
|
|
||||||
sf::IntRect(TILE_SIZE * 5, 0, TILE_SIZE, TILE_SIZE),
|
|
||||||
sf::IntRect(TILE_SIZE * 5, TILE_SIZE, TILE_SIZE, TILE_SIZE)
|
|
||||||
), {
|
|
||||||
{0, 1, 0},
|
|
||||||
{1, 1, 1},
|
|
||||||
{0, 0, 0}
|
|
||||||
}
|
|
||||||
));
|
|
||||||
|
|
||||||
// Z Block
|
|
||||||
list.push_back(BlockType(new TileType(
|
|
||||||
sf::IntRect(TILE_SIZE * 6, 0, TILE_SIZE, TILE_SIZE),
|
|
||||||
sf::IntRect(TILE_SIZE * 6, TILE_SIZE, TILE_SIZE, TILE_SIZE)
|
|
||||||
), {
|
|
||||||
{1, 1, 0},
|
|
||||||
{0, 1, 1},
|
|
||||||
{0, 0, 0}
|
|
||||||
}
|
|
||||||
));
|
|
||||||
|
|
||||||
inited = true;
|
|
||||||
}
|
|
@ -1,505 +0,0 @@
|
|||||||
#include "packed/textures/icon_texture_data.hpp"
|
|
||||||
#include "packed/textures/paused_texture_data.hpp"
|
|
||||||
#include <SFML/Audio.hpp>
|
|
||||||
#include <SFML/Graphics.hpp>
|
|
||||||
#include <SFML/Graphics/Color.hpp>
|
|
||||||
#include <SFML/Graphics/Image.hpp>
|
|
||||||
#include <SFML/Graphics/Rect.hpp>
|
|
||||||
#include <SFML/Graphics/RectangleShape.hpp>
|
|
||||||
#include <SFML/Graphics/Texture.hpp>
|
|
||||||
#include <SFML/System/Vector2.hpp>
|
|
||||||
#include <SFML/Window/Keyboard.hpp>
|
|
||||||
#include <initializer_list>
|
|
||||||
#include <iterator>
|
|
||||||
#include <math.h>
|
|
||||||
#include <fstream>
|
|
||||||
#include <filesystem>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <pwd.h>
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
#include <packed/SharedResources.hpp>
|
|
||||||
|
|
||||||
#include <Config.hpp>
|
|
||||||
#include <NumberRenderer.hpp>
|
|
||||||
#include <TileType.hpp>
|
|
||||||
#include <BlockType.hpp>
|
|
||||||
#include <Block.hpp>
|
|
||||||
|
|
||||||
uint get_level(int lines) {
|
|
||||||
return std::min(lines / LINES_PER_LEVEL, 15);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint get_update_interval(int level) {
|
|
||||||
// From Tetris Worlds, see https://harddrop.com/wiki/Tetris_Worlds#Gravity
|
|
||||||
return pow(0.8 - (level - 1) * 0.007, level - 1) * 1000;
|
|
||||||
}
|
|
||||||
|
|
||||||
int gcd(int n, int m) {
|
|
||||||
for (int i = m<=n ? m:n; i > 1; i--) {
|
|
||||||
if (n % i == 0 && m % i==0)
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int main()
|
|
||||||
{
|
|
||||||
srand(time(NULL));
|
|
||||||
|
|
||||||
sf::RenderWindow window(sf::VideoMode(WINDOW_WIDTH, WINDOW_HEIGHT), "septadrop", sf::Style::Close);
|
|
||||||
window.setFramerateLimit(60);
|
|
||||||
window.setKeyRepeatEnabled(false); // prevent keys from retriggering when held
|
|
||||||
|
|
||||||
sf::Image icon;
|
|
||||||
icon.loadFromMemory(ICON_TEXTURE_DATA, sizeof(ICON_TEXTURE_DATA));
|
|
||||||
auto icon_size = icon.getSize();
|
|
||||||
window.setIcon(icon_size.x, icon_size.y, icon.getPixelsPtr());
|
|
||||||
|
|
||||||
Block block;
|
|
||||||
Block next_block;
|
|
||||||
|
|
||||||
TileType* grid[GRID_HEIGHT][GRID_WIDTH] = { nullptr };
|
|
||||||
|
|
||||||
sf::Texture blocks_texture;
|
|
||||||
blocks_texture.loadFromMemory(&BLOCKS_TEXTURE_DATA, sizeof(BLOCKS_TEXTURE_DATA));
|
|
||||||
sf::Sprite sprite;
|
|
||||||
sprite.setTexture(blocks_texture);
|
|
||||||
|
|
||||||
sf::Texture background_texture;
|
|
||||||
background_texture.loadFromMemory(&BACKGROUND_TEXTURE_DATA, sizeof(BACKGROUND_TEXTURE_DATA));
|
|
||||||
sf::Sprite background;
|
|
||||||
background.setTexture(background_texture);
|
|
||||||
|
|
||||||
sf::Texture numeral_texture;
|
|
||||||
numeral_texture.loadFromMemory(&NUMERALS_TEXTURE_DATA, sizeof(NUMERALS_TEXTURE_DATA));
|
|
||||||
NumberRenderer number_renderer(numeral_texture, sf::IntRect(134, 0, 10, 16), {
|
|
||||||
sf::IntRect(0, 0, 14, 16),
|
|
||||||
sf::IntRect(14, 0, 8, 16),
|
|
||||||
sf::IntRect(22, 0, 14, 16),
|
|
||||||
sf::IntRect(36, 0, 14, 16),
|
|
||||||
sf::IntRect(50, 0, 14, 16),
|
|
||||||
sf::IntRect(64, 0, 14, 16),
|
|
||||||
sf::IntRect(78, 0, 14, 16),
|
|
||||||
sf::IntRect(92, 0, 14, 16),
|
|
||||||
sf::IntRect(106, 0, 14, 16),
|
|
||||||
sf::IntRect(120, 0, 14, 16)
|
|
||||||
});
|
|
||||||
|
|
||||||
bool rotate = false;
|
|
||||||
bool move_left = false;
|
|
||||||
bool move_right = false;
|
|
||||||
bool move_left_immediate = false;
|
|
||||||
bool move_right_immediate = false;
|
|
||||||
bool snap = false;
|
|
||||||
bool paused = false;
|
|
||||||
bool paused_from_lost_focus = false;
|
|
||||||
sf::Clock update_clock, move_clock, pause_clock;
|
|
||||||
uint pause_offset = 0;
|
|
||||||
|
|
||||||
sf::RectangleShape paused_clear;
|
|
||||||
paused_clear.setFillColor(sf::Color(81, 62, 69));
|
|
||||||
|
|
||||||
sf::Texture paused_texture;
|
|
||||||
paused_texture.loadFromMemory(PAUSED_TEXTURE_DATA, sizeof(PAUSED_TEXTURE_DATA));
|
|
||||||
auto paused_texture_size = paused_texture.getSize();
|
|
||||||
|
|
||||||
sf::Sprite paused_text;
|
|
||||||
paused_text.setTexture(paused_texture);
|
|
||||||
paused_text.setPosition(
|
|
||||||
PLAYFIELD_X + ((float)GRID_WIDTH * TILE_SIZE / 2) - (float)paused_texture_size.x / 2,
|
|
||||||
PLAYFIELD_Y + ((float)GRID_HEIGHT * TILE_SIZE / 2) - (float)paused_texture_size.y / 2
|
|
||||||
);
|
|
||||||
|
|
||||||
// https://stackoverflow.com/a/478088
|
|
||||||
const char *homedir;
|
|
||||||
if ((homedir = getenv("HOME")) == NULL) {
|
|
||||||
homedir = getpwuid(getuid())->pw_dir;
|
|
||||||
}
|
|
||||||
std::string highscore_file_path = homedir;
|
|
||||||
highscore_file_path += "/.septadrop";
|
|
||||||
|
|
||||||
if (!std::filesystem::exists(highscore_file_path)) {
|
|
||||||
std::ofstream highscore_file(highscore_file_path);
|
|
||||||
highscore_file << "0";
|
|
||||||
highscore_file.close();
|
|
||||||
}
|
|
||||||
std::fstream highscore_file(highscore_file_path);
|
|
||||||
std::string highscore_string;
|
|
||||||
highscore_file >> highscore_string;
|
|
||||||
uint highscore = std::stoi(highscore_string);
|
|
||||||
uint point_gcd = gcd(POINTS_1_LINE, gcd(POINTS_2_LINES, gcd(POINTS_3_LINES, POINTS_4_LINES)));
|
|
||||||
if (highscore % point_gcd != 0) {
|
|
||||||
std::cout << "It seems your system is misconfigured. Please see this guide for fixing the issue: https://www.youtube.com/watch?v=dQw4w9WgXcQ" << std::endl;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint score = 0;
|
|
||||||
uint lines = 0;
|
|
||||||
uint blocks = 0;
|
|
||||||
uint tiles = 0;
|
|
||||||
|
|
||||||
uint update_interval = get_update_interval(0);
|
|
||||||
|
|
||||||
// https://sfxr.me/#57uBnWWZeyDTsBRrJsAp2Vwd76cMVrdeRQ7DirNQW5XekKxcrCUNx47Zggh7Uqw4R5FdeUpyk362uhjWmpNHmqxE7JBp3EkxDxfJ1VjzMRpuSHieW6B5iyVFM
|
|
||||||
sf::SoundBuffer rotate_buffer;
|
|
||||||
rotate_buffer.loadFromMemory(&ROTATE_AUDIO_DATA, sizeof(ROTATE_AUDIO_DATA));
|
|
||||||
|
|
||||||
sf::Sound rotate_sound;
|
|
||||||
rotate_sound.setBuffer(rotate_buffer);
|
|
||||||
|
|
||||||
// https://sfxr.me/#57uBnWTMa2LUtaPa3P8xWZekiRxNwCPFWpRoPDVXDJM9KHkiGJcs6J62FRcjMY5oVNdT73MtmUf5rXCPvSZWL7AZuTRWWjKbPKTpZjT85AcZ6htUqTswkjksZ
|
|
||||||
sf::SoundBuffer snap_buffer;
|
|
||||||
snap_buffer.loadFromMemory(&SNAP_AUDIO_DATA, sizeof(SNAP_AUDIO_DATA));
|
|
||||||
|
|
||||||
sf::Sound snap_sound;
|
|
||||||
snap_sound.setBuffer(snap_buffer);
|
|
||||||
|
|
||||||
// https://sfxr.me/#57uBnWbareN7MJJsWGD8eFCrqjikS9f8JXg8jvmKzMdVtqmRsb81eToSUpnkqgFhvxD2QoAjpw4SmGZHZjbhEiPQKetRSHCHXYFZzD7Q6RVVS9CRSeRAb6bZp
|
|
||||||
sf::SoundBuffer game_over_buffer;
|
|
||||||
game_over_buffer.loadFromMemory(&GAME_OVER_AUDIO_DATA, sizeof(GAME_OVER_AUDIO_DATA));
|
|
||||||
|
|
||||||
sf::Sound game_over_sound;
|
|
||||||
game_over_sound.setBuffer(game_over_buffer);
|
|
||||||
|
|
||||||
// https://sfxr.me/#7BMHBGMfGk8EHV8czJkUucUm8EMAnMNxiqYyTfKkMpHFJu44GEdD7xP6E8NM3K7RKRExTpagPBAiWf7BLtC52CEWJVGHh8hwDLygoEG86tcPth2UtmfdrXLoh
|
|
||||||
sf::SoundBuffer row_clear_buffer;
|
|
||||||
row_clear_buffer.loadFromMemory(&ROW_CLEAR_AUDIO_DATA, sizeof(ROW_CLEAR_AUDIO_DATA));
|
|
||||||
|
|
||||||
sf::Sound row_clear_sound;
|
|
||||||
row_clear_sound.setBuffer(row_clear_buffer);
|
|
||||||
|
|
||||||
// https://sfxr.me/#57uBnWg8448kTPqWAxeDvZ5CP5JWbrfJGWuRcTjva5uX3vvBnEAZ6SfiH9oLKMXgsusuJwGWx6KPfvLfHtqnhLxr476ptGv4jPbfNhQaFMYeMHFdHk9SotQ4X
|
|
||||||
sf::SoundBuffer level_up_buffer;
|
|
||||||
level_up_buffer.loadFromMemory(&LEVEL_UP_AUDIO_DATA, sizeof(LEVEL_UP_AUDIO_DATA));
|
|
||||||
|
|
||||||
sf::Sound level_up_sound;
|
|
||||||
level_up_sound.setBuffer(level_up_buffer);
|
|
||||||
|
|
||||||
// https://sfxr.me/#34T6PkzvrkfdahGDBAh1uYGXTwZ8rG54kxfHpgdVCPxqG7yyK5UuqgiK9Z8Q5177itxbkSNfLSHm4zTkemT4iyxJpW89VJx82feaq8qxZeA5AJR2nWZZR59hq
|
|
||||||
sf::SoundBuffer new_highscore_buffer;
|
|
||||||
new_highscore_buffer.loadFromMemory(&NEW_HIGHSCORE_AUDIO_DATA, sizeof(NEW_HIGHSCORE_AUDIO_DATA));
|
|
||||||
|
|
||||||
sf::Sound new_highscore_sound;
|
|
||||||
new_highscore_sound.setBuffer(new_highscore_buffer);
|
|
||||||
|
|
||||||
auto toggle_pause = [&] () {
|
|
||||||
paused = !paused;
|
|
||||||
if (paused) {
|
|
||||||
pause_clock.restart();
|
|
||||||
paused_clear.setPosition(sf::Vector2f(PLAYFIELD_X, PLAYFIELD_Y));
|
|
||||||
paused_clear.setSize(sf::Vector2f(GRID_WIDTH * TILE_SIZE, GRID_HEIGHT * TILE_SIZE));
|
|
||||||
window.draw(paused_clear);
|
|
||||||
auto size = sf::Vector2f(NEXT_WIDTH * TILE_SIZE, NEXT_HEIGHT * TILE_SIZE);
|
|
||||||
paused_clear.setPosition(sf::Vector2f(NEXT_X, NEXT_Y) - size / 2.0f);
|
|
||||||
paused_clear.setSize(size);
|
|
||||||
window.draw(paused_clear);
|
|
||||||
window.draw(paused_text);
|
|
||||||
window.display();
|
|
||||||
} else {
|
|
||||||
pause_offset = pause_clock.getElapsedTime().asMilliseconds();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
while (window.isOpen())
|
|
||||||
{
|
|
||||||
sf::Event event;
|
|
||||||
while (window.pollEvent(event))
|
|
||||||
{
|
|
||||||
switch (event.type) {
|
|
||||||
case sf::Event::Closed:
|
|
||||||
window.close();
|
|
||||||
break;
|
|
||||||
case sf::Event::GainedFocus:
|
|
||||||
if (paused && paused_from_lost_focus) {
|
|
||||||
toggle_pause();
|
|
||||||
paused_from_lost_focus = false;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case sf::Event::LostFocus:
|
|
||||||
if (!paused) {
|
|
||||||
toggle_pause();
|
|
||||||
paused_from_lost_focus = true;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case sf::Event::KeyPressed:
|
|
||||||
switch (event.key.code) {
|
|
||||||
case sf::Keyboard::Escape:
|
|
||||||
toggle_pause();
|
|
||||||
break;
|
|
||||||
case sf::Keyboard::Space:
|
|
||||||
snap = !paused;
|
|
||||||
break;
|
|
||||||
case sf::Keyboard::Up:
|
|
||||||
rotate = !paused;
|
|
||||||
break;
|
|
||||||
case sf::Keyboard::Left:
|
|
||||||
move_left = !paused;
|
|
||||||
move_left_immediate = !paused;
|
|
||||||
move_clock.restart();
|
|
||||||
break;
|
|
||||||
case sf::Keyboard::Right:
|
|
||||||
move_right = !paused;
|
|
||||||
move_right_immediate = !paused;
|
|
||||||
move_clock.restart();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case sf::Event::KeyReleased:
|
|
||||||
switch (event.key.code) {
|
|
||||||
case sf::Keyboard::Left:
|
|
||||||
move_left = false;
|
|
||||||
break;
|
|
||||||
case sf::Keyboard::Right:
|
|
||||||
move_right = false;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (paused) {
|
|
||||||
// window.display() is where SFML implements frame rate limiting
|
|
||||||
// If we don't run this here, then when paused septadrop will max out the thread
|
|
||||||
window.display();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool is_update_frame = update_clock.getElapsedTime().asMilliseconds() - pause_offset > (sf::Keyboard::isKeyPressed(sf::Keyboard::Down) ? std::min({update_interval, (uint)MAX_FAST_FORWARD_INTERVAL}) : update_interval);
|
|
||||||
if (is_update_frame) {
|
|
||||||
update_clock.restart();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool is_move_frame = move_clock.getElapsedTime().asMilliseconds() - pause_offset > MOVE_FRAME_INTERVAL;
|
|
||||||
if (is_move_frame) {
|
|
||||||
move_clock.restart();
|
|
||||||
}
|
|
||||||
|
|
||||||
pause_offset = 0;
|
|
||||||
|
|
||||||
// Rotation
|
|
||||||
if (rotate) {
|
|
||||||
block.rotation_state++;
|
|
||||||
// Check to see if new rotation state is overlapping any tiles
|
|
||||||
int offset_required = 0;
|
|
||||||
for (auto tile : block.get_tiles()) {
|
|
||||||
if (grid[tile.y][tile.x]) {
|
|
||||||
// Can't wall kick off of blocks
|
|
||||||
block.rotation_state--;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (tile.x <= 0) {
|
|
||||||
int potential_offset = -tile.x;
|
|
||||||
if (potential_offset > abs(offset_required)) {
|
|
||||||
offset_required = potential_offset;
|
|
||||||
}
|
|
||||||
} else if (tile.x >= GRID_WIDTH) {
|
|
||||||
int potential_offset = GRID_WIDTH - tile.x - 1;
|
|
||||||
if (-potential_offset > abs(offset_required)) {
|
|
||||||
offset_required = potential_offset;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
block.position.x += offset_required;
|
|
||||||
rotate = false;
|
|
||||||
rotate_sound.play();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Horizontal movement
|
|
||||||
int movement = 0;
|
|
||||||
if (move_left_immediate || is_move_frame && move_left) {
|
|
||||||
movement--;
|
|
||||||
move_left_immediate = false;
|
|
||||||
}
|
|
||||||
if (move_right_immediate || is_move_frame && move_right) {
|
|
||||||
movement++;
|
|
||||||
move_right_immediate = false;
|
|
||||||
}
|
|
||||||
if (movement != 0) {
|
|
||||||
for (auto tile : block.get_tiles()) {
|
|
||||||
if (tile.x + movement < 0 || tile.x + movement >= GRID_WIDTH || grid[tile.y][tile.x + movement]) {
|
|
||||||
goto after_movement_loop;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
block.position.x += movement;
|
|
||||||
}
|
|
||||||
after_movement_loop:
|
|
||||||
|
|
||||||
// Snapping
|
|
||||||
int snap_offset = 0;
|
|
||||||
while (true) {
|
|
||||||
for (auto tile : block.get_tiles()) {
|
|
||||||
int y = tile.y + snap_offset;
|
|
||||||
if (y == GRID_HEIGHT - 1 || grid[y + 1][tile.x] != nullptr) {
|
|
||||||
goto after_snap_loop;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
snap_offset++;
|
|
||||||
}
|
|
||||||
after_snap_loop:
|
|
||||||
bool landed = snap;
|
|
||||||
if (snap) {
|
|
||||||
block.position.y += snap_offset;
|
|
||||||
snap = false;
|
|
||||||
snap_sound.play();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Land checking
|
|
||||||
if (!snap && is_update_frame) {
|
|
||||||
for (auto tile : block.get_tiles()) {
|
|
||||||
if (tile.y == GRID_HEIGHT - 1 || grid[tile.y + 1][tile.x] != nullptr) {
|
|
||||||
landed = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clear window
|
|
||||||
// Normally, one would run window.clear(),
|
|
||||||
// but the background image covers the entire window.
|
|
||||||
window.draw(background);
|
|
||||||
|
|
||||||
// Draw block
|
|
||||||
if (!landed) {
|
|
||||||
for (auto tile : block.get_tiles()) {
|
|
||||||
int snap_y = tile.y + snap_offset;
|
|
||||||
sprite.setTextureRect(block.type->tile_type->texture_rect);
|
|
||||||
sprite.setPosition(PLAYFIELD_X + tile.x * TILE_SIZE, PLAYFIELD_Y + tile.y * TILE_SIZE);
|
|
||||||
window.draw(sprite);
|
|
||||||
sprite.setTextureRect(block.type->tile_type->ghost_texture_rect);
|
|
||||||
sprite.setPosition(PLAYFIELD_X + tile.x * TILE_SIZE, PLAYFIELD_Y + snap_y * TILE_SIZE);
|
|
||||||
window.draw(sprite);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Draw next block
|
|
||||||
auto next_block_tiles = next_block.get_tiles();
|
|
||||||
// This is assuming the next block spawns unrotated.
|
|
||||||
// Refactoring is needed if random rotations are added
|
|
||||||
uint x_offset = next_block.type->width * TILE_SIZE / 2;
|
|
||||||
uint y_offset = (next_block.type->height + next_block.type->starting_line * 2) * TILE_SIZE / 2;
|
|
||||||
for (auto tile : next_block_tiles) {
|
|
||||||
sprite.setTextureRect(next_block.type->tile_type->texture_rect);
|
|
||||||
sprite.setPosition(
|
|
||||||
NEXT_X + (tile.x - next_block.position.x) * TILE_SIZE - x_offset,
|
|
||||||
NEXT_Y + (tile.y - next_block.position.y) * TILE_SIZE - y_offset
|
|
||||||
);
|
|
||||||
window.draw(sprite);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Landing (transfering block to grid and reinitializing)
|
|
||||||
if (landed) {
|
|
||||||
if (block.position.y == 0) {
|
|
||||||
score = 0;
|
|
||||||
lines = 0;
|
|
||||||
blocks = 0;
|
|
||||||
tiles = 0;
|
|
||||||
for (int y = 0; y < GRID_HEIGHT; y++) {
|
|
||||||
for (int x = 0; x < GRID_WIDTH; x++) {
|
|
||||||
grid[y][x] = nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
update_interval = get_update_interval(0);
|
|
||||||
game_over_sound.play();
|
|
||||||
} else {
|
|
||||||
tiles += block.get_tiles().size();
|
|
||||||
blocks++;
|
|
||||||
for (auto tile : block.get_tiles()) {
|
|
||||||
grid[tile.y][tile.x] = block.type->tile_type;
|
|
||||||
}
|
|
||||||
uint cleared_lines = 0;
|
|
||||||
// Check for completed rows
|
|
||||||
for (int y = 0; y < GRID_HEIGHT; y++) {
|
|
||||||
bool completed = true;
|
|
||||||
for (int x = 0; x < GRID_WIDTH; x++) {
|
|
||||||
if (!grid[y][x]) {
|
|
||||||
completed = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!completed) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
for (int z = y - 1; z >= 0; z--) {
|
|
||||||
for (int x = 0; x < GRID_WIDTH; x++) {
|
|
||||||
grid[z + 1][x] = grid[z][x];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
cleared_lines++;
|
|
||||||
}
|
|
||||||
uint scored;
|
|
||||||
switch (cleared_lines) {
|
|
||||||
case 0:
|
|
||||||
scored = 0;
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
scored = POINTS_1_LINE;
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
scored = POINTS_2_LINES;
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
scored = POINTS_3_LINES;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
scored = POINTS_4_LINES;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (scored > 0) {
|
|
||||||
int level = get_level(lines);
|
|
||||||
scored *= level + 1;
|
|
||||||
if (score + scored > highscore && score < highscore) {
|
|
||||||
new_highscore_sound.play();
|
|
||||||
}
|
|
||||||
score += scored;
|
|
||||||
lines += cleared_lines;
|
|
||||||
if (level != get_level(lines)) {
|
|
||||||
level_up_sound.play();
|
|
||||||
}
|
|
||||||
if (score > highscore) {
|
|
||||||
highscore = score;
|
|
||||||
std::ofstream highscore_file(highscore_file_path);
|
|
||||||
highscore_file << highscore;
|
|
||||||
highscore_file.close();
|
|
||||||
}
|
|
||||||
update_interval = get_update_interval(level);
|
|
||||||
row_clear_sound.play();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
block = next_block;
|
|
||||||
next_block = Block();
|
|
||||||
} else if(is_update_frame) {
|
|
||||||
block.position.y++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Drawing grid
|
|
||||||
for (int y = 0; y < GRID_HEIGHT; y++) {
|
|
||||||
for (int x = 0; x < GRID_WIDTH; x++) {
|
|
||||||
auto tile_type = grid[y][x];
|
|
||||||
if (tile_type == nullptr) {
|
|
||||||
// If tile_type is a nullptr (no block), continue
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
sprite.setTextureRect(tile_type->texture_rect);
|
|
||||||
sprite.setPosition(PLAYFIELD_X + x * TILE_SIZE, PLAYFIELD_Y + y * TILE_SIZE);
|
|
||||||
window.draw(sprite);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
number_renderer.render(&window, score, 477, 162);
|
|
||||||
number_renderer.render(&window, highscore, 477, 202);
|
|
||||||
number_renderer.render(&window, lines, 477, 242);
|
|
||||||
number_renderer.render(&window, get_level(lines), 477, 282);
|
|
||||||
number_renderer.render(&window, blocks, 477, 322);
|
|
||||||
number_renderer.render(&window, tiles, 477, 362);
|
|
||||||
|
|
||||||
window.display();
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
@ -1,51 +0,0 @@
|
|||||||
#include <SFML/Graphics.hpp>
|
|
||||||
#include <sys/types.h>
|
|
||||||
|
|
||||||
#include <NumberRenderer.hpp>
|
|
||||||
|
|
||||||
NumberRenderer::NumberRenderer(
|
|
||||||
sf::Texture _texture,
|
|
||||||
sf::IntRect _comma_rect,
|
|
||||||
std::initializer_list<sf::IntRect> _numeral_rects
|
|
||||||
) {
|
|
||||||
texture = _texture;
|
|
||||||
comma_rect = _comma_rect;
|
|
||||||
sprite = sf::Sprite(texture);
|
|
||||||
int i = 0;
|
|
||||||
for (auto numeral_rect = _numeral_rects.begin(); numeral_rect != _numeral_rects.end(); ++numeral_rect) {
|
|
||||||
numeral_rects[i] = *numeral_rect;
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void NumberRenderer::render(sf::RenderWindow* window, uint number, int x, int y) {
|
|
||||||
auto number_string = std::to_string(number);
|
|
||||||
std::string numeral_string;
|
|
||||||
numeral_string.push_back(number_string.back());
|
|
||||||
auto numeral_rect = numeral_rects[std::stoi(numeral_string)];
|
|
||||||
int x_offset = -numeral_rect.width;
|
|
||||||
uint digits = number_string.length();
|
|
||||||
for (int i = digits - 1; i >= 0; i--) {
|
|
||||||
char numeral_string[] = {number_string[i]};
|
|
||||||
auto numeral_rect = numeral_rects[std::stoi(numeral_string)];
|
|
||||||
if ((digits - i) % 3 == 1 && i != digits - 1) {
|
|
||||||
sprite.setTextureRect(comma_rect);
|
|
||||||
sprite.setPosition(x + x_offset, y);
|
|
||||||
window->draw(sprite);
|
|
||||||
x_offset -= numeral_rect.width;
|
|
||||||
}
|
|
||||||
sprite.setTextureRect(numeral_rect);
|
|
||||||
sprite.setPosition(x + x_offset, y);
|
|
||||||
window->draw(sprite);
|
|
||||||
if (i == 0) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if ((digits - i) % 3 == 0) {
|
|
||||||
x_offset -= comma_rect.width;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
numeral_string[0] = number_string[i - 1];
|
|
||||||
numeral_rect = numeral_rects[std::stoi(numeral_string)];
|
|
||||||
x_offset -= numeral_rect.width;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,8 +0,0 @@
|
|||||||
#include <SFML/Graphics/Rect.hpp>
|
|
||||||
|
|
||||||
#include <TileType.hpp>
|
|
||||||
|
|
||||||
TileType::TileType(sf::IntRect _texture_rect, sf::IntRect _ghost_texture_rect) {
|
|
||||||
texture_rect = _texture_rect;
|
|
||||||
ghost_texture_rect = _ghost_texture_rect;
|
|
||||||
}
|
|
@ -0,0 +1,3 @@
|
|||||||
|
fn main() {
|
||||||
|
println!("Hello, world!");
|
||||||
|
}
|
Loading…
Reference in new issue