Compare commits
26 commits
main
...
dev/n0ffie
Author | SHA1 | Date | |
---|---|---|---|
c33f1528b6 | |||
d93544b846 | |||
bb646ff009 | |||
c58a00608d | |||
e856e2c054 | |||
ea72294a3e | |||
37a249dc62 | |||
72d1bf3bfb | |||
5372f2ecb0 | |||
12f6c5fb59 | |||
d4e83614fa | |||
7e00f5d327 | |||
f58d8a6280 | |||
de72aead56 | |||
4536c62dad | |||
c0e3af64d6 | |||
bf0c7ab8ef | |||
9f616e196c | |||
b1230534c5 | |||
2dbfa1b99e | |||
fdebdd3ca2 | |||
39abfaa978 | |||
04d7c97e93 | |||
b7ddc3f292 | |||
23a40216de | |||
9504620227 |
13 changed files with 2037 additions and 69 deletions
87
.gitignore
vendored
87
.gitignore
vendored
|
@ -1,68 +1,19 @@
|
|||
# ---> C
|
||||
# Prerequisites
|
||||
*.d
|
||||
|
||||
# Object files
|
||||
*.o
|
||||
*.ko
|
||||
*.obj
|
||||
*.elf
|
||||
|
||||
# Linker output
|
||||
*.ilk
|
||||
*.map
|
||||
*.exp
|
||||
|
||||
# Precompiled Headers
|
||||
*.gch
|
||||
*.pch
|
||||
|
||||
# Libraries
|
||||
*.lib
|
||||
*.a
|
||||
*.la
|
||||
*.lo
|
||||
|
||||
# Shared objects (inc. Windows DLLs)
|
||||
*.dll
|
||||
*.so
|
||||
*.so.*
|
||||
*.dylib
|
||||
|
||||
# Executables
|
||||
*.exe
|
||||
*.out
|
||||
*.app
|
||||
*.i*86
|
||||
*.x86_64
|
||||
*.hex
|
||||
|
||||
# Debug files
|
||||
*.dSYM/
|
||||
*.su
|
||||
*.idb
|
||||
*.pdb
|
||||
|
||||
# Kernel Module Compile Results
|
||||
*.mod*
|
||||
*.cmd
|
||||
.tmp_versions/
|
||||
modules.order
|
||||
Module.symvers
|
||||
Mkfile.old
|
||||
dkms.conf
|
||||
|
||||
# ---> CMake
|
||||
CMakeLists.txt.user
|
||||
CMakeCache.txt
|
||||
CMakeFiles
|
||||
CMakeScripts
|
||||
Testing
|
||||
Makefile
|
||||
cmake_install.cmake
|
||||
install_manifest.txt
|
||||
compile_commands.json
|
||||
CTestTestfile.cmake
|
||||
_deps
|
||||
CMakeUserPresets.json
|
||||
|
||||
.bake_cache
|
||||
.DS_Store
|
||||
.vscode
|
||||
.vs
|
||||
gcov
|
||||
bin
|
||||
build
|
||||
.cache
|
||||
.idea
|
||||
cmake-**/
|
||||
.kdev4
|
||||
*.kdev4
|
||||
assets/
|
||||
assets/**
|
||||
*.cymf
|
||||
*.png
|
||||
*.bmp
|
||||
*.jpg
|
||||
test.**
|
||||
|
|
66
CMakeLists.txt
Normal file
66
CMakeLists.txt
Normal file
|
@ -0,0 +1,66 @@
|
|||
cmake_minimum_required(VERSION 3.20)
|
||||
|
||||
project(colysis
|
||||
LANGUAGES CXX
|
||||
VERSION 0.0.1
|
||||
)
|
||||
|
||||
# Set C/C++ standards
|
||||
set(CMAKE_C_STANDARD 11)
|
||||
set(CMAKE_C_STANDARD_REQUIRED ON)
|
||||
set(CMAKE_C_EXTENSIONS OFF)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 23)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
set(CMAKE_CXX_EXTENSIONS OFF)
|
||||
|
||||
# Set compiler flags
|
||||
set(CMAKE_EXPORT_COMPILE_COMMANDS ON) # Generate compile commands (useful for IDEs)
|
||||
set(USE_FOLDERS ON) # Organize targets into folders (for IDEs)
|
||||
set(BUILD_SHARED_LIBS OFF CACHE BOOL "" FORCE) # Build static libraries by default
|
||||
|
||||
|
||||
include(cmake/CPM.cmake)
|
||||
|
||||
# sfml
|
||||
CPMAddPackage(
|
||||
NAME sfml
|
||||
GITHUB_REPOSITORY SFML/SFML
|
||||
GIT_TAG 3.0.0
|
||||
)
|
||||
|
||||
# # flecs
|
||||
# CPMAddPackage(
|
||||
# NAME flecs
|
||||
# GITHUB_REPOSITORY SanderMertens/flecs
|
||||
# GIT_TAG v4.0.4
|
||||
# )
|
||||
|
||||
|
||||
include(cmake/utils.cmake)
|
||||
|
||||
# Get files in src/ and add them to the executable
|
||||
|
||||
find_files(colysis_src src cpp hpp cxx hxx c h)
|
||||
add_executable(colysis
|
||||
${colysis_src}
|
||||
)
|
||||
|
||||
target_link_libraries(colysis
|
||||
SFML::Audio
|
||||
SFML::Graphics
|
||||
SFML::Window
|
||||
SFML::System
|
||||
)
|
||||
|
||||
target_compile_definitions(colysis PUBLIC "$<$<CONFIG:DEBUG>:_DEBUG>")
|
||||
|
||||
target_include_directories(colysis PUBLIC include)
|
||||
|
||||
# put the assets folder path as a C preprocessor define
|
||||
set(ASSETS_PATH "${CMAKE_CURRENT_SOURCE_DIR}/assets/")
|
||||
target_compile_definitions(colysis PRIVATE ASSETS_PATH="${ASSETS_PATH}")
|
||||
message(STATUS "Assets path : ${ASSETS_PATH}")
|
||||
|
||||
|
||||
# put_targets_into_folder(FOLDER "vendor/flecs" TARGETS flecs::flecs flecs::flecs_static)
|
36
README.md
36
README.md
|
@ -1,2 +1,36 @@
|
|||
# colysis
|
||||
# Colysis
|
||||
A simple game written in C++ and using SFML.
|
||||
|
||||
## Building
|
||||
To build the project, you need to have [CMake](https://cmake.org/) installed.
|
||||
|
||||
### Linux
|
||||
```sh
|
||||
mkdir build
|
||||
cd build
|
||||
cmake ..
|
||||
make
|
||||
```
|
||||
|
||||
### Windows
|
||||
```sh
|
||||
mkdir build
|
||||
cd build
|
||||
cmake -G "Visual Studio 17 2022" ..
|
||||
cmake --build . --config Release
|
||||
```
|
||||
|
||||
### macOS
|
||||
```sh
|
||||
mkdir build
|
||||
cd build
|
||||
cmake -G "Xcode" ..
|
||||
cmake --build . --config Release
|
||||
```
|
||||
|
||||
## Running
|
||||
After building, you can run the game by executing the `colysis` executable.
|
||||
|
||||
## License
|
||||
The game will be open source *but* without the game assets. \
|
||||
So you will be able to make your own game from colysis but the assets can only be purchased.
|
||||
|
|
1289
cmake/CPM.cmake
Normal file
1289
cmake/CPM.cmake
Normal file
File diff suppressed because it is too large
Load diff
33
cmake/utils.cmake
Normal file
33
cmake/utils.cmake
Normal file
|
@ -0,0 +1,33 @@
|
|||
|
||||
function(put_targets_into_folder)
|
||||
set(oneValueArgs FOLDER)
|
||||
set(multiValueArgs TARGETS)
|
||||
cmake_parse_arguments(ARGS "" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
|
||||
|
||||
foreach(target ${ARGS_TARGETS})
|
||||
# Check if target exists
|
||||
if (NOT TARGET ${target})
|
||||
message(FATAL_ERROR "${target} target not found")
|
||||
endif()
|
||||
|
||||
# Get the actual target (if it is aliased)
|
||||
get_target_property(actual_target ${target} ALIASED_TARGET)
|
||||
if (NOT actual_target)
|
||||
set(actual_target ${target})
|
||||
endif()
|
||||
|
||||
# Set the folder property for the target
|
||||
set_target_properties(${actual_target} PROPERTIES FOLDER ${ARGS_FOLDER})
|
||||
endforeach()
|
||||
endfunction()
|
||||
|
||||
|
||||
function(find_files var_name path)
|
||||
set(sources)
|
||||
foreach(ext ${ARGN})
|
||||
file(GLOB_RECURSE files "${path}/*.${ext}")
|
||||
list(APPEND sources ${files})
|
||||
endforeach()
|
||||
set(${var_name} ${${var_name}} ${sources} PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
23
src/Enemy/Enemy.cpp
Normal file
23
src/Enemy/Enemy.cpp
Normal file
|
@ -0,0 +1,23 @@
|
|||
#include "Enemy.hpp"
|
||||
|
||||
#include <ctgmath>
|
||||
|
||||
Enemy::Enemy(sf::Vector2f position) : rectangle(sf::Vector2f{100, 100})
|
||||
{
|
||||
rectangle.move(position);
|
||||
rectangle.setFillColor(sf::Color::Red);
|
||||
}
|
||||
|
||||
void Enemy::look_at(sf::Vector2f target)
|
||||
{
|
||||
float dx = target.x - rectangle.getPosition().x;
|
||||
float dy = target.y - rectangle.getPosition().y;
|
||||
|
||||
float angle = atan2(dy, dx);
|
||||
rectangle.setRotation(sf::degrees(angle));
|
||||
}
|
||||
|
||||
void Enemy::draw(sf::RenderTarget& target, const sf::RenderStates states) const
|
||||
{
|
||||
target.draw(rectangle, states);
|
||||
}
|
13
src/Enemy/Enemy.hpp
Normal file
13
src/Enemy/Enemy.hpp
Normal file
|
@ -0,0 +1,13 @@
|
|||
#pragma once
|
||||
#include <SFML/Graphics.hpp>
|
||||
|
||||
class Enemy : public sf::Drawable
|
||||
{
|
||||
sf::RectangleShape rectangle;
|
||||
public:
|
||||
explicit Enemy(sf::Vector2f position);
|
||||
|
||||
void look_at(sf::Vector2f target);
|
||||
|
||||
void draw(sf::RenderTarget& target, sf::RenderStates states) const override;
|
||||
};
|
51
src/Game.cpp
Normal file
51
src/Game.cpp
Normal file
|
@ -0,0 +1,51 @@
|
|||
#include "Game.hpp"
|
||||
|
||||
Game::Game(sf::RenderWindow& window) : window(window)
|
||||
{
|
||||
}
|
||||
|
||||
#include <iostream>
|
||||
void Game::run()
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
std::cout << "Loading map... Version: " MAP_VERSION_STRING << std::endl;
|
||||
const auto start = std::chrono::system_clock::now();
|
||||
#endif
|
||||
|
||||
auto [message, code] = map.load(ASSETS_PATH "/test.cymf");
|
||||
|
||||
#ifdef _DEBUG
|
||||
const auto end = std::chrono::system_clock::now();
|
||||
const auto milliseconds = std::chrono::duration_cast<std::chrono::microseconds>(end - start);
|
||||
std::cout << "Loading took: " << milliseconds << std::endl;
|
||||
#endif
|
||||
|
||||
map.setPosition(sf::Vector2f{20, 20});
|
||||
|
||||
if (code != 0)
|
||||
{
|
||||
std::cout << message << std::endl;
|
||||
return;
|
||||
}
|
||||
#ifdef _DEBUG
|
||||
map.debug();
|
||||
#endif
|
||||
while (window.isOpen())
|
||||
{
|
||||
while (const auto event = window.pollEvent())
|
||||
{
|
||||
if (event->is<sf::Event::Closed>())
|
||||
{
|
||||
window.close();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Render game
|
||||
window.clear({0x20, 0x20, 0x20,0xff});
|
||||
|
||||
window.draw(map);
|
||||
|
||||
window.display();
|
||||
}
|
||||
}
|
19
src/Game.hpp
Normal file
19
src/Game.hpp
Normal file
|
@ -0,0 +1,19 @@
|
|||
#pragma once
|
||||
|
||||
#include <SFML/Graphics.hpp>
|
||||
|
||||
#include "Enemy/Enemy.hpp"
|
||||
#include "Map/Map.hpp"
|
||||
|
||||
#include <vector>
|
||||
class Game
|
||||
{
|
||||
Map map;
|
||||
public:
|
||||
explicit Game(sf::RenderWindow& window);
|
||||
|
||||
void run();
|
||||
private:
|
||||
sf::RenderWindow& window;
|
||||
};
|
||||
|
262
src/Map/Map.cpp
Normal file
262
src/Map/Map.cpp
Normal file
|
@ -0,0 +1,262 @@
|
|||
#include "Map.hpp"
|
||||
|
||||
#include <fstream>
|
||||
|
||||
bool operator==(uint32_t lhs, TileType rhs) {
|
||||
return lhs == static_cast<uint32_t>(rhs);
|
||||
}
|
||||
|
||||
bool operator&(uint8_t lhs, MapFlags rhs)
|
||||
{
|
||||
return lhs & static_cast<uint8_t>(rhs);
|
||||
}
|
||||
|
||||
bool operator==(int lhs, TileType rhs)
|
||||
{
|
||||
return lhs == static_cast<int>(rhs);
|
||||
}
|
||||
|
||||
auto operator<=>(int lhs, TileType rhs)
|
||||
{
|
||||
return lhs <=> static_cast<int>(rhs);
|
||||
}
|
||||
|
||||
MapError Map::populate_vertex_array() {
|
||||
if (!tiles) return {"Map: [Loading] Tilemap is not loaded", 2};
|
||||
|
||||
atlas.vertices.setPrimitiveType(sf::PrimitiveType::Triangles);
|
||||
atlas.vertices.resize(map_size.x * map_size.y * 6);
|
||||
|
||||
const auto xw = static_cast<float>(atlas.tile_size.x);
|
||||
const auto yw = static_cast<float>(atlas.tile_size.y);
|
||||
const auto tex_w = static_cast<float>(atlas.tile_size.x);
|
||||
const auto tex_h = static_cast<float>(atlas.tile_size.y);
|
||||
for (uint32_t x = 0; x < map_size.y; x++) {
|
||||
for (uint32_t y = 0; y < map_size.z; y++)
|
||||
{
|
||||
const int32_t tile = tiles[x + y * map_size.y];
|
||||
if (tile < -atlas.wall_tiles || tile > atlas.other_tiles) return {"Map: [Loading] Invalid tile! Tile type does not have a texture; ID: " + std::to_string(tile), 3};
|
||||
// map tile type to atlas
|
||||
/*
|
||||
* Atlas:
|
||||
* +++++
|
||||
* +++--
|
||||
* ---##
|
||||
*
|
||||
* + = wall
|
||||
* # = special
|
||||
* - = other
|
||||
*
|
||||
* wall_tiles = 8
|
||||
* other_tiles = 5
|
||||
* special_tiles = 2
|
||||
*
|
||||
* Tile:
|
||||
* -1 <= wall
|
||||
* 0 == special @ .type == tile_type
|
||||
* 1 >= other
|
||||
*/
|
||||
if (tile == 0) return {"Map: [Loading] [Not Implemented!] Tile is a special tile", 3};
|
||||
|
||||
// atlas tile index
|
||||
const uint32_t atlas_tile = atlas.wall_tiles + (tile - 1);
|
||||
if (atlas_tile >= atlas.wall_tiles + atlas.other_tiles) return {"Map: [Loading] Invalid tile! Tile type does not have a texture", 3};
|
||||
|
||||
// add the vertices
|
||||
const auto xf = static_cast<float>(x * atlas.tile_size.x);
|
||||
const auto yf = static_cast<float>(y * atlas.tile_size.y);
|
||||
const uint32_t tile_x = atlas_tile % atlas.tile_count.x;
|
||||
const uint32_t tile_y = atlas_tile / atlas.tile_count.x;
|
||||
const auto tex_x = static_cast<float>(tile_x * atlas.tile_size.x);
|
||||
const auto tex_y = static_cast<float>(tile_y * atlas.tile_size.y);
|
||||
|
||||
sf::Vertex tl = {{xf, yf}, sf::Color::White, {tex_x, tex_y}};
|
||||
sf::Vertex tr = {{xf + xw, yf}, sf::Color::White, {tex_x + tex_w, tex_y}};
|
||||
sf::Vertex bl = {{xf, yf + yw}, sf::Color::White, {tex_x, tex_y + tex_h}};
|
||||
sf::Vertex br = {{xf + xw, yf + yw}, sf::Color::White, {tex_x + tex_w, tex_y + tex_h}};
|
||||
|
||||
atlas.vertices.append(tl);
|
||||
atlas.vertices.append(tr);
|
||||
atlas.vertices.append(bl);
|
||||
|
||||
atlas.vertices.append(bl);
|
||||
atlas.vertices.append(tr);
|
||||
atlas.vertices.append(br);
|
||||
}
|
||||
}
|
||||
|
||||
return {"Map: [Loading] Success", 0};
|
||||
}
|
||||
|
||||
void Map::LoadDefaultTilemap() {
|
||||
atlas.wall_tiles = 0;
|
||||
atlas.other_tiles = 1;
|
||||
atlas.special_tiles = 0;
|
||||
atlas.tile_count = {1, 1};
|
||||
atlas.tile_size = {16, 16};
|
||||
if (!atlas.texture.loadFromFile(ASSETS_PATH "/default_tilemap.png")) {
|
||||
throw std::runtime_error("Map: [Loading] Could not load default tilemap -> Fatal");
|
||||
}
|
||||
}
|
||||
|
||||
Map::Map(): atlas() {
|
||||
}
|
||||
|
||||
|
||||
#include <iostream>
|
||||
#include <cstring>
|
||||
|
||||
#include <filesystem>
|
||||
|
||||
MapError Map::load(const std::filesystem::path& path)
|
||||
{
|
||||
// opening the file and checking the magic number
|
||||
std::ifstream file(path, std::ios::binary | std::ios::in);
|
||||
|
||||
if (!file.is_open()) {
|
||||
return {"Map: [Loading] Could not open file: " + path.string(), 1};
|
||||
}
|
||||
|
||||
char magic[4];
|
||||
file.read(magic, 4);
|
||||
|
||||
if (std::memcmp(magic, "CYMF", 4) != 0) {
|
||||
return {"Map: [Loading] Invalid magic number: " + std::string(magic, 4) + " (expected CYMF)", 1};
|
||||
}
|
||||
|
||||
// reading the version
|
||||
uint8_t version[3];
|
||||
file.read(reinterpret_cast<char*>(version), 3);
|
||||
if (version[0] != MAP_VERSION_MAJOR || version[1] > MAP_VERSION_MINOR)
|
||||
{
|
||||
return {"Map: [Loading] Invalid version; Current: " MAP_VERSION_STRING, 1};
|
||||
}
|
||||
|
||||
// reading the flags
|
||||
uint8_t flags;
|
||||
file.read(reinterpret_cast<char*>(&flags), 1);
|
||||
|
||||
// flag CustomTilemap -> load the tilemap
|
||||
if (flags & MapFlags::CustomTilemap)
|
||||
{
|
||||
uint32_t filepath_buffer_size;
|
||||
file.read(reinterpret_cast<char*>(&filepath_buffer_size), 4);
|
||||
|
||||
char* filepath_buffer = new char[filepath_buffer_size];
|
||||
file.read(filepath_buffer, filepath_buffer_size);
|
||||
|
||||
return {"Map: [Loading] [Not Implemented] Custom Tilemap is not implemented. Tilemap file: " + std::string(filepath_buffer, filepath_buffer_size), 1};
|
||||
|
||||
delete[] filepath_buffer;
|
||||
}
|
||||
else {
|
||||
LoadDefaultTilemap();
|
||||
}
|
||||
|
||||
|
||||
// load the map info
|
||||
uint32_t map_info[3];
|
||||
file.read(reinterpret_cast<char*>(map_info), 12);
|
||||
map_size = sf::Vector3<size_t>(static_cast<size_t>(map_info[0])*map_info[1], map_info[0], map_info[1]);
|
||||
|
||||
// load the tiles
|
||||
tiles = new int[map_info[0] * map_info[1]];
|
||||
for (int i = 0; i < map_info[0] * map_info[1]; i++)
|
||||
{
|
||||
// read the special if needed
|
||||
file.read(reinterpret_cast<char*>(&tiles[i]), 4);
|
||||
if (tiles[i] == TileType::Special)
|
||||
{
|
||||
MapSpecial special{};
|
||||
file.read(reinterpret_cast<char*>(&special), sizeof(MapSpecial));
|
||||
// get position
|
||||
uint32_t tile_x = i % map_info[0];
|
||||
uint32_t tile_y = i / map_info[0];
|
||||
specials.emplace_back(std::pair<sf::Vector2u, MapSpecial>({tile_x, tile_y}, special));
|
||||
}
|
||||
}
|
||||
|
||||
// load the player spawn
|
||||
uint32_t t_player_spawn[2];
|
||||
file.read(reinterpret_cast<char*>(t_player_spawn), 8);
|
||||
player_spawn = sf::Vector2u{t_player_spawn[0], t_player_spawn[1]};
|
||||
if (player_spawn.x >= map_size.y || player_spawn.y >= map_size.z)
|
||||
{
|
||||
return {"Map: [Loading] Player: Spawn out of bounds", 2};
|
||||
}
|
||||
int player_tile = tiles[player_spawn.x + player_spawn.y * map_size.x];
|
||||
if (player_tile <= TileType::Special)
|
||||
{
|
||||
return {"Map: [Loading] Player: Spawn is not a valid tile (invalid: wall, special; valid: Floor)", 2};
|
||||
}
|
||||
|
||||
// load all the enemy spawns
|
||||
uint32_t number_enemy_spawns;
|
||||
file.read(reinterpret_cast<char*>(&number_enemy_spawns), 4);
|
||||
if (number_enemy_spawns > map_size.x)
|
||||
{
|
||||
return {"Map: [Loading] Enemies: Too many enemy spawns (More than tile in the map)", 3};
|
||||
}
|
||||
for (int i = 0; i < number_enemy_spawns; i++)
|
||||
{
|
||||
uint32_t t_enemy_spawn[2];
|
||||
file.read(reinterpret_cast<char*>(t_enemy_spawn), 8);
|
||||
if (t_enemy_spawn[0] >= map_size.x || t_enemy_spawn[1] >= map_size.y)
|
||||
{
|
||||
return {"Map: [Loading] Enemy: Spawn out of bounds", 4};
|
||||
}
|
||||
if (tiles[t_enemy_spawn[0] + t_enemy_spawn[1] * map_size.y] <= TileType::Special)
|
||||
{
|
||||
return {"Map: [Loading] Enemy: Spawn is not a valid tile (invalid: wall, special; valid: Floor)", 4};
|
||||
}
|
||||
if (t_enemy_spawn[0] == player_spawn.x && t_enemy_spawn[1] == player_spawn.y)
|
||||
{
|
||||
return {"Map: [Loading] Enemy: Spawn is the same as the player spawn", 4};
|
||||
}
|
||||
enemy_spawns.emplace_back(t_enemy_spawn[0], t_enemy_spawn[1]);
|
||||
}
|
||||
|
||||
// Everything went well
|
||||
return populate_vertex_array();
|
||||
}
|
||||
|
||||
sf::Vector2u Map::getSize() const
|
||||
{
|
||||
return {static_cast<uint32_t>(map_size.y), static_cast<uint32_t>(map_size.z)};
|
||||
}
|
||||
|
||||
void Map::draw(sf::RenderTarget& target, sf::RenderStates states) const
|
||||
{
|
||||
if (!tiles) return;
|
||||
|
||||
// apply the transform
|
||||
states.transform *= getTransform();
|
||||
|
||||
// apply the tileset texture
|
||||
states.texture = &atlas.texture;
|
||||
|
||||
// draw the vertex array
|
||||
target.draw(atlas.vertices, states);
|
||||
}
|
||||
|
||||
|
||||
#ifdef _DEBUG
|
||||
void Map::debug()
|
||||
{
|
||||
std::cout << "Map Debug" << std::endl;
|
||||
std::cout << "\tSize : " << map_size.x << ", " << map_size.y << ", " << map_size.z << std::endl;
|
||||
std::cout << "\tTiles : " << tiles << std::endl;
|
||||
for (auto& special : specials)
|
||||
{
|
||||
std::cout << "\t\tSpecial : " << special.first.x << ", " << special.first.y << std::endl;
|
||||
std::cout << "\t\t\tType : " << special.second.type << std::endl;
|
||||
std::cout << "\t\t\tPortal : " << special.second.portal_end[0] << ", " << special.second.portal_end[1] << std::endl;
|
||||
}
|
||||
std::cout << "\t\tEnemy Spawns : " << enemy_spawns.size() << std::endl;
|
||||
for (auto& spawn : enemy_spawns)
|
||||
{
|
||||
std::cout << "\t\t\tSpawn : " << spawn.x << ", " << spawn.y << std::endl;
|
||||
}
|
||||
std::cout << "\t\tPlayer Spawn : " << player_spawn.x << ", " << player_spawn.y << std::endl;
|
||||
}
|
||||
#endif
|
116
src/Map/Map.hpp
Normal file
116
src/Map/Map.hpp
Normal file
|
@ -0,0 +1,116 @@
|
|||
|
||||
/******************************************************************
|
||||
* ==============================================================
|
||||
* Map File Format
|
||||
* ==============================================================
|
||||
*
|
||||
* int8_t magic[4] = 'CYMF' (Colysis Map File) : 4 bytes
|
||||
* uint8_t version[3] : major, minor, patch
|
||||
*
|
||||
* uint8_t flags
|
||||
* if (flags):
|
||||
* case MapFlags::CustomTilemap:
|
||||
* uint32_t filepath_buffer_size
|
||||
* char filepath_buffer[filepath_buffer_size]
|
||||
* uint32_t tile_size[2] : width, height
|
||||
* uint32_t tile_count[2] : width, height
|
||||
*
|
||||
* uint32_t map_size[3] : x, y, specials
|
||||
* int32_t tiles[x * y + specials * (sizeof(MapSpecial)/4)] : tilemap data
|
||||
* // a special tile has a type and its tilemap data
|
||||
* if tiles[i] == Special:
|
||||
* uint8_t type
|
||||
* MapSpecial data
|
||||
* else:
|
||||
* uint8_t tile
|
||||
*
|
||||
* uint32_t player_spawn[2] : x, y
|
||||
* uint32_t number_enemy_spawns
|
||||
* uint32_t enemy_spawns[number_enemy_spawns][2] : x, y
|
||||
*
|
||||
*******************************************************************/
|
||||
|
||||
#pragma once
|
||||
#include <SFML/Graphics.hpp>
|
||||
|
||||
#define STR(name) #name
|
||||
#define STR_VALUE(name) STR(name)
|
||||
|
||||
#define MAP_VERSION_MAJOR 0
|
||||
#define MAP_VERSION_MINOR 1
|
||||
#define MAP_VERSION_PATCH 0
|
||||
#define MAP_VERSION (MAP_VERSION_MAJOR << 16 | MAP_VERSION_MINOR << 8 | MAP_VERSION_PATCH)
|
||||
#define MAP_VERSION_STRING STR_VALUE(MAP_VERSION_MAJOR) "." STR_VALUE(MAP_VERSION_MINOR) "." STR_VALUE(MAP_VERSION_PATCH)
|
||||
|
||||
|
||||
struct MapSpecial
|
||||
{
|
||||
int type;
|
||||
uint32_t portal_end[2];
|
||||
};
|
||||
|
||||
enum class MapFlags : uint8_t
|
||||
{
|
||||
None = 0,
|
||||
CustomTilemap = 1 << 0,
|
||||
UNDEFINED = 1 << 1,
|
||||
};
|
||||
|
||||
enum class TileType : int
|
||||
{
|
||||
Wall = -1,
|
||||
Special = 0,
|
||||
Other = 1,
|
||||
};
|
||||
|
||||
|
||||
struct MapError
|
||||
{
|
||||
std::string message;
|
||||
int code;
|
||||
};
|
||||
|
||||
|
||||
class Map : public sf::Drawable, public sf::Transformable
|
||||
{
|
||||
static_assert(sizeof(MapSpecial)%4 == 0);
|
||||
|
||||
struct {
|
||||
sf::Vector2u tile_size;
|
||||
sf::Vector2u tile_count;
|
||||
|
||||
uint32_t wall_tiles;
|
||||
uint32_t other_tiles;
|
||||
uint32_t special_tiles;
|
||||
|
||||
sf::Texture texture;
|
||||
sf::VertexArray vertices;
|
||||
} atlas;
|
||||
|
||||
sf::Vector3<size_t> map_size; // width * height, width, height
|
||||
int *tiles = nullptr;
|
||||
|
||||
std::vector<std::pair<sf::Vector2u, MapSpecial>> specials;
|
||||
|
||||
std::vector<sf::Vector2u> enemy_spawns;
|
||||
sf::Vector2u player_spawn;
|
||||
|
||||
MapError populate_vertex_array();
|
||||
|
||||
void LoadDefaultTilemap();
|
||||
|
||||
public:
|
||||
Map();
|
||||
|
||||
MapError load(const std::filesystem::path& path);
|
||||
|
||||
sf::Vector2u getSize() const;
|
||||
|
||||
void draw(sf::RenderTarget& target, sf::RenderStates states) const override;
|
||||
|
||||
#ifdef _DEBUG
|
||||
void debug();
|
||||
#endif
|
||||
};
|
||||
|
||||
|
31
src/main.cpp
Normal file
31
src/main.cpp
Normal file
|
@ -0,0 +1,31 @@
|
|||
#include <SFML/Graphics.hpp>
|
||||
#include <SFML/Window.hpp>
|
||||
|
||||
#include "Game.hpp"
|
||||
|
||||
#include <iostream>
|
||||
int main()
|
||||
{
|
||||
sf::RenderWindow window(sf::VideoMode({800, 450}), "Colysis", sf::Style::Close | sf::Style::Titlebar);
|
||||
window.setMinimumSize(sf::Vector2u{800, 450});
|
||||
|
||||
try {
|
||||
Game game(window);
|
||||
game.run();
|
||||
}
|
||||
catch (const std::runtime_error& e)
|
||||
{
|
||||
std::cerr << e.what() << std::endl;
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
std::cerr << e.what() << std::endl;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
std::cerr << "Unknown error" << std::endl;
|
||||
}
|
||||
|
||||
std::flush(std::cerr);
|
||||
return 0;
|
||||
}
|
80
utils/MapFile.hexpat
Normal file
80
utils/MapFile.hexpat
Normal file
|
@ -0,0 +1,80 @@
|
|||
#pragma endian little
|
||||
|
||||
struct Version {
|
||||
u8 major;
|
||||
u8 minor;
|
||||
u8 patch;
|
||||
};
|
||||
|
||||
bitfield OptionFlags {
|
||||
bool CustomeTilemap : 1;
|
||||
};
|
||||
|
||||
struct vec2<T> {
|
||||
T x,y;
|
||||
}[[single_color]];
|
||||
|
||||
struct TilemapInfo {
|
||||
vec2<u32> dimentions;
|
||||
vec2<u32> tile_size;
|
||||
vec2<u32> tile_count;
|
||||
u32 wall_tiles;
|
||||
u32 other_tiles;
|
||||
u32 special_tiles;
|
||||
};
|
||||
|
||||
struct Options {
|
||||
OptionFlags flags;
|
||||
if (flags.CustomeTilemap) {
|
||||
u32 filepath_length;
|
||||
char filepath[filepath_length];
|
||||
TilemapInfo info;
|
||||
}
|
||||
};
|
||||
|
||||
struct SpecialData {
|
||||
u32 data;
|
||||
};
|
||||
|
||||
struct Tile {
|
||||
u32 type;
|
||||
if (type == 0) {
|
||||
SpecialData special;
|
||||
}
|
||||
}[[single_color]];
|
||||
|
||||
struct Map
|
||||
{
|
||||
u32 width;
|
||||
u32 height;
|
||||
u32 specials;
|
||||
|
||||
Tile tiles[width * height];
|
||||
};
|
||||
|
||||
struct Spawn {
|
||||
u32 x,y;
|
||||
}[[single_color]];
|
||||
|
||||
struct EnemySpawns {
|
||||
u32 count;
|
||||
Spawn spawns[count];
|
||||
};
|
||||
|
||||
import std.io as io;
|
||||
|
||||
char magic[4] @$;
|
||||
if (magic != "CYMF") {
|
||||
io::warning("Magic does not match: \"" + magic + "\"; Expected: \"CYMF\"");
|
||||
}
|
||||
|
||||
Version version @$ [[single_color]];
|
||||
|
||||
Options options @$;
|
||||
|
||||
|
||||
Map map @$;
|
||||
|
||||
Spawn player @$ [[single_color]];
|
||||
|
||||
EnemySpawns enemies @$;
|
Loading…
Reference in a new issue