Showing preview only (313K chars total). Download the full file or copy to clipboard to get everything.
Repository: thebracket/rltk
Branch: master
Commit: 58635419d248
Files: 64
Total size: 295.8 KB
Directory structure:
gitextract_vk2s8wpi/
├── .gitignore
├── CMakeLists.txt
├── CMakeSettings.json
├── LICENSE
├── README.md
├── assets/
│ ├── fonts.txt
│ └── nyan.xp
├── cmake_modules/
│ ├── FindSFML.cmake
│ └── Findcereal.cmake
├── examples/
│ ├── ex1/
│ │ └── main.cpp
│ ├── ex10/
│ │ └── main.cpp
│ ├── ex11/
│ │ └── main.cpp
│ ├── ex2/
│ │ └── main.cpp
│ ├── ex3/
│ │ └── main.cpp
│ ├── ex4/
│ │ └── main.cpp
│ ├── ex5/
│ │ └── main.cpp
│ ├── ex6/
│ │ └── main.cpp
│ ├── ex7/
│ │ └── main.cpp
│ ├── ex8/
│ │ └── main.cpp
│ └── ex9/
│ └── main.cpp
└── rltk/
├── astar.hpp
├── color_t.cpp
├── color_t.hpp
├── colors.hpp
├── ecs.cpp
├── ecs.hpp
├── ecs_impl.hpp
├── filesystem.hpp
├── font_manager.cpp
├── font_manager.hpp
├── fsa.hpp
├── geometry.cpp
├── geometry.hpp
├── gui.cpp
├── gui.hpp
├── gui_control_t.cpp
├── gui_control_t.hpp
├── input_handler.cpp
├── input_handler.hpp
├── layer_t.cpp
├── layer_t.hpp
├── path_finding.hpp
├── perlin_noise.cpp
├── perlin_noise.hpp
├── rexspeeder.cpp
├── rexspeeder.hpp
├── rltk.cpp
├── rltk.hpp
├── rng.cpp
├── rng.hpp
├── scaling.cpp
├── scaling.hpp
├── serialization_utils.hpp
├── texture.hpp
├── texture_resources.cpp
├── texture_resources.hpp
├── vchar.hpp
├── virtual_terminal.cpp
├── virtual_terminal.hpp
├── virtual_terminal_sparse.cpp
├── virtual_terminal_sparse.hpp
├── visibility.hpp
├── xml.cpp
└── xml.hpp
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
/build/
/.kdev4/
/bgame.kdev4
/build_eclipse/
.DS_Store
x64
x84
/RltkMaster/packages
/RltkMaster/rltk/Debug
/RltkMaster/rltk/SFML-2.3.2
*.opendb
/RltkMaster/.vs/RltkMaster/v14/.suo
================================================
FILE: CMakeLists.txt
================================================
cmake_minimum_required(VERSION 3.1)
project("rltk")
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${PROJECT_SOURCE_DIR}/cmake_modules")
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED on)
find_package(ZLIB REQUIRED)
find_package(SFML 2 COMPONENTS system window graphics REQUIRED)
find_package(cereal REQUIRED)
add_library(rltk rltk/rltk.cpp
rltk/texture_resources.cpp
rltk/color_t.cpp
rltk/virtual_terminal.cpp
rltk/rng.cpp
rltk/geometry.cpp
rltk/input_handler.cpp
rltk/font_manager.cpp
rltk/gui.cpp
rltk/layer_t.cpp
rltk/gui_control_t.cpp
rltk/virtual_terminal_sparse.cpp
rltk/ecs.cpp
rltk/xml.cpp
rltk/perlin_noise.cpp
rltk/rexspeeder.cpp
rltk/scaling.cpp)
target_include_directories(rltk PUBLIC
"$<BUILD_INTERFACE:${SFML_INCLUDE_DIR}>"
"$<BUILD_INTERFACE:${CEREAL_INCLUDE_DIR}>"
"$<BUILD_INTERFACE:${ZLIB_INCLUDE_DIRS}>"
)
target_link_libraries(rltk PUBLIC ${ZLIB_LIBRARIES} ${SFML_LIBRARIES})
if(NOT MSVC) # Why was this here? I exempted the wierd linker flags
target_compile_options(rltk PUBLIC -O3 -Wall -Wpedantic -march=native -mtune=native -g)
else()
target_compile_options(rltk PUBLIC /W3 /EHsc)
endif()
install (TARGETS rltk
ARCHIVE DESTINATION lib
LIBRARY DESTINATION lib
RUNTIME DESTINATION bin)
set(RLTK_HEADERS
rltk/astar.hpp
rltk/colors.hpp
rltk/color_t.hpp
rltk/ecs.hpp
rltk/ecs_impl.hpp
rltk/filesystem.hpp
rltk/font_manager.hpp
rltk/fsa.hpp
rltk/geometry.hpp
rltk/gui.hpp
rltk/gui_control_t.hpp
rltk/input_handler.hpp
rltk/layer_t.hpp
rltk/path_finding.hpp
rltk/perlin_noise.hpp
rltk/rexspeeder.hpp
rltk/rltk.hpp
rltk/rng.hpp
rltk/scaling.hpp
rltk/serialization_utils.hpp
rltk/texture.hpp
rltk/texture_resources.hpp
rltk/vchar.hpp
rltk/virtual_terminal.hpp
rltk/virtual_terminal_sparse.hpp
rltk/visibility.hpp
rltk/xml.hpp)
install(FILES ${RLTK_HEADERS}
DESTINATION "include/rltk"
)
# Examples
# Add all of the example executables and their library dependency
add_executable(ex1 examples/ex1/main.cpp)
add_executable(ex2 examples/ex2/main.cpp)
add_executable(ex3 examples/ex3/main.cpp)
add_executable(ex4 examples/ex4/main.cpp)
add_executable(ex5 examples/ex5/main.cpp)
add_executable(ex6 examples/ex6/main.cpp)
add_executable(ex7 examples/ex7/main.cpp)
add_executable(ex8 examples/ex8/main.cpp)
add_executable(ex9 examples/ex9/main.cpp)
add_executable(ex10 examples/ex10/main.cpp)
add_executable(ex11 examples/ex11/main.cpp)
target_link_libraries(ex1 rltk)
target_link_libraries(ex2 rltk)
target_link_libraries(ex3 rltk)
target_link_libraries(ex4 rltk)
target_link_libraries(ex5 rltk)
target_link_libraries(ex6 rltk)
target_link_libraries(ex7 rltk)
target_link_libraries(ex8 rltk)
target_link_libraries(ex9 rltk)
target_link_libraries(ex10 rltk)
target_link_libraries(ex11 rltk)
================================================
FILE: CMakeSettings.json
================================================
{
// See https://go.microsoft.com//fwlink//?linkid=834763 for more information about this file.
"configurations": [
{
"name": "x86-Debug",
"generator": "Visual Studio 15 2017",
"configurationType": "Debug",
"buildRoot": "${env.LOCALAPPDATA}\\CMakeBuild\\${workspaceHash}\\build\\${name}",
"cmakeCommandArgs": "",
"buildCommandArgs": "-m -v:minimal",
"ctestCommandArgs": "",
"variables": [
{
"name": "CMAKE_TOOLCHAIN_FILE",
"value": "C:/Users/Herbert/Source/Repos/vcpkg/scripts/buildsystems/vcpkg.cmake"
}
]
},
{
"name": "x86-Release",
"generator": "Visual Studio 15 2017",
"configurationType": "Release",
"buildRoot": "${env.LOCALAPPDATA}\\CMakeBuild\\${workspaceHash}\\build\\${name}",
"cmakeCommandArgs": "",
"buildCommandArgs": "-m -v:minimal",
"ctestCommandArgs": "",
"variables": [
{
"name": "CMAKE_TOOLCHAIN_FILE",
"value": "C:/Users/Herbert/Source/Repos/vcpkg/scripts/buildsystems/vcpkg.cmake"
}
]
},
{
"name": "x64-Debug",
"generator": "Visual Studio 15 2017 Win64",
"configurationType": "Debug",
"buildRoot": "${env.LOCALAPPDATA}\\CMakeBuild\\${workspaceHash}\\build\\${name}",
"cmakeCommandArgs": "",
"buildCommandArgs": "-m -v:minimal",
"ctestCommandArgs": "",
"variables": [
{
"name": "CMAKE_TOOLCHAIN_FILE",
"value": "C:/Users/Herbert/Source/Repos/vcpkg/scripts/buildsystems/vcpkg.cmake"
}
]
},
{
"name": "x64-Release",
"generator": "Visual Studio 15 2017 Win64",
"configurationType": "Release",
"buildRoot": "${env.LOCALAPPDATA}\\CMakeBuild\\${workspaceHash}\\build\\${name}",
"cmakeCommandArgs": "",
"buildCommandArgs": "-m -v:minimal",
"ctestCommandArgs": "",
"variables": [
{
"name": "CMAKE_TOOLCHAIN_FILE",
"value": "C:/Users/Herbert/Source/Repos/vcpkg/scripts/buildsystems/vcpkg.cmake"
}
]
}
]
}
================================================
FILE: LICENSE
================================================
Copyright (c) 2016 Bracket Productions (Herbert Wolverson)
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
================================================
FILE: README.md
================================================
# rltk : Roguelike Toolkit - Modern (C++14) SFML-based toolkit for creating roguelikes.
It's very early days, but I hope that this can be a useful tool. Black Future was getting messy, and I needed to separate out some
engine logic from game logic for my sanity; I realized that others might find the underlying engine code useful.
Right now, it's a very fast ASCII (code-page 437) terminal renderer compatible with fonts from libtcod and Dwarf Fortress.
Eventually, it will provide assistance with a number of game-related topics including path-finding, line-plotting,
and probably some of the entity-component-system I've been enjoying.
**Credit to Pyridine for the REXPaint format code. Original located at: [https://github.com/pyridine/REXSpeeder](https://github.com/pyridine/REXSpeeder)**
## Building from source
You need SFML for your platform, Boost, and cmake. Make a "build" folder, and use CMake to generate build files for your platform (I'll expand upon this later, when this is a more useful library).
## Building on Visual Studio 2017
* Setup VCPKG, following the instructions [here](https://blogs.msdn.microsoft.com/vcblog/2016/09/19/vcpkg-a-tool-to-acquire-and-build-c-open-source-libraries-on-windows/)
* Ensure that you've integrated it, with `vcpkg integrate install` (see [here](https://github.com/Microsoft/vcpkg/blob/master/docs/examples/using-sqlite.md))
* Install packages: `vcpkg install sfml` and `vcpkg install cereal`. These take a while.
* Open Visual Studio 2017, and use "Open Folder" to open the RLTK folder to which you cloned everything. The CVPKG stuff will ensure that SFML is linked correctly.
* If you've previously opened the project in VS2017, use the CMake menu to delete your cache and regenerate everything. You really shouldn't have to do this, but CMake integration is young.
* You should now be able to select an output, and build/run it.
## Included Examples (with lots of comments!)
I'll write proper documentation as the library evolves; I don't really want to write up a lot of docs and have to revise them
heavily as things solidify. I'm doing my best to include examples evolving towards a real roguelike. Currently, these are:
### Example 1: Hello World

[Example 1](https://github.com/thebracket/rltk/blob/master/examples/ex1/main.cpp): demonstrates a Hello World with frame-rate.
### Example 2: Randomly moving @

[Example 2](https://github.com/thebracket/rltk/blob/master/examples/ex2/main.cpp): a randomly moving yellow @ on a field of white dots.
### Example 3: Bresenham's Line Pathing

[Example 3](https://github.com/thebracket/rltk/blob/master/examples/ex3/main.cpp): our @ dude again, this time using Bresenham's line to find his way. It also renders additional glyphs, as Mr @ finds his way to his destination.
### Example 4: A-Star Pathing

[Example 4](https://github.com/thebracket/rltk/blob/master/examples/ex4/main.cpp): our @ dude again, now on a defined map with obstacles and using A* to find his way to the heart. This demonstrates using templates to specialize map support - we won't force you to use a specific map representation!
### Example 5: Mouse Controlled Path-Finding

[Example 5](https://github.com/thebracket/rltk/blob/master/examples/ex5/main.cpp): our @ dude again, using A* pathing to find his way to the mouse
cursor. Click and he goes there.
### Example 6: Visibility

[Example 6](https://github.com/thebracket/rltk/blob/master/examples/ex6/main.cpp): Example 5, but now we have true visibility plotted as you wander.
### Example 7: Multi-font ASCII Layout

[Example 7](https://github.com/thebracket/rltk/blob/master/examples/ex7/main.cpp): A complex GUI with multiple fonts and layers, dynamically resizable.
### Example 8: Owner draw, and retained-mode GUI elements

[Example 8](https://github.com/thebracket/rltk/blob/master/examples/ex8/main.cpp): Demonstrates an "owner draw" panel (with SFML render target callback), drawing a background image. Some ASCII consoles are spawned, and one is populated with a mouse-over, a checkbox, radio-button set, a list-box and some status bars. The other panel displays the results.
### Example 9: Sparse layer with effects

[Example 9](https://github.com/thebracket/rltk/blob/master/examples/ex9/main.cpp): This demo uses a regular console layer to draw the map,
and a "sparse" console layer for the character and traversal path. It uses sub-character alignment to smoothly move the @ around, and
demonstrates rotation of the @ by leaning left or right as he travels (not an effect I recommend for a game, but it works as a demo!).
### Example 10: The beginnings of a roguelike

[Example 10](https://github.com/thebracket/rltk/blob/master/examples/ex10/main.cpp): This example generates a random map, and you can move your @ around with the arrow keys. It is the first example to use the Entity-Component-System (ECS) provided by RLTK; it makes for a relatively straightforward and modern way to design a roguelike - with very little code, we have the basics of wandering around a map. Note: message passing isn't implemented yet; when it is - this example will be even smaller!
### Example 11: REXPaint support (http://www.gridsagegames.com/rexpaint/)

[Example 11](https://github.com/thebracket/rltk/blob/master/examples/ex11/main.cpp): This example is basically Hello World, but with a REX Paint image loaded (Nyan Cat) and displayed.
## Example
The goal is to keep it simple from the user's point of view. The following code is enough to setup an ASCII terminal,
and display **Hello World** with a frame-rate displayed (around 100 FPS on my workstation):
```c++
#include "../../rltk/rltk.hpp"
#include <sstream>
using namespace rltk;
using namespace rltk::colors;
void tick(double duration_ms) {
std::stringstream ss;
ss << "Frame duration: " << duration_ms << " ms (" << (1000.0/duration_ms) << " FPS).";
console->print(1, 1, "Hello World", WHITE, BLACK);
console->print(1, 2, ss.str(), YELLOW, BLUE);
}
int main()
{
init(config_simple_px("../assets"));
run(tick);
return 0;
}
```
================================================
FILE: assets/fonts.txt
================================================
8x8,terminal8x8.png,8,8
16x16,terminal16x16.png,16,16
32x32,terminal32x32.png,32,32
8x16,VGA8x16.png,8,16
================================================
FILE: cmake_modules/FindSFML.cmake
================================================
# This script locates the SFML library
# ------------------------------------
#
# Usage
# -----
#
# When you try to locate the SFML libraries, you must specify which modules you want to use (system, window, graphics, network, audio, main).
# If none is given, the SFML_LIBRARIES variable will be empty and you'll end up linking to nothing.
# example:
# find_package(SFML COMPONENTS graphics window system) # find the graphics, window and system modules
#
# You can enforce a specific version, either MAJOR.MINOR or only MAJOR.
# If nothing is specified, the version won't be checked (i.e. any version will be accepted).
# example:
# find_package(SFML COMPONENTS ...) # no specific version required
# find_package(SFML 2 COMPONENTS ...) # any 2.x version
# find_package(SFML 2.4 COMPONENTS ...) # version 2.4 or greater
#
# By default, the dynamic libraries of SFML will be found. To find the static ones instead,
# you must set the SFML_STATIC_LIBRARIES variable to TRUE before calling find_package(SFML ...).
# Since you have to link yourself all the SFML dependencies when you link it statically, the following
# additional variables are defined: SFML_XXX_DEPENDENCIES and SFML_DEPENDENCIES (see their detailed
# description below).
# In case of static linking, the SFML_STATIC macro will also be defined by this script.
# example:
# set(SFML_STATIC_LIBRARIES TRUE)
# find_package(SFML 2 COMPONENTS network system)
#
# On Mac OS X if SFML_STATIC_LIBRARIES is not set to TRUE then by default CMake will search for frameworks unless
# CMAKE_FIND_FRAMEWORK is set to "NEVER" for example. Please refer to CMake documentation for more details.
# Moreover, keep in mind that SFML frameworks are only available as release libraries unlike dylibs which
# are available for both release and debug modes.
#
# If SFML is not installed in a standard path, you can use the SFML_ROOT CMake (or environment) variable
# to tell CMake where SFML is.
#
# Output
# ------
#
# This script defines the following variables:
# - For each specified module XXX (system, window, graphics, network, audio, main):
# - SFML_XXX_LIBRARY_DEBUG: the name of the debug library of the xxx module (set to SFML_XXX_LIBRARY_RELEASE is no debug version is found)
# - SFML_XXX_LIBRARY_RELEASE: the name of the release library of the xxx module (set to SFML_XXX_LIBRARY_DEBUG is no release version is found)
# - SFML_XXX_LIBRARY: the name of the library to link to for the xxx module (includes both debug and optimized names if necessary)
# - SFML_XXX_FOUND: true if either the debug or release library of the xxx module is found
# - SFML_XXX_DEPENDENCIES: the list of libraries the module depends on, in case of static linking
# - SFML_LIBRARIES: the list of all libraries corresponding to the required modules
# - SFML_FOUND: true if all the required modules are found
# - SFML_INCLUDE_DIR: the path where SFML headers are located (the directory containing the SFML/Config.hpp file)
# - SFML_DEPENDENCIES: the list of libraries SFML depends on, in case of static linking
#
# example:
# find_package(SFML 2 COMPONENTS system window graphics audio REQUIRED)
# include_directories(${SFML_INCLUDE_DIR})
# add_executable(myapp ...)
# target_link_libraries(myapp ${SFML_LIBRARIES})
# define the SFML_STATIC macro if static build was chosen
if(SFML_STATIC_LIBRARIES)
add_definitions(-DSFML_STATIC)
endif()
# define the list of search paths for headers and libraries
set(FIND_SFML_PATHS
${SFML_ROOT}
$ENV{SFML_ROOT}
~/Library/Frameworks
/Library/Frameworks
/usr/local
/usr
/sw
/opt/local
/opt/csw
/opt)
# find the SFML include directory
find_path(SFML_INCLUDE_DIR SFML/Config.hpp
PATH_SUFFIXES include
PATHS ${FIND_SFML_PATHS})
# check the version number
set(SFML_VERSION_OK TRUE)
if(SFML_FIND_VERSION AND SFML_INCLUDE_DIR)
# extract the major and minor version numbers from SFML/Config.hpp
# we have to handle framework a little bit differently:
if("${SFML_INCLUDE_DIR}" MATCHES "SFML.framework")
set(SFML_CONFIG_HPP_INPUT "${SFML_INCLUDE_DIR}/Headers/Config.hpp")
else()
set(SFML_CONFIG_HPP_INPUT "${SFML_INCLUDE_DIR}/SFML/Config.hpp")
endif()
FILE(READ "${SFML_CONFIG_HPP_INPUT}" SFML_CONFIG_HPP_CONTENTS)
STRING(REGEX REPLACE ".*#define SFML_VERSION_MAJOR ([0-9]+).*" "\\1" SFML_VERSION_MAJOR "${SFML_CONFIG_HPP_CONTENTS}")
STRING(REGEX REPLACE ".*#define SFML_VERSION_MINOR ([0-9]+).*" "\\1" SFML_VERSION_MINOR "${SFML_CONFIG_HPP_CONTENTS}")
STRING(REGEX REPLACE ".*#define SFML_VERSION_PATCH ([0-9]+).*" "\\1" SFML_VERSION_PATCH "${SFML_CONFIG_HPP_CONTENTS}")
if (NOT "${SFML_VERSION_PATCH}" MATCHES "^[0-9]+$")
set(SFML_VERSION_PATCH 0)
endif()
math(EXPR SFML_REQUESTED_VERSION "${SFML_FIND_VERSION_MAJOR} * 10000 + ${SFML_FIND_VERSION_MINOR} * 100 + ${SFML_FIND_VERSION_PATCH}")
# if we could extract them, compare with the requested version number
if (SFML_VERSION_MAJOR)
# transform version numbers to an integer
math(EXPR SFML_VERSION "${SFML_VERSION_MAJOR} * 10000 + ${SFML_VERSION_MINOR} * 100 + ${SFML_VERSION_PATCH}")
# compare them
if(SFML_VERSION LESS SFML_REQUESTED_VERSION)
set(SFML_VERSION_OK FALSE)
endif()
else()
# SFML version is < 2.0
if (SFML_REQUESTED_VERSION GREATER 10900)
set(SFML_VERSION_OK FALSE)
set(SFML_VERSION_MAJOR 1)
set(SFML_VERSION_MINOR x)
set(SFML_VERSION_PATCH x)
endif()
endif()
endif()
# find the requested modules
set(SFML_FOUND TRUE) # will be set to false if one of the required modules is not found
foreach(FIND_SFML_COMPONENT ${SFML_FIND_COMPONENTS})
string(TOLOWER ${FIND_SFML_COMPONENT} FIND_SFML_COMPONENT_LOWER)
string(TOUPPER ${FIND_SFML_COMPONENT} FIND_SFML_COMPONENT_UPPER)
set(FIND_SFML_COMPONENT_NAME sfml-${FIND_SFML_COMPONENT_LOWER})
# no suffix for sfml-main, it is always a static library
if(FIND_SFML_COMPONENT_LOWER STREQUAL "main")
# release library
find_library(SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_RELEASE
NAMES ${FIND_SFML_COMPONENT_NAME}
PATH_SUFFIXES lib64 lib
PATHS ${FIND_SFML_PATHS})
# debug library
find_library(SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_DEBUG
NAMES ${FIND_SFML_COMPONENT_NAME}-d
PATH_SUFFIXES lib64 lib
PATHS ${FIND_SFML_PATHS})
else()
# static release library
find_library(SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_STATIC_RELEASE
NAMES ${FIND_SFML_COMPONENT_NAME}-s
PATH_SUFFIXES lib64 lib
PATHS ${FIND_SFML_PATHS})
# static debug library
find_library(SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_STATIC_DEBUG
NAMES ${FIND_SFML_COMPONENT_NAME}-s-d
PATH_SUFFIXES lib64 lib
PATHS ${FIND_SFML_PATHS})
# dynamic release library
find_library(SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_DYNAMIC_RELEASE
NAMES ${FIND_SFML_COMPONENT_NAME}
PATH_SUFFIXES lib64 lib
PATHS ${FIND_SFML_PATHS})
# dynamic debug library
find_library(SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_DYNAMIC_DEBUG
NAMES ${FIND_SFML_COMPONENT_NAME}-d
PATH_SUFFIXES lib64 lib
PATHS ${FIND_SFML_PATHS})
# choose the entries that fit the requested link type
if(SFML_STATIC_LIBRARIES)
if(SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_STATIC_RELEASE)
set(SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_RELEASE ${SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_STATIC_RELEASE})
endif()
if(SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_STATIC_DEBUG)
set(SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_DEBUG ${SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_STATIC_DEBUG})
endif()
else()
if(SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_DYNAMIC_RELEASE)
set(SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_RELEASE ${SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_DYNAMIC_RELEASE})
endif()
if(SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_DYNAMIC_DEBUG)
set(SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_DEBUG ${SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_DYNAMIC_DEBUG})
endif()
endif()
endif()
if (SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_DEBUG OR SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_RELEASE)
# library found
set(SFML_${FIND_SFML_COMPONENT_UPPER}_FOUND TRUE)
# if both are found, set SFML_XXX_LIBRARY to contain both
if (SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_DEBUG AND SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_RELEASE)
set(SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY debug ${SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_DEBUG}
optimized ${SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_RELEASE})
endif()
# if only one debug/release variant is found, set the other to be equal to the found one
if (SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_DEBUG AND NOT SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_RELEASE)
# debug and not release
set(SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_RELEASE ${SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_DEBUG})
set(SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY ${SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_DEBUG})
endif()
if (SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_RELEASE AND NOT SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_DEBUG)
# release and not debug
set(SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_DEBUG ${SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_RELEASE})
set(SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY ${SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_RELEASE})
endif()
else()
# library not found
set(SFML_FOUND FALSE)
set(SFML_${FIND_SFML_COMPONENT_UPPER}_FOUND FALSE)
set(SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY "")
set(FIND_SFML_MISSING "${FIND_SFML_MISSING} SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY")
endif()
# mark as advanced
MARK_AS_ADVANCED(SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY
SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_RELEASE
SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_DEBUG
SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_STATIC_RELEASE
SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_STATIC_DEBUG
SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_DYNAMIC_RELEASE
SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_DYNAMIC_DEBUG)
# add to the global list of libraries
set(SFML_LIBRARIES ${SFML_LIBRARIES} "${SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY}")
endforeach()
# in case of static linking, we must also define the list of all the dependencies of SFML libraries
if(SFML_STATIC_LIBRARIES)
# detect the OS
if(${CMAKE_SYSTEM_NAME} MATCHES "Windows")
set(FIND_SFML_OS_WINDOWS 1)
elseif(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
set(FIND_SFML_OS_LINUX 1)
elseif(${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD")
set(FIND_SFML_OS_FREEBSD 1)
elseif(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
set(FIND_SFML_OS_MACOSX 1)
endif()
# start with an empty list
set(SFML_DEPENDENCIES)
set(FIND_SFML_DEPENDENCIES_NOTFOUND)
# macro that searches for a 3rd-party library
macro(find_sfml_dependency output friendlyname)
# No lookup in environment variables (PATH on Windows), as they may contain wrong library versions
find_library(${output} NAMES ${ARGN} PATHS ${FIND_SFML_PATHS} PATH_SUFFIXES lib NO_SYSTEM_ENVIRONMENT_PATH)
if(${${output}} STREQUAL "${output}-NOTFOUND")
unset(output)
set(FIND_SFML_DEPENDENCIES_NOTFOUND "${FIND_SFML_DEPENDENCIES_NOTFOUND} ${friendlyname}")
endif()
endmacro()
# sfml-system
list(FIND SFML_FIND_COMPONENTS "system" FIND_SFML_SYSTEM_COMPONENT)
if(NOT ${FIND_SFML_SYSTEM_COMPONENT} EQUAL -1)
# update the list -- these are only system libraries, no need to find them
if(FIND_SFML_OS_LINUX OR FIND_SFML_OS_FREEBSD OR FIND_SFML_OS_MACOSX)
set(SFML_SYSTEM_DEPENDENCIES "pthread")
endif()
if(FIND_SFML_OS_LINUX)
set(SFML_SYSTEM_DEPENDENCIES ${SFML_SYSTEM_DEPENDENCIES} "rt")
endif()
if(FIND_SFML_OS_WINDOWS)
set(SFML_SYSTEM_DEPENDENCIES "winmm")
endif()
set(SFML_DEPENDENCIES ${SFML_SYSTEM_DEPENDENCIES} ${SFML_DEPENDENCIES})
endif()
# sfml-network
list(FIND SFML_FIND_COMPONENTS "network" FIND_SFML_NETWORK_COMPONENT)
if(NOT ${FIND_SFML_NETWORK_COMPONENT} EQUAL -1)
# update the list -- these are only system libraries, no need to find them
if(FIND_SFML_OS_WINDOWS)
set(SFML_NETWORK_DEPENDENCIES "ws2_32")
endif()
set(SFML_DEPENDENCIES ${SFML_NETWORK_DEPENDENCIES} ${SFML_DEPENDENCIES})
endif()
# sfml-window
list(FIND SFML_FIND_COMPONENTS "window" FIND_SFML_WINDOW_COMPONENT)
if(NOT ${FIND_SFML_WINDOW_COMPONENT} EQUAL -1)
# find libraries
if(FIND_SFML_OS_LINUX OR FIND_SFML_OS_FREEBSD)
find_sfml_dependency(X11_LIBRARY "X11" X11)
find_sfml_dependency(XRANDR_LIBRARY "Xrandr" Xrandr)
endif()
if(FIND_SFML_OS_LINUX)
find_sfml_dependency(UDEV_LIBRARIES "UDev" udev libudev)
endif()
# update the list
if(FIND_SFML_OS_WINDOWS)
set(SFML_WINDOW_DEPENDENCIES ${SFML_WINDOW_DEPENDENCIES} "opengl32" "winmm" "gdi32")
elseif(FIND_SFML_OS_LINUX)
set(SFML_WINDOW_DEPENDENCIES ${SFML_WINDOW_DEPENDENCIES} "GL" ${X11_LIBRARY} ${XRANDR_LIBRARY} ${UDEV_LIBRARIES})
elseif(FIND_SFML_OS_FREEBSD)
set(SFML_WINDOW_DEPENDENCIES ${SFML_WINDOW_DEPENDENCIES} "GL" ${X11_LIBRARY} ${XRANDR_LIBRARY} "usbhid")
elseif(FIND_SFML_OS_MACOSX)
set(SFML_WINDOW_DEPENDENCIES ${SFML_WINDOW_DEPENDENCIES} "-framework OpenGL -framework Foundation -framework AppKit -framework IOKit -framework Carbon")
endif()
set(SFML_DEPENDENCIES ${SFML_WINDOW_DEPENDENCIES} ${SFML_DEPENDENCIES})
endif()
# sfml-graphics
list(FIND SFML_FIND_COMPONENTS "graphics" FIND_SFML_GRAPHICS_COMPONENT)
if(NOT ${FIND_SFML_GRAPHICS_COMPONENT} EQUAL -1)
# find libraries
find_sfml_dependency(FREETYPE_LIBRARY "FreeType" freetype)
find_sfml_dependency(JPEG_LIBRARY "libjpeg" jpeg)
# update the list
set(SFML_GRAPHICS_DEPENDENCIES ${FREETYPE_LIBRARY} ${JPEG_LIBRARY})
set(SFML_DEPENDENCIES ${SFML_GRAPHICS_DEPENDENCIES} ${SFML_DEPENDENCIES})
endif()
# sfml-audio
list(FIND SFML_FIND_COMPONENTS "audio" FIND_SFML_AUDIO_COMPONENT)
if(NOT ${FIND_SFML_AUDIO_COMPONENT} EQUAL -1)
# find libraries
find_sfml_dependency(OPENAL_LIBRARY "OpenAL" openal openal32)
find_sfml_dependency(OGG_LIBRARY "Ogg" ogg)
find_sfml_dependency(VORBIS_LIBRARY "Vorbis" vorbis)
find_sfml_dependency(VORBISFILE_LIBRARY "VorbisFile" vorbisfile)
find_sfml_dependency(VORBISENC_LIBRARY "VorbisEnc" vorbisenc)
find_sfml_dependency(FLAC_LIBRARY "FLAC" FLAC)
# update the list
set(SFML_AUDIO_DEPENDENCIES ${OPENAL_LIBRARY} ${FLAC_LIBRARY} ${VORBISENC_LIBRARY} ${VORBISFILE_LIBRARY} ${VORBIS_LIBRARY} ${OGG_LIBRARY})
set(SFML_DEPENDENCIES ${SFML_DEPENDENCIES} ${SFML_AUDIO_DEPENDENCIES})
endif()
endif()
# handle errors
if(NOT SFML_VERSION_OK)
# SFML version not ok
set(FIND_SFML_ERROR "SFML found but version too low (requested: ${SFML_FIND_VERSION}, found: ${SFML_VERSION_MAJOR}.${SFML_VERSION_MINOR}.${SFML_VERSION_PATCH})")
set(SFML_FOUND FALSE)
elseif(SFML_STATIC_LIBRARIES AND FIND_SFML_DEPENDENCIES_NOTFOUND)
set(FIND_SFML_ERROR "SFML found but some of its dependencies are missing (${FIND_SFML_DEPENDENCIES_NOTFOUND})")
set(SFML_FOUND FALSE)
elseif(NOT SFML_FOUND)
# include directory or library not found
set(FIND_SFML_ERROR "Could NOT find SFML (missing: ${FIND_SFML_MISSING})")
endif()
if (NOT SFML_FOUND)
if(SFML_FIND_REQUIRED)
# fatal error
message(FATAL_ERROR ${FIND_SFML_ERROR})
elseif(NOT SFML_FIND_QUIETLY)
# error but continue
message("${FIND_SFML_ERROR}")
endif()
endif()
# handle success
if(SFML_FOUND AND NOT SFML_FIND_QUIETLY)
message(STATUS "Found SFML ${SFML_VERSION_MAJOR}.${SFML_VERSION_MINOR}.${SFML_VERSION_PATCH} in ${SFML_INCLUDE_DIR}")
endif()
================================================
FILE: cmake_modules/Findcereal.cmake
================================================
# - Try to find Cereal lib
#
# This sets the following variables:
# CEREAL_FOUND - True if Cereal was found.
# CEREAL_INCLUDE_DIRS - Directories containing the Cereal include files.
find_path(CEREAL_INCLUDE_DIRS cereal
HINTS "$ENV{CMAKE_SOURCE_DIR}/include" "/usr/include" "$ENV{CMAKE_BINARY_DIR}/cereal/include")
set(CEREAL_INCLUDE_DIRS ${CEREAL_INCLUDE_DIRS})
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(Cereal DEFAULT_MSG CEREAL_INCLUDE_DIRS)
mark_as_advanced(CEREAL_INCLUDE_DIRS)
if(CEREAL_FOUND)
MESSAGE(STATUS "Found Cereal: ${CEREAL_INCLUDE_DIRS}")
endif(CEREAL_FOUND)
================================================
FILE: examples/ex1/main.cpp
================================================
/* RLTK (RogueLike Tool Kit) 1.00
* Copyright (c) 2016-Present, Bracket Productions.
* Licensed under the MIT license - see LICENSE file.
*
* Example 1: A truly minimal hello world root console, demonstrating
* how to get started with RLTK.
*/
// You need to include the RLTK header
#include "../../rltk/rltk.hpp"
// We're using a stringstream to build the hello world message.
#include <sstream>
// For convenience, import the whole rltk namespace. You may not want to do this
// in larger projects, to avoid naming collisions.
using namespace rltk;
using namespace rltk::colors;
// Tick is called every frame. The parameter specifies how many ms have elapsed
// since the last time it was called.
void tick(double duration_ms) {
// In this case, we just want to print "Hello World" in white on black.
if (console->dirty) {
console->clear();
console->print(1,1,"Hello World", WHITE, BLACK);
}
}
// Your main function
int main()
{
// Initialize the library. Here, we are providing plenty of into so you can see what is
// available. There's also the option to use config_simple_px to configure by pixels
// rather than characters.
// The first parameter is the path to the font files.
// The second and third parameters specify the desired console size in screen characters (80x25).
// The fourth parameter is the window title.
// The fifth parameter says that we'd like the default console to use an 8x16 VGA font. Not so great for games, but easy to read!
// The final parameter controls whether or not we want to go full screen.
init(config_simple("../assets", 80, 25, "RLTK Hello World", "8x16", false));
// Enter the main loop. "tick" is the function we wrote above.
run(tick);
return 0;
}
================================================
FILE: examples/ex10/main.cpp
================================================
/* RLTK (RogueLike Tool Kit) 1.00
* Copyright (c) 2016-Present, Bracket Productions.
* Licensed under the MIT license - see LICENSE file.
*
* Example 10: Not really an example yet, playing with getting the ECS working.
*/
// You need to include the RLTK header
#include "../../rltk/rltk.hpp"
// We're using a stringstream to build the hello world message.
#include <sstream>
#include <algorithm>
// For convenience, import the whole rltk namespace. You may not want to do this
// in larger projects, to avoid naming collisions.
using namespace rltk;
using namespace rltk::colors;
using std::size_t;
constexpr int map_width = 100;
constexpr int map_height = 100;
constexpr int map_size = map_width * map_height;
int map_idx(const int x, const int y) { return (y * map_width) + x; }
std::vector<int> map_tiles;
std::vector<uint8_t> visible;
std::vector<bool> revealed;
random_number_generator rng;
size_t player_id;
struct position {
position() {}
position(const int X, const int Y) : x(X), y(Y) {}
int x, y;
void bounds_check() {
if (x < 0) x = 0;
if (x > map_width) x = map_width;
if (y < 0) y = 0;
if (y > map_height) y = map_height;
}
};
struct renderable {
renderable() {}
renderable(const char Glyph, const color_t foreground) : glyph(Glyph), fg(foreground) {}
int glyph;
color_t fg=colors::WHITE;
color_t bg=colors::BLACK;
};
struct navigator_helper {
static int get_x(const position &loc) { return loc.x; }
static int get_y(const position &loc) { return loc.y; }
static position get_xy(const int &x, const int &y) { return position{x,y}; }
};
// Clipping info
int left_x, right_x, top_y, bottom_y;
struct actor_moved_message : base_message_t {
actor_moved_message() {}
actor_moved_message(entity_t * ACTOR, const int fx, const int fy, const int dx, const int dy) :
mover(ACTOR), from_x(fx), from_y(fy), destination_x(dx), destination_y(dy) {}
entity_t * mover;
int from_x, from_y, destination_x, destination_y;
};
struct player_moved_message : base_message_t {};
struct camera_system : public base_system {
virtual void configure() override {
system_name = "Camera System";
// Create the player
auto player = create_entity()
->assign(position{map_width/2, map_height/2})
->assign(renderable('@', colors::YELLOW));
player_id = player->id;
}
virtual void update(const double duration_ms) override {
if (console->dirty) {
console->clear();
// Find the camera
auto camera_loc = entity(player_id)->component<position>();
left_x = camera_loc->x - (console->term_width / 2);
right_x = camera_loc->x + (console->term_width / 2);
top_y = camera_loc->y - (console->term_height/2);
bottom_y = camera_loc->y + (console->term_height/2)+1;
for (int y=top_y; y<bottom_y; ++y) {
for (int x=left_x; x<right_x; ++x) {
if (x >= 0 && x < map_width && y >= 0 && y < map_height) {
vchar map_char{'.', color_t(0,0,64), colors::BLACK};
const int map_index = map_idx(x,y);
if (revealed[map_index]) {
switch (map_tiles[map_index]) {
case 0 : map_char.glyph = '.'; break;
case 1 : map_char.glyph = '#'; break;
default : map_char.glyph = 'E'; // This shouldn't happen
}
map_char.foreground = color_t(96,96,96);
}
if (visible[map_index] > 0) {
uint8_t brightness =(visible[map_index]*16) + 127;
map_char.foreground = color_t(brightness, brightness, brightness);
} else {
if (map_tiles[map_index] == 0) map_char.glyph = ' ';
}
console->set_char(x-left_x, y-top_y, map_char);
}
}
}
}
}
};
struct actor_render_system : public base_system {
virtual void configure() override {
system_name = "Actor Render System";
}
virtual void update(const double duration_ms) override {
each<position, renderable>([] (entity_t &entity, position &pos, renderable &render) {
const int map_index = map_idx(pos.x, pos.y);
if (visible[map_index]) {
console->set_char(pos.x-left_x, pos.y-top_y, vchar{ render.glyph, render.fg, render.bg });
}
});
}
};
struct player_system : public base_system {
virtual void configure() override {
system_name = "Player System";
subscribe<actor_moved_message>([this](actor_moved_message &msg) {
if (map_tiles[map_idx(msg.destination_x, msg.destination_y)] == 0) {
msg.mover->component<position>()->x = msg.destination_x;
msg.mover->component<position>()->y = msg.destination_y;
msg.mover->component<position>()->bounds_check();
console->dirty = true;
emit(player_moved_message{});
}
});
subscribe_mbox<key_pressed_t>();
}
virtual void update(const double duration_ms) override {
auto camera_loc = entity(player_id)->component<position>();
// Loop through the keyboard input list
std::queue<key_pressed_t> * messages = mbox<key_pressed_t>();
while (!messages->empty()) {
key_pressed_t e = messages->front();
messages->pop();
if (e.event.key.code == sf::Keyboard::Left) emit(actor_moved_message{ entity(player_id), camera_loc->x, camera_loc->y, camera_loc->x - 1, camera_loc->y });
if (e.event.key.code == sf::Keyboard::Right) emit(actor_moved_message{ entity(player_id), camera_loc->x, camera_loc->y, camera_loc->x + 1, camera_loc->y });
if (e.event.key.code == sf::Keyboard::Up) emit(actor_moved_message{ entity(player_id), camera_loc->x, camera_loc->y, camera_loc->x, camera_loc->y-1 });
if (e.event.key.code == sf::Keyboard::Down) emit(actor_moved_message{ entity(player_id), camera_loc->x, camera_loc->y, camera_loc->x, camera_loc->y+1 });
if (e.event.key.code == sf::Keyboard::F1) {
std::string timings = ecs_profile_dump();
std::cout << timings << "\n";
}
}
}
};
struct visibility_system : public base_system {
virtual void configure() override {
system_name = "Visibility System";
subscribe<player_moved_message>([this](player_moved_message &msg) {
auto camera_loc = entity(player_id)->component<position>();
position camera_loc_deref = *camera_loc;
std::fill(visible.begin(), visible.end(), 0);
visibility_sweep_2d<position, navigator_helper>(camera_loc_deref, 10,
[](position reveal) {
reveal.bounds_check();
const int idx = map_idx(reveal.x, reveal.y);
++visible[idx];
if (visible[idx] > 8) visible[idx] = 8;
revealed[idx] = true;
}, [](position visibility_check) {
visibility_check.bounds_check();
return (map_tiles[map_idx(visibility_check.x, visibility_check.y)] == 0);
});
});
}
bool firstrun = true;
virtual void update(const double duration_ms) override {
if (firstrun) {
emit(player_moved_message{});
firstrun = false;
}
}
};
// Tick is called every frame. The parameter specifies how many ms have elapsed
// since the last time it was called.
void tick(double duration_ms) {
ecs_tick(duration_ms);
}
// Your main function
int main()
{
// Initialize the library. Here, we are providing plenty of into so you can see what is
// available. There's also the option to use config_simple_px to configure by pixels
// rather than characters.
// The first parameter is the path to the font files.
// The second and third parameters specify the desired console size in screen characters (80x25).
// The fourth parameter is the window title.
// The final parameter says that we'd like the default console to use an 8x16 VGA font. Not so great for games, but easy to read!
init(config_simple("../assets", 80, 50, "RLTK Hello World", "8x8"));
// Zero the map other than the edges
map_tiles.resize(map_size);
visible.resize(map_size);
revealed.resize(map_size);
std::fill(map_tiles.begin(), map_tiles.end(), 0);
std::fill(visible.begin(), visible.end(), false);
std::fill(revealed.begin(), revealed.end(), false);
for (int i=0; i<map_width; ++i) {
map_tiles[map_idx(i, 0)] = 1;
map_tiles[map_idx(i, map_height-1)] = 1;
}
for (int i=0; i<map_width; ++i) {
map_tiles[map_idx(0, i)] = 1;
map_tiles[map_idx(map_width-1, i)] = 1;
}
// Random debris
for (int y=1; y<map_height-1; ++y) {
for (int x=1; x<map_width-1; ++x) {
if (rng.roll_dice(1,4)==1 && (x!=map_width/2 || y!=map_height/2)) map_tiles[map_idx(x,y)]=1;
}
}
// Create our systems
add_system<player_system>();
add_system<visibility_system>();
add_system<camera_system>();
add_system<actor_render_system>();
// Enter the main loop. "tick" is the function we wrote above.
ecs_configure();
run(tick);
return 0;
}
================================================
FILE: examples/ex11/main.cpp
================================================
/* RLTK (RogueLike Tool Kit) 1.00
* Copyright (c) 2016-Present, Bracket Productions.
* Licensed under the MIT license - see LICENSE file.
*
* Example 11: Hello World and a REX Paint object
*/
// You need to include the RLTK header
#include "../../rltk/rltk.hpp"
// We're using a stringstream to build the hello world message.
#include <sstream>
// For convenience, import the whole rltk namespace. You may not want to do this
// in larger projects, to avoid naming collisions.
using namespace rltk;
using namespace rltk::colors;
rltk::xp::rex_sprite nyan_cat("../assets/nyan.xp");
// Tick is called every frame. The parameter specifies how many ms have elapsed
// since the last time it was called.
void tick(double duration_ms) {
// In this case, we just want to print "Hello World" in white on black.
if (console->dirty) {
console->clear();
console->print(1,1,"Hello World", WHITE, BLACK);
console->draw_sprite(1,3,nyan_cat);
}
}
// Your main function
int main()
{
// Initialize the library. Here, we are providing plenty of into so you can see what is
// available. There's also the option to use config_simple_px to configure by pixels
// rather than characters.
// The first parameter is the path to the font files.
// The second and third parameters specify the desired console size in screen characters (80x25).
// The fourth parameter is the window title.
// The final parameter says that we'd like the default console to use an 8x16 VGA font. Not so great for games, but easy to read!
init(config_simple("../assets", 80, 25, "RLTK Hello World", "8x16"));
// Enter the main loop. "tick" is the function we wrote above.
run(tick);
return 0;
}
================================================
FILE: examples/ex2/main.cpp
================================================
/* RLTK (RogueLike Tool Kit) 1.00
* Copyright (c) 2016-Present, Bracket Productions.
* Licensed under the MIT license - see LICENSE file.
*
* Example 2: A wandering @ dude, demonstrating the random number generator,
* character rendering, directed screen clearing, and frame-rate independent
* tick lengths.
*/
// You need to include the RLTK header
#include "../../rltk/rltk.hpp"
// For convenience, import the whole rltk namespace. You may not want to do this
// in larger projects, to avoid naming collisions.
using namespace rltk;
using namespace rltk::colors;
// For now, we always want our "dude" to be a yellow @ - so he's constexpr
const vchar dude{'@', YELLOW, BLACK};
// The dude's location in X/Y terms
int dude_x = 10;
int dude_y = 10;
// A default-defined random number generator. You can specify a seed to get
// the same results each time, but for now we're keeping it simple.
random_number_generator rng;
// We want to keep the game running at a steady pace, rather than however
// fast our super graphics card wants to go! To do this, we set a constant
// duration for a "tick" and only process after that much time has elapsed.
// Most roguelikes are turn-based and won't actually use this, but that's
// for a later example when we get to input.
constexpr double tick_duration = 5.0;
double tick_time = 0.0;
// Tick is called every frame. The parameter specifies how many ms have elapsed
// since the last time it was called.
void tick(double duration_ms) {
// Rather than clearing the screen to black, we set it to all white dots. We only want
// to do this if something has forced the screen to re-render (such as re-sizing)
if (console->dirty) console->clear(vchar{'.', GREY, BLACK});
// Increase the tick time by the frame duration. If it has exceeded
// the tick duration, then we move the @.
tick_time += duration_ms;
if (tick_time > tick_duration) {
// Using the RNG's handy roll_dice function, we roll 1d4. Each option
// represents a possible move in this case. The function is just like D&D's
// venerable XdY system - you can roll 10d12 with roll_dice(10,12). You
// aren't limited to dice sizes that exist or make sense.
int direction = rng.roll_dice(1,4);
switch (direction) {
case 1 : --dude_x; break;
case 2 : ++dude_x; break;
case 3 : --dude_y; break;
case 4 : ++dude_y; break;
}
// Important: we clear the tick count after the update.
tick_time = 0.0;
// Clear the console, which has the nice side effect of setting the terminal
// to dirty.
console->clear(vchar{'.', GREY, BLACK});
// Clipping: keep the dude on the screen. Why are we doing this here, and not
// after an update? For now, we aren't handling the concept of a map that is larger
// than the screen - so if the window resizes, the @ gets clipped to a visible area.
if (dude_x < 0) dude_x = 0;
if (dude_x > console->term_width) dude_x = console->term_width;
if (dude_y < 0) dude_y = 0;
if (dude_y > console->term_height) dude_x = console->term_height;
// Finally, we render the @ symbol. dude_x and dude_y are in terminal coordinates.
console->set_char(console->at(dude_x, dude_y), dude);
}
}
// Your main function
int main()
{
// Initialize with defaults.
init(config_simple_px("../assets"));
// Enter the main loop. "tick" is the function we wrote above.
run(tick);
return 0;
}
================================================
FILE: examples/ex3/main.cpp
================================================
/* RLTK (RogueLike Tool Kit) 1.00
* Copyright (c) 2016-Present, Bracket Productions.
* Licensed under the MIT license - see LICENSE file.
*
* Example 3: A wandering @ dude, this time using Bresenham's line functions to
* plot his path through the world. We play around a bit, rendering the destination
* and path as well as the simple "world" our little @ lives in.
*/
// You need to include the RLTK header
#include "../../rltk/rltk.hpp"
// We're using a deque to represent our path
#include <deque>
// For convenience, import the whole rltk namespace. You may not want to do this
// in larger projects, to avoid naming collisions.
using namespace rltk;
using namespace rltk::colors;
// For now, we always want our "dude" to be a yellow @ - so he's constexpr
const vchar dude{'@', YELLOW, BLACK};
// We're also going to render our destination as a pink heart. Aww.
const vchar destination{3, MAGENTA, BLACK};
// We'll also render our planned path ahead as a series of stars
const vchar star{'*', GREEN, BLACK};
// The dude's location in X/Y terms
int dude_x = 10;
int dude_y = 10;
// Where the dude would like to go; we'll start with him being happy where he is.
int destination_x = 10;
int destination_y = 10;
// We'll store the path to the goal as a simple queue of x/y (represented as an std::pair of ints).
// A queue naturally represents the task - each step, in order. A deque has the added property
// of being iteratable - so we are using it.
std::deque<std::pair<int,int>> path;
// A default-defined random number generator. You can specify a seed to get
// the same results each time, but for now we're keeping it simple.
random_number_generator rng;
// We want to keep the game running at a steady pace, rather than however
// fast our super graphics card wants to go! To do this, we set a constant
// duration for a "tick" and only process after that much time has elapsed.
// Most roguelikes are turn-based and won't actually use this, but that's
// for a later example when we get to input.
// Note that this is faster than previous examples; I liked it better that way!
constexpr double tick_duration = 5.0;
double tick_time = 0.0;
// Tick is called every frame. The parameter specifies how many ms have elapsed
// since the last time it was called.
void tick(double duration_ms) {
// Rather than clearing the screen to black, we set it to all white dots.
console->clear(vchar{'.', GREY, BLACK});
// Increase the tick time by the frame duration. If it has exceeded
// the tick duration, then we move the @.
tick_time += duration_ms;
if (tick_time > tick_duration) {
// If we're at our destination, we need a new one!
if ((destination_x == dude_x && destination_y == dude_y) || path.empty()) {
// We use the RNG to determine where we want to go
destination_x = rng.roll_dice(1, console->term_width)-1;
destination_y = rng.roll_dice(1, console->term_height)-1;
// Now we use "line_func". The prototype for this is:
// void line_func(int x1, int y1, const int x2, const int y2, std::function<void(int, int)> func);
// What this means in practice is line_func(from_x, from_y, to_x, to_y, callback function for each step).
// We'll use a lambda for the callback, to keep it inline and tight.
line_func(dude_x, dude_y, destination_x, destination_y, [] (int nx, int ny) {
// Simply add the next step to the path
path.push_back(std::make_pair(nx,ny));
});
} else {
// We aren't there yet, so we follow our path. We take the first element on the list,
// and then use pop_back to remove it.
// std::tie is a handy way to extract two parts of an std::pair (or tuple) in one fell swoop.
std::tie(dude_x, dude_y) = path.front();
path.pop_front();
}
// Important: we clear the tick count after the update.
tick_time = 0.0;
}
// Clipping: keep the dude on the screen. Why are we doing this here, and not
// after an update? For now, we aren't handling the concept of a map that is larger
// than the screen - so if the window resizes, the @ gets clipped to a visible area.
if (dude_x < 0) dude_x = 0;
if (dude_x > console->term_width) dude_x = console->term_width;
if (dude_y < 0) dude_y = 0;
if (dude_y > console->term_height) dude_x = console->term_height;
// Render our planned path. We're using auto and a range-for to avoid typing all
// the iterator stuff
for (auto step : path) {
console->set_char(console->at(step.first, step.second), star);
}
// Render our destination
console->set_char(console->at(destination_x, destination_y), destination);
// Finally, we render the @ symbol. dude_x and dude_y are in terminal coordinates.
console->set_char(console->at(dude_x, dude_y), dude);
}
// Your main function
int main()
{
// Initialize with defaults.
init(config_simple_px("../assets"));
// Enter the main loop. "tick" is the function we wrote above.
run(tick);
return 0;
}
================================================
FILE: examples/ex4/main.cpp
================================================
#include <iostream>
/* RLTK (RogueLike Tool Kit) 1.00
* Copyright (c) 2016-Present, Bracket Productions.
* Licensed under the MIT license - see LICENSE file.
*
* Example 4: Now we implement a basic map, and use A* to find our way around it.
* This example is a bit more in-depth, since it demonstrates the library's ability
* to use templates to specialize itself around your map design - we won't force a
* map type on you!
*/
// You need to include the RLTK header
#include "../../rltk/rltk.hpp"
// We're using a vector to represent the map
#include <vector>
// We're also going to be using a shared_ptr to a map. Why shared? Because the library
// hands it off to you and it's up to you to use it; this provides some safety that it
// will be disposed when you are done with it.
#include <memory>
// For convenience, import the whole rltk namespace. You may not want to do this
// in larger projects, to avoid naming collisions.
using namespace rltk;
using namespace rltk::colors;
// A default-defined random number generator. You can specify a seed to get
// the same results each time, but for now we're keeping it simple.
random_number_generator rng;
// For now, we always want our "dude" to be a yellow @ - so he's constexpr
const vchar dude{'@', YELLOW, BLACK};
// We're also going to render our destination as a pink heart. Aww.
const vchar destination_glyph{3, MAGENTA, BLACK};
// We now need to represent walls and floors, too
const vchar wall_tile{'#', WHITE, BLACK};
const vchar floor_tile{'.', GREY, BLACK}; // Note that "floor" is taken as a name in C++!
// Now we define a structure to represent a location. In this case, it's a simple
// x/y coordinate.
struct location_t {
int x=-1; // I like to set uninitialized values to something invalid for help with debugging
int y=-1;
// For convenience, we're overriding the quality operator. This gives a very
// quick and natural looking way to say "are these locations the same?"
bool operator==(location_t &rhs) { return (x==rhs.x && y==rhs.y); }
location_t() {}
location_t(const int X, const int Y) : x(X), y(Y) {}
};
// Now we define our basic map. Why a struct? Because a struct is just a class with
// everything public in it!
struct map_t {
map_t(const int &w, const int &h) : width(w), height(h) {
// Resize the vector to hold the whole map; this way it won't reallocate
walkable.resize(w*h);
// Set the entire map to walkable
std::fill(walkable.begin(), walkable.end(), true);
// We want the perimeter to be solid
for (int x=0; x<width; ++x) {
walkable[at(x,0)]=false;
walkable[at(x,height-1)]=false;
}
for (int y=0; y<height; ++y) {
walkable[at(0,y)] = false;
walkable[at(width-1,y)] = false;
}
// Every tile other than 10,10 (starting) has a 16% chance of being solid
for (int y=1; y<height-2; ++y) {
for (int x=1; x<width-2; ++x) {
if ((x != 10 && y != 10) && rng.roll_dice(1,6)==1) walkable[at(x,y)] = false;
}
}
}
// Calculate the vector offset of a grid location
inline int at(const int &x, const int &y) { return (y*width)+x; }
// The width and height of the map
const int width, height;
// The actual walkable storage vector
std::vector<bool> walkable;
};
// The A* library returns a navigation path with a template specialization to our location_t.
// Store the path here. Normally, you'd use "auto" for this type, it is a lot less typing!
std::shared_ptr<navigation_path<location_t>> path;
// We're using 1024x768, with 8 pixel wide chars. That gives a console grid of
// 128 x 96. We'll go with that for the map, even though in reality the screen
// might change. Worrying about that is for a future example!
constexpr int MAP_WIDTH = 128;
constexpr int MAP_HEIGHT = 96;
map_t map(MAP_WIDTH, MAP_HEIGHT);
// Instead of raw ints, we'll use the location structure to represent where our
// dude is. Using C++14 initialization, it's nice and clean.
location_t dude_position {10,10};
// We'll also use a location_t to represent the intended destination.
location_t destination {10,10};
// The A* library also requires a helper class to understand your map format.
struct navigator {
// This lets you define a distance heuristic. Manhattan distance works really well, but
// for now we'll just use a simple euclidian distance squared.
// The geometry system defines one for us.
static float get_distance_estimate(location_t &pos, location_t &goal) {
float d = distance2d_squared(pos.x, pos.y, goal.x, goal.y);
return d;
}
// Heuristic to determine if we've reached our destination? In some cases, you'd not want
// this to be a simple comparison with the goal - for example, if you just want to be
// adjacent to (or even a preferred distance from) the goal. In this case,
// we're trying to get to the goal rather than near it.
static bool is_goal(location_t &pos, location_t &goal) {
return pos == goal;
}
// This is where we calculate where you can go from a given tile. In this case, we check
// all 8 directions, and if the destination is walkable return it as an option.
static bool get_successors(location_t pos, std::vector<location_t> &successors) {
//std::cout << pos.x << "/" << pos.y << "\n";
if (map.walkable[map.at(pos.x-1, pos.y-1)]) successors.push_back(location_t(pos.x-1, pos.y-1));
if (map.walkable[map.at(pos.x, pos.y-1)]) successors.push_back(location_t(pos.x, pos.y-1));
if (map.walkable[map.at(pos.x+1, pos.y-1)]) successors.push_back(location_t(pos.x+1, pos.y-1));
if (map.walkable[map.at(pos.x-1, pos.y)]) successors.push_back(location_t(pos.x-1, pos.y));
if (map.walkable[map.at(pos.x+1, pos.y)]) successors.push_back(location_t(pos.x+1, pos.y));
if (map.walkable[map.at(pos.x-1, pos.y+1)]) successors.push_back(location_t(pos.x-1, pos.y+1));
if (map.walkable[map.at(pos.x, pos.y+1)]) successors.push_back(location_t(pos.x, pos.y+1));
if (map.walkable[map.at(pos.x+1, pos.y+1)]) successors.push_back(location_t(pos.x+1, pos.y+1));
return true;
}
// This function lets you set a cost on a tile transition. For now, we'll always use a cost of 1.0.
static float get_cost(location_t &position, location_t &successor) {
return 1.0f;
}
// This is a simple comparison to determine if two locations are the same. It just passes
// through to the location_t's equality operator in this instance (we didn't do that automatically)
// because there are times you might want to behave differently.
static bool is_same_state(location_t &lhs, location_t &rhs) {
return lhs == rhs;
}
};
// Lets go really fast!
constexpr double tick_duration = 1.0;
double tick_time = 0.0;
// Tick is called every frame. The parameter specifies how many ms have elapsed
// since the last time it was called.
void tick(double duration_ms) {
// Iterate over the whole map, rendering as appropriate
for (int y=0; y<MAP_HEIGHT; ++y) {
for (int x=0; x<MAP_WIDTH; ++x) {
if (map.walkable[map.at(x,y)]) {
console->set_char(console->at(x,y), floor_tile);
} else {
console->set_char(console->at(x,y), wall_tile);
}
}
}
// Increase the tick time by the frame duration. If it has exceeded
// the tick duration, then we move the @.
tick_time += duration_ms;
if (tick_time > tick_duration) {
// Are we there yet?
if (dude_position == destination) {
// We are there! We need to pick a new destination.
destination.x = rng.roll_dice(1, MAP_WIDTH-1);
destination.y = rng.roll_dice(1, MAP_HEIGHT-1);
// Lets make sure that the destination is walkable
while (map.walkable[map.at(destination.x,destination.y)] == false) {
destination.x = rng.roll_dice(1, MAP_WIDTH-1);
destination.y = rng.roll_dice(1, MAP_HEIGHT-1);
}
// Now determine how to get there
if (path) path.reset();
path = find_path<location_t, navigator>(dude_position, destination);
if (!path->success) {
destination = dude_position;
std::cout << "RESET: THIS ISN'T MEANT TO HAPPEN!\n";
}
} else {
// Follow the breadcrumbs!
location_t next_step = path->steps.front();
dude_position.x = next_step.x;
dude_position.y = next_step.y;
path->steps.pop_front();
}
// Important: we clear the tick count after the update.
tick_time = 0.0;
}
// Render our planned path. We're using auto and a range-for to avoid typing all
// the iterator stuff
if (path) {
// We're going to show off a bit and "lerp" the color along the path; the red
// lightens as it approaches the destination. This is a preview of some of the
// color functions.
const float n_steps = static_cast<float>(path->steps.size());
float i = 0;
for (auto step : path->steps) {
const float lerp_amount = i / n_steps;
vchar highlight{ 177, lerp(DARK_GREEN, LIGHTEST_GREEN, lerp_amount), BLACK };
console->set_char(console->at(step.x, step.y), highlight);
++i;
}
}
// Render our destination
console->set_char(console->at(destination.x, destination.y), destination_glyph);
// Finally, we render the @ symbol. dude_x and dude_y are in terminal coordinates.
console->set_char(console->at(dude_position.x, dude_position.y), dude);
}
// Your main function
int main()
{
// Initialize with defaults
init(config_simple_px("../assets"));
// Enter the main loop. "tick" is the function we wrote above.
run(tick);
return 0;
}
================================================
FILE: examples/ex5/main.cpp
================================================
#include <iostream>
/* RLTK (RogueLike Tool Kit) 1.00
* Copyright (c) 2016-Present, Bracket Productions.
* Licensed under the MIT license - see LICENSE file.
*
* Example 5: Extend example 4 to use the mouse to guide player movement.
*/
// You need to include the RLTK header
#include "../../rltk/rltk.hpp"
// We're using a vector to represent the map
#include <vector>
// We're also going to be using a shared_ptr to a map. Why shared? Because the library
// hands it off to you and it's up to you to use it; this provides some safety that it
// will be disposed when you are done with it.
#include <memory>
// For convenience, import the whole rltk namespace. You may not want to do this
// in larger projects, to avoid naming collisions.
using namespace rltk;
using namespace rltk::colors;
// A default-defined random number generator. You can specify a seed to get
// the same results each time, but for now we're keeping it simple.
random_number_generator rng;
// For now, we always want our "dude" to be a yellow @ - so he's constexpr
const vchar dude{'@', YELLOW, BLACK};
// We're also going to render our destination as a pink heart. Aww.
const vchar destination_glyph{3, MAGENTA, BLACK};
// We now need to represent walls and floors, too
const vchar wall_tile{'#', WHITE, BLACK};
const vchar floor_tile{'.', GREY, BLACK}; // Note that "floor" is taken as a name in C++!
// Now we define a structure to represent a location. In this case, it's a simple
// x/y coordinate.
struct location_t {
int x=-1; // I like to set uninitialized values to something invalid for help with debugging
int y=-1;
// For convenience, we're overriding the quality operator. This gives a very
// quick and natural looking way to say "are these locations the same?"
bool operator==(location_t &rhs) { return (x==rhs.x && y==rhs.y); }
location_t() {}
location_t(const int X, const int Y) : x(X), y(Y) {}
};
// Now we define our basic map. Why a struct? Because a struct is just a class with
// everything public in it!
struct map_t {
map_t(const int &w, const int &h) : width(w), height(h) {
// Resize the vector to hold the whole map; this way it won't reallocate
walkable.resize(w*h);
// Set the entire map to walkable
std::fill(walkable.begin(), walkable.end(), true);
// We want the perimeter to be solid
for (int x=0; x<width; ++x) {
walkable[at(x,0)]=false;
walkable[at(x,height-1)]=false;
}
for (int y=0; y<height; ++y) {
walkable[at(0,y)] = false;
walkable[at(width-1,y)] = false;
}
// Every tile other than 10,10 (starting) has a 33% chance of being solid. We've
// made it more likely to have obstacles, since we're no longer relying on the RNG
// to find our way.
for (int y=1; y<height-2; ++y) {
for (int x=1; x<width-2; ++x) {
if (rng.roll_dice(1,3)==1) walkable[at(x,y)] = false;
}
}
walkable[at(10,10)] = true;
}
// Calculate the vector offset of a grid location
inline int at(const int &x, const int &y) { return (y*width)+x; }
// The width and height of the map
const int width, height;
// The actual walkable storage vector
std::vector<bool> walkable;
};
// The A* library returns a navigation path with a template specialization to our location_t.
// Store the path here. Normally, you'd use "auto" for this type, it is a lot less typing!
std::shared_ptr<navigation_path<location_t>> path;
// We're using 1024x768, with 8 pixel wide chars. That gives a console grid of
// 128 x 96. We'll go with that for the map, even though in reality the screen
// might change. Worrying about that is for a future example!
constexpr int MAP_WIDTH = 128;
constexpr int MAP_HEIGHT = 96;
map_t map(MAP_WIDTH, MAP_HEIGHT);
// Instead of raw ints, we'll use the location structure to represent where our
// dude is. Using C++14 initialization, it's nice and clean.
location_t dude_position {10,10};
// We'll also use a location_t to represent the intended destination.
location_t destination {10,10};
// The A* library also requires a helper class to understand your map format.
struct navigator {
// This lets you define a distance heuristic. Manhattan distance works really well, but
// for now we'll just use a simple euclidian distance squared.
// The geometry system defines one for us.
static float get_distance_estimate(location_t &pos, location_t &goal) {
float d = distance2d_squared(pos.x, pos.y, goal.x, goal.y);
return d;
}
// Heuristic to determine if we've reached our destination? In some cases, you'd not want
// this to be a simple comparison with the goal - for example, if you just want to be
// adjacent to (or even a preferred distance from) the goal. In this case,
// we're trying to get to the goal rather than near it.
static bool is_goal(location_t &pos, location_t &goal) {
return pos == goal;
}
// This is where we calculate where you can go from a given tile. In this case, we check
// all 8 directions, and if the destination is walkable return it as an option.
static bool get_successors(location_t pos, std::vector<location_t> &successors) {
//std::cout << pos.x << "/" << pos.y << "\n";
if (map.walkable[map.at(pos.x-1, pos.y-1)]) successors.push_back(location_t(pos.x-1, pos.y-1));
if (map.walkable[map.at(pos.x, pos.y-1)]) successors.push_back(location_t(pos.x, pos.y-1));
if (map.walkable[map.at(pos.x+1, pos.y-1)]) successors.push_back(location_t(pos.x+1, pos.y-1));
if (map.walkable[map.at(pos.x-1, pos.y)]) successors.push_back(location_t(pos.x-1, pos.y));
if (map.walkable[map.at(pos.x+1, pos.y)]) successors.push_back(location_t(pos.x+1, pos.y));
if (map.walkable[map.at(pos.x-1, pos.y+1)]) successors.push_back(location_t(pos.x-1, pos.y+1));
if (map.walkable[map.at(pos.x, pos.y+1)]) successors.push_back(location_t(pos.x, pos.y+1));
if (map.walkable[map.at(pos.x+1, pos.y+1)]) successors.push_back(location_t(pos.x+1, pos.y+1));
return true;
}
// This function lets you set a cost on a tile transition. For now, we'll always use a cost of 1.0.
static float get_cost(location_t &position, location_t &successor) {
return 1.0f;
}
// This is a simple comparison to determine if two locations are the same. It just passes
// through to the location_t's equality operator in this instance (we didn't do that automatically)
// because there are times you might want to behave differently.
static bool is_same_state(location_t &lhs, location_t &rhs) {
return lhs == rhs;
}
};
// Lets go really fast!
constexpr double tick_duration = 1.0;
double tick_time = 0.0;
// Tick is called every frame. The parameter specifies how many ms have elapsed
// since the last time it was called.
void tick(double duration_ms) {
// Iterate over the whole map, rendering as appropriate
for (int y=0; y<MAP_HEIGHT; ++y) {
for (int x=0; x<MAP_WIDTH; ++x) {
if (map.walkable[map.at(x,y)]) {
console->set_char(console->at(x,y), floor_tile);
} else {
console->set_char(console->at(x,y), wall_tile);
}
}
}
// Increase the tick time by the frame duration. If it has exceeded
// the tick duration, then we move the @.
tick_time += duration_ms;
if (tick_time > tick_duration) {
// Are we there yet?
if (dude_position == destination) {
// Now we poll the mouse to determine where we want to go
int mouse_x, mouse_y;
std::tie(mouse_x, mouse_y) = get_mouse_position();
const int terminal_x = mouse_x / 8;
const int terminal_y = mouse_y / 8;
const bool walkable = map.walkable[map.at(terminal_x, terminal_y)];
if (walkable && get_mouse_button_state(rltk::button::LEFT)) {
destination.x = terminal_x;
destination.y = terminal_y;
// Now determine how to get there
if (path) path.reset();
path = find_path<location_t, navigator>(dude_position, destination);
if (!path->success) {
destination = dude_position;
std::cout << "RESET: THIS ISN'T MEANT TO HAPPEN!\n";
}
} else if (walkable) {
if (path) path.reset();
path = find_path<location_t, navigator>(dude_position, location_t{terminal_x, terminal_y});
}
} else {
// Follow the breadcrumbs!
if (path) {
location_t next_step = path->steps.front();
dude_position.x = next_step.x;
dude_position.y = next_step.y;
path->steps.pop_front();
}
}
// Important: we clear the tick count after the update.
tick_time = 0.0;
}
// Render our planned path. We're using auto and a range-for to avoid typing all
// the iterator stuff
if (path) {
// We're going to show off a bit and "lerp" the color along the path; the red
// lightens as it approaches the destination. This is a preview of some of the
// color functions.
const float n_steps = static_cast<float>(path->steps.size());
float i = 0;
for (auto step : path->steps) {
const float lerp_amount = i / n_steps;
vchar highlight;
if (dude_position == destination) {
highlight = { 177, lerp(DARK_GREEN, LIGHTEST_GREEN, lerp_amount), BLACK };
} else {
highlight = { 177, lerp(DARK_RED, LIGHTEST_RED, lerp_amount), BLACK };
}
console->set_char(console->at(step.x, step.y), highlight);
++i;
}
}
// Render our destination
console->set_char(console->at(destination.x, destination.y), destination_glyph);
// Finally, we render the @ symbol. dude_x and dude_y are in terminal coordinates.
console->set_char(console->at(dude_position.x, dude_position.y), dude);
}
// Your main function
int main()
{
// Initialize with defaults
init(config_simple_px("../assets"));
// Enter the main loop. "tick" is the function we wrote above.
run(tick);
return 0;
}
================================================
FILE: examples/ex6/main.cpp
================================================
#include <iostream>
/* RLTK (RogueLike Tool Kit) 1.00
* Copyright (c) 2016-Present, Bracket Productions.
* Licensed under the MIT license - see LICENSE file.
*
* Example 6: Extend example 5 to include visibility and map revealed status.
*/
// You need to include the RLTK header
#include "../../rltk/rltk.hpp"
// We're using a vector to represent the map
#include <vector>
// We're also going to be using a shared_ptr to a map. Why shared? Because the library
// hands it off to you and it's up to you to use it; this provides some safety that it
// will be disposed when you are done with it.
#include <memory>
// For convenience, import the whole rltk namespace. You may not want to do this
// in larger projects, to avoid naming collisions.
using namespace rltk;
using namespace rltk::colors;
// A default-defined random number generator. You can specify a seed to get
// the same results each time, but for now we're keeping it simple.
random_number_generator rng;
// For now, we always want our "dude" to be a yellow @ - so he's constexpr
const vchar dude{'@', YELLOW, BLACK};
// We're also going to render our destination as a pink heart. Aww.
const vchar destination_glyph{3, MAGENTA, BLACK};
// Now we define a structure to represent a location. In this case, it's a simple
// x/y coordinate.
struct location_t {
int x=-1; // I like to set uninitialized values to something invalid for help with debugging
int y=-1;
// For convenience, we're overriding the quality operator. This gives a very
// quick and natural looking way to say "are these locations the same?"
bool operator==(location_t &rhs) { return (x==rhs.x && y==rhs.y); }
location_t() {}
location_t(const int X, const int Y) : x(X), y(Y) {}
};
// Now we define our basic map. Why a struct? Because a struct is just a class with
// everything public in it!
struct map_t {
map_t(const int &w, const int &h) : width(w), height(h) {
// Resize the vectors to hold the whole map; this way it won't reallocate
walkable.resize(w*h);
revealed.resize(w*h);
visible.resize(w*h);
// Set the entire map to walkable, not visible and not revealed
std::fill(walkable.begin(), walkable.end(), true);
std::fill(revealed.begin(), revealed.end(), false);
std::fill(visible.begin(), visible.end(), false);
// We want the perimeter to be solid
for (int x=0; x<width; ++x) {
walkable[at(x,0)]=false;
walkable[at(x,height-1)]=false;
}
for (int y=0; y<height; ++y) {
walkable[at(0,y)] = false;
walkable[at(width-1,y)] = false;
}
// Every tile other than 10,10 (starting) has a 33% chance of being solid. We've
// made it more likely to have obstacles, since we're no longer relying on the RNG
// to find our way.
for (int y=1; y<height-2; ++y) {
for (int x=1; x<width-2; ++x) {
if (rng.roll_dice(1,3)==1) walkable[at(x,y)] = false;
}
}
walkable[at(10,10)]=true;
}
// Calculate the vector offset of a grid location
inline int at(const int &x, const int &y) { return (y*width)+x; }
// The width and height of the map
const int width, height;
// The actual walkable storage vector
std::vector<bool> walkable;
// Revealed: has a tile been shown yet?
std::vector<bool> revealed;
// Visible: is a tile currently visible?
std::vector<bool> visible;
};
// The A* library returns a navigation path with a template specialization to our location_t.
// Store the path here. Normally, you'd use "auto" for this type, it is a lot less typing!
std::shared_ptr<navigation_path<location_t>> path;
// We're using 1024x768, with 8 pixel wide chars. That gives a console grid of
// 128 x 96. We'll go with that for the map, even though in reality the screen
// might change. Worrying about that is for a future example!
constexpr int MAP_WIDTH = 128;
constexpr int MAP_HEIGHT = 96;
map_t map(MAP_WIDTH, MAP_HEIGHT);
// Instead of raw ints, we'll use the location structure to represent where our
// dude is. Using C++14 initialization, it's nice and clean.
location_t dude_position {10,10};
// We'll also use a location_t to represent the intended destination.
location_t destination {10,10};
// The A* library also requires a helper class to understand your map format.
struct navigator {
// This lets you define a distance heuristic. Manhattan distance works really well, but
// for now we'll just use a simple euclidian distance squared.
// The geometry system defines one for us.
static float get_distance_estimate(location_t &pos, location_t &goal) {
float d = distance2d_squared(pos.x, pos.y, goal.x, goal.y);
return d;
}
// Heuristic to determine if we've reached our destination? In some cases, you'd not want
// this to be a simple comparison with the goal - for example, if you just want to be
// adjacent to (or even a preferred distance from) the goal. In this case,
// we're trying to get to the goal rather than near it.
static bool is_goal(location_t &pos, location_t &goal) {
return pos == goal;
}
// This is where we calculate where you can go from a given tile. In this case, we check
// all 8 directions, and if the destination is walkable return it as an option.
static bool get_successors(location_t pos, std::vector<location_t> &successors) {
//std::cout << pos.x << "/" << pos.y << "\n";
if (map.walkable[map.at(pos.x-1, pos.y-1)]) successors.push_back(location_t(pos.x-1, pos.y-1));
if (map.walkable[map.at(pos.x, pos.y-1)]) successors.push_back(location_t(pos.x, pos.y-1));
if (map.walkable[map.at(pos.x+1, pos.y-1)]) successors.push_back(location_t(pos.x+1, pos.y-1));
if (map.walkable[map.at(pos.x-1, pos.y)]) successors.push_back(location_t(pos.x-1, pos.y));
if (map.walkable[map.at(pos.x+1, pos.y)]) successors.push_back(location_t(pos.x+1, pos.y));
if (map.walkable[map.at(pos.x-1, pos.y+1)]) successors.push_back(location_t(pos.x-1, pos.y+1));
if (map.walkable[map.at(pos.x, pos.y+1)]) successors.push_back(location_t(pos.x, pos.y+1));
if (map.walkable[map.at(pos.x+1, pos.y+1)]) successors.push_back(location_t(pos.x+1, pos.y+1));
return true;
}
// This function lets you set a cost on a tile transition. For now, we'll always use a cost of 1.0.
static float get_cost(location_t &position, location_t &successor) {
return 1.0f;
}
// This is a simple comparison to determine if two locations are the same. It just passes
// through to the location_t's equality operator in this instance (we didn't do that automatically)
// because there are times you might want to behave differently.
static bool is_same_state(location_t &lhs, location_t &rhs) {
return lhs == rhs;
}
// We're using the Bresneham's line optimization for pathing this time, which requires a few extra
// static methods. These are designed to translate between your map format and co-ordinates used by
// the library (we don't want to force you to structure things a certain way).
static int get_x(const location_t &loc) { return loc.x; }
static int get_y(const location_t &loc) { return loc.y; }
static location_t get_xy(const int &x, const int &y) { return location_t{x,y}; }
static bool is_walkable(const location_t &loc) { return map.walkable[map.at(loc.x, loc.y)]; }
};
// Lets go really fast!
constexpr double tick_duration = 0.0;
double tick_time = 0.0;
// Helper function: calls the RLTK visibility sweep 2D algorithm with lambdas to
// assist in understanding our map format.
inline void visibility_sweep() {
visibility_sweep_2d<location_t, navigator>(dude_position, 10,
[] (location_t reveal) {
map.revealed[map.at(reveal.x, reveal.y)] = true;
map.visible[map.at(reveal.x, reveal.y)] = true;
},
[] (auto test_visibility) { return map.walkable[map.at(test_visibility.x, test_visibility.y)]; }
);
}
// Tick is called every frame. The parameter specifies how many ms have elapsed
// since the last time it was called.
void tick(double duration_ms) {
// Iterate over the whole map, rendering as appropriate
for (int y=0; y<MAP_HEIGHT; ++y) {
for (int x=0; x<MAP_WIDTH; ++x) {
const int map_idx = map.at(x,y); // Caching so we don't keep doing the calculation
if (map.walkable[map_idx]) {
if (map.visible[map_idx]) {
// Visible tile: render full color
console->set_char(map_idx, vchar{'.', GREEN, BLACK});
} else if (map.revealed[map_idx]) {
// Revealed tile: render grey
console->set_char(map_idx, vchar{'.', LIGHTER_GREY, BLACK});
} else {
// We haven't seen it yet - darkest gray
console->set_char(map_idx, vchar{'.', DARK_GREY, BLACK});
}
} else {
if (map.visible[map_idx]) {
// Visible tile: render full color
console->set_char(map_idx, vchar{'#', CYAN, BLACK});
} else if (map.revealed[map_idx]) {
// Revealed tile: render grey
console->set_char(map_idx, vchar{'#', GREY, BLACK});
} else {
// We haven't seen it yet - darkest gray
console->set_char(map_idx, vchar{'#', DARKER_GREY, BLACK});
}
}
}
}
// Increase the tick time by the frame duration. If it has exceeded
// the tick duration, then we move the @.
tick_time += duration_ms;
if (tick_time > tick_duration) {
// Are we there yet?
if (dude_position == destination) {
// Now we poll the mouse to determine where we want to go
// This requests the mouse position in PIXELS, and ties it into our mouse_x/mouse_y variables.
int mouse_x, mouse_y;
std::tie(mouse_x, mouse_y) = get_mouse_position();
// Since we're using an 8x8, it's just a matter of dividing by 8 to find the terminal-character
// coordinates. There will be a helper function for this once we get into retained GUIs.
const int terminal_x = mouse_x / 8;
const int terminal_y = mouse_y / 8;
// If the mouse is pointing at a walkable location, and the left button is down - path to the mouse.
const bool walkable = map.walkable[map.at(terminal_x, terminal_y)];
if (walkable && get_mouse_button_state(rltk::button::LEFT)) {
destination.x = terminal_x;
destination.y = terminal_y;
// Now determine how to get there
if (path) path.reset();
path = find_path<location_t, navigator>(dude_position, destination);
if (!path->success) {
destination = dude_position;
std::cout << "RESET: THIS ISN'T MEANT TO HAPPEN!\n";
}
} else if (walkable) {
// If the mouse is not clicked, then path to the mouse cursor for display only
if (path) path.reset();
path = find_path_2d<location_t, navigator>(dude_position, location_t{terminal_x, terminal_y});
}
} else {
// Follow the breadcrumbs!
if (path) {
location_t next_step = path->steps.front();
dude_position.x = next_step.x;
dude_position.y = next_step.y;
path->steps.pop_front();
// Update the map visibility
std::fill(map.visible.begin(), map.visible.end(), false);
visibility_sweep();
}
}
// Important: we clear the tick count after the update.
tick_time = 0.0;
}
// Render our planned path. We're using auto and a range-for to avoid typing all
// the iterator stuff
if (path) {
// We're going to show off a bit and "lerp" the color along the path; the red
// lightens as it approaches the destination. This is a preview of some of the
// color functions.
const float n_steps = static_cast<float>(path->steps.size());
float i = 0;
for (auto step : path->steps) {
const float lerp_amount = i / n_steps;
vchar highlight;
// If we're at our destination, we are showing possible paths - highlight green;
// otherwise, highlight red to indicate that we are en route.
if (dude_position == destination) {
highlight = { 177, lerp(DARK_GREEN, LIGHTEST_GREEN, lerp_amount), BLACK };
} else {
highlight = { 177, lerp(DARK_RED, LIGHTEST_RED, lerp_amount), BLACK };
}
console->set_char(console->at(step.x, step.y), highlight);
++i;
}
}
// Render our destination
console->set_char(console->at(destination.x, destination.y), destination_glyph);
// Finally, we render the @ symbol. dude_x and dude_y are in terminal coordinates.
console->set_char(console->at(dude_position.x, dude_position.y), dude);
}
// Your main function
int main()
{
// Initialize with defaults
init(config_simple_px("../assets"));
// We do a visibility sweep to start, so your starting position is revealed
visibility_sweep();
// Enter the main loop. "tick" is the function we wrote above.
run(tick);
return 0;
}
================================================
FILE: examples/ex7/main.cpp
================================================
/* RLTK (RogueLike Tool Kit) 1.00
* Copyright (c) 2016-Present, Bracket Productions.
* Licensed under the MIT license - see LICENSE file.
*
* Example 7: Introduction to complex GUIs. This example demonstrates how you can create multiple layers,
* and use call-backs to resize them as the window adjusts. It also displays a layer on top of another,
* with alpha transparency (useful for effects).
*/
// You need to include the RLTK header
#include "../../rltk/rltk.hpp"
#include <sstream>
#include <iomanip>
// For convenience, import the whole rltk namespace. You may not want to do this
// in larger projects, to avoid naming collisions.
using namespace rltk;
using namespace rltk::colors;
// For convenience, we'll define our GUI section handles here. These are just ID numbers.
constexpr int TITLE_LAYER = 0;
constexpr int MAIN_LAYER = 1;
constexpr int LOG_LAYER = 2;
constexpr int OVERLAY_LAYER = 3;
// Tick is called every frame. The parameter specifies how many ms have elapsed
// since the last time it was called.
void tick(double duration_ms) {
term(TITLE_LAYER)->clear(vchar{' ', YELLOW, BLUE});
term(TITLE_LAYER)->print_center(0, "Big 32x32 Title", YELLOW, BLUE);
term(MAIN_LAYER)->clear(vchar{'.', GREY, BLACK});
term(MAIN_LAYER)->box(GREY, BLACK, true);
term(MAIN_LAYER)->set_char(10, 10, vchar{'@', YELLOW, BLACK});
term(LOG_LAYER)->clear(vchar{' ', WHITE, DARKEST_GREEN});
term(LOG_LAYER)->box(DARKEST_GREEN, BLACK);
term(LOG_LAYER)->print(1,1, "Log Entry", LIGHT_GREEN, DARKEST_GREEN);
term(LOG_LAYER)->print(1,2, "More text!", LIGHT_GREEN, DARKEST_GREEN);
term(LOG_LAYER)->print(1,3, "Even more...", LIGHT_GREEN, DARKEST_GREEN);
term(LOG_LAYER)->print(1,4, "... goes here", LIGHT_GREEN, DARKEST_GREEN);
term(OVERLAY_LAYER)->clear();
term(OVERLAY_LAYER)->set_char(11, 10, vchar{17, LIGHT_GREEN, BLACK}); // Draw a left arrow
term(OVERLAY_LAYER)->print(12, 10, "Translucent Tool-tip", LIGHT_GREEN, BLACK);
std::stringstream ss;
ss << std::setiosflags(std::ios::fixed) << std::setprecision(0) << (1000.0/duration_ms) << " FPS";
term(LOG_LAYER)->print(1,6, ss.str(), WHITE, DARKEST_GREEN);
}
// This is called when the screen resizes, to allow the GUI to redefine itself.
void resize_title(layer_t * l, int w, int h) {
// Simply set the width to the whole window width
l->w = w;
l->h = 32; // Not really necessary - here for clarity
}
// This is called when the screen resizes, to allow the GUI to redefine itself.
void resize_main(layer_t * l, int w, int h) {
// Simply set the width to the whole window width, and the whole window minus 16 pixels (for the heading)
l->w = w - 160;
l->h = h - 32;
if (l->w < 0) l->w = 160; // If the width is too small with the log window, display anyway.
}
// This is called when the screen resizes, to allow the GUI to redefine itself.
void resize_log(layer_t * l, int w, int h) {
// Simply set the width to the whole window width, and the whole window minus 16 pixels (for the heading)
l->w = w - 160;
l->h = h - 32;
// If the log window would take up the whole screen, hide it
if (l->w < 0) {
l->console->visible = false;
} else {
l->console->visible = true;
}
l->x = w - 160;
}
// Your main function
int main()
{
// This time, we're using a full initialization: width, height, window title, and "false" meaning we don't
// want an automatically generated root console. This is necessary when you want to use the complex layout
// functions.
init(config_advanced("../assets"));
gui->add_layer(TITLE_LAYER, 0, 0, 1024, 32, "32x32", resize_title);
gui->add_layer(MAIN_LAYER, 0, 32, 1024-160, 768-32, "8x8", resize_main);
gui->add_layer(LOG_LAYER, 864, 32, 160, 768-32, "8x16", resize_log);
gui->add_layer(OVERLAY_LAYER, 0, 32, 1024-160, 768-32, "8x8", resize_main); // We re-use resize_main, we want it over the top
term(OVERLAY_LAYER)->set_alpha(196); // Make the overlay translucent
run(tick);
return 0;
}
================================================
FILE: examples/ex8/main.cpp
================================================
/* RLTK (RogueLike Tool Kit) 1.00
* Copyright (c) 2016-Present, Bracket Productions.
* Licensed under the MIT license - see LICENSE file.
*
* Example 7: Advanced GUI with retained-mode GUI elements and an owner-draw background.
*/
// You need to include the RLTK header
#include "../../rltk/rltk.hpp"
#include <sstream>
#include <iomanip>
// For convenience, import the whole rltk namespace. You may not want to do this
// in larger projects, to avoid naming collisions.
using namespace rltk;
using namespace rltk::colors;
random_number_generator rng;
constexpr int BACKDROP_LAYER = 1;
constexpr int LOG_LAYER = 2;
constexpr int RETAINED_TEST_LAYER = 3;
constexpr int TEST_BOUNDARY_BOX = 1;
constexpr int TEST_STATIC_TEST = 2;
constexpr int TEST_MOUSE_HOVER = 3;
constexpr int TEST_CHECKBOX = 4;
constexpr int TEST_RADIOSET = 5;
constexpr int TEST_HBAR = 6;
constexpr int TEST_VBAR = 7;
constexpr int TEST_LISTBOX = 8;
void resize_bg(layer_t * l, int w, int h) {
// Use the whole window
l->w = w;
l->h = h;
}
void draw_bg(layer_t * l, sf::RenderTexture &window) {
sf::Texture * bg = get_texture("backdrop");
sf::Sprite backdrop(*bg);
window.draw(backdrop);
}
void resize_log(layer_t * l, int w, int h) {
// Simply set the width to the whole window width, and the whole window minus 16 pixels (for the heading)
l->w = w - 160;
l->h = h - 32;
// If the log window would take up the whole screen, hide it
if (l->w < 0) {
l->console->visible = false;
} else {
l->console->visible = true;
}
l->x = w - 160;
}
void resize_retained(layer_t * l, int w, int h) {
// Do nothing - we'll just keep on rendering away.
l->x = 100;
l->y = 100;
l->w = 400;
l->h = 200;
}
// Tick is called every frame. The parameter specifies how many ms have elapsed
// since the last time it was called.
void tick(double duration_ms) {
term(LOG_LAYER)->clear(vchar{' ', WHITE, DARKEST_GREEN});
term(LOG_LAYER)->box(DARKEST_GREEN, BLACK);
layer_t * retained = layer(RETAINED_TEST_LAYER);
if ( retained->control<gui_checkbox_t>(TEST_CHECKBOX)->checked ) {
term(LOG_LAYER)->print(1,1, "Checked", LIGHTEST_GREEN, DARKEST_GREEN);
} else {
term(LOG_LAYER)->print(1,1, "Not Checked", DARK_GREEN, DARKEST_GREEN);
}
std::stringstream radio_ss;
radio_ss << "Option: " << retained->control<gui_radiobuttons_t>(TEST_RADIOSET)->selected_value;
term(LOG_LAYER)->print(1,2, radio_ss.str(), LIGHT_GREEN, DARKEST_GREEN);
std::stringstream list_ss;
list_ss << "List: " << retained->control<gui_listbox_t>(TEST_LISTBOX)->selected_value;
term(LOG_LAYER)->print(1,3, list_ss.str(), LIGHT_GREEN, DARKEST_GREEN);
term(LOG_LAYER)->print(1,4, "... goes here", LIGHT_GREEN, DARKEST_GREEN);
std::stringstream ss;
ss << std::setiosflags(std::ios::fixed) << std::setprecision(0) << (1000.0/duration_ms) << " FPS";
term(LOG_LAYER)->print(1,6, ss.str(), WHITE, DARKEST_GREEN);
if (rng.roll_dice(1,20)==1) {
retained->control<gui_hbar_t>(TEST_HBAR)->value = rng.roll_dice(1,100);
retained->control<gui_vbar_t>(TEST_VBAR)->value = rng.roll_dice(1,100);
}
}
// Your main function
int main()
{
// This time, we're using a full initialization: width, height, window title, and "false" meaning we don't
// want an automatically generated root console. This is necessary when you want to use the complex layout
// functions.
init(config_advanced("../assets"));
// We're going to be using a bitmap, so we need to load it. The library makes this easy:
register_texture("../assets/background_image.png", "backdrop");
// Now we add an owner-draw background layer. "Owner-draw" means that it the library will ask it to
// draw itself with a call-back function.
gui->add_owner_layer(BACKDROP_LAYER, 0, 0, 1024, 768, resize_bg, draw_bg);
gui->add_layer(LOG_LAYER, 864, 32, 160, 768-32, "8x16", resize_log);
term(LOG_LAYER)->set_alpha(196); // Make the overlay translucent
gui->add_layer(RETAINED_TEST_LAYER, 100, 100, 400, 400, "8x16", resize_retained);
// To reduce typing, grab a pointer to the retained layer:
layer_t * retained = layer(RETAINED_TEST_LAYER);
// Now we build some retained-mode controls. These don't require additional work during rendering
// Note that we are providing a handle to the control. That lets us access it later with
// layer(layerhandle)->control(controlhandle). It's up to you to store the handles; they can be any
// int.
retained->add_boundary_box(TEST_BOUNDARY_BOX, true, DARK_GREY, BLACK);
retained->add_static_text(TEST_STATIC_TEST, 1, 1, "Retained Mode Static Text", YELLOW, BLACK);
// For this control, we'll define an on-mouse-over. We're using a lambda, but it could be any function
// with that takes a gui_control_t * as a parameter. We'll also use "on render start" to define a function
// run when the control rendering starts.
retained->add_static_text(TEST_MOUSE_HOVER, 1, 2, "Hover the mouse over me!", WHITE, BLACK);
retained->control(TEST_MOUSE_HOVER)->on_render_start = [] (gui_control_t * control) {
auto static_text = static_cast<gui_static_text_t *>(control);
static_text->background = BLACK;
static_text->text = "Hover the mouse over me!";
};
retained->control(TEST_MOUSE_HOVER)->on_mouse_over = [] (gui_control_t * control, int terminal_x, int terminal_y) {
auto static_text = static_cast<gui_static_text_t *>(control);
static_text->background = RED;
static_text->text = "Why Hello There! ";
};
// A checkbox
retained->add_checkbox(TEST_CHECKBOX, 1, 3, "I'm a checkbox - click me!", false, LIGHT_GREEN, BLACK);
// A radioset
retained->add_radioset(TEST_RADIOSET, 1, 5, "Test radio buttons", CYAN, BLACK, {
{true, "Option A", 0}, {false, "Option B", 1}, {false, "Option C", 2}
});
// Add a horizontal and vertical color bar (e.g. health)
retained->add_hbar(TEST_HBAR, 1, 9, 46, 0, 100, 50, color_t(128,0,0), color_t(255,0,0), color_t(128,128,128), color_t(64,64,64), WHITE, "Health: ");
retained->add_vbar(TEST_VBAR, 48, 1, 20, 0, 100, 50, color_t(0,0,128), color_t(0,0,128), color_t(128,128,128), color_t(64,64,64), CYAN, "Mana: ");
// Listbox
retained->add_listbox(TEST_LISTBOX, 1, 11, 1, { {1, "Option 1"}, {2, "Option 2"}, {3, "Option 3"} }, "Listbox Options", WHITE, BLACK, WHITE, BLACK, WHITE, BLUE);
// Main loop - calls the 'tick' function you defined for each frame.
run(tick);
return 0;
}
================================================
FILE: examples/ex9/main.cpp
================================================
#include <iostream>
/* RLTK (RogueLike Tool Kit) 1.00
* Copyright (c) 2016-Present, Bracket Productions.
* Licensed under the MIT license - see LICENSE file.
*
* Example 9: This is example 6, but using two consoles. One for the map, and one sparse. This allows
* for some trickery to speed up map rendering (we're only redrawing when we need to). We also use smooth
* movement, which many people may or may not like - but is an important feature to offer. Finally, we're
* 'bouncing' the @ left and right to demonstrate rotation.
*/
// You need to include the RLTK header
#include "../../rltk/rltk.hpp"
// We're using a vector to represent the map
#include <vector>
// We're also going to be using a shared_ptr to a map. Why shared? Because the library
// hands it off to you and it's up to you to use it; this provides some safety that it
// will be disposed when you are done with it.
#include <memory>
// For convenience, import the whole rltk namespace. You may not want to do this
// in larger projects, to avoid naming collisions.
using namespace rltk;
using namespace rltk::colors;
// A default-defined random number generator. You can specify a seed to get
// the same results each time, but for now we're keeping it simple.
random_number_generator rng;
// For now, we always want our "dude" to be a yellow @ - so he's constexpr
const vchar dude{'@', YELLOW, BLACK};
// We're also going to render our destination as a pink heart. Aww.
const vchar destination_glyph{3, MAGENTA, BLACK};
// Now we define a structure to represent a location. In this case, it's a simple
// x/y coordinate.
struct location_t {
float x=-1.0f; // I like to set uninitialized values to something invalid for help with debugging
float y=-1.0f;
// For convenience, we're overriding the quality operator. This gives a very
// quick and natural looking way to say "are these locations the same?"
bool operator==(location_t &rhs) { return (std::floor(x)==std::floor(rhs.x) && std::floor(y)==std::floor(rhs.y)); }
location_t() {}
location_t(const int X, const int Y) : x(static_cast<float>(X)), y(static_cast<float>(Y)) {}
};
// Now we define our basic map. Why a struct? Because a struct is just a class with
// everything public in it!
struct map_t {
map_t(const int &w, const int &h) : width(w), height(h) {
// Resize the vectors to hold the whole map; this way it won't reallocate
walkable.resize(w*h);
revealed.resize(w*h);
visible.resize(w*h);
// Set the entire map to walkable, not visible and not revealed
std::fill(walkable.begin(), walkable.end(), true);
std::fill(revealed.begin(), revealed.end(), false);
std::fill(visible.begin(), visible.end(), false);
// We want the perimeter to be solid
for (int x=0; x<width; ++x) {
walkable[at(x,0)]=false;
walkable[at(x,height-1)]=false;
}
for (int y=0; y<height; ++y) {
walkable[at(0,y)] = false;
walkable[at(width-1,y)] = false;
}
// Every tile other than 10,10 (starting) has a 33% chance of being solid. We've
// made it more likely to have obstacles, since we're no longer relying on the RNG
// to find our way.
for (int y=1; y<height-2; ++y) {
for (int x=1; x<width-2; ++x) {
if (rng.roll_dice(1,3)==1) walkable[at(x,y)] = false;
}
}
walkable[at(10,10)]=true;
}
// Calculate the vector offset of a grid location
inline int at(const int &x, const int &y) { return (y*width)+x; }
// The width and height of the map
const int width, height;
// The actual walkable storage vector
std::vector<bool> walkable;
// Revealed: has a tile been shown yet?
std::vector<bool> revealed;
// Visible: is a tile currently visible?
std::vector<bool> visible;
};
// The A* library returns a navigation path with a template specialization to our location_t.
// Store the path here. Normally, you'd use "auto" for this type, it is a lot less typing!
std::shared_ptr<navigation_path<location_t>> path;
// We're using 1024x768, with 8 pixel wide chars. That gives a console grid of
// 128 x 96. We'll go with that for the map, even though in reality the screen
// might change. Worrying about that is for a future example!
constexpr int MAP_WIDTH = 128;
constexpr int MAP_HEIGHT = 96;
map_t map(MAP_WIDTH, MAP_HEIGHT);
// Instead of raw ints, we'll use the location structure to represent where our
// dude is. Using C++14 initialization, it's nice and clean.
location_t dude_position {10,10};
// We'll also use a location_t to represent the intended destination.
location_t destination {10,10};
// The A* library also requires a helper class to understand your map format.
struct navigator {
// This lets you define a distance heuristic. Manhattan distance works really well, but
// for now we'll just use a simple euclidian distance squared.
// The geometry system defines one for us.
static float get_distance_estimate(location_t &pos, location_t &goal) {
float d = distance2d_squared(static_cast<int>(pos.x), static_cast<int>(pos.y), static_cast<int>(goal.x), static_cast<int>(goal.y));
return d;
}
// Heuristic to determine if we've reached our destination? In some cases, you'd not want
// this to be a simple comparison with the goal - for example, if you just want to be
// adjacent to (or even a preferred distance from) the goal. In this case,
// we're trying to get to the goal rather than near it.
static bool is_goal(location_t &pos, location_t &goal) {
return pos == goal;
}
// This is where we calculate where you can go from a given tile. In this case, we check
// all 8 directions, and if the destination is walkable return it as an option.
static bool get_successors(location_t pos, std::vector<location_t> &successors) {
//std::cout << pos.x << "/" << pos.y << "\n";
if (map.walkable[map.at(static_cast<int>(pos.x-1), static_cast<int>(pos.y-1))]) successors.push_back(location_t(static_cast<int>(pos.x-1), static_cast<int>(pos.y-1)));
if (map.walkable[map.at(static_cast<int>(pos.x), static_cast<int>(pos.y-1))]) successors.push_back(location_t(static_cast<int>(pos.x), static_cast<int>(pos.y-1)));
if (map.walkable[map.at(static_cast<int>(pos.x+1), static_cast<int>(pos.y-1))]) successors.push_back(location_t(static_cast<int>(pos.x+1), static_cast<int>(pos.y-1)));
if (map.walkable[map.at(static_cast<int>(pos.x-1), static_cast<int>(pos.y))]) successors.push_back(location_t(static_cast<int>(pos.x-1), static_cast<int>(pos.y)));
if (map.walkable[map.at(static_cast<int>(pos.x+1), static_cast<int>(pos.y))]) successors.push_back(location_t(static_cast<int>(pos.x+1), static_cast<int>(pos.y)));
if (map.walkable[map.at(static_cast<int>(pos.x-1), static_cast<int>(pos.y+1))]) successors.push_back(location_t(static_cast<int>(pos.x-1), static_cast<int>(pos.y+1)));
if (map.walkable[map.at(static_cast<int>(pos.x), static_cast<int>(pos.y+1))]) successors.push_back(location_t(static_cast<int>(pos.x), static_cast<int>(pos.y+1)));
if (map.walkable[map.at(static_cast<int>(pos.x+1), static_cast<int>(pos.y+1))]) successors.push_back(location_t(static_cast<int>(pos.x+1), static_cast<int>(pos.y+1)));
return true;
}
// This function lets you set a cost on a tile transition. For now, we'll always use a cost of 1.0.
static float get_cost(location_t &position, location_t &successor) {
return 1.0f;
}
// This is a simple comparison to determine if two locations are the same. It just passes
// through to the location_t's equality operator in this instance (we didn't do that automatically)
// because there are times you might want to behave differently.
static bool is_same_state(location_t &lhs, location_t &rhs) {
return lhs == rhs;
}
// We're using the Bresneham's line optimization for pathing this time, which requires a few extra
// static methods. These are designed to translate between your map format and co-ordinates used by
// the library (we don't want to force you to structure things a certain way).
static int get_x(const location_t &loc) { return static_cast<int>(loc.x); }
static int get_y(const location_t &loc) { return static_cast<int>(loc.y); }
static location_t get_xy(const int &x, const int &y) { return location_t{x,y}; }
static bool is_walkable(const location_t &loc) { return map.walkable[map.at(static_cast<int>(loc.x), static_cast<int>(loc.y))]; }
};
// Lets go really fast!
constexpr double tick_duration = 0.0;
double tick_time = 0.0;
// Helper function: calls the RLTK visibility sweep 2D algorithm with lambdas to
// assist in understanding our map format.
inline void visibility_sweep() {
visibility_sweep_2d<location_t, navigator>(dude_position, 10,
[] (location_t reveal) {
map.revealed[map.at(static_cast<int>(reveal.x), static_cast<int>(reveal.y))] = true;
map.visible[map.at(static_cast<int>(reveal.x), static_cast<int>(reveal.y))] = true;
},
[] (auto test_visibility) { return map.walkable[map.at(static_cast<int>(test_visibility.x), static_cast<int>(test_visibility.y))]; }
);
}
// Tick is called every frame. The parameter specifies how many ms have elapsed
// since the last time it was called.
void tick(double duration_ms) {
int angle = 0;
// Increase the tick time by the frame duration. If it has exceeded
// the tick duration, then we move the @.
tick_time += duration_ms;
if (tick_time > tick_duration) {
// Are we there yet?
if (dude_position == destination) {
// Now we poll the mouse to determine where we want to go
// This requests the mouse position in PIXELS, and ties it into our mouse_x/mouse_y variables.
int mouse_x, mouse_y;
std::tie(mouse_x, mouse_y) = get_mouse_position();
// Since we're using an 8x8, it's just a matter of dividing by 8 to find the terminal-character
// coordinates. There will be a helper function for this once we get into retained GUIs.
const int terminal_x = mouse_x / 8;
const int terminal_y = mouse_y / 8;
// If the mouse is pointing at a walkable location, and the left button is down - path to the mouse.
const bool walkable = map.walkable[map.at(terminal_x, terminal_y)];
if (walkable && get_mouse_button_state(rltk::button::LEFT)) {
destination.x = static_cast<float>(terminal_x);
destination.y = static_cast<float>(terminal_y);
// Now determine how to get there
if (path) path.reset();
path = find_path<location_t, navigator>(dude_position, destination);
if (!path->success) {
destination = dude_position;
std::cout << "RESET: THIS ISN'T MEANT TO HAPPEN!\n";
}
} else if (walkable) {
// If the mouse is not clicked, then path to the mouse cursor for display only
if (path) path.reset();
path = find_path_2d<location_t, navigator>(dude_position, location_t{terminal_x, terminal_y});
}
} else {
// Follow the breadcrumbs!
if (path) {
location_t next_step = path->steps.front();
//dude_position.x = next_step.x;
//dude_position.y = next_step.y;
if (dude_position.x > next_step.x) { dude_position.x -= 0.25f; angle = 315; }
if (dude_position.x < next_step.x) { dude_position.x += 0.25f; angle = 45; }
if (dude_position.y > next_step.y) dude_position.y -= 0.25f;
if (dude_position.y < next_step.y) dude_position.y += 0.25f;
if (std::floor(dude_position.x) == next_step.x && std::floor(dude_position.y) == next_step.y) path->steps.pop_front();
// Update the map visibility
std::fill(map.visible.begin(), map.visible.end(), false);
visibility_sweep();
term(1)->dirty = true;
}
}
// Important: we clear the tick count after the update.
tick_time = 0.0;
}
// Render our planned path. We're using auto and a range-for to avoid typing all
// the iterator stuff
sterm(2)->clear();
if (path) {
// We're going to show off a bit and "lerp" the color along the path; the red
// lightens as it approaches the destination. This is a preview of some of the
// color functions.
const float n_steps = static_cast<float>(path->steps.size());
float i = 0;
for (auto step : path->steps) {
const float lerp_amount = i / n_steps;
vchar highlight;
// If we're at our destination, we are showing possible paths - highlight green;
// otherwise, highlight red to indicate that we are en route.
if (dude_position == destination) {
highlight = { 177, lerp(DARK_GREEN, LIGHTEST_GREEN, lerp_amount), BLACK };
} else {
highlight = { 177, lerp(DARK_RED, LIGHTEST_RED, lerp_amount), BLACK };
}
sterm(2)->add(xchar( 177, highlight.foreground, static_cast<float>(step.x), static_cast<float>(step.y) ));
++i;
}
}
// Render our destination
term(1)->set_char(term(1)->at(static_cast<int>(destination.x), static_cast<int>(destination.y)), destination_glyph);
// Finally, we render the @ symbol. dude_x and dude_y are in terminal coordinates.
//term(1)->set_char(term(1)->at(dude_position.x, dude_position.y), dude);
sterm(2)->add(xchar(
'@', YELLOW, static_cast<float>(dude_position.x), static_cast<float>(dude_position.y), angle
));
// Iterate over the whole map, rendering as appropriate
if (term(1)->dirty) {
for (int y=0; y<MAP_HEIGHT; ++y) {
for (int x=0; x<MAP_WIDTH; ++x) {
const int map_idx = map.at(x,y); // Caching so we don't keep doing the calculation
if (map.walkable[map_idx]) {
if (map.visible[map_idx]) {
// Visible tile: render full color
term(1)->set_char(map_idx, vchar{'.', GREEN, BLACK});
} else if (map.revealed[map_idx]) {
// Revealed tile: render grey
term(1)->set_char(map_idx, vchar{'.', LIGHTER_GREY, BLACK});
} else {
// We haven't seen it yet - darkest gray
term(1)->set_char(map_idx, vchar{'.', DARK_GREY, BLACK});
}
} else {
if (map.visible[map_idx]) {
// Visible tile: render full color
term(1)->set_char(map_idx, vchar{'#', CYAN, BLACK});
} else if (map.revealed[map_idx]) {
// Revealed tile: render grey
term(1)->set_char(map_idx, vchar{'#', GREY, BLACK});
} else {
// We haven't seen it yet - darkest gray
term(1)->set_char(map_idx, vchar{'#', DARKER_GREY, BLACK});
}
}
}
}
}
}
void resize_map(layer_t * l, int w, int h) {
// Use the whole window
l->w = w;
l->h = h;
}
// Your main function
int main()
{
// Initialize as a 1024x768 window with a title
init(config_advanced("../assets", 1020, 768, "RLTK - Example 9", false));
// Add a regular layer
gui->add_layer(1, 0, 0, 1024, 768, "8x8", resize_map);
// Add a spare layer so we can animate the @ symbol bending over
gui->add_sparse_layer(2, 0, 0, 1024, 768, "8x8", resize_map); // Our sparse layer
// We do a visibility sweep to start, so your starting position is revealed
visibility_sweep();
// Enter the main loop. "tick" is the function we wrote above.
run(tick);
return 0;
}
================================================
FILE: rltk/astar.hpp
================================================
/*
A* Algorithm Implementation using STL is
Copyright (C)2001-2005 Justin Heyes-Jones
Permission is given by the author to freely redistribute and
include this code in any program as long as this credit is
given where due.
COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED,
INCLUDING, WITHOUT LIMITATION, WARRANTIES THAT THE COVERED CODE
IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE
OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND
PERFORMANCE OF THE COVERED CODE IS WITH YOU. SHOULD ANY COVERED
CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT THE INITIAL
DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY
NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF
WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE
OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER
THIS DISCLAIMER.
Use at your own risk!
*/
#pragma once
// used for text debugging
#include <iostream>
#include <stdio.h>
//#include <conio.h>
#include <assert.h>
// stl includes
#include <algorithm>
#include <set>
#include <vector>
#include <cfloat>
using std::vector;
// fast fixed size memory allocator, used for fast node memory management
#include "fsa.hpp"
// Fixed size memory allocator can be disabled to compare performance
// Uses std new and delete instead if you turn it off
#define USE_FSA_MEMORY 1
// disable warning that debugging information has lines that are truncated
// occurs in stl headers
#if defined(WIN32) && defined(_WINDOWS)
#pragma warning( disable : 4786 )
#endif
template<class T> class AStarState;
// The AStar search class. UserState is the users state space type
template<class UserState> class AStarSearch
{
public:
// data
enum
{
SEARCH_STATE_NOT_INITIALISED,
SEARCH_STATE_SEARCHING,
SEARCH_STATE_SUCCEEDED,
SEARCH_STATE_FAILED,
SEARCH_STATE_OUT_OF_MEMORY,
SEARCH_STATE_INVALID
};
// A node represents a possible state in the search
// The user provided state type is included inside this type
public:
class Node
{
public:
Node *parent; // used during the search to record the parent of successor nodes
Node *child; // used after the search for the application to view the search in reverse
float g; // cost of this node + it's predecessors
float h; // heuristic estimate of distance to goal
float f; // sum of cumulative cost of predecessors and self and heuristic
Node() :
parent(0), child(0), g(0.0f), h(0.0f), f(0.0f)
{
}
UserState m_UserState;
};
// For sorting the heap the STL needs compare function that lets us compare
// the f value of two nodes
class HeapCompare_f
{
public:
bool operator()(const Node *x, const Node *y) const
{
return x->f > y->f;
}
};
public:
// methods
// constructor just initialises private data
AStarSearch() : m_State(SEARCH_STATE_NOT_INITIALISED), m_CurrentSolutionNode( NULL),
#if USE_FSA_MEMORY
m_FixedSizeAllocator(10000),
#endif
m_AllocateNodeCount(0), m_CancelRequest(false)
{
}
AStarSearch(int MaxNodes) :
m_State(SEARCH_STATE_NOT_INITIALISED), m_CurrentSolutionNode( NULL),
#if USE_FSA_MEMORY
m_FixedSizeAllocator(MaxNodes),
#endif
m_AllocateNodeCount(0), m_CancelRequest(false)
{
}
// call at any time to cancel the search and free up all the memory
void CancelSearch()
{
m_CancelRequest = true;
}
// Set Start and goal states
void SetStartAndGoalStates(UserState &Start, UserState &Goal)
{
m_CancelRequest = false;
m_Start = AllocateNode();
m_Goal = AllocateNode();
assert((m_Start != NULL && m_Goal != NULL));
m_Start->m_UserState = Start;
m_Goal->m_UserState = Goal;
m_State = SEARCH_STATE_SEARCHING;
// Initialise the AStar specific parts of the Start Node
// The user only needs fill out the state information
m_Start->g = 0;
m_Start->h = m_Start->m_UserState.GoalDistanceEstimate(
m_Goal->m_UserState);
m_Start->f = m_Start->g + m_Start->h;
m_Start->parent = m_Start;
// Push the start node on the Open list
m_OpenList.push_back(m_Start); // heap now unsorted
// Sort back element into heap
push_heap(m_OpenList.begin(), m_OpenList.end(), HeapCompare_f());
// Initialise counter for search steps
m_Steps = 0;
}
// Advances search one step
unsigned int SearchStep()
{
// Firstly break if the user has not initialised the search
assert((m_State > SEARCH_STATE_NOT_INITIALISED) && (m_State < SEARCH_STATE_INVALID));
// Next I want it to be safe to do a searchstep once the search has succeeded...
if ((m_State == SEARCH_STATE_SUCCEEDED) || (m_State == SEARCH_STATE_FAILED))
{
return m_State;
}
// Failure is defined as emptying the open list as there is nothing left to
// search...
// New: Allow user abort
if (m_OpenList.empty() || m_CancelRequest)
{
FreeAllNodes();
m_State = SEARCH_STATE_FAILED;
return m_State;
}
// Incremement step count
m_Steps++;
// Pop the best node (the one with the lowest f)
Node *n = m_OpenList.front(); // get pointer to the node
pop_heap(m_OpenList.begin(), m_OpenList.end(), HeapCompare_f());
m_OpenList.pop_back();
// Check for the goal, once we pop that we're done
if (n->m_UserState.IsGoal(m_Goal->m_UserState))
{
// The user is going to use the Goal Node he passed in
// so copy the parent pointer of n
m_Goal->parent = n->parent;
m_Goal->g = n->g;
// A special case is that the goal was passed in as the start state
// so handle that here
if (false == n->m_UserState.IsSameState(m_Start->m_UserState))
{
FreeNode(n);
// set the child pointers in each node (except Goal which has no child)
Node *nodeChild = m_Goal;
Node *nodeParent = m_Goal->parent;
do
{
nodeParent->child = nodeChild;
nodeChild = nodeParent;
nodeParent = nodeParent->parent;
} while (nodeChild != m_Start); // Start is always the first node by definition
}
// delete nodes that aren't needed for the solution
FreeUnusedNodes();
m_State = SEARCH_STATE_SUCCEEDED;
return m_State;
}
else // not goal
{
// We now need to generate the successors of this node
// The user helps us to do this, and we keep the new nodes in
// m_Successors ...
m_Successors.clear(); // empty vector of successor nodes to n
// User provides this functions and uses AddSuccessor to add each successor of
// node 'n' to m_Successors
bool ret = n->m_UserState.GetSuccessors(this, n->parent ? &n->parent->m_UserState : NULL);
if (!ret)
{
typename vector<Node *>::iterator successor;
// free the nodes that may previously have been added
for (successor = m_Successors.begin();
successor != m_Successors.end(); successor++)
{
FreeNode((*successor));
}
m_Successors.clear(); // empty vector of successor nodes to n
// free up everything else we allocated
FreeAllNodes();
m_State = SEARCH_STATE_OUT_OF_MEMORY;
return m_State;
}
// Now handle each successor to the current node ...
for (typename vector<Node *>::iterator successor =
m_Successors.begin(); successor != m_Successors.end();
successor++)
{
// The g value for this successor ...
float newg = n->g
+ n->m_UserState.GetCost((*successor)->m_UserState);
// Now we need to find whether the node is on the open or closed lists
// If it is but the node that is already on them is better (lower g)
// then we can forget about this successor
// First linear search of open list to find node
typename vector<Node *>::iterator openlist_result;
for (openlist_result = m_OpenList.begin();
openlist_result != m_OpenList.end(); openlist_result++)
{
if ((*openlist_result)->m_UserState.IsSameState(
(*successor)->m_UserState))
{
break;
}
}
if (openlist_result != m_OpenList.end())
{
// we found this state on open
if ((*openlist_result)->g <= newg)
{
FreeNode((*successor));
// the one on Open is cheaper than this one
continue;
}
}
typename vector<Node *>::iterator closedlist_result;
for (closedlist_result = m_ClosedList.begin();
closedlist_result != m_ClosedList.end();
closedlist_result++)
{
if ((*closedlist_result)->m_UserState.IsSameState(
(*successor)->m_UserState))
{
break;
}
}
if (closedlist_result != m_ClosedList.end())
{
// we found this state on closed
if ((*closedlist_result)->g <= newg)
{
// the one on Closed is cheaper than this one
FreeNode((*successor));
continue;
}
}
// This node is the best node so far with this particular state
// so lets keep it and set up its AStar specific data ...
(*successor)->parent = n;
(*successor)->g = newg;
(*successor)->h =
(*successor)->m_UserState.GoalDistanceEstimate(
m_Goal->m_UserState);
(*successor)->f = (*successor)->g + (*successor)->h;
// Remove successor from closed if it was on it
if (closedlist_result != m_ClosedList.end())
{
// remove it from Closed
FreeNode((*closedlist_result));
m_ClosedList.erase(closedlist_result);
// Fix thanks to ...
// Greg Douglas <gregdouglasmail@gmail.com>
// who noticed that this code path was incorrect
// Here we have found a new state which is already CLOSED
// anus
}
// Update old version of this node
if (openlist_result != m_OpenList.end())
{
FreeNode((*openlist_result));
m_OpenList.erase(openlist_result);
// re-make the heap
// make_heap rather than sort_heap is an essential bug fix
// thanks to Mike Ryynanen for pointing this out and then explaining
// it in detail. sort_heap called on an invalid heap does not work
make_heap(m_OpenList.begin(), m_OpenList.end(),
HeapCompare_f());
}
// heap now unsorted
m_OpenList.push_back((*successor));
// sort back element into heap
push_heap(m_OpenList.begin(), m_OpenList.end(),
HeapCompare_f());
}
// push n onto Closed, as we have expanded it now
m_ClosedList.push_back(n);
} // end else (not goal so expand)
return m_State; // Succeeded bool is false at this point.
}
// User calls this to add a successor to a list of successors
// when expanding the search frontier
bool AddSuccessor(UserState &State)
{
Node *node = AllocateNode();
if (node)
{
node->m_UserState = State;
m_Successors.push_back(node);
return true;
}
return false;
}
// Free the solution nodes
// This is done to clean up all used Node memory when you are done with the
// search
void FreeSolutionNodes()
{
Node *n = m_Start;
if (m_Start->child)
{
do
{
Node *del = n;
n = n->child;
FreeNode(del);
del = NULL;
} while (n != m_Goal);
FreeNode(n); // Delete the goal
}
else
{
// if the start node is the solution we need to just delete the start and goal
// nodes
FreeNode(m_Start);
FreeNode(m_Goal);
}
}
// Functions for traversing the solution
// Get start node
UserState *GetSolutionStart()
{
m_CurrentSolutionNode = m_Start;
if (m_Start)
{
return &m_Start->m_UserState;
}
else
{
return NULL;
}
}
// Get next node
UserState *GetSolutionNext()
{
if (m_CurrentSolutionNode)
{
if (m_CurrentSolutionNode->child)
{
Node *child = m_CurrentSolutionNode->child;
m_CurrentSolutionNode = m_CurrentSolutionNode->child;
return &child->m_UserState;
}
}
return NULL;
}
// Get end node
UserState *GetSolutionEnd()
{
m_CurrentSolutionNode = m_Goal;
if (m_Goal)
{
return &m_Goal->m_UserState;
}
else
{
return NULL;
}
}
// Step solution iterator backwards
UserState *GetSolutionPrev()
{
if (m_CurrentSolutionNode)
{
if (m_CurrentSolutionNode->parent)
{
Node *parent = m_CurrentSolutionNode->parent;
m_CurrentSolutionNode = m_CurrentSolutionNode->parent;
return &parent->m_UserState;
}
}
return NULL;
}
// Get final cost of solution
// Returns FLT_MAX if goal is not defined or there is no solution
float GetSolutionCost()
{
if (m_Goal && m_State == SEARCH_STATE_SUCCEEDED)
{
return m_Goal->g;
}
else
{
return FLT_MAX;
}
}
// For educational use and debugging it is useful to be able to view
// the open and closed list at each step, here are two functions to allow that.
UserState *GetOpenListStart()
{
float f, g, h;
return GetOpenListStart(f, g, h);
}
UserState *GetOpenListStart(float &f, float &g, float &h)
{
iterDbgOpen = m_OpenList.begin();
if (iterDbgOpen != m_OpenList.end())
{
f = (*iterDbgOpen)->f;
g = (*iterDbgOpen)->g;
h = (*iterDbgOpen)->h;
return &(*iterDbgOpen)->m_UserState;
}
return NULL;
}
UserState *GetOpenListNext()
{
float f, g, h;
return GetOpenListNext(f, g, h);
}
UserState *GetOpenListNext(float &f, float &g, float &h)
{
iterDbgOpen++;
if (iterDbgOpen != m_OpenList.end())
{
f = (*iterDbgOpen)->f;
g = (*iterDbgOpen)->g;
h = (*iterDbgOpen)->h;
return &(*iterDbgOpen)->m_UserState;
}
return NULL;
}
UserState *GetClosedListStart()
{
float f, g, h;
return GetClosedListStart(f, g, h);
}
UserState *GetClosedListStart(float &f, float &g, float &h)
{
iterDbgClosed = m_ClosedList.begin();
if (iterDbgClosed != m_ClosedList.end())
{
f = (*iterDbgClosed)->f;
g = (*iterDbgClosed)->g;
h = (*iterDbgClosed)->h;
return &(*iterDbgClosed)->m_UserState;
}
return NULL;
}
UserState *GetClosedListNext()
{
float f, g, h;
return GetClosedListNext(f, g, h);
}
UserState *GetClosedListNext(float &f, float &g, float &h)
{
iterDbgClosed++;
if (iterDbgClosed != m_ClosedList.end())
{
f = (*iterDbgClosed)->f;
g = (*iterDbgClosed)->g;
h = (*iterDbgClosed)->h;
return &(*iterDbgClosed)->m_UserState;
}
return NULL;
}
// Get the number of steps
int GetStepCount()
{
return m_Steps;
}
void EnsureMemoryFreed()
{
#if USE_FSA_MEMORY
assert(m_AllocateNodeCount == 0);
#endif
}
private:
// methods
// This is called when a search fails or is cancelled to free all used
// memory
void FreeAllNodes()
{
// iterate open list and delete all nodes
typename vector<Node *>::iterator iterOpen = m_OpenList.begin();
while (iterOpen != m_OpenList.end())
{
Node *n = (*iterOpen);
FreeNode(n);
iterOpen++;
}
m_OpenList.clear();
// iterate closed list and delete unused nodes
typename vector<Node *>::iterator iterClosed;
for (iterClosed = m_ClosedList.begin();
iterClosed != m_ClosedList.end(); iterClosed++)
{
Node *n = (*iterClosed);
FreeNode(n);
}
m_ClosedList.clear();
// delete the goal
FreeNode(m_Goal);
}
// This call is made by the search class when the search ends. A lot of nodes may be
// created that are still present when the search ends. They will be deleted by this
// routine once the search ends
void FreeUnusedNodes()
{
// iterate open list and delete unused nodes
typename vector<Node *>::iterator iterOpen = m_OpenList.begin();
while (iterOpen != m_OpenList.end())
{
Node *n = (*iterOpen);
if (!n->child)
{
FreeNode(n);
n = NULL;
}
iterOpen++;
}
m_OpenList.clear();
// iterate closed list and delete unused nodes
typename vector<Node *>::iterator iterClosed;
for (iterClosed = m_ClosedList.begin();
iterClosed != m_ClosedList.end(); iterClosed++)
{
Node *n = (*iterClosed);
if (!n->child)
{
FreeNode(n);
n = NULL;
}
}
m_ClosedList.clear();
}
// Node memory management
Node *AllocateNode()
{
#if !USE_FSA_MEMORY
Node *p = new Node;
return p;
#else
Node *address = m_FixedSizeAllocator.alloc();
if (!address)
{
return NULL;
}
m_AllocateNodeCount++;
Node *p = new (address) Node;
return p;
#endif
}
void FreeNode(Node *node)
{
m_AllocateNodeCount--;
#if !USE_FSA_MEMORY
delete node;
#else
node->~Node();
m_FixedSizeAllocator.free(node);
#endif
}
private:
// data
// Heap (simple vector but used as a heap, cf. Steve Rabin's game gems article)
vector<Node *> m_OpenList;
// Closed list is a vector.
vector<Node *> m_ClosedList;
// Successors is a vector filled out by the user each type successors to a node
// are generated
vector<Node *> m_Successors;
// State
unsigned int m_State;
// Counts steps
int m_Steps;
// Start and goal state pointers
Node *m_Start;
Node *m_Goal;
Node *m_CurrentSolutionNode;
#if USE_FSA_MEMORY
// Memory
FixedSizeAllocator<Node> m_FixedSizeAllocator;
#endif
//Debug : need to keep these two iterators around
// for the user Dbg functions
typename vector<Node *>::iterator iterDbgOpen;
typename vector<Node *>::iterator iterDbgClosed;
// debugging : count memory allocation and free's
int m_AllocateNodeCount;
bool m_CancelRequest;
};
template<class T> class AStarState
{
public:
virtual ~AStarState()
{
}
virtual float GoalDistanceEstimate(T &nodeGoal) = 0; // Heuristic function which computes the estimated cost to the goal node
virtual bool IsGoal(T &nodeGoal) = 0; // Returns true if this node is the goal node
virtual bool GetSuccessors(AStarSearch<T> *astarsearch, T *parent_node) = 0; // Retrieves all successors to this node and adds them via astarsearch.addSuccessor()
virtual float GetCost(T &successor) = 0; // Computes the cost of traveling from this node to the successor node
virtual bool IsSameState(T &rhs) = 0; // Returns true if this node is the same as the rhs node
};
================================================
FILE: rltk/color_t.cpp
================================================
#include "color_t.hpp"
#include <cmath>
using std::min;
using std::max;
using std::fmod;
namespace rltk {
// Credit: https://gist.github.com/fairlight1337/4935ae72bcbcc1ba5c72
std::tuple<float, float, float> color_to_hsv(const color_t &col) {
float fR = (col.r / 255.0f);
float fG = (col.g / 255.0f);
float fB = (col.b / 255.0f);
float fH=0.0f, fS=0.0f, fV=0.0f;
float fCMax = max(max(fR, fG), fB);
float fCMin = min(min(fR, fG), fB);
float fDelta = fCMax - fCMin;
if(fDelta > 0) {
if(fCMax == fR) {
fH = 60.0f * (fmodf(((fG - fB) / fDelta), 6.0f));
} else if(fCMax == fG) {
fH = 60.0f * (((fB - fR) / fDelta) + 2.0f);
} else if(fCMax == fB) {
fH = 60.0f * (((fR - fG) / fDelta) + 4.0f);
}
if(fCMax > 0) {
fS = fDelta / fCMax;
} else {
fS = 0;
}
fV = fCMax;
} else {
fH = 0;
fS = 0;
fV = fCMax;
}
if(fH < 0) {
fH = 360 + fH;
}
return std::make_tuple(fH, fS, fV);
}
// Credit: https://gist.github.com/fairlight1337/4935ae72bcbcc1ba5c72
std::tuple<uint8_t, uint8_t, uint8_t> color_from_hsv(const float hue, const float saturation, const float value) {
float fH = hue;
float fS = saturation;
float fV = value;
float fR, fG, fB;
float fC = fV * fS; // Chroma
float fHPrime = fmodf(fH / 60.0f, 6.0f);
float fX = fC * (1.0f - fabsf(fmodf(fHPrime, 2.0f) - 1.0f));
float fM = fV - fC;
if(0 <= fHPrime && fHPrime < 1) {
fR = fC;
fG = fX;
fB = 0;
} else if(1 <= fHPrime && fHPrime < 2) {
fR = fX;
fG = fC;
fB = 0;
} else if(2 <= fHPrime && fHPrime < 3) {
fR = 0;
fG = fC;
fB = fX;
} else if(3 <= fHPrime && fHPrime < 4) {
fR = 0;
fG = fX;
fB = fC;
} else if(4 <= fHPrime && fHPrime < 5) {
fR = fX;
fG = 0;
fB = fC;
} else if(5 <= fHPrime && fHPrime < 6) {
fR = fC;
fG = 0;
fB = fX;
} else {
fR = 0;
fG = 0;
fB = 0;
}
fR += fM;
fG += fM;
fB += fM;
return std::make_tuple<uint8_t, uint8_t, uint8_t>(static_cast<uint8_t>(fR*255.0), static_cast<uint8_t>(fG*255.0), static_cast<uint8_t>(fB*255.0));
}
/*
* Calculates the luminance of a color, and converts it to grey-scale.
*/
color_t greyscale(const color_t &col)
{
unsigned char red = col.r;
unsigned char green = col.g;
unsigned char blue = col.b;
float RED = red / 255.0F;
float GREEN = green / 255.0F;
float BLUE = blue / 255.0F;
float luminance = 0.299f * RED + 0.587f * GREEN + 0.114f * BLUE;
red = static_cast<unsigned char>(luminance * 255.0F);
green = static_cast<unsigned char>(luminance * 255.0F);
blue = static_cast<unsigned char>(luminance * 255.0F);
return color_t(red, green, blue);
}
/*
* Darkens a color by the specified amount.
*/
color_t darken(const int &amount, const color_t &col)
{
unsigned char red = col.r;
unsigned char green = col.g;
unsigned char blue = col.b;
if (red > amount)
{
red -= amount;
}
else
{
red = 0;
}
if (green > amount)
{
green -= amount;
}
else
{
green = 0;
}
if (blue > amount)
{
blue -= amount;
}
else
{
blue = 0;
}
return color_t(red, green, blue);
}
/* Applies colored lighting effect; colors that don't exist remain dark. Lights are from 0.0 to 1.0. */
color_t apply_colored_light(const color_t &col, const std::tuple<float,float,float> &light) {
unsigned char red = col.r;
unsigned char green = col.g;
unsigned char blue = col.b;
float RED = red / 255.0F;
float GREEN = green / 255.0F;
float BLUE = blue / 255.0F;
RED *= std::get<0>(light);
GREEN *= std::get<1>(light);
BLUE *= std::get<2>(light);
if (RED > 1.0) RED = 1.0;
if (RED < 0.0) RED = 0.0;
if (GREEN > 1.0) GREEN = 1.0;
if (GREEN < 0.0) GREEN = 0.0;
if (BLUE > 1.0) BLUE = 1.0;
if (BLUE < 0.0) BLUE = 0.0;
red = static_cast<unsigned char>(RED * 255.0F);
green = static_cast<unsigned char>(GREEN * 255.0F);
blue = static_cast<unsigned char>(BLUE * 255.0F);
return color_t(red, green, blue);
}
color_t lerp(const color_t &first, const color_t &second, float amount) {
const float r1 = first.r;
const float g1 = first.g;
const float b1 = first.b;
const float r2 = second.r;
const float g2 = second.g;
const float b2 = second.b;
const float rdiff = r2 - r1;
const float gdiff = g2 - g1;
const float bdiff = b2 - b1;
float red = r1 + (rdiff * amount);
float green = g1 + (gdiff * amount);
float blue = b1 + (bdiff * amount);
if (red > 255.0F) red = 255.0F;
if (green > 255.0F) green = 255.0F;
if (blue > 255.0F) blue = 255.0F;
if (red < 0.0F) red = 0.0F;
if (green < 0.0F) green = 0.0F;
if (blue < 0.0F) blue = 0.0F;
const int r = static_cast<const int>(red);
const int g = static_cast<const int>(green);
const int b = static_cast<const int>(blue);
return color_t(r,g,b);
}
}
================================================
FILE: rltk/color_t.hpp
================================================
#pragma once
/* RLTK (RogueLike Tool Kit) 1.00
* Copyright (c) 2016-Present, Bracket Productions.
* Licensed under the MIT license - see LICENSE file.
*
* Color functions
*/
#include <tuple>
#include <SFML/Graphics.hpp>
#include <cereal/cereal.hpp>
namespace rltk {
/* Converts HSV into an RGB tuple */
extern std::tuple<uint8_t, uint8_t, uint8_t> color_from_hsv(const float hue, const float saturation, const float value);
struct color_t {
/* Default empty constructor */
color_t() {}
/* Convenience constructor from red/green/blue; accepts ints and casts them */
color_t(const int R, const int G, const int B) : r(static_cast<uint8_t>(R)), g(static_cast<uint8_t>(G)), b(static_cast<uint8_t>(B)) {}
/* Construct from red/green/blue, in the range of 0-255 per component. */
color_t(const uint8_t R, const uint8_t G, const uint8_t B) : r(R), g(G), b(B) {}
/* Construct from HSV, in the range of 0-1.0 as floats. */
color_t(const float hue, const float saturation, const float value) {
std::tie(r,g,b) = color_from_hsv(hue, saturation, value);
}
/* Construct from an RGB tuple */
color_t(const std::tuple<uint8_t, uint8_t, uint8_t> &c) { std::tie(r,g,b) = c; }
/* You can add colors together, for example as a quick blend/lighten */
color_t operator+(const color_t &other) {
int red = r + other.r;
int green = g + other.g;
int blue = b + other.b;
if (red > 255) red = 255;
if (green > 255) green = 255;
if (blue > 255) blue = 255;
return color_t(red, green, blue);
}
/* You can subtract colors */
color_t operator-(const color_t &other) {
int red = r - other.r;
int green = g - other.g;
int blue = b - other.b;
if (red < 0) red = 0;
if (green < 0) green = 0;
if (blue < 0) blue = 0;
return color_t(red, green, blue);
}
/* You can multiply colors */
color_t operator*(const color_t &other) {
int red = r * other.r;
int green = g * other.g;
int blue = b * other.b;
if (red < 0) red = 0;
if (green < 0) green = 0;
if (blue < 0) blue = 0;
if (red > 255) red = 255;
if (green > 255) green = 255;
if (blue > 255) blue = 255;
return color_t(red, green, blue);
}
/* You can compare colors */
bool operator==(const color_t &other) const {
if (other.r == r && other.g == g && other.b == b) {
return true;
} else {
return false;
}
}
/* RGB storage */
uint8_t r,g,b;
template<class Archive>
void serialize(Archive & archive)
{
archive( r, g, b ); // serialize things by passing them to the archive
}
};
/* Converts a color_t to an SFML color */
inline sf::Color color_to_sfml(const color_t &col) { return sf::Color(col.r, col.g, col.b); }
/* Converts a color_t to an RGB tuple */
inline std::tuple<uint8_t, uint8_t, uint8_t> color_to_rgb(const color_t &col) { return std::make_tuple(col.r, col.g, col.b); }
/* Converts a color_t to an HSV tuple */
extern std::tuple<float, float, float> color_to_hsv(const color_t &col);
/* Calculates the luminance of a color, and converts it to grey-scale. */
extern color_t greyscale(const color_t &col);
/* Darkens a color by the specified amount. */
color_t darken(const int &amount, const color_t &col);
/* Applies colored lighting effect; colors that don't exist remain dark. Lights are from 0.0 to 1.0. */
color_t apply_colored_light(const color_t &col, const std::tuple<float,float,float> &light);
/* Calculates an intermediate color on a linear RGB color ramp. Amount is from 0 to 1 */
extern color_t lerp(const color_t &first, const color_t &second, float amount);
}
================================================
FILE: rltk/colors.hpp
================================================
#pragma once
#include "color_t.hpp"
namespace rltk {
namespace colors {
const color_t AliceBlue(240, 248, 255);
const color_t AntiqueWhite(250, 235, 215);
const color_t Aqua(0, 255, 255);
const color_t Aquamarine(127, 255, 212);
const color_t Beige(245, 245, 220);
const color_t Black(0, 0, 0);
const color_t BlanchedAlmond(255, 235, 205);
const color_t Blue(0, 0, 255);
const color_t BlueViolet(138, 43, 226);
const color_t Brown(165, 42, 42);
const color_t BurlyWood(222, 184, 135);
const color_t CadetBlue(95, 158, 160);
const color_t Chartreuse(127, 255, 0);
const color_t Chocolate(210, 105, 20);
const color_t Coral(255, 127, 80);
const color_t CornflowerBlue(100, 149, 237);
const color_t Cornsilk(255, 248, 220);
const color_t Crimson(220, 20, 60);
const color_t Cyan(0, 0, 255);
const color_t DarkBlue(0, 0, 139);
const color_t DarkCyan(0, 139, 139);
const color_t DarkGoldenRod(184, 134, 11);
const color_t DarkGray(169, 169, 169);
const color_t DarkGreen(0, 100, 0);
const color_t DarkKhaki(189, 183, 107);
const color_t DarkMagenta(139, 0, 139);
const color_t DarkOliveGreen(85, 107, 47);
const color_t Darkorange(255, 140, 0);
const color_t DarkOrchid(255, 140, 0);
const color_t DarkRed(139, 0, 0);
const color_t DarkSalmon(233, 150, 122);
const color_t DarkSeaGreen(143, 188, 143);
const color_t DarkSlateBlue(72, 61, 139);
const color_t DarkSlateGray(47, 79, 79);
const color_t DarkTurquoise(0, 206, 209);
const color_t DarkViolet(148, 0, 211);
const color_t DeepPink(255, 20, 147);
const color_t DeepSkyBlue(0, 191, 255);
const color_t DimGray(105, 105, 105);
const color_t DodgerBlue(30, 144, 255);
const color_t FireBrick(178, 34, 34);
const color_t FloralWhite(255, 250, 240);
const color_t ForestGreen(34, 139, 34);
const color_t Fuchsia(255, 0, 255);
const color_t Gainsboro(220, 220, 220);
const color_t GhostWhite(248, 248, 255);
const color_t Gold(255, 215, 0);
const color_t GoldenRod(218, 165, 32);
const color_t Grey(128, 128, 128);
const color_t Green(0, 128, 0);
const color_t GreenYellow(173, 255, 47);
const color_t HoneyDew(240, 255, 240);
const color_t HotPink(255, 105, 180);
const color_t IndianRed(205, 92, 92);
const color_t Indigo(72, 0, 130);
const color_t Ivory(255, 255, 240);
const color_t Khaki(240, 230, 140);
const color_t Lavender(230, 230, 250);
const color_t LavenderBlush(255, 240, 245);
const color_t LawnGreen(124, 252, 0);
const color_t LemonChiffon(255, 250, 205);
const color_t LightBlue(173, 216, 203);
const color_t LightCoral(240, 128, 128);
const color_t LightCyan(240, 128, 128);
const color_t LightGoldenRodYellow(250, 250, 210);
const color_t LightGrey(211, 211, 211);
const color_t LightGreen(144, 238, 144);
const color_t LightPink(255, 182, 193);
const color_t LightSalmon(255, 160, 122);
const color_t LightSeaGreen(32, 178, 170);
const color_t LightSkyBlue(135, 206, 250);
const color_t LightSlateGrey(119, 136, 153);
const color_t LightSteelBlue(176, 196, 222);
const color_t LightYellow(255, 255, 224);
const color_t Lime(0, 255, 0);
const color_t LimeGreen(50, 205, 50);
const color_t Linen(250, 240, 230);
const color_t Magenta(255, 0, 255);
const color_t Maroon(128, 0, 0);
const color_t MediumAquaMarine(102, 205, 170);
const color_t MediumBlue(0, 0, 205);
const color_t MediumOrchid(186, 85, 211);
const color_t MediumPurple(147, 112, 219);
const color_t MediumSeaGreen(60, 179, 113);
const color_t MediumSlateBlue(123, 104, 238);
const color_t MediumSpringGreen(0, 250, 154);
const color_t MediumTurquoise(72, 209, 204);
const color_t MediumVioletRed(199, 21, 133);
const color_t MidnightBlue(25, 25, 112);
const color_t MintCream(245, 255, 250);
const color_t MistyRose(255, 228, 225);
const color_t Moccasin(255, 228, 181);
const color_t NavajoWhite(255, 222, 173);
const color_t Navy(0, 0, 128);
const color_t OldLace(253, 245, 230);
const color_t Olive(128, 128, 0);
const color_t OliveDrab(107, 142, 35);
const color_t Orange(255, 165, 0);
const color_t OrangeRed(255, 69, 0);
const color_t Orchid(218, 112, 214);
const color_t PaleGoldenRod(238, 232, 170);
const color_t PaleGreen(152, 251, 152);
const color_t PaleTurquoise(175, 238, 238);
const color_t PaleVioletRed(219, 112, 147);
const color_t PapayaWhip(225, 239, 213);
const color_t PeachPuff(225, 218, 185);
const color_t Peru(205, 133, 63);
const color_t Pink(255, 192, 203);
const color_t Plum(221, 160, 221);
const color_t PowderBlue(176, 224, 230);
const color_t Purple(128, 0, 128);
const color_t Red(255, 0, 0);
const color_t RosyBrown(188, 143, 143);
const color_t RoyalBlue(65, 105, 225);
const color_t SaddleBrown(139, 69, 19);
const color_t Salmon(250, 128, 114);
const color_t SandyBrown(244, 164, 96);
const color_t SeaGreen(46, 139, 87);
const color_t SeaShell(255, 245, 238);
const color_t Sienna(160, 82, 45);
const color_t Silver(192, 192, 192);
const color_t SkyBlue(135, 206, 235);
const color_t SlateBlue(106, 90, 205);
const color_t SlateGrey(112, 128, 144);
const color_t Snow(255, 250, 250);
const color_t SpringGreen(0, 255, 127);
const color_t SteelBlue(70, 130, 180);
const color_t Tan(210, 180, 140);
const color_t Teal(0, 128, 128);
const color_t Thistle(216, 191, 216);
const color_t Tomato(255, 99, 71);
const color_t Turquoise(64, 224, 208);
const color_t Violet(238, 130, 238);
const color_t Wheat(245, 222, 179);
const color_t White(255, 255, 255);
const color_t WhiteSmoke(245, 245, 245);
const color_t Yellow(255, 0, 0);
const color_t YellowGreen(154, 205, 50);
const color_t BLACK(0,0,0);
const color_t WHITE(255,255,255);
const color_t DESATURATED_RED(128,64,64);
const color_t LIGHTEST_RED(255,191,191);
const color_t LIGHTER_RED(255,166,166);
const color_t LIGHT_RED(255,115,115);
const color_t RED(255,0,0);
const color_t DARK_RED(191,0,0);
const color_t DARKER_RED(128,0,0);
const color_t DARKEST_RED(64,0,0);
const color_t FLAME(255,63,0);
const color_t ORANGE(255,127,0);
const color_t AMBER(255,191,0);
const color_t YELLOW(255,255,0);
const color_t LIME(191,255,0);
const color_t CHARTREUSE(127,255,0);
const color_t DESATURATED_GREEN(64,128,64);
const color_t LIGHTEST_GREEN(191,255,191);
const color_t LIGHTER_GREEN(166,255,166);
const color_t LIGHT_GREEN(115,255,115);
const color_t GREEN(0,255,0);
const color_t DARK_GREEN(0,191,0);
const color_t DARKER_GREEN(0,128,0);
const color_t DARKEST_GREEN(0,64,0);
const color_t SEA(0,255,127);
const color_t TURQUOISE(0,255,191);
const color_t CYAN(0,255,255);
const color_t SKY(0,191,255);
const color_t AZURE(0,127,255);
const color_t BLUE(0,0,255);
const color_t HAN(63,0,255);
const color_t VIOLET(127,0,255);
const color_t PURPLE(191,0,255);
const color_t FUCHSIA(255,0,191);
const color_t MAGENTA(255,0,255);
const color_t PINK(255,0,127);
const color_t CRIMSON(255,0,63);
const color_t BRASS(191,151,96);
const color_t COPPER(200,117,51);
const color_t GOLD(229,191,0);
const color_t SILVER(203,203,203);
const color_t CELADON(172,255,171);
const color_t PEACH(255,159,127);
const color_t LIGHTEST_GREY(223,223,223);
const color_t LIGHTER_GREY(191,191,191);
const color_t LIGHT_GREY(159,159,159);
const color_t GREY(127,127,127);
const color_t DARK_GREY(95,95,95);
const color_t DARKER_GREY(63,63,63);
const color_t DARKEST_GREY(31,31,31);
const color_t LIGHTEST_SEPIA(222,211,195);
const color_t LIGHTER_SEPIA(191,171,143);
const color_t LIGHT_SEPIA(158,134,100);
const color_t SEPIA(127,101,63);
const color_t DARK_SEPIA(94,75,47);
const color_t DARKER_SEPIA(63,50,31);
const color_t DARKEST_SEPIA(31,24,15);
}
}
================================================
FILE: rltk/ecs.cpp
================================================
#include "ecs.hpp"
#include <cereal/types/polymorphic.hpp>
#include <cereal/archives/binary.hpp>
namespace rltk {
std::size_t impl::base_component_t::type_counter = 1;
std::size_t base_message_t::type_counter = 1;
std::size_t entity_t::entity_counter{1}; // Not using zero since it is used as null so often
ecs default_ecs;
entity_t * ecs::entity(const std::size_t id) noexcept {
entity_t * result = nullptr;
auto finder = entity_store.find(id);
if (finder == entity_store.end()) return result;
if (finder->second.deleted) return result;
result = &finder->second;
return result;
}
entity_t * ecs::create_entity() {
entity_t new_entity;
while (entity_store.find(new_entity.id) != entity_store.end()) {
++entity_t::entity_counter;
new_entity.id = entity_t::entity_counter;
}
//std::cout << "New Entity ID#: " << new_entity.id << "\n";
entity_store.emplace(new_entity.id, new_entity);
return entity(new_entity.id);
}
entity_t * ecs::create_entity(const std::size_t new_id) {
entity_t new_entity(new_id);
if (entity_store.find(new_entity.id) != entity_store.end()) {
throw std::runtime_error("WARNING: Duplicate entity ID. Odd things will happen\n");
}
entity_store.emplace(new_entity.id, new_entity);
return entity(new_entity.id);
}
void ecs::each(std::function<void(entity_t &)> &&func) {
for (auto it=entity_store.begin(); it!=entity_store.end(); ++it) {
if (!it->second.deleted) {
func(it->second);
}
}
}
void ecs::delete_all_systems() {
system_store.clear();
system_profiling.clear();
pubsub_holder.clear();
}
void ecs::ecs_configure() {
for (std::unique_ptr<base_system> & sys : system_store) {
sys->configure();
}
}
void ecs::ecs_tick(const double duration_ms) {
std::size_t count = 0;
for (std::unique_ptr<base_system> & sys : system_store) {
std::chrono::high_resolution_clock::time_point t1 = std::chrono::high_resolution_clock::now();
sys->update(duration_ms);
deliver_messages();
std::chrono::high_resolution_clock::time_point t2 = std::chrono::high_resolution_clock::now();
double duration = static_cast<double>(std::chrono::duration_cast<std::chrono::microseconds>( t2 - t1 ).count());
system_profiling[count].last = duration;
if (duration > system_profiling[count].worst) system_profiling[count].worst = duration;
if (duration < system_profiling[count].best) system_profiling[count].best = duration;
++count;
}
ecs_garbage_collect();
}
void ecs::ecs_save(std::unique_ptr<std::ofstream> &lbfile) {
cereal::BinaryOutputArchive oarchive(*lbfile);
oarchive(*this);
}
void ecs::ecs_load(std::unique_ptr<std::ifstream> &lbfile) {
entity_store.clear();
component_store.clear();
cereal::BinaryInputArchive iarchive(*lbfile);
iarchive(*this);
std::cout << "Loaded " << entity_store.size() << " entities, and " << component_store.size() << " component types.\n";
}
std::string ecs::ecs_profile_dump() {
std::stringstream ss;
ss.precision(3);
ss << std::fixed;
ss << "SYSTEMS PERFORMANCE IN MICROSECONDS:\n";
ss << std::setw(20) << "System" << std::setw(20) << "Last" << std::setw(20) << "Best" << std::setw(20) << "Worst\n";
for (std::size_t i=0; i<system_profiling.size(); ++i) {
ss << std::setw(20) << system_store[i]->system_name
<< std::setw(20) << system_profiling[i].last
<< std::setw(20) << system_profiling[i].best
<< std::setw(20) << system_profiling[i].worst << "\n";
}
return ss.str();
}
}
================================================
FILE: rltk/ecs.hpp
================================================
#pragma once
#include <bitset>
#include <vector>
#include <iostream>
#include <unordered_map>
#include <unordered_set>
#include <memory>
#include <functional>
#include <algorithm>
#include <fstream>
#include <chrono>
#include <sstream>
#include <iomanip>
#include <queue>
#include <future>
#include <mutex>
#include <typeinfo>
#include <atomic>
#include "serialization_utils.hpp"
#include "xml.hpp"
#include <cereal/types/polymorphic.hpp>
#include "ecs_impl.hpp"
namespace rltk {
/* Public interface to allow existing calls to continue to work */
extern ecs default_ecs;
inline entity_t * entity(ecs &ECS, const std::size_t id) noexcept {
return ECS.entity(id);
}
inline entity_t * entity(const std::size_t id) noexcept {
return entity(default_ecs, id);
}
inline entity_t * create_entity(ecs &ECS) {
return ECS.create_entity();
}
inline entity_t * create_entity() {
return create_entity(default_ecs);
}
inline entity_t * create_entity(ecs &ECS, const std::size_t new_id) {
return ECS.create_entity(new_id);
}
inline entity_t * create_entity(const std::size_t new_id) {
return create_entity(default_ecs, new_id);
}
inline void delete_entity(ecs &ECS, const std::size_t id) noexcept {
ECS.delete_entity(id);
}
inline void delete_entity(const std::size_t id) noexcept {
delete_entity(default_ecs, id);
}
inline void delete_entity(ecs &ECS, entity_t &e) noexcept {
ECS.delete_entity(e);
}
inline void delete_entity(entity_t &e) noexcept {
delete_entity(default_ecs, e);
}
inline void delete_all_entities(ecs &ECS) noexcept {
ECS.delete_all_entities();
}
inline void delete_all_entities() noexcept {
delete_all_entities(default_ecs);
}
template<class C>
inline void delete_component(ecs &ECS, const std::size_t entity_id, bool delete_entity_if_empty=false) noexcept {
ECS.delete_component<C>(entity_id, delete_entity_if_empty);
}
template<class C>
inline void delete_component(const std::size_t entity_id, bool delete_entity_if_empty=false) noexcept {
delete_component<C>(default_ecs, entity_id, delete_entity_if_empty);
}
template<class C>
inline std::vector<entity_t *> entities_with_component(ecs &ECS) {
return ECS.entities_with_component<C>();
}
template<class C>
inline std::vector<entity_t *> entities_with_component() {
return entities_with_component<C>(default_ecs);
}
template <class C>
inline void all_components(ecs &ECS, typename std::function<void(entity_t &, C &)> func) {
ECS.all_components<C>(func);
}
template <class C>
inline void all_components(typename std::function<void(entity_t &, C &)> func) {
all_components<C>(default_ecs, func);
}
template <typename... Cs, typename F>
inline void each(ecs &ECS, F callback) {
ECS.each<Cs...>(callback);
}
template <typename... Cs, typename F>
inline void each(F callback) {
each<Cs...>(default_ecs, callback);
}
template <typename... Cs, typename P, typename F>
inline void each_if(ecs &ECS, P&& predicate, F callback) {
ECS.each_if<Cs...>(predicate, callback);
}
template <typename... Cs, typename P, typename F>
inline void each_if(P&& predicate, F callback) {
each_if<Cs...>(default_ecs, predicate, callback);
}
inline void ecs_garbage_collect(ecs &ECS) {
ECS.ecs_garbage_collect();
}
inline void ecs_garbage_collect() {
ecs_garbage_collect(default_ecs);
}
template <class MSG>
inline void emit(ecs &ECS, MSG message) {
ECS.emit<MSG>(message);
}
template <class MSG>
inline void emit(MSG message) {
default_ecs.emit<MSG>(message);
}
template <class MSG>
inline void emit_deferred(ecs &ECS, MSG message) {
ECS.emit_deferred<MSG>(message);
}
template <class MSG>
inline void emit_deferred(MSG message) {
emit_deferred<MSG>(default_ecs, message);
}
template<typename S, typename ...Args>
inline void add_system( ecs &ECS, Args && ... args ) {
ECS.add_system<S, Args...>(args...);
}
template<typename S, typename ...Args>
inline void add_system( Args && ... args ) {
add_system<S, Args...>(default_ecs, args...);
}
inline void delete_all_systems(ecs &ECS) {
ECS.delete_all_systems();
}
inline void delete_all_systems() {
delete_all_systems(default_ecs);
}
inline void ecs_configure(ecs &ECS) {
ECS.ecs_configure();
}
inline void ecs_configure() {
ecs_configure(default_ecs);
}
inline void ecs_tick(ecs &ECS, const double duration_ms) {
ECS.ecs_tick(duration_ms);
}
inline void ecs_tick(const double duration_ms) {
ecs_tick(default_ecs, duration_ms);
}
inline void ecs_save(ecs &ECS, std::unique_ptr<std::ofstream> &lbfile) {
ECS.ecs_save(lbfile);
}
inline void ecs_save(std::unique_ptr<std::ofstream> &lbfile) {
ecs_save(default_ecs, lbfile);
}
inline void ecs_load(ecs &ECS, std::unique_ptr<std::ifstream> &lbfile) {
ECS.ecs_load(lbfile);
}
inline void ecs_load(std::unique_ptr<std::ifstream> &lbfile) {
ecs_load(default_ecs, lbfile);
}
inline std::string ecs_profile_dump(ecs &ECS) {
return ECS.ecs_profile_dump();
}
inline std::string ecs_profile_dump() {
return ecs_profile_dump(default_ecs);
}
}
================================================
FILE: rltk/ecs_impl.hpp
================================================
#pragma once
#include <cereal/cereal.hpp>
#include <cereal/types/memory.hpp>
#include <cereal/types/unordered_map.hpp>
#include <cereal/types/bitset.hpp>
#include <cereal/types/vector.hpp>
namespace rltk {
// Forward declarations
class ecs;
struct entity_t;
struct base_system;
extern ecs default_ecs;
namespace impl {
template<class C>
inline void assign(ecs &ECS, entity_t &E, C component);
template <class C>
inline C * component(ecs &ECS, entity_t &E) noexcept;
template<class MSG>
inline void subscribe(ecs &ECS, base_system &B, std::function<void(MSG &message)> destination);
template<class MSG>
inline void subscribe_mbox(ecs &ECS, base_system &B);
inline void unset_component_mask(ecs &ECS, const std::size_t id, const std::size_t family_id, bool delete_if_empty=false);
}
/*
* Base class from which all messages must derive.
*/
struct base_message_t {
static std::size_t type_counter;
};
/* Class for storing profile data */
struct system_profiling_t {
double last = 0.0;
double best = 1000000.0;
double worst = 0.0;
};
struct base_system;
namespace impl {
/*
* Constant defining the maximum number of components to support. This sizes the bitsets,
* so we don't want it to be much bigger than needed.
*/
constexpr std::size_t MAX_COMPONENTS = 128;
/*
* If the current component set does not support serialization, this will become true.
*/
static bool ecs_supports_serialization = true;
/*
* Base type for component handles. Exists so that we can have a vector of pointers to
* derived classes. entity_id is included to allow a quick reference without a static cast.
* type_counter is used as a static member, referenced from component_t - the handle class.
*/
struct base_component_t {
static std::size_t type_counter;
std::size_t entity_id;
bool deleted = false;
template<class Archive>
void serialize(Archive & archive)
{
archive( entity_id, deleted ); // serialize things by passing them to the archive
}
};
/* Extracts xml_identity from a class, or uses the RTTI name if one isn't available */
template< class T >
struct has_to_xml_identity
{
typedef char(&YesType)[1];
typedef char(&NoType)[2];
template< class, class > struct Sfinae;
template< class T2 > static YesType Test( Sfinae<T2, decltype(std::declval<T2>().xml_identity)> *);
template< class T2 > static NoType Test( ... );
static const bool value = sizeof(Test<T>(0))==sizeof(YesType);
};
template <typename T>
struct _calc_xml_identity {
template<class Q = T>
typename std::enable_if< has_to_xml_identity<Q>::value, void >::type
test(T &data, std::string &id)
{
id = data.xml_identity;
}
template<class Q = T>
typename std::enable_if< !has_to_xml_identity<Q>::value, void >::type
test(T &data, std::string &id)
{
id = typeid(data).name();
}
};
template<class T>
struct _ecs_check_for_to_xml
{
template<class Q = T>
typename std::enable_if< serial::has_to_xml_method<Q>::value, void >::type
test(xml_node * c, T &data)
{
data.to_xml(c);
}
template<class Q = T>
typename std::enable_if< !serial::has_to_xml_method<Q>::value, void >::type
test(xml_node * c, T &data)
{
ecs_supports_serialization = false;
}
};
/*
* component_t is a handle class for components. It inherits from base_component, allowing
* the component store to have vectors of base_component_t *, where each type is a concrete
* specialized class containing the component data. It does some magic with a static type_counter
* to ensure that each instance with the same template type will have a unique family_id - this is
* then used to reference the correct component store.
*/
template<class C>
struct component_t : public base_component_t {
component_t() {
data = C{};
family();
}
component_t(C comp) : data(comp) {
family();
}
std::size_t family_id;
C data;
template<class Archive>
void serialize(Archive & archive)
{
archive( cereal::base_class<base_component_t>(this), family_id, data ); // serialize things by passing them to the archive
}
inline void family() {
static std::size_t family_id_tmp = base_component_t::type_counter++;
family_id = family_id_tmp;
}
inline std::string xml_identity() {
std::string id;
_calc_xml_identity<C>().test(data, id);
return id;
}
inline void to_xml(xml_node * c) {
_ecs_check_for_to_xml<C> serial;
serial.test(c, data);
}
};
/*
* Base class for the component store. Concrete component stores derive from this.
*/
struct base_component_store {
virtual void erase_by_entity_id(ecs &ECS, const std::size_t &id)=0;
virtual void really_delete()=0;
virtual void save(xml_node * xml)=0;
virtual std::size_t size()=0;
template<class Archive>
void serialize(Archive & archive)
{
}
};
/*
* Component stores are just a vector of type C (the component). They inherit from
* base_component_store, to allow for a vector of base_component_store*, with each
* casting to a concrete vector of that type. The types are indexed by the family_id
* created for a type with component_t<C>. This guarantees that each component type
* is stored in a big contiguous vector, with only one de-reference required to find
* the right store.
*/
template<class C>
struct component_store_t : public base_component_store {
std::vector<C> components;
virtual void erase_by_entity_id(ecs &ECS, const std::size_t &id) override final {
for (auto &item : components) {
if (item.entity_id == id) {
item.deleted=true;
impl::unset_component_mask(ECS, id, item.family_id);
}
}
}
virtual void really_delete() override final {
components.erase(std::remove_if(components.begin(), components.end(),
[] (auto x) { return x.deleted; }),
components.end());
}
virtual void save(xml_node * xml) override final {
for (auto &item : components) {
xml_node * body = xml->add_node(item.xml_identity());
item.to_xml(body);
body->add_value("entity_id", rltk::serial::to_string(item.entity_id));
}
}
virtual std::size_t size() override final {
return components.size();
}
template<class Archive>
void serialize(Archive & archive)
{
archive( cereal::base_class<base_component_store>(this), components ); // serialize things by passing them to the archive
}
};
/*
* Handle class for messages
*/
template<class C>
struct message_t : public base_message_t {
message_t() {
C empty;
data = empty;
family();
}
message_t(C comp) : data(comp) {
family();
}
std::size_t family_id;
C data;
inline void family() {
static std::size_t family_id_tmp = base_message_t::type_counter++;
family_id = family_id_tmp;
}
};
/*
* Base class for storing subscriptions to messages
*/
struct subscription_base_t {
virtual void deliver_messages()=0;
};
/* Base class for subscription mailboxes */
struct subscription_mailbox_t {
};
/* Implementation class for mailbox subscriptions; stores a queue */
template <class C>
struct mailbox_t : subscription_mailbox_t {
std::queue<C> messages;
};
/*
* Class that holds subscriptions, and determines delivery mechanism.
*/
template <class C>
struct subscription_holder_t : subscription_base_t {
std::queue<C> delivery_queue;
std::mutex delivery_mutex;
std::vector<std::tuple<bool,std::function<void(C& message)>,base_system *>> subscriptions;
virtual void deliver_messages() override {
std::lock_guard<std::mutex> guard(delivery_mutex);
while (!delivery_queue.empty()) {
C message = delivery_queue.front();
delivery_queue.pop();
message_t<C> handle(message);
for (auto &func : subscriptions) {
if (std::get<0>(func) && std::get<1>(func)) {
std::get<1>(func)(message);
} else {
// It is destined for the system's mailbox queue.
auto finder = std::get<2>(func)->mailboxes.find(handle.family_id);
if (finder != std::get<2>(func)->mailboxes.end()) {
static_cast<mailbox_t<C> *>(finder->second.get())->messages.push(message);
}
}
}
}
}
};
} // End impl namespace
/*
* All entities are of type entity_t. They should be created with create_entity (below).
*/
struct entity_t {
/*
* Default constructor - use the next available entity id #.
*/
entity_t() {
++entity_t::entity_counter;
id = entity_t::entity_counter;
}
/*
* Construct with a specified entity #. Moves the next available entity # to this id+1.
*/
entity_t(const std::size_t ID) {
entity_t::entity_counter = ID+1;
id = ID;
}
/*
* Static ID counter - used to ensure that entity IDs are unique. This would need to be atomic
* in a threaded app.
*/
static std::size_t entity_counter;
/*
* The entities ID number. Used to identify the entity. These should be unique.
*/
std::size_t id;
/*
* Overload == and != to allow entities to be compared for likeness.
*/
bool operator == (const entity_t &other) const { return other.id == id; }
bool operator != (const entity_t &other) const { return other.id != id; }
bool deleted = false;
/*
* A bitset storing whether or not an entity has each component type. These are set with the family_id
* determined in the component_t system above.
*/
std::bitset<impl::MAX_COMPONENTS> component_mask;
/*
* Assign a component to this entity. Determines the family_id of the component type, sets the bitmask to
* include the component, marks the component as belonging to the entity, and puts it in the appropriate
* component store.
*/
template<class C>
inline entity_t * assign(ecs &ECS, C component) {
if (deleted) throw std::runtime_error("Cannot assign to a deleted entity");
impl::assign<C>(ECS, *this, component);
return this;
}
template<class C>
inline entity_t * assign(C component) {
return assign<C>(default_ecs, component);
}
/*
* Find a component of the specified type that belongs to the entity.
*/
template <class C>
inline C * component(ecs &ECS) noexcept {
return impl::component<C>(ECS, *this);
}
template <class C>
inline C * component() noexcept {
return component<C>(default_ecs);
}
template<class Archive>
void serialize(Archive & archive)
{
archive( component_mask, id, deleted ); // serialize things by passing them to the archive
}
};
/*
* Systems should inherit from this class.
*/
struct base_system {
virtual void configure() {}
virtual void update(const double duration_ms)=0;
std::string system_name = "Unnamed System";
std::unordered_map<std::size_t, std::unique_ptr<impl::subscription_mailbox_t>> mailboxes;
template<class MSG>
void subscribe(ecs &ECS, std::function<void(MSG &message)> destination) {
impl::subscribe<MSG>(ECS, *this, destination);
}
template<class MSG>
void subscribe(std::function<void(MSG &message)> destination) {
subscribe<MSG>(default_ecs, destination);
}
template<class MSG>
void subscribe_mbox(ecs &ECS) {
impl::subscribe_mbox<MSG>(ECS, *this);
}
template<class MSG>
void subscribe_mbox() {
subscribe_mbox<MSG>(default_ecs);
}
template<class MSG>
std::queue<MSG> * mbox() {
impl::message_t<MSG> handle(MSG{});
auto finder = mailboxes.find(handle.family_id);
if (finder != mailboxes.end()) {
return &static_cast<impl::mailbox_t<MSG> *>(finder->second.get())->messages;
} else {
return nullptr;
}
}
template<class MSG>
void each_mbox(const std::function<void(const MSG&)> &func) {
std::queue<MSG> * mailbox = mbox<MSG>();
while (!mailbox->empty()) {
MSG msg = mailbox->front();
mailbox->pop();
func(msg);
}
}
};
/* A pre-implemented simple system for systems that only handle messages. */
template <class MSG>
struct mailbox_system : public base_system {
virtual void configure() override final {
subscribe_mbox<MSG>();
}
virtual void update(const double duration_ms) override final {
std::queue<MSG> * mailbox = base_system::mbox<MSG>();
while (!mailbox->empty()) {
MSG msg = mailbox->front();
mailbox->pop();
on_message(msg);
}
}
virtual void on_message(const MSG &msg)=0;
};
/*
* Class that holds an entity-component-system. This was moved to a class to allow for multiple instances.
*/
class ecs {
public:
/*
* entity(ID) is used to reference an entity. So you can, for example, do:
* entity(12)->component<position_component>()->x = 3;
*/
entity_t * entity(const std::size_t id) noexcept;
/*
* Creates an entity with a new ID #. Returns a pointer to the entity, to enable
* call chaining. For example create_entity()->assign(foo)->assign(bar)
*/
entity_t * create_entity();
/*
* Creates an entity with a specified ID #. You generally only do this during loading.
*/
entity_t * create_entity(const std::size_t new_id);
/*
* Marks an entity (specified by ID#) as deleted.
*/
inline void delete_entity(const std::size_t id) noexcept {
auto e = entity(id);
if (!e) return;
e->deleted = true;
for (auto &store : component_store) {
if (store) store->erase_by_entity_id(*this, id);
}
}
/*
* Marks an entity as deleted.
*/
inline void delete_entity(entity_t &e) noexcept {
delete_entity(e.id);
}
/*
* Deletes all entities
*/
inline void delete_all_entities() noexcept {
for (auto it=entity_store.begin(); it!=entity_store.end(); ++it) {
delete_entity(it->first);
}
}
/*
* Marks an entity's component as deleted.
*/
template<class C>
inline void delete_component(const std::size_t entity_id, bool delete_entity_if_empty=false) noexcept {
auto eptr = entity(entity_id);
if (!eptr) return;
entity_t e = *entity(entity_id);
C empty_component;
impl::component_t<C> temp(empty_component);
if (!e.component_mask.test(temp.family_id)) return;
for (impl::component_t<C> &component : static_cast<impl::component_store_t<impl::component_t<C>> *>(component_store[temp.family_id].get())->components) {
if (component.entity_id == entity_id) {
component.deleted = true;
unset_component_mask(entity_id, temp.family_id, delete_entity_if_empty);
}
}
}
/*
* Finds all entities that have a component of the type specified, and returns a
* vector of pointers to the entities. It does not check for component deletion.
*/
template<class C>
inline std::vector<entity_t *> entities_with_component() {
C empty_component;
std::vector<entity_t *> result;
impl::component_t<C> temp(empty_component);
for (auto it=entity_store.begin(); it!=entity_store.end(); ++it) {
if (!it->second.deleted && it->second.component_mask.test(temp.family_id)) {
result.push_back(&it->second);
}
}
return result;
}
/*
* all_components takes a component type, and calls the provided function/lambda on
* every component, alongside it's owning entity. For example,
* all_components<position>([] (entity_t &e, position &p) {...}) would execute the
* function body (...) for every entity/component position pair.
*/
template <class C>
inline void all_components(typename std::function<void(entity_t &, C &)> func) {
C empty_component;
impl::component_t<C> temp(empty_component);
for (impl::component_t<C> &component : static_cast<impl::component_store_t<impl::component_t<C>> *>(component_store[temp.family_id].get())->components) {
entity_t e = *entity(component.entity_id);
if (!e.deleted && !component.deleted) {
func(e, component.data);
}
}
}
/*
* each, overloaded with a function/lambda that accepts an entity, will call the provided
* function on _every_ entity in the system.
*/
void each(std::function<void(entity_t &)> &&func);
/*
* Variadic each. Use this to call a function for all entities having a discrete set of components. For example,
* each<position, ai>([] (entity_t &e, position &pos, ai &brain) { ... code ... });
*/
template <typename... Cs, typename F>
inline void each(F callback) {
std::array<size_t, sizeof...(Cs)> family_ids{ {impl::component_t<Cs>{}.family_id...} };
for (auto it=entity_store.begin(); it!=entity_store.end(); ++it) {
if (!it->second.deleted) {
bool matches = true;
for (const std::size_t &compare : family_ids) {
if (!it->second.component_mask.test(compare)) {
matches = false;
break;
}
}
if (matches) {
// Call the functor
callback(it->second, *it->second.component<Cs>()...);
}
}
}
}
/*
* Variadic each_if. Use this to call a function for all entities having a discrete set of components. For example,
* each<position, ai>([] (entity_t &e, position &pos, ai &brain) { ... code returns true if needs processing ... },
* [] (entity_t &e, position &pos, ai &brain) { ... code ... });
*/
template <typename... Cs, typename P, typename F>
inline void each_if(P&& predicate, F callback) {
std::array<size_t, sizeof...(Cs)> family_ids{ {impl::component_t<Cs>{}.family_id...} };
for (auto it=entity_store.begin(); it!=entity_store.end(); ++it) {
if (!it->second.deleted) {
bool matches = true;
for (const std::size_t &compare : family_ids) {
if (!it->second.component_mask.test(compare)) {
matches = false;
break;
}
}
if (matches && predicate(it->second, *it->second.component<Cs>()...)) {
// Call the functor
callback(it->second, *it->second.component<Cs>()...);
}
}
}
}
/*
* This should be called periodically to actually erase all entities and components that are marked as deleted.
*/
inline void ecs_garbage_collect() {
std::unordered_set<std::size_t> entities_to_delete;
// Ensure that components are marked as deleted, and list out entities for erasure
for (auto it=entity_store.begin(); it!=entity_store.end(); ++it) {
if (it->second.deleted) {
for (std::unique_ptr<impl::base_component_store> &store : component_store) {
if (store) store->erase_by_entity_id(*this, it->second.id);
}
entities_to_delete.insert(it->second.id);
}
}
// Actually delete entities
for (const std::size_t &id : entities_to_delete) entity_store.erase(id);
// Now we erase components
for (std::unique_ptr<impl::base_component_store> &store : component_store) {
if (store) store->really_delete();
}
}
/*
* Submits a message for delivery. It will be delivered to every system that has issued a subscribe or subscribe_mbox
* call.
*/
template <class MSG>
inline void emit(MSG message) {
impl::message_t<MSG> handle(message);
if (pubsub_holder.size() > handle.family_id) {
for (auto &func : static_cast<impl::subscription_holder_t<MSG> *>(pubsub_holder[handle.family_id].get())->subscriptions) {
if (std::get<0>(func) && std::get<1>(func)) {
std::get<1>(func)(message);
} else {
// It is destined for the system's mailbox queue.
auto finder = std::get<2>(func)->mailboxes.find(handle.family_id);
if (finder != std::get<2>(func)->mailboxes.end()) {
static_cast<impl::mailbox_t<MSG> *>(finder->second.get())->messages.push(message);
}
}
}
}
}
/*
* Submits a message for delivery. It will be delivered to every system that has issued a subscribe or subscribe_mbox
* call at the end of the next system execution. This is thead-safe, so you can emit_defer from within a parallel_each.
*/
template <class MSG>
inline void emit_deferred(MSG message) {
impl::message_t<MSG> handle(message);
if (pubsub_holder.size() > handle.family_id) {
auto * subholder = static_cast<impl::subscription_holder_t<MSG> *>(pubsub_holder[handle.family_id].get());
std::lock_guard<std::mutex> postlock(subholder->delivery_mutex);
subholder->delivery_queue.push(message);
}
}
/* Add a system to the mix */
template<typename S, typename ...Args>
inline void add_system( Args && ... args ) {
system_store.push_back(std::make_unique<S>( std::forward<Args>(args) ... ));
system_profiling.push_back(system_profiling_t{});
}
void delete_all_systems();
void ecs_configure();
void ecs_tick(const double duration_ms);
void ecs_save(std::unique_ptr<std::ofstream> &lbfile);
void ecs_load(std::unique_ptr<std::ifstream> &lbfile);
std::string ecs_profile_dump();
// The ECS component store
std::vector<std::unique_ptr<impl::base_component_store>> component_store;
// The ECS entity store
std::unordered_map<std::size_t, entity_t> entity_store;
// Mailbox system
std::vector<std::unique_ptr<impl::subscription_base_t>> pubsub_holder;
// Storage of systems
std::vector<std::unique_ptr<base_system>> system_store;
// Profile data storage
std::vector<system_profiling_t> system_profiling;
// Helpers
inline void unset_component_mask(const std::size_t id, const std::size_t family_id, bool delete_if_empty) {
auto finder = entity_store.find(id);
if (finder != entity_store.end()) {
finder->second.component_mask.reset(family_id);
if (delete_if_empty && finder->second.component_mask.none()) finder->second.deleted = true;
}
}
/* Delivers the queue; called at the end of each system call */
inline void deliver_messages() {
for (auto &holder : pubsub_holder) {
if (holder) holder->deliver_messages();
}
}
/*
* Cereal support for save/load
*/
template<class Archive>
void serialize(Archive & archive)
{
archive( entity_store, component_store, entity_t::entity_counter, impl::base_component_t::type_counter ); // serialize things by passing them to the archive
}
};
namespace impl {
template <class C>
inline void assign(ecs &ECS, entity_t &E, C component) {
impl::component_t<C> temp(component);
temp.entity_id = E.id;
if (ECS.component_store.size() < temp.family_id+1) {
ECS.component_store.resize(temp.family_id+1);
}
if (!ECS.component_store[temp.family_id]) ECS.component_store[temp.family_id] = std::move(std::make_unique<impl::component_store_t<impl::component_t<C>>>());
static_cast<impl::component_store_t<impl::component_t<C>> *>(ECS.component_store[temp.family_id].get())->components.push_back(temp);
E.component_mask.set(temp.family_id);
}
template <class C>
inline C * component(ecs &ECS, entity_t &E) noexcept {
C * result = nullptr;
if (E.deleted) return result;
C empty_component;
impl::component_t<C> temp(empty_component);
if (!E.component_mask.test(temp.family_id)) return result;
for (impl::component_t<C> &component : static_cast<impl::component_store_t<impl::component_t<C>> *>(ECS.component_store[temp.family_id].get())->components) {
if (component.entity_id == E.id) {
result = &component.data;
return result;
}
}
return result;
}
template<class MSG>
inline void subscribe(ecs &ECS, base_system &B, std::function<void(MSG &message)> destination) {
MSG empty_message{};
impl::message_t<MSG> handle(empty_message);
if (ECS.pubsub_holder.size() < handle.family_id + 1) {
ECS.pubsub_holder.resize(handle.family_id + 1);
}
if (!ECS.pubsub_holder[handle.family_id]) {
ECS.pubsub_holder[handle.family_id] = std::move(std::make_unique<subscription_holder_t<MSG>>());
}
static_cast<subscription_holder_t<MSG> *>(ECS.pubsub_holder[handle.family_id].get())->subscriptions.push_back(std::make_tuple(true,destination,nullptr));
}
template<class MSG>
inline void subscribe_mbox(ecs &ECS, base_system &B) {
MSG empty_message{};
impl::message_t<MSG> handle(empty_message);
if (ECS.pubsub_holder.size() < handle.family_id + 1) {
ECS.pubsub_holder.resize(handle.family_id + 1);
}
if (!ECS.pubsub_holder[handle.family_id]) {
ECS.pubsub_holder[handle.family_id] = std::move(std::make_unique<subscription_holder_t<MSG>>());
}
std::function<void(MSG &message)> destination; // Deliberately empty
static_cast<impl::subscription_holder_t<MSG> *>(ECS.pubsub_holder[handle.family_id].get())->subscriptions.push_back(std::make_tuple(false,destination,&B));
B.mailboxes[handle.family_id] = std::make_unique<impl::mailbox_t<MSG>>();
}
inline void unset_component_mask(ecs &ECS, const std::size_t id, const std::size_t family_id, bool delete_if_empty) {
ECS.unset_component_mask(id, family_id, delete_if_empty);
}
}
} // End RLTK namespace
CEREAL_REGISTER_ARCHIVE(rltk::ecs)
================================================
FILE: rltk/filesystem.hpp
================================================
/* RLTK (RogueLike Tool Kit) 1.00
* Copyright (c) 2016-Present, Bracket Productions.
* Licensed under the MIT license - see LICENSE file.
*
* Minimal filesystem tools
*/
#pragma once
#include <string>
#include <sys/stat.h>
namespace rltk {
inline bool exists(const std::string &filename) noexcept {
struct stat buffer;
return (stat (filename.c_str(), &buffer) == 0);
}
}
================================================
FILE: rltk/font_manager.cpp
================================================
#include "font_manager.hpp"
#include "texture_resources.hpp"
#include <unordered_map>
#include <stdexcept>
#include <iostream>
#include <sstream>
#include <fstream>
#include "filesystem.hpp"
namespace rltk {
namespace font_detail {
std::vector<std::string> split ( const std::string &str, const char &delimiter )
{
std::vector<std::string> internal;
std::stringstream ss ( str ); // Turn the string into a stream.
std::string tok;
while ( getline ( ss, tok, delimiter ) ) {
internal.push_back ( tok );
}
return internal;
}
std::unordered_map<std::string, rltk::bitmap_font> atlas;
}
bitmap_font * get_font(const std::string font_tag) {
auto finder = font_detail::atlas.find(font_tag);
if (finder == font_detail::atlas.end()) {
throw std::runtime_error("Unable to locate bitmap font with tag " + font_tag);
} else {
return &finder->second;
}
}
inline void check_for_duplicate_font(const std::string &tag) {
auto finder = font_detail::atlas.find(tag);
if (finder != font_detail::atlas.end()) {
throw std::runtime_error("Attempting to insert duplicate font with tag " + tag);
}
}
inline void check_texture_exists(const std::string &texture_tag) {
if (get_texture(texture_tag) == nullptr) {
throw std::runtime_error("No such texture resource: " + texture_tag);
}
}
void register_font(const std::string font_tag, const std::string filename, int width, int height) {
const std::string texture_tag = "font_tex_" + filename;
check_for_duplicate_font(font_tag);
register_texture(filename, texture_tag);
check_texture_exists(texture_tag);
font_detail::atlas.emplace(std::make_pair(font_tag, bitmap_font(texture_tag, width, height)));
}
void register_font_directory(const std::string path) {
if (!exists(path)) throw std::runtime_error("Font directory does not exist.");
const std::string info_file = path + "/fonts.txt";
if (!exists(info_file)) throw std::runtime_error("No fonts.txt file in font directory.");
std::ifstream f(info_file);
std::string line;
while (getline(f, line)) {
auto split = font_detail::split(line, ',');
if (split.size() == 4) {
register_font(split[0], path + "/" + split[1], std::stoi(split[2]), std::stoi(split[3]));
}
}
/*
ptree font_tree;
read_json(info_file, font_tree);
ptree::const_iterator end = font_tree.get_child("fonts").end();
for (ptree::const_iterator it = font_tree.get_child("fonts").begin(); it != end; ++it) {
const std::string font_name = it->first;
const std::string font_tree_path = "fonts." + font_name + ".";
const std::string font_file = font_tree.get<std::string>(font_tree_path + "file");
const int width = font_tree.get<int>(font_tree_path + "width");
const int height = font_tree.get<int>(font_tree_path + "height");
register_font(font_name, path + "/" + font_file, width, height);
}*/
}
}
================================================
FILE: rltk/font_manager.hpp
================================================
/* RLTK (RogueLike Tool Kit) 1.00
* Copyright (c) 2016-Present, Bracket Productions.
* Licensed under the MIT license - see LICENSE file.
*
* Font manager
*/
#pragma once
#include <string>
#include <utility>
namespace rltk {
struct bitmap_font {
bitmap_font(const std::string tag, const int width, const int height) : texture_tag(tag), character_size({width,height}) {}
const std::string texture_tag;
const std::pair<int,int> character_size;
};
void register_font_directory(const std::string path);
bitmap_font * get_font(const std::string font_tag);
void register_font(const std::string font_tag, const std::string filename, int width=8, int height=8);
}
================================================
FILE: rltk/fsa.hpp
================================================
/*
A* Algorithm Implementation using STL is
Copyright (C)2001-2005 Justin Heyes-Jones
Permission is given by the author to freely redistribute and
include this code in any program as long as this credit is
given where due.
COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED,
INCLUDING, WITHOUT LIMITATION, WARRANTIES THAT THE COVERED CODE
IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE
OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND
PERFORMANCE OF THE COVERED CODE IS WITH YOU. SHOULD ANY COVERED
CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT THE INITIAL
DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY
NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF
WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE
OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER
THIS DISCLAIMER.
Use at your own risk!
FixedSizeAllocator class
Copyright 2001 Justin Heyes-Jones
This class is a constant time O(1) memory manager for objects of
a specified type. The type is specified using a template class.
Memory is allocated from a fixed size buffer which you can specify in the
class constructor or use the default.
Using GetFirst and GetNext it is possible to iterate through the elements
one by one, and this would be the most common use for the class.
I would suggest using this class when you want O(1) add and delete
and you don't do much searching, which would be O(n). Structures such as binary
trees can be used instead to get O(logn) access time.
*/
#pragma once
#include <string.h>
#include <stdio.h>
template<class USER_TYPE> class FixedSizeAllocator
{
public:
// Constants
enum
{
FSA_DEFAULT_SIZE = 100
};
// This class enables us to transparently manage the extra data
// needed to enable the user class to form part of the double-linked
// list class
struct FSA_ELEMENT
{
USER_TYPE UserType;
FSA_ELEMENT *pPrev;
FSA_ELEMENT *pNext;
};
public:
// methods
FixedSizeAllocator(unsigned int MaxElements = FSA_DEFAULT_SIZE) :
m_pFirstUsed(NULL), m_MaxElements(MaxElements)
{
// Allocate enough memory for the maximum number of elements
char *pMem = new char[m_MaxElements * sizeof(FSA_ELEMENT)];
m_pMemory = (FSA_ELEMENT *) pMem;
// Set the free list first pointer
m_pFirstFree = m_pMemory;
// Clear the memory
memset(m_pMemory, 0, sizeof(FSA_ELEMENT) * m_MaxElements);
// Point at first element
FSA_ELEMENT *pElement = m_pFirstFree;
// Set the double linked free list
for (unsigned int i = 0; i < m_MaxElements; i++)
{
pElement->pPrev = pElement - 1;
pElement->pNext = pElement + 1;
pElement++;
}
// first element should have a null prev
m_pFirstFree->pPrev = NULL;
// last element should have a null next
(pElement - 1)->pNext = NULL;
}
~FixedSizeAllocator()
{
// Free up the memory
delete[] (char *) m_pMemory;
}
// Allocate a new USER_TYPE and return a pointer to it
USER_TYPE *alloc()
{
FSA_ELEMENT *pNewNode = NULL;
if (!m_pFirstFree)
{
return NULL;
}
else
{
pNewNode = m_pFirstFree;
m_pFirstFree = pNewNode->pNext;
// if the new node points to another free node then
// change that nodes prev free pointer...
if (pNewNode->pNext)
{
pNewNode->pNext->pPrev = NULL;
}
// node is now on the used list
pNewNode->pPrev = NULL; // the allocated node is always first in the list
if (m_pFirstUsed == NULL)
{
pNewNode->pNext = NULL; // no other nodes
}
else
{
m_pFirstUsed->pPrev = pNewNode; // insert this at the head of the used list
pNewNode->pNext = m_pFirstUsed;
}
m_pFirstUsed = pNewNode;
}
return reinterpret_cast<USER_TYPE*>(pNewNode);
}
// Free the given user type
// For efficiency I don't check whether the user_data is a valid
// pointer that was allocated. I may add some debug only checking
// (To add the debug check you'd need to make sure the pointer is in
// the m_pMemory area and is pointing at the start of a node)
void free(USER_TYPE *user_data)
{
FSA_ELEMENT *pNode = reinterpret_cast<FSA_ELEMENT*>(user_data);
// manage used list, remove this node from it
if (pNode->pPrev)
{
pNode->pPrev->pNext = pNode->pNext;
}
else
{
// this handles the case that we delete the first node in the used list
m_pFirstUsed = pNode->pNext;
}
if (pNode->pNext)
{
pNode->pNext->pPrev = pNode->pPrev;
}
// add to free list
if (m_pFirstFree == NULL)
{
// free list was empty
m_pFirstFree = pNode;
pNode->pPrev = NULL;
pNode->pNext = NULL;
}
else
{
// Add this node at the start of the free list
m_pFirstFree->pPrev = pNode;
pNode->pNext = m_pFirstFree;
m_pFirstFree = pNode;
}
}
// For debugging this displays both lists (using the prev/next list pointers)
void Debug()
{
printf("free list ");
FSA_ELEMENT *p = m_pFirstFree;
while (p)
{
printf("%x!%x ", p->pPrev, p->pNext);
p = p->pNext;
}
printf("\n");
printf("used list ");
p = m_pFirstUsed;
while (p)
{
printf("%x!%x ", p->pPrev, p->pNext);
p = p->pNext;
}
printf("\n");
}
// Iterators
USER_TYPE *GetFirst()
{
return reinterpret_cast<USER_TYPE *>(m_pFirstUsed);
}
USER_TYPE *GetNext(USER_TYPE *node)
{
return reinterpret_cast<USER_TYPE *>((reinterpret_cast<FSA_ELEMENT *>(node))->pNext);
}
public:
// data
private:
// methods
private:
// data
FSA_ELEMENT *m_pFirstFree;
FSA_ELEMENT *m_pFirstUsed;
unsigned int m_MaxElements;
FSA_ELEMENT *m_pMemory;
};
================================================
FILE: rltk/geometry.cpp
================================================
#include "geometry.hpp"
#include <cstdlib>
#include <cmath>
namespace rltk {
/*
* From a given point x/y, project forward radius units (generally tiles) at an angle of degrees_radians degrees
* (in radians).
*/
std::pair<int, int> project_angle(const int &x, const int &y, const double &radius, const double °rees_radians) noexcept
{
return std::make_pair(static_cast<int>(x + radius * std::cos(degrees_radians)), static_cast<int>(y + radius * std::sin(degrees_radians)));
}
}
================================================
FILE: rltk/geometry.hpp
================================================
#pragma once
/* RLTK (RogueLike Tool Kit) 1.00
* Copyright (c) 2016-Present, Bracket Productions.
* Licensed under the MIT license - see LICENSE file.
*
* Random number generator class.
*/
#include <functional>
#include <utility>
#include <cmath>
namespace rltk {
/*
* From a given point x/y, project forward radius units (generally tiles) at an angle of degrees_radians degrees
* (in radians).
*/
std::pair<int, int> project_angle(const int &x, const int &y, const double &radius, const double °rees_radians) noexcept;
/*
* Provides a correct 2D distance between two points.
*/
inline float distance2d(const int &x1, const int &y1, const int &x2, const int &y2) noexcept {
const float dx = (float)x1 - (float)x2;
const float dy = (float)y1 - (float)y2;
return std::sqrt((dx*dx) + (dy*dy));
}
/*
* Provides a fast 2D distance between two points, omitting the square-root; compare
* with other squared distances.
*/
inline float distance2d_squared(const int &x1, const int &y1, const int &x2, const int &y2) noexcept {
const float dx = (float)x1 - (float)x2;
const float dy = (float)y1 - (float)y2;
return (dx*dx) + (dy*dy);
}
/*
* Provides 2D Manhattan distance between two points.
*/
inline float distance2d_manhattan(const int &x1, const int &y1, const int &x2, const int &y2) noexcept {
const float dx = (float)x1 - (float)x2;
const float dy = (float)y1 - (float)y2;
return std::abs(dx) + std::abs(dy);
}
/*
* Provides a correct 3D distance between two points.
*/
inline float distance3d(const int &x1, const int &y1, const int &z1, const int &x2, const int &y2, const int &z2) noexcept
{
const float dx = (float)x1 - (float)x2;
const float dy = (float)y1 - (float)y2;
const float dz = (float)z1 - (float)z2;
return std::sqrt((dx*dx) + (dy*dy) + (dz*dz));
}
/*
* Provides a fast 3D distance between two points, omitting the square-root; compare
* with other squared distances.
*/
inline float distance3d_squared(const int &x1, const int &y1, const int &z1, const int &x2, const int &y2, const int &z2) noexcept
{
float dx = (float)x1 - (float)x2;
float dy = (float)y1 - (float)y2;
float dz = (float)z1 - (float)z2;
return (dx*dx) + (dy*dy) + (dz*dz);
}
/*
* Provides Manhattan distance between two 3D points.
*/
inline float distance3d_manhattan(const int &x1, const int &y1, const int &z1, const int &x2, const int &y2, const int &z2) noexcept
{
const float dx = (float)x1 - (float)x2;
const float dy = (float)y1 - (float)y2;
const float dz = (float)z1 - (float)z2;
return std::abs(dx) + std::abs(dy) + std::abs(dz);
}
/*
* Perform a function for each line element between x1/y1 and x2/y2. We used to use Bresenham's line,
* but benchmarking showed a simple float-based setup to be faster.
*/
inline void line_func(const int &x1, const int &y1, const int &x2, const int &y2, std::function<void(int, int)> &&func) noexcept
{
float x = static_cast<float>(x1) + 0.5F;
float y = static_cast<float>(y1) + 0.5F;
const float dest_x = static_cast<float>(x2);
const float dest_y = static_cast<float>(y2);
const float n_steps = distance2d(x1,y1,x2,y2);
const int steps = static_cast<const int>(std::floor(n_steps) + 1);
const float slope_x = (dest_x - x) / n_steps;
const float slope_y = (dest_y - y) / n_steps;
for (int i = 0; i < steps; ++i) {
func(static_cast<int>(x), static_cast<int>(y));
x += slope_x;
y += slope_y;
}
}
/*
* Perform a function for each line element between x1/y1/z1 and x2/y2/z2. Uses a 3D
* implementation of Bresenham's line algorithm.
* https://gist.github.com/yamamushi/5823518
*/
template <typename F>
void line_func_3d(const int &x1, const int &y1, const int &z1, const int &x2, const int &y2, const int &z2, F &&func) noexcept
{
float x = static_cast<float>(x1)+0.5F;
float y = static_cast<float>(y1)+0.5F;
float z = static_cast<float>(z1)+0.5F;
float length = distance3d(x1, y1, z1, x2, y2, z2);
int steps = static_cast<int>(std::floor(length));
float x_step = (x - x2) / length;
float y_step = (y - y2) / length;
float z_step = (z - z2) / length;
for (int i=0; i<steps; ++i) {
x += x_step;
y += y_step;
z += z_step;
func(static_cast<int>(std::floor(x)), static_cast<int>(std::floor(y)), static_cast<int>(std::floor(z)));
}
}
/*
* Perform a function for each line element between x1/y1 and x2/y2. We used to use Bresenham's algorithm,
* but benchmarking showed that a simple float based vector was faster.
*/
template <typename F>
inline void line_func_cancellable(const int &x1, const int &y1, const int &x2, const int &y
gitextract_vk2s8wpi/
├── .gitignore
├── CMakeLists.txt
├── CMakeSettings.json
├── LICENSE
├── README.md
├── assets/
│ ├── fonts.txt
│ └── nyan.xp
├── cmake_modules/
│ ├── FindSFML.cmake
│ └── Findcereal.cmake
├── examples/
│ ├── ex1/
│ │ └── main.cpp
│ ├── ex10/
│ │ └── main.cpp
│ ├── ex11/
│ │ └── main.cpp
│ ├── ex2/
│ │ └── main.cpp
│ ├── ex3/
│ │ └── main.cpp
│ ├── ex4/
│ │ └── main.cpp
│ ├── ex5/
│ │ └── main.cpp
│ ├── ex6/
│ │ └── main.cpp
│ ├── ex7/
│ │ └── main.cpp
│ ├── ex8/
│ │ └── main.cpp
│ └── ex9/
│ └── main.cpp
└── rltk/
├── astar.hpp
├── color_t.cpp
├── color_t.hpp
├── colors.hpp
├── ecs.cpp
├── ecs.hpp
├── ecs_impl.hpp
├── filesystem.hpp
├── font_manager.cpp
├── font_manager.hpp
├── fsa.hpp
├── geometry.cpp
├── geometry.hpp
├── gui.cpp
├── gui.hpp
├── gui_control_t.cpp
├── gui_control_t.hpp
├── input_handler.cpp
├── input_handler.hpp
├── layer_t.cpp
├── layer_t.hpp
├── path_finding.hpp
├── perlin_noise.cpp
├── perlin_noise.hpp
├── rexspeeder.cpp
├── rexspeeder.hpp
├── rltk.cpp
├── rltk.hpp
├── rng.cpp
├── rng.hpp
├── scaling.cpp
├── scaling.hpp
├── serialization_utils.hpp
├── texture.hpp
├── texture_resources.cpp
├── texture_resources.hpp
├── vchar.hpp
├── virtual_terminal.cpp
├── virtual_terminal.hpp
├── virtual_terminal_sparse.cpp
├── virtual_terminal_sparse.hpp
├── visibility.hpp
├── xml.cpp
└── xml.hpp
SYMBOL INDEX (569 symbols across 55 files)
FILE: examples/ex1/main.cpp
function tick (line 22) | void tick(double duration_ms) {
function main (line 31) | int main()
FILE: examples/ex10/main.cpp
function map_idx (line 24) | int map_idx(const int x, const int y) { return (y * map_width) + x; }
type position (line 32) | struct position {
method position (line 33) | position() {}
method position (line 34) | position(const int X, const int Y) : x(X), y(Y) {}
method bounds_check (line 38) | void bounds_check() {
type renderable (line 46) | struct renderable {
method renderable (line 47) | renderable() {}
method renderable (line 48) | renderable(const char Glyph, const color_t foreground) : glyph(Glyph),...
type navigator_helper (line 54) | struct navigator_helper {
method get_x (line 55) | static int get_x(const position &loc) { return loc.x; }
method get_y (line 56) | static int get_y(const position &loc) { return loc.y; }
method position (line 57) | static position get_xy(const int &x, const int &y) { return position{x...
type actor_moved_message (line 63) | struct actor_moved_message : base_message_t {
method actor_moved_message (line 64) | actor_moved_message() {}
method actor_moved_message (line 65) | actor_moved_message(entity_t * ACTOR, const int fx, const int fy, cons...
type player_moved_message (line 72) | struct player_moved_message : base_message_t {}
type camera_system (line 74) | struct camera_system : public base_system {
method configure (line 75) | virtual void configure() override {
method update (line 84) | virtual void update(const double duration_ms) override {
type actor_render_system (line 123) | struct actor_render_system : public base_system {
method configure (line 124) | virtual void configure() override {
method update (line 128) | virtual void update(const double duration_ms) override {
type player_system (line 138) | struct player_system : public base_system {
method configure (line 139) | virtual void configure() override {
method update (line 154) | virtual void update(const double duration_ms) override {
type visibility_system (line 175) | struct visibility_system : public base_system {
method configure (line 176) | virtual void configure() override {
method update (line 199) | virtual void update(const double duration_ms) override {
function tick (line 209) | void tick(double duration_ms) {
function main (line 214) | int main()
FILE: examples/ex11/main.cpp
function tick (line 23) | void tick(double duration_ms) {
function main (line 33) | int main()
FILE: examples/ex2/main.cpp
function tick (line 38) | void tick(double duration_ms) {
function main (line 80) | int main()
FILE: examples/ex3/main.cpp
function tick (line 55) | void tick(double duration_ms) {
function main (line 112) | int main()
FILE: examples/ex4/main.cpp
type location_t (line 42) | struct location_t {
method location_t (line 50) | location_t() {}
method location_t (line 51) | location_t(const int X, const int Y) : x(X), y(Y) {}
type map_t (line 56) | struct map_t {
method map_t (line 57) | map_t(const int &w, const int &h) : width(w), height(h) {
method at (line 83) | inline int at(const int &x, const int &y) { return (y*width)+x; }
type navigator (line 111) | struct navigator {
method get_distance_estimate (line 115) | static float get_distance_estimate(location_t &pos, location_t &goal) {
method is_goal (line 124) | static bool is_goal(location_t &pos, location_t &goal) {
method get_successors (line 130) | static bool get_successors(location_t pos, std::vector<location_t> &su...
method get_cost (line 147) | static float get_cost(location_t &position, location_t &successor) {
method is_same_state (line 154) | static bool is_same_state(location_t &lhs, location_t &rhs) {
function tick (line 165) | void tick(double duration_ms) {
function main (line 236) | int main()
FILE: examples/ex5/main.cpp
type location_t (line 39) | struct location_t {
method location_t (line 47) | location_t() {}
method location_t (line 48) | location_t(const int X, const int Y) : x(X), y(Y) {}
type map_t (line 53) | struct map_t {
method map_t (line 54) | map_t(const int &w, const int &h) : width(w), height(h) {
method at (line 83) | inline int at(const int &x, const int &y) { return (y*width)+x; }
type navigator (line 111) | struct navigator {
method get_distance_estimate (line 115) | static float get_distance_estimate(location_t &pos, location_t &goal) {
method is_goal (line 124) | static bool is_goal(location_t &pos, location_t &goal) {
method get_successors (line 130) | static bool get_successors(location_t pos, std::vector<location_t> &su...
method get_cost (line 147) | static float get_cost(location_t &position, location_t &successor) {
method is_same_state (line 154) | static bool is_same_state(location_t &lhs, location_t &rhs) {
function tick (line 165) | void tick(double duration_ms) {
function main (line 248) | int main()
FILE: examples/ex6/main.cpp
type location_t (line 36) | struct location_t {
method location_t (line 44) | location_t() {}
method location_t (line 45) | location_t(const int X, const int Y) : x(X), y(Y) {}
type map_t (line 50) | struct map_t {
method map_t (line 51) | map_t(const int &w, const int &h) : width(w), height(h) {
method at (line 84) | inline int at(const int &x, const int &y) { return (y*width)+x; }
type navigator (line 118) | struct navigator {
method get_distance_estimate (line 122) | static float get_distance_estimate(location_t &pos, location_t &goal) {
method is_goal (line 131) | static bool is_goal(location_t &pos, location_t &goal) {
method get_successors (line 137) | static bool get_successors(location_t pos, std::vector<location_t> &su...
method get_cost (line 154) | static float get_cost(location_t &position, location_t &successor) {
method is_same_state (line 161) | static bool is_same_state(location_t &lhs, location_t &rhs) {
method get_x (line 168) | static int get_x(const location_t &loc) { return loc.x; }
method get_y (line 169) | static int get_y(const location_t &loc) { return loc.y; }
method location_t (line 170) | static location_t get_xy(const int &x, const int &y) { return location...
method is_walkable (line 171) | static bool is_walkable(const location_t &loc) { return map.walkable[m...
function visibility_sweep (line 180) | inline void visibility_sweep() {
function tick (line 192) | void tick(double duration_ms) {
function main (line 306) | int main()
FILE: examples/ex7/main.cpp
function tick (line 28) | void tick(double duration_ms) {
function resize_title (line 50) | void resize_title(layer_t * l, int w, int h) {
function resize_main (line 57) | void resize_main(layer_t * l, int w, int h) {
function resize_log (line 65) | void resize_log(layer_t * l, int w, int h) {
function main (line 80) | int main()
FILE: examples/ex8/main.cpp
function resize_bg (line 33) | void resize_bg(layer_t * l, int w, int h) {
function draw_bg (line 39) | void draw_bg(layer_t * l, sf::RenderTexture &window) {
function resize_log (line 45) | void resize_log(layer_t * l, int w, int h) {
function resize_retained (line 59) | void resize_retained(layer_t * l, int w, int h) {
function tick (line 69) | void tick(double duration_ms) {
function main (line 101) | int main()
FILE: examples/ex9/main.cpp
type location_t (line 39) | struct location_t {
method location_t (line 47) | location_t() {}
method location_t (line 48) | location_t(const int X, const int Y) : x(static_cast<float>(X)), y(sta...
type map_t (line 53) | struct map_t {
method map_t (line 54) | map_t(const int &w, const int &h) : width(w), height(h) {
method at (line 87) | inline int at(const int &x, const int &y) { return (y*width)+x; }
type navigator (line 121) | struct navigator {
method get_distance_estimate (line 125) | static float get_distance_estimate(location_t &pos, location_t &goal) {
method is_goal (line 134) | static bool is_goal(location_t &pos, location_t &goal) {
method get_successors (line 140) | static bool get_successors(location_t pos, std::vector<location_t> &su...
method get_cost (line 157) | static float get_cost(location_t &position, location_t &successor) {
method is_same_state (line 164) | static bool is_same_state(location_t &lhs, location_t &rhs) {
method get_x (line 171) | static int get_x(const location_t &loc) { return static_cast<int>(loc....
method get_y (line 172) | static int get_y(const location_t &loc) { return static_cast<int>(loc....
method location_t (line 173) | static location_t get_xy(const int &x, const int &y) { return location...
method is_walkable (line 174) | static bool is_walkable(const location_t &loc) { return map.walkable[m...
function visibility_sweep (line 183) | inline void visibility_sweep() {
function tick (line 195) | void tick(double duration_ms) {
function resize_map (line 322) | void resize_map(layer_t * l, int w, int h) {
function main (line 329) | int main()
FILE: rltk/astar.hpp
class AStarState (line 55) | class AStarState
class AStarSearch (line 58) | class AStarSearch
class Node (line 79) | class Node
method Node (line 90) | Node() :
class HeapCompare_f (line 101) | class HeapCompare_f
method AStarSearch (line 115) | AStarSearch() : m_State(SEARCH_STATE_NOT_INITIALISED), m_CurrentSoluti...
method AStarSearch (line 123) | AStarSearch(int MaxNodes) :
method CancelSearch (line 133) | void CancelSearch()
method SetStartAndGoalStates (line 139) | void SetStartAndGoalStates(UserState &Start, UserState &Goal)
method SearchStep (line 174) | unsigned int SearchStep()
method AddSuccessor (line 405) | bool AddSuccessor(UserState &State)
method FreeSolutionNodes (line 424) | void FreeSolutionNodes()
method UserState (line 456) | UserState *GetSolutionStart()
method UserState (line 470) | UserState *GetSolutionNext()
method UserState (line 489) | UserState *GetSolutionEnd()
method UserState (line 503) | UserState *GetSolutionPrev()
method GetSolutionCost (line 523) | float GetSolutionCost()
method UserState (line 538) | UserState *GetOpenListStart()
method UserState (line 544) | UserState *GetOpenListStart(float &f, float &g, float &h)
method UserState (line 558) | UserState *GetOpenListNext()
method UserState (line 564) | UserState *GetOpenListNext(float &f, float &g, float &h)
method UserState (line 578) | UserState *GetClosedListStart()
method UserState (line 584) | UserState *GetClosedListStart(float &f, float &g, float &h)
method UserState (line 599) | UserState *GetClosedListNext()
method UserState (line 605) | UserState *GetClosedListNext(float &f, float &g, float &h)
method GetStepCount (line 622) | int GetStepCount()
method EnsureMemoryFreed (line 627) | void EnsureMemoryFreed()
method FreeAllNodes (line 640) | void FreeAllNodes()
method FreeUnusedNodes (line 675) | void FreeUnusedNodes()
method Node (line 717) | Node *AllocateNode()
method Node (line 90) | Node() :
method FreeNode (line 736) | void FreeNode(Node *node)
class AStarState (line 791) | class AStarState
FILE: rltk/color_t.cpp
type rltk (line 8) | namespace rltk {
function color_to_hsv (line 11) | std::tuple<float, float, float> color_to_hsv(const color_t &col) {
function color_from_hsv (line 52) | std::tuple<uint8_t, uint8_t, uint8_t> color_from_hsv(const float hue, ...
function color_t (line 104) | color_t greyscale(const color_t &col)
function color_t (line 125) | color_t darken(const int &amount, const color_t &col)
function color_t (line 160) | color_t apply_colored_light(const color_t &col, const std::tuple<float...
function color_t (line 187) | color_t lerp(const color_t &first, const color_t &second, float amount) {
FILE: rltk/color_t.hpp
type rltk (line 14) | namespace rltk {
type color_t (line 19) | struct color_t {
method color_t (line 21) | color_t() {}
method color_t (line 24) | color_t(const int R, const int G, const int B) : r(static_cast<uint8...
method color_t (line 27) | color_t(const uint8_t R, const uint8_t G, const uint8_t B) : r(R), g...
method color_t (line 30) | color_t(const float hue, const float saturation, const float value) {
method color_t (line 35) | color_t(const std::tuple<uint8_t, uint8_t, uint8_t> &c) { std::tie(r...
method color_t (line 38) | color_t operator+(const color_t &other) {
method color_t (line 49) | color_t operator-(const color_t &other) {
method color_t (line 60) | color_t operator*(const color_t &other) {
method serialize (line 86) | void serialize(Archive & archive)
function color_to_sfml (line 93) | inline sf::Color color_to_sfml(const color_t &col) { return sf::Color(...
function color_to_rgb (line 96) | inline std::tuple<uint8_t, uint8_t, uint8_t> color_to_rgb(const color_...
FILE: rltk/colors.hpp
type rltk (line 5) | namespace rltk {
type colors (line 7) | namespace colors {
FILE: rltk/ecs.cpp
type rltk (line 5) | namespace rltk {
function entity_t (line 12) | entity_t * ecs::entity(const std::size_t id) noexcept {
function entity_t (line 21) | entity_t * ecs::create_entity() {
function entity_t (line 33) | entity_t * ecs::create_entity(const std::size_t new_id) {
FILE: rltk/ecs.hpp
type rltk (line 25) | namespace rltk {
function entity_t (line 31) | inline entity_t * entity(ecs &ECS, const std::size_t id) noexcept {
function entity_t (line 35) | inline entity_t * entity(const std::size_t id) noexcept {
function entity_t (line 39) | inline entity_t * create_entity(ecs &ECS) {
function entity_t (line 43) | inline entity_t * create_entity() {
function entity_t (line 47) | inline entity_t * create_entity(ecs &ECS, const std::size_t new_id) {
function entity_t (line 51) | inline entity_t * create_entity(const std::size_t new_id) {
function delete_entity (line 55) | inline void delete_entity(ecs &ECS, const std::size_t id) noexcept {
function delete_entity (line 59) | inline void delete_entity(const std::size_t id) noexcept {
function delete_entity (line 63) | inline void delete_entity(ecs &ECS, entity_t &e) noexcept {
function delete_entity (line 67) | inline void delete_entity(entity_t &e) noexcept {
function delete_all_entities (line 71) | inline void delete_all_entities(ecs &ECS) noexcept {
function delete_all_entities (line 75) | inline void delete_all_entities() noexcept {
function delete_component (line 80) | inline void delete_component(ecs &ECS, const std::size_t entity_id, bo...
function delete_component (line 85) | inline void delete_component(const std::size_t entity_id, bool delete_...
function entities_with_component (line 90) | inline std::vector<entity_t *> entities_with_component(ecs &ECS) {
function entities_with_component (line 95) | inline std::vector<entity_t *> entities_with_component() {
function all_components (line 100) | inline void all_components(ecs &ECS, typename std::function<void(entit...
function all_components (line 105) | inline void all_components(typename std::function<void(entity_t &, C &...
function each (line 110) | inline void each(ecs &ECS, F callback) {
function each (line 115) | inline void each(F callback) {
function each_if (line 120) | inline void each_if(ecs &ECS, P&& predicate, F callback) {
function each_if (line 125) | inline void each_if(P&& predicate, F callback) {
function ecs_garbage_collect (line 129) | inline void ecs_garbage_collect(ecs &ECS) {
function ecs_garbage_collect (line 133) | inline void ecs_garbage_collect() {
function emit (line 138) | inline void emit(ecs &ECS, MSG message) {
function emit (line 143) | inline void emit(MSG message) {
function emit_deferred (line 148) | inline void emit_deferred(ecs &ECS, MSG message) {
function emit_deferred (line 153) | inline void emit_deferred(MSG message) {
function add_system (line 158) | inline void add_system( ecs &ECS, Args && ... args ) {
function add_system (line 163) | inline void add_system( Args && ... args ) {
function delete_all_systems (line 167) | inline void delete_all_systems(ecs &ECS) {
function delete_all_systems (line 171) | inline void delete_all_systems() {
function ecs_configure (line 175) | inline void ecs_configure(ecs &ECS) {
function ecs_configure (line 179) | inline void ecs_configure() {
function ecs_tick (line 183) | inline void ecs_tick(ecs &ECS, const double duration_ms) {
function ecs_tick (line 187) | inline void ecs_tick(const double duration_ms) {
function ecs_save (line 191) | inline void ecs_save(ecs &ECS, std::unique_ptr<std::ofstream> &lbfile) {
function ecs_save (line 195) | inline void ecs_save(std::unique_ptr<std::ofstream> &lbfile) {
function ecs_load (line 199) | inline void ecs_load(ecs &ECS, std::unique_ptr<std::ifstream> &lbfile) {
function ecs_load (line 203) | inline void ecs_load(std::unique_ptr<std::ifstream> &lbfile) {
function ecs_profile_dump (line 207) | inline std::string ecs_profile_dump(ecs &ECS) {
function ecs_profile_dump (line 211) | inline std::string ecs_profile_dump() {
FILE: rltk/ecs_impl.hpp
type rltk (line 9) | namespace rltk {
class ecs (line 12) | class ecs
method delete_entity (line 483) | inline void delete_entity(const std::size_t id) noexcept {
method delete_entity (line 496) | inline void delete_entity(entity_t &e) noexcept {
method delete_all_entities (line 503) | inline void delete_all_entities() noexcept {
method delete_component (line 513) | inline void delete_component(const std::size_t entity_id, bool delet...
method entities_with_component (line 533) | inline std::vector<entity_t *> entities_with_component() {
method all_components (line 552) | inline void all_components(typename std::function<void(entity_t &, C...
method each (line 574) | inline void each(F callback) {
method each_if (line 599) | inline void each_if(P&& predicate, F callback) {
method ecs_garbage_collect (line 621) | inline void ecs_garbage_collect() {
method emit (line 648) | inline void emit(MSG message) {
method emit_deferred (line 670) | inline void emit_deferred(MSG message) {
method add_system (line 682) | inline void add_system( Args && ... args ) {
method unset_component_mask (line 715) | inline void unset_component_mask(const std::size_t id, const std::si...
method deliver_messages (line 724) | inline void deliver_messages() {
method serialize (line 734) | void serialize(Archive & archive)
type entity_t (line 13) | struct entity_t
method entity_t (line 313) | entity_t() {
method entity_t (line 321) | entity_t(const std::size_t ID) {
method entity_t (line 357) | inline entity_t * assign(ecs &ECS, C component) {
method entity_t (line 364) | inline entity_t * assign(C component) {
method C (line 372) | inline C * component(ecs &ECS) noexcept {
method C (line 377) | inline C * component() noexcept {
method serialize (line 382) | void serialize(Archive & archive)
type base_system (line 14) | struct base_system
method configure (line 392) | virtual void configure() {}
method subscribe (line 398) | void subscribe(ecs &ECS, std::function<void(MSG &message)> destinati...
method subscribe (line 403) | void subscribe(std::function<void(MSG &message)> destination) {
method subscribe_mbox (line 408) | void subscribe_mbox(ecs &ECS) {
method subscribe_mbox (line 413) | void subscribe_mbox() {
method each_mbox (line 429) | void each_mbox(const std::function<void(const MSG&)> &func) {
type impl (line 17) | namespace impl {
type base_component_t (line 68) | struct base_component_t {
method serialize (line 74) | void serialize(Archive & archive)
type has_to_xml_identity (line 82) | struct has_to_xml_identity
type Sfinae (line 86) | struct Sfinae
type _calc_xml_identity (line 94) | struct _calc_xml_identity {
method test (line 97) | typename std::enable_if< has_to_xml_identity<Q>::value, void >::type
method test (line 104) | typename std::enable_if< !has_to_xml_identity<Q>::value, void >::type
type _ecs_check_for_to_xml (line 112) | struct _ecs_check_for_to_xml
method test (line 115) | typename std::enable_if< serial::has_to_xml_method<Q>::value, void...
method test (line 122) | typename std::enable_if< !serial::has_to_xml_method<Q>::value, voi...
type component_t (line 137) | struct component_t : public base_component_t {
method component_t (line 138) | component_t() {
method component_t (line 142) | component_t(C comp) : data(comp) {
method serialize (line 149) | void serialize(Archive & archive)
method family (line 154) | inline void family() {
method xml_identity (line 159) | inline std::string xml_identity() {
method to_xml (line 165) | inline void to_xml(xml_node * c) {
type base_component_store (line 174) | struct base_component_store {
method serialize (line 181) | void serialize(Archive & archive)
type component_store_t (line 195) | struct component_store_t : public base_component_store {
method erase_by_entity_id (line 198) | virtual void erase_by_entity_id(ecs &ECS, const std::size_t &id) o...
method really_delete (line 207) | virtual void really_delete() override final {
method save (line 213) | virtual void save(xml_node * xml) override final {
method size (line 221) | virtual std::size_t size() override final {
method serialize (line 226) | void serialize(Archive & archive)
type message_t (line 237) | struct message_t : public base_message_t {
method message_t (line 238) | message_t() {
method message_t (line 243) | message_t(C comp) : data(comp) {
method family (line 249) | inline void family() {
type subscription_base_t (line 258) | struct subscription_base_t {
type subscription_mailbox_t (line 263) | struct subscription_mailbox_t {
type mailbox_t (line 268) | struct mailbox_t : subscription_mailbox_t {
type subscription_holder_t (line 276) | struct subscription_holder_t : subscription_base_t {
method deliver_messages (line 281) | virtual void deliver_messages() override {
function assign (line 742) | inline void assign(ecs &ECS, entity_t &E, C component) {
function C (line 755) | inline C * component(ecs &ECS, entity_t &E) noexcept {
function subscribe (line 772) | inline void subscribe(ecs &ECS, base_system &B, std::function<void(M...
function subscribe_mbox (line 785) | inline void subscribe_mbox(ecs &ECS, base_system &B) {
function unset_component_mask (line 799) | inline void unset_component_mask(ecs &ECS, const std::size_t id, con...
type base_message_t (line 37) | struct base_message_t {
type system_profiling_t (line 42) | struct system_profiling_t {
type base_system (line 48) | struct base_system
method configure (line 392) | virtual void configure() {}
method subscribe (line 398) | void subscribe(ecs &ECS, std::function<void(MSG &message)> destinati...
method subscribe (line 403) | void subscribe(std::function<void(MSG &message)> destination) {
method subscribe_mbox (line 408) | void subscribe_mbox(ecs &ECS) {
method subscribe_mbox (line 413) | void subscribe_mbox() {
method each_mbox (line 429) | void each_mbox(const std::function<void(const MSG&)> &func) {
type impl (line 50) | namespace impl {
type base_component_t (line 68) | struct base_component_t {
method serialize (line 74) | void serialize(Archive & archive)
type has_to_xml_identity (line 82) | struct has_to_xml_identity
type Sfinae (line 86) | struct Sfinae
type _calc_xml_identity (line 94) | struct _calc_xml_identity {
method test (line 97) | typename std::enable_if< has_to_xml_identity<Q>::value, void >::type
method test (line 104) | typename std::enable_if< !has_to_xml_identity<Q>::value, void >::type
type _ecs_check_for_to_xml (line 112) | struct _ecs_check_for_to_xml
method test (line 115) | typename std::enable_if< serial::has_to_xml_method<Q>::value, void...
method test (line 122) | typename std::enable_if< !serial::has_to_xml_method<Q>::value, voi...
type component_t (line 137) | struct component_t : public base_component_t {
method component_t (line 138) | component_t() {
method component_t (line 142) | component_t(C comp) : data(comp) {
method serialize (line 149) | void serialize(Archive & archive)
method family (line 154) | inline void family() {
method xml_identity (line 159) | inline std::string xml_identity() {
method to_xml (line 165) | inline void to_xml(xml_node * c) {
type base_component_store (line 174) | struct base_component_store {
method serialize (line 181) | void serialize(Archive & archive)
type component_store_t (line 195) | struct component_store_t : public base_component_store {
method erase_by_entity_id (line 198) | virtual void erase_by_entity_id(ecs &ECS, const std::size_t &id) o...
method really_delete (line 207) | virtual void really_delete() override final {
method save (line 213) | virtual void save(xml_node * xml) override final {
method size (line 221) | virtual std::size_t size() override final {
method serialize (line 226) | void serialize(Archive & archive)
type message_t (line 237) | struct message_t : public base_message_t {
method message_t (line 238) | message_t() {
method message_t (line 243) | message_t(C comp) : data(comp) {
method family (line 249) | inline void family() {
type subscription_base_t (line 258) | struct subscription_base_t {
type subscription_mailbox_t (line 263) | struct subscription_mailbox_t {
type mailbox_t (line 268) | struct mailbox_t : subscription_mailbox_t {
type subscription_holder_t (line 276) | struct subscription_holder_t : subscription_base_t {
method deliver_messages (line 281) | virtual void deliver_messages() override {
function assign (line 742) | inline void assign(ecs &ECS, entity_t &E, C component) {
function C (line 755) | inline C * component(ecs &ECS, entity_t &E) noexcept {
function subscribe (line 772) | inline void subscribe(ecs &ECS, base_system &B, std::function<void(M...
function subscribe_mbox (line 785) | inline void subscribe_mbox(ecs &ECS, base_system &B) {
function unset_component_mask (line 799) | inline void unset_component_mask(ecs &ECS, const std::size_t id, con...
type entity_t (line 308) | struct entity_t {
method entity_t (line 313) | entity_t() {
method entity_t (line 321) | entity_t(const std::size_t ID) {
method entity_t (line 357) | inline entity_t * assign(ecs &ECS, C component) {
method entity_t (line 364) | inline entity_t * assign(C component) {
method C (line 372) | inline C * component(ecs &ECS) noexcept {
method C (line 377) | inline C * component() noexcept {
method serialize (line 382) | void serialize(Archive & archive)
type base_system (line 391) | struct base_system {
method configure (line 392) | virtual void configure() {}
method subscribe (line 398) | void subscribe(ecs &ECS, std::function<void(MSG &message)> destinati...
method subscribe (line 403) | void subscribe(std::function<void(MSG &message)> destination) {
method subscribe_mbox (line 408) | void subscribe_mbox(ecs &ECS) {
method subscribe_mbox (line 413) | void subscribe_mbox() {
method each_mbox (line 429) | void each_mbox(const std::function<void(const MSG&)> &func) {
type mailbox_system (line 441) | struct mailbox_system : public base_system {
method configure (line 442) | virtual void configure() override final {
method update (line 446) | virtual void update(const double duration_ms) override final {
class ecs (line 461) | class ecs {
method delete_entity (line 483) | inline void delete_entity(const std::size_t id) noexcept {
method delete_entity (line 496) | inline void delete_entity(entity_t &e) noexcept {
method delete_all_entities (line 503) | inline void delete_all_entities() noexcept {
method delete_component (line 513) | inline void delete_component(const std::size_t entity_id, bool delet...
method entities_with_component (line 533) | inline std::vector<entity_t *> entities_with_component() {
method all_components (line 552) | inline void all_components(typename std::function<void(entity_t &, C...
method each (line 574) | inline void each(F callback) {
method each_if (line 599) | inline void each_if(P&& predicate, F callback) {
method ecs_garbage_collect (line 621) | inline void ecs_garbage_collect() {
method emit (line 648) | inline void emit(MSG message) {
method emit_deferred (line 670) | inline void emit_deferred(MSG message) {
method add_system (line 682) | inline void add_system( Args && ... args ) {
method unset_component_mask (line 715) | inline void unset_component_mask(const std::size_t id, const std::si...
method deliver_messages (line 724) | inline void deliver_messages() {
method serialize (line 734) | void serialize(Archive & archive)
type impl (line 740) | namespace impl {
type base_component_t (line 68) | struct base_component_t {
method serialize (line 74) | void serialize(Archive & archive)
type has_to_xml_identity (line 82) | struct has_to_xml_identity
type Sfinae (line 86) | struct Sfinae
type _calc_xml_identity (line 94) | struct _calc_xml_identity {
method test (line 97) | typename std::enable_if< has_to_xml_identity<Q>::value, void >::type
method test (line 104) | typename std::enable_if< !has_to_xml_identity<Q>::value, void >::type
type _ecs_check_for_to_xml (line 112) | struct _ecs_check_for_to_xml
method test (line 115) | typename std::enable_if< serial::has_to_xml_method<Q>::value, void...
method test (line 122) | typename std::enable_if< !serial::has_to_xml_method<Q>::value, voi...
type component_t (line 137) | struct component_t : public base_component_t {
method component_t (line 138) | component_t() {
method component_t (line 142) | component_t(C comp) : data(comp) {
method serialize (line 149) | void serialize(Archive & archive)
method family (line 154) | inline void family() {
method xml_identity (line 159) | inline std::string xml_identity() {
method to_xml (line 165) | inline void to_xml(xml_node * c) {
type base_component_store (line 174) | struct base_component_store {
method serialize (line 181) | void serialize(Archive & archive)
type component_store_t (line 195) | struct component_store_t : public base_component_store {
method erase_by_entity_id (line 198) | virtual void erase_by_entity_id(ecs &ECS, const std::size_t &id) o...
method really_delete (line 207) | virtual void really_delete() override final {
method save (line 213) | virtual void save(xml_node * xml) override final {
method size (line 221) | virtual std::size_t size() override final {
method serialize (line 226) | void serialize(Archive & archive)
type message_t (line 237) | struct message_t : public base_message_t {
method message_t (line 238) | message_t() {
method message_t (line 243) | message_t(C comp) : data(comp) {
method family (line 249) | inline void family() {
type subscription_base_t (line 258) | struct subscription_base_t {
type subscription_mailbox_t (line 263) | struct subscription_mailbox_t {
type mailbox_t (line 268) | struct mailbox_t : subscription_mailbox_t {
type subscription_holder_t (line 276) | struct subscription_holder_t : subscription_base_t {
method deliver_messages (line 281) | virtual void deliver_messages() override {
function assign (line 742) | inline void assign(ecs &ECS, entity_t &E, C component) {
function C (line 755) | inline C * component(ecs &ECS, entity_t &E) noexcept {
function subscribe (line 772) | inline void subscribe(ecs &ECS, base_system &B, std::function<void(M...
function subscribe_mbox (line 785) | inline void subscribe_mbox(ecs &ECS, base_system &B) {
function unset_component_mask (line 799) | inline void unset_component_mask(ecs &ECS, const std::size_t id, con...
FILE: rltk/filesystem.hpp
type rltk (line 12) | namespace rltk {
function exists (line 14) | inline bool exists(const std::string &filename) noexcept {
FILE: rltk/font_manager.cpp
type rltk (line 10) | namespace rltk {
type font_detail (line 12) | namespace font_detail {
function split (line 14) | std::vector<std::string> split ( const std::string &str, const char ...
function bitmap_font (line 30) | bitmap_font * get_font(const std::string font_tag) {
function check_for_duplicate_font (line 39) | inline void check_for_duplicate_font(const std::string &tag) {
function check_texture_exists (line 46) | inline void check_texture_exists(const std::string &texture_tag) {
function register_font (line 52) | void register_font(const std::string font_tag, const std::string filen...
function register_font_directory (line 60) | void register_font_directory(const std::string path) {
FILE: rltk/font_manager.hpp
type rltk (line 13) | namespace rltk {
type bitmap_font (line 15) | struct bitmap_font {
method bitmap_font (line 16) | bitmap_font(const std::string tag, const int width, const int height...
FILE: rltk/fsa.hpp
class FixedSizeAllocator (line 50) | class FixedSizeAllocator
type FSA_ELEMENT (line 63) | struct FSA_ELEMENT
method FixedSizeAllocator (line 73) | FixedSizeAllocator(unsigned int MaxElements = FSA_DEFAULT_SIZE) :
method USER_TYPE (line 114) | USER_TYPE *alloc()
method free (line 160) | void free(USER_TYPE *user_data)
method Debug (line 199) | void Debug()
method USER_TYPE (line 224) | USER_TYPE *GetFirst()
method USER_TYPE (line 229) | USER_TYPE *GetNext(USER_TYPE *node)
FILE: rltk/geometry.cpp
type rltk (line 5) | namespace rltk {
function project_angle (line 11) | std::pair<int, int> project_angle(const int &x, const int &y, const do...
FILE: rltk/geometry.hpp
type rltk (line 14) | namespace rltk {
function distance2d (line 25) | inline float distance2d(const int &x1, const int &y1, const int &x2, c...
function distance2d_squared (line 35) | inline float distance2d_squared(const int &x1, const int &y1, const in...
function distance2d_manhattan (line 44) | inline float distance2d_manhattan(const int &x1, const int &y1, const ...
function distance3d (line 53) | inline float distance3d(const int &x1, const int &y1, const int &z1, c...
function distance3d_squared (line 65) | inline float distance3d_squared(const int &x1, const int &y1, const in...
function distance3d_manhattan (line 76) | inline float distance3d_manhattan(const int &x1, const int &y1, const ...
function line_func (line 88) | inline void line_func(const int &x1, const int &y1, const int &x2, con...
function line_func_3d (line 112) | void line_func_3d(const int &x1, const int &y1, const int &z1, const i...
function line_func_cancellable (line 137) | inline void line_func_cancellable(const int &x1, const int &y1, const ...
function line_func_3d_cancellable (line 160) | void line_func_3d_cancellable(const int &x1, const int &y1, const int ...
FILE: rltk/gui.cpp
type rltk (line 6) | namespace rltk {
type gui_detail (line 8) | namespace gui_detail {
function layer_t (line 96) | layer_t * gui_t::get_layer(const int handle) {
FILE: rltk/gui.hpp
type rltk (line 18) | namespace rltk {
type gui_t (line 23) | struct gui_t {
method gui_t (line 25) | gui_t(const int w, const int h) : screen_width(w), screen_height(h) {}
method check_handle_uniqueness (line 47) | inline void check_handle_uniqueness(const int handle) {
FILE: rltk/gui_control_t.cpp
type rltk (line 5) | namespace rltk {
FILE: rltk/gui_control_t.hpp
type rltk (line 17) | namespace rltk {
type gui_control_t (line 22) | struct gui_control_t {
method mouse_in_control (line 24) | virtual bool mouse_in_control(const int tx, const int ty) { return f...
type gui_static_text_t (line 33) | struct gui_static_text_t : public gui_control_t {
method gui_static_text_t (line 34) | gui_static_text_t(const int X, const int Y, const std::string txt, c...
method mouse_in_control (line 44) | virtual bool mouse_in_control(const int tx, const int ty) override {...
type gui_border_box_t (line 47) | struct gui_border_box_t : public gui_control_t {
method gui_border_box_t (line 48) | gui_border_box_t(const bool double_lines, const color_t fg, const co...
type gui_checkbox_t (line 58) | struct gui_checkbox_t : public gui_control_t {
method gui_checkbox_t (line 59) | gui_checkbox_t(const int X, const int Y, const bool is_checked, cons...
method mouse_in_control (line 83) | virtual bool mouse_in_control(const int tx, const int ty) override {
type radio (line 88) | struct radio {
type gui_radiobuttons_t (line 94) | struct gui_radiobuttons_t : public gui_control_t {
method gui_radiobuttons_t (line 95) | gui_radiobuttons_t(const int X, const int Y, const std::string headi...
method mouse_in_control (line 140) | virtual bool mouse_in_control(const int tx, const int ty) override {
type gui_hbar_t (line 148) | struct gui_hbar_t : public gui_control_t {
method gui_hbar_t (line 149) | gui_hbar_t(const int X, const int Y, const int W, const int MIN, con...
type gui_vbar_t (line 172) | struct gui_vbar_t : public gui_control_t {
method gui_vbar_t (line 173) | gui_vbar_t(const int X, const int Y, const int H, const int MIN, con...
type list_item (line 196) | struct list_item {
type gui_listbox_t (line 201) | struct gui_listbox_t : public gui_control_t {
method gui_listbox_t (line 202) | gui_listbox_t(const int X, const int Y, const int VAL, std::vector<l...
method mouse_in_control (line 245) | virtual bool mouse_in_control(const int tx, const int ty) override {
FILE: rltk/input_handler.cpp
type rltk (line 6) | namespace rltk {
type state (line 8) | namespace state {
function is_window_focused (line 15) | bool is_window_focused() {
function set_window_focus_state (line 19) | void set_window_focus_state(const bool &s) {
function reset_mouse_state (line 23) | void reset_mouse_state() {
function set_mouse_button_state (line 29) | void set_mouse_button_state(const int button, const bool state) {
function get_mouse_button_state (line 33) | bool get_mouse_button_state(const int button) {
function set_mouse_position (line 37) | void set_mouse_position(const int x, const int y) {
function get_mouse_position (line 42) | std::pair<int,int> get_mouse_position() {
function enqueue_key_pressed (line 46) | void enqueue_key_pressed(sf::Event &event) {
FILE: rltk/input_handler.hpp
type rltk (line 16) | namespace rltk {
type button (line 19) | namespace button {
type key_pressed_t (line 49) | struct key_pressed_t : base_message_t {
method key_pressed_t (line 51) | key_pressed_t() {}
method key_pressed_t (line 52) | key_pressed_t(sf::Event ev) : event(ev) {}
FILE: rltk/layer_t.cpp
type rltk (line 4) | namespace rltk {
function resize_fullscreen (line 84) | void resize_fullscreen(rltk::layer_t * l, int w, int h) {
FILE: rltk/layer_t.hpp
type rltk (line 14) | namespace rltk {
type layer_t (line 19) | struct layer_t {
method layer_t (line 21) | layer_t(const int X, const int Y, const int W, const int H, std::str...
method layer_t (line 29) | layer_t(bool sparse, const int X, const int Y, const int W, const in...
method layer_t (line 38) | layer_t(const int X, const int Y, const int W, const int H, std::fun...
method T (line 88) | T * control(const int handle) {
method gui_control_t (line 94) | gui_control_t * control(const int handle) {
method remove_control (line 100) | inline void remove_control(const int handle) {
method check_handle_uniqueness (line 104) | inline void check_handle_uniqueness(const int handle) {
method add_static_text (line 109) | inline void add_static_text(const int handle, const int x, const int...
method add_boundary_box (line 114) | inline void add_boundary_box(const int handle, const bool double_lin...
method add_checkbox (line 119) | inline void add_checkbox(const int handle, const int x, const int y,...
method add_radioset (line 124) | inline void add_radioset(const int handle, const int x, const int y,...
method add_hbar (line 129) | inline void add_hbar(const int handle, const int X, const int Y, con...
method add_vbar (line 136) | inline void add_vbar(const int handle, const int X, const int Y, con...
method add_listbox (line 143) | inline void add_listbox(const int handle, const int X, const int Y, ...
method clear_gui (line 151) | inline void clear_gui() {
FILE: rltk/path_finding.hpp
type rltk (line 17) | namespace rltk {
class map_search_node (line 23) | class map_search_node {
method map_search_node (line 27) | map_search_node() {}
method map_search_node (line 28) | map_search_node(location_t loc) : pos(loc) {}
method GoalDistanceEstimate (line 30) | float GoalDistanceEstimate(map_search_node<location_t, navigator_t> ...
method IsGoal (line 36) | bool IsGoal(map_search_node<location_t, navigator_t> &node_goal) {
method GetSuccessors (line 42) | bool GetSuccessors(AStarSearch<map_search_node<location_t, navigator...
method GetCost (line 60) | float GetCost(map_search_node<location_t, navigator_t> &successor) {
method IsSameState (line 66) | bool IsSameState(map_search_node<location_t, navigator_t> &rhs) {
type navigation_path (line 75) | struct navigation_path {
function find_path_3d (line 91) | std::shared_ptr<navigation_path<location_t>> find_path_3d(const locati...
function find_path_2d (line 152) | std::shared_ptr<navigation_path<location_t>> find_path_2d(const locati...
function find_path (line 209) | std::shared_ptr<navigation_path<location_t>> find_path(const location_...
FILE: rltk/perlin_noise.cpp
type rltk (line 8) | namespace rltk {
FILE: rltk/perlin_noise.hpp
type rltk (line 9) | namespace rltk {
class perlin_noise (line 11) | class perlin_noise {
FILE: rltk/rexspeeder.cpp
type rltk (line 7) | namespace rltk {
function make_rexception (line 15) | inline std::runtime_error make_rexception(gzFile g) {
function s_gzread (line 22) | static void s_gzread(gzFile g, voidp buf, unsigned int len)
function s_gzwrite (line 34) | static void s_gzwrite(gzFile g, voidp buf, unsigned int len)
function gzFile (line 42) | static gzFile s_gzopen(const std::string filename, const char* permiss...
type xp (line 60) | namespace xp {
FILE: rltk/rexspeeder.hpp
type rltk (line 16) | namespace rltk {
type xp (line 18) | namespace xp {
function is_transparent (line 23) | inline bool is_transparent(const rltk::vchar * tile)
function transparent_tile (line 30) | inline rltk::vchar transparent_tile() {
type rex_layer (line 34) | struct rex_layer {
method rex_layer (line 35) | rex_layer() {}
method rex_layer (line 36) | rex_layer(int width, int height)
class rex_sprite (line 49) | class rex_sprite {
method get_version (line 68) | inline int get_version() { return version; }
method get_width (line 69) | inline int get_width() { return width; }
method get_height (line 70) | inline int get_height() { return height; }
method get_num_layers (line 71) | inline int get_num_layers() { return num_layers; }
method set_tile (line 82) | inline void set_tile(int layer, int x, int y, rltk::vchar& val) { ...
method set_tile (line 85) | inline void set_tile(int layer, int i, rltk::vchar& val) { *get_ti...
FILE: rltk/rltk.cpp
type rltk (line 5) | namespace rltk {
type main_detail (line 11) | namespace main_detail {
function gui_t (line 21) | gui_t * get_gui() {
function init (line 25) | void init(const config_simple &config) {
function init (line 45) | void init(const config_simple_px &config) {
function init (line 63) | void init(const config_advanced &config) {
function run (line 88) | void run(std::function<void(double)> on_tick) {
function request_screenshot (line 162) | void request_screenshot(const std::string &filename) {
FILE: rltk/rltk.hpp
type rltk (line 26) | namespace rltk {
type config_simple_px (line 31) | struct config_simple_px {
method config_simple_px (line 32) | config_simple_px(const std::string fontpath, const int width=1024, c...
type config_simple (line 47) | struct config_simple {
method config_simple (line 48) | config_simple(const std::string fontpath, const int width_term=128, ...
type config_advanced (line 63) | struct config_advanced {
method config_advanced (line 64) | config_advanced(const std::string fontpath, const int width=1024, co...
function layer_t (line 117) | inline layer_t * layer(const int &handle) { return gui->get_layer(hand...
function virtual_terminal (line 118) | inline virtual_terminal * term(const int &handle) { return gui->get_la...
function virtual_terminal_sparse (line 119) | inline virtual_terminal_sparse * sterm(const int &handle) { return gui...
FILE: rltk/rng.cpp
type rltk (line 6) | namespace rltk {
FILE: rltk/rng.hpp
type rltk (line 12) | namespace rltk
class random_number_generator (line 15) | class random_number_generator
FILE: rltk/scaling.cpp
type rltk (line 3) | namespace rltk {
FILE: rltk/scaling.hpp
type rltk (line 3) | namespace rltk {
FILE: rltk/serialization_utils.hpp
type rltk (line 13) | namespace rltk {
type serial (line 18) | namespace serial {
function to_string (line 29) | inline std::string to_string(T val) {
function to_string (line 35) | inline std::string to_string(uint8_t val) {
function __component_to_xml (line 42) | void __component_to_xml(xml_node *c, T arg) {
type has_to_xml_method (line 47) | struct has_to_xml_method
type Sfinae (line 51) | struct Sfinae
type _component_to_xml_check_for_to_xml (line 61) | struct _component_to_xml_check_for_to_xml
method test (line 64) | typename std::enable_if< has_to_xml_method<Q>::value, void >::type
method test (line 71) | typename std::enable_if< !has_to_xml_method<Q>::value, void >::type
function _component_to_xml (line 79) | inline void _component_to_xml(xml_node * c, std::pair<const char *,T...
function _component_to_xml (line 84) | inline void _component_to_xml(xml_node * c, std::pair<const char *,r...
function _component_to_xml (line 92) | inline void _component_to_xml(xml_node * c, std::pair<const char *,r...
function _component_to_xml (line 101) | inline void _component_to_xml(xml_node *c, std::pair<const char *, s...
function _component_to_xml (line 109) | inline void _component_to_xml(xml_node *c, std::pair<const char *, s...
function _component_to_xml (line 121) | inline void _component_to_xml(xml_node *c, std::pair<const char *, s...
function _component_to_xml (line 130) | inline void _component_to_xml(xml_node *c, std::pair<const char *, s...
function _component_to_xml (line 140) | inline void _component_to_xml(xml_node * c, std::pair<const char *, ...
function _component_to_xml (line 151) | void _component_to_xml(xml_node * c, First arg, Rest... args) {
function component_to_xml (line 159) | inline void component_to_xml(xml_node * c, const T... args) {
function serialize (line 166) | inline void serialize(std::ostream &lbfile, const T &target) {
function serialize (line 170) | inline void serialize(std::ostream &lbfile, const std::string &target) {
function serialize (line 179) | inline void serialize(std::ostream &lbfile, const rltk::color_t &col) {
function serialize (line 186) | inline void serialize(std::ostream &lbfile, const std::vector<T> &vec) {
function serialize (line 194) | inline void serialize(std::ostream &lbfile, const std::vector<bool> &v...
function deserialize (line 205) | inline void deserialize(std::istream &lbfile, T &target)
function deserialize (line 210) | inline void deserialize(std::istream &lbfile, std::string &target)
function deserialize (line 224) | inline void deserialize(std::istream &lbfile, rltk::color_t &target) {
function deserialize (line 230) | inline void deserialize(std::istream &lbfile, std::vector<T> &vec) {
type gzip_file (line 241) | struct gzip_file {
method gzip_file (line 242) | gzip_file(const std::string fn, const char* perms) : filename(fn), p...
method throw_gzip_exception (line 261) | inline void throw_gzip_exception(gzFile &gzfile) {
method serialize (line 268) | inline void serialize(const T &target) {
method serialize (line 273) | inline void serialize(const std::string &target) {
method serialize (line 282) | inline void serialize(const rltk::color_t &col) {
method serialize_vector_bool (line 287) | inline void serialize_vector_bool(const std::vector<bool> &vec) {
method serialize (line 296) | inline void serialize(const std::vector<T> &vec) {
method deserialize (line 305) | inline void deserialize(T &target)
method deserialize (line 311) | inline void deserialize(std::string &target)
method deserialize (line 325) | inline void deserialize(rltk::color_t &target) {
method deserialize (line 331) | inline void deserialize(std::vector<T> &vec) {
FILE: rltk/texture.hpp
type rltk (line 14) | namespace rltk {
type texture (line 16) | struct texture {
method texture (line 17) | texture() {}
method texture (line 18) | texture(const std::string &filename) {
FILE: rltk/texture_resources.cpp
type rltk (line 6) | namespace rltk {
type texture_detail (line 8) | namespace texture_detail {
function register_texture (line 14) | void register_texture(const std::string &filename, const std::string &...
FILE: rltk/texture_resources.hpp
type rltk (line 12) | namespace rltk {
FILE: rltk/vchar.hpp
type rltk (line 12) | namespace rltk {
type vchar (line 16) | struct vchar {
method vchar (line 17) | vchar() {}
method vchar (line 18) | vchar(const uint32_t &g, const color_t &f, const color_t &b) : glyph...
method vchar (line 19) | vchar(const int &g, const color_t &f, const color_t &b) : glyph(stat...
method vchar (line 20) | vchar(const uint32_t &gly, const uint8_t &fr, const uint8_t &fg, con...
method serialize (line 28) | void serialize(Archive & archive)
FILE: rltk/virtual_terminal.cpp
type rltk (line 8) | namespace rltk {
FILE: rltk/virtual_terminal.hpp
type rltk (line 19) | namespace rltk {
type virtual_terminal (line 25) | struct virtual_terminal {
method virtual_terminal (line 34) | virtual_terminal(const std::string fontt, const int x=0, const int y...
method at (line 62) | inline int at(const int x, const int y) noexcept { return ( y * term...
method set_char (line 73) | inline void set_char(const int x, const int y, vchar target) noexcep...
method box (line 90) | inline void box(const color_t &fg = colors::WHITE, const color_t &bg...
method set_alpha (line 119) | inline void set_alpha(const uint8_t new_alpha) noexcept { alpha = ne...
method set_tint (line 124) | inline void set_tint(const color_t new_tint) noexcept { tint = new_t...
method set_offset (line 129) | inline void set_offset(int x, int y) noexcept { offset_x = x; offset...
method get_font_size (line 134) | inline std::pair<int,int> get_font_size() noexcept { return font->ch...
method get_font_tag (line 136) | inline std::string get_font_tag() noexcept { return font->texture_ta...
FILE: rltk/virtual_terminal_sparse.cpp
type rltk (line 5) | namespace rltk {
FILE: rltk/virtual_terminal_sparse.hpp
type rltk (line 20) | namespace rltk {
type xchar (line 25) | struct xchar {
method xchar (line 26) | xchar() {}
method xchar (line 27) | xchar(const int Glyph, const color_t fg, const float X, const float ...
method xchar (line 28) | xchar(const int Glyph, const color_t fg, const float X, const float ...
type virtual_terminal_sparse (line 39) | struct virtual_terminal_sparse {
method virtual_terminal_sparse (line 41) | virtual_terminal_sparse(const std::string fontt, const int x=0, cons...
method clear (line 47) | inline void clear() {
method add (line 51) | inline void add(const xchar target) {
FILE: rltk/visibility.hpp
type rltk (line 12) | namespace rltk {
type visibility_private (line 14) | namespace visibility_private {
function internal_2d_sweep (line 24) | void internal_2d_sweep(const location_t_ &position, const int &range...
function visibility_sweep_2d (line 57) | void visibility_sweep_2d(const location_t_ &position, const int &range...
FILE: rltk/xml.cpp
type rltk (line 12) | namespace rltk {
function xml_node (line 14) | xml_node * xml_node::add_node(const std::string &name) {
function erase_all (line 67) | static inline void erase_all(std::string &s, const std::string &to_rem...
function remove_xml_braces (line 75) | static inline std::string remove_xml_braces(std::string s) {
function remove_colon_value (line 81) | static inline std::string remove_colon_value(std::string s) {
FILE: rltk/xml.hpp
type rltk (line 14) | namespace rltk {
function T (line 17) | inline T from_string(const std::string &val) {
function from_string (line 25) | inline uint8_t from_string(const std::string &val) {
function from_string (line 33) | inline std::string from_string(const std::string &val) {
type xml_node (line 37) | struct xml_node {
method xml_node (line 38) | xml_node() {}
method xml_node (line 39) | xml_node(const std::string &Name) : name(Name) {}
method xml_node (line 40) | xml_node(const std::string &Name, const int Depth) : name(Name), dep...
method count (line 52) | std::size_t count() {
method count (line 60) | void count(std::size_t &count) {
method xml_node (line 67) | xml_node * find(const std::string name) {
method T (line 75) | T val(const std::string &key) {
method iterate_child (line 84) | inline void iterate_child(const std::string &name, const std::functi...
method color_t (line 91) | inline color_t color(const std::string &name) {
method vchar (line 96) | inline rltk::vchar vchar() {
type xml_writer (line 110) | struct xml_writer {
method xml_writer (line 111) | xml_writer(const std::string &fn, const std::string &root_name) : fi...
method xml_writer (line 116) | xml_writer(std::unique_ptr<std::ofstream> &&f, const std::string &ro...
method commit (line 118) | inline void commit() {
method xml_node (line 122) | inline xml_node * add_node(const std::string &name) {
type xml_reader (line 132) | struct xml_reader {
method xml_reader (line 133) | xml_reader(const std::string &fn) : filename(fn) {
method xml_reader (line 139) | xml_reader(std::unique_ptr<std::ifstream> &&f) : lbfile(std::move(f)) {
method xml_node (line 143) | inline xml_node * get() { return &root; }
Condensed preview — 64 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (323K chars).
[
{
"path": ".gitignore",
"chars": 182,
"preview": "/build/\n/.kdev4/\n/bgame.kdev4\n/build_eclipse/\n.DS_Store\nx64\nx84\n\n/RltkMaster/packages\n/RltkMaster/rltk/Debug\n/RltkMaster"
},
{
"path": "CMakeLists.txt",
"chars": 2871,
"preview": "cmake_minimum_required(VERSION 3.1)\nproject(\"rltk\")\n\nset(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} \"${PROJECT_SOURCE_DIR}/c"
},
{
"path": "CMakeSettings.json",
"chars": 2510,
"preview": "{\n // See https://go.microsoft.com//fwlink//?linkid=834763 for more information about this file.\n \"configurations\""
},
{
"path": "LICENSE",
"chars": 1083,
"preview": "Copyright (c) 2016 Bracket Productions (Herbert Wolverson)\n\nPermission is hereby granted, free of charge, to any person "
},
{
"path": "README.md",
"chars": 7385,
"preview": "# rltk : Roguelike Toolkit - Modern (C++14) SFML-based toolkit for creating roguelikes.\n\nIt's very early days, but I hop"
},
{
"path": "assets/fonts.txt",
"chars": 107,
"preview": "8x8,terminal8x8.png,8,8\n16x16,terminal16x16.png,16,16\n32x32,terminal32x32.png,32,32\n8x16,VGA8x16.png,8,16\n\n"
},
{
"path": "cmake_modules/FindSFML.cmake",
"chars": 17084,
"preview": "# This script locates the SFML library\n# ------------------------------------\n#\n# Usage\n# -----\n#\n# When you try to loca"
},
{
"path": "cmake_modules/Findcereal.cmake",
"chars": 615,
"preview": "# - Try to find Cereal lib\n#\n# This sets the following variables:\n# CEREAL_FOUND - True if Cereal was found.\n# CEREAL_IN"
},
{
"path": "examples/ex1/main.cpp",
"chars": 1730,
"preview": "/* RLTK (RogueLike Tool Kit) 1.00\n * Copyright (c) 2016-Present, Bracket Productions.\n * Licensed under the MIT license "
},
{
"path": "examples/ex10/main.cpp",
"chars": 8441,
"preview": "/* RLTK (RogueLike Tool Kit) 1.00\n * Copyright (c) 2016-Present, Bracket Productions.\n * Licensed under the MIT license "
},
{
"path": "examples/ex11/main.cpp",
"chars": 1686,
"preview": "/* RLTK (RogueLike Tool Kit) 1.00\n * Copyright (c) 2016-Present, Bracket Productions.\n * Licensed under the MIT license "
},
{
"path": "examples/ex2/main.cpp",
"chars": 3371,
"preview": "/* RLTK (RogueLike Tool Kit) 1.00\n * Copyright (c) 2016-Present, Bracket Productions.\n * Licensed under the MIT license "
},
{
"path": "examples/ex3/main.cpp",
"chars": 4905,
"preview": "/* RLTK (RogueLike Tool Kit) 1.00\n * Copyright (c) 2016-Present, Bracket Productions.\n * Licensed under the MIT license "
},
{
"path": "examples/ex4/main.cpp",
"chars": 9297,
"preview": "#include <iostream>\n/* RLTK (RogueLike Tool Kit) 1.00\n * Copyright (c) 2016-Present, Bracket Productions.\n * Licensed un"
},
{
"path": "examples/ex5/main.cpp",
"chars": 9586,
"preview": "#include <iostream>\n/* RLTK (RogueLike Tool Kit) 1.00\n * Copyright (c) 2016-Present, Bracket Productions.\n * Licensed un"
},
{
"path": "examples/ex6/main.cpp",
"chars": 12390,
"preview": "#include <iostream>\n/* RLTK (RogueLike Tool Kit) 1.00\n * Copyright (c) 2016-Present, Bracket Productions.\n * Licensed un"
},
{
"path": "examples/ex7/main.cpp",
"chars": 3928,
"preview": "/* RLTK (RogueLike Tool Kit) 1.00\n * Copyright (c) 2016-Present, Bracket Productions.\n * Licensed under the MIT license "
},
{
"path": "examples/ex8/main.cpp",
"chars": 6329,
"preview": "/* RLTK (RogueLike Tool Kit) 1.00\n * Copyright (c) 2016-Present, Bracket Productions.\n * Licensed under the MIT license "
},
{
"path": "examples/ex9/main.cpp",
"chars": 14751,
"preview": "#include <iostream>\n/* RLTK (RogueLike Tool Kit) 1.00\n * Copyright (c) 2016-Present, Bracket Productions.\n * Licensed un"
},
{
"path": "rltk/astar.hpp",
"chars": 17722,
"preview": "/*\n A* Algorithm Implementation using STL is\n Copyright (C)2001-2005 Justin Heyes-Jones\n\n Permission is given by the aut"
},
{
"path": "rltk/color_t.cpp",
"chars": 4665,
"preview": "#include \"color_t.hpp\"\n#include <cmath>\n\nusing std::min;\nusing std::max;\nusing std::fmod;\n\nnamespace rltk {\n\n// Credit: "
},
{
"path": "rltk/color_t.hpp",
"chars": 3517,
"preview": "#pragma once\n\n/* RLTK (RogueLike Tool Kit) 1.00\n * Copyright (c) 2016-Present, Bracket Productions.\n * Licensed under th"
},
{
"path": "rltk/colors.hpp",
"chars": 7463,
"preview": "#pragma once\n\n#include \"color_t.hpp\"\n\nnamespace rltk {\n\nnamespace colors {\n\nconst color_t AliceBlue(240, 248, 255);\ncons"
},
{
"path": "rltk/ecs.cpp",
"chars": 3465,
"preview": "#include \"ecs.hpp\"\n#include <cereal/types/polymorphic.hpp>\n#include <cereal/archives/binary.hpp>\n\nnamespace rltk {\n\nstd:"
},
{
"path": "rltk/ecs.hpp",
"chars": 5647,
"preview": "#pragma once\n\n#include <bitset>\n#include <vector>\n#include <iostream>\n#include <unordered_map>\n#include <unordered_set>\n"
},
{
"path": "rltk/ecs_impl.hpp",
"chars": 30515,
"preview": "#pragma once\n\n#include <cereal/cereal.hpp>\n#include <cereal/types/memory.hpp>\n#include <cereal/types/unordered_map.hpp>\n"
},
{
"path": "rltk/filesystem.hpp",
"chars": 388,
"preview": "/* RLTK (RogueLike Tool Kit) 1.00\n * Copyright (c) 2016-Present, Bracket Productions.\n * Licensed under the MIT license "
},
{
"path": "rltk/font_manager.cpp",
"chars": 2870,
"preview": "#include \"font_manager.hpp\"\n#include \"texture_resources.hpp\"\n#include <unordered_map>\n#include <stdexcept>\n#include <ios"
},
{
"path": "rltk/font_manager.hpp",
"chars": 671,
"preview": "/* RLTK (RogueLike Tool Kit) 1.00\n * Copyright (c) 2016-Present, Bracket Productions.\n * Licensed under the MIT license "
},
{
"path": "rltk/fsa.hpp",
"chars": 5635,
"preview": "/* \n\n A* Algorithm Implementation using STL is\n Copyright (C)2001-2005 Justin Heyes-Jones\n\n Permission is given by the a"
},
{
"path": "rltk/geometry.cpp",
"chars": 486,
"preview": "#include \"geometry.hpp\"\n#include <cstdlib>\n#include <cmath>\n\nnamespace rltk {\n\n/*\n * From a given point x/y, project for"
},
{
"path": "rltk/geometry.hpp",
"chars": 6282,
"preview": "#pragma once\n\n/* RLTK (RogueLike Tool Kit) 1.00\n * Copyright (c) 2016-Present, Bracket Productions.\n * Licensed under th"
},
{
"path": "rltk/gui.cpp",
"chars": 3065,
"preview": "#include \"gui.hpp\"\n#include <stdexcept>\n#include <utility>\n#include <algorithm>\n\nnamespace rltk {\n\nnamespace gui_detail "
},
{
"path": "rltk/gui.hpp",
"chars": 1783,
"preview": "/* RLTK (RogueLike Tool Kit) 1.00\n * Copyright (c) 2016-Present, Bracket Productions.\n * Licensed under the MIT license "
},
{
"path": "rltk/gui_control_t.cpp",
"chars": 3644,
"preview": "#include \"gui_control_t.hpp\"\n#include <sstream>\n#include <algorithm>\n\nnamespace rltk {\n\nvoid gui_static_text_t::render(v"
},
{
"path": "rltk/gui_control_t.hpp",
"chars": 7757,
"preview": "/* RLTK (RogueLike Tool Kit) 1.00\n * Copyright (c) 2016-Present, Bracket Productions.\n * Licensed under the MIT license "
},
{
"path": "rltk/input_handler.cpp",
"chars": 1159,
"preview": "#include \"input_handler.hpp\"\n#include \"scaling.hpp\"\n#include <array>\n#include <algorithm>\n\nnamespace rltk {\n\nnamespace s"
},
{
"path": "rltk/input_handler.hpp",
"chars": 1488,
"preview": "#pragma once\n/* RLTK (RogueLike Tool Kit) 1.00\n * Copyright (c) 2016-Present, Bracket Productions.\n * Licensed under the"
},
{
"path": "rltk/layer_t.cpp",
"chars": 2532,
"preview": "#include \"layer_t.hpp\"\n#include \"input_handler.hpp\"\n\nnamespace rltk {\n\nvoid layer_t::make_owner_draw_backing() {\n\tif (!b"
},
{
"path": "rltk/layer_t.hpp",
"chars": 6632,
"preview": "/* RLTK (RogueLike Tool Kit) 1.00\n * Copyright (c) 2016-Present, Bracket Productions.\n * Licensed under the MIT license "
},
{
"path": "rltk/path_finding.hpp",
"chars": 8962,
"preview": "#pragma once\n\n/* RLTK (RogueLike Tool Kit) 1.00\n * Copyright (c) 2016-Present, Bracket Productions.\n * Licensed under th"
},
{
"path": "rltk/perlin_noise.cpp",
"chars": 3777,
"preview": "#include \"perlin_noise.hpp\"\n#include <iostream>\n#include <cmath>\n#include <random>\n#include <numeric>\n#include <algorith"
},
{
"path": "rltk/perlin_noise.hpp",
"chars": 950,
"preview": "// THIS CLASS IS A TRANSLATION TO C++11 FROM THE REFERENCE\n// JAVA IMPLEMENTATION OF THE IMPROVED PERLIN FUNCTION (see h"
},
{
"path": "rltk/rexspeeder.cpp",
"chars": 5562,
"preview": "#include \"rexspeeder.hpp\"\nextern \"C\" {\n#include <zlib.h>\n}\n#include <stdexcept>\n\nnamespace rltk {\n\n//==================="
},
{
"path": "rltk/rexspeeder.hpp",
"chars": 3536,
"preview": "#pragma once\n/* RLTK (RogueLike Tool Kit) 1.00\n * Copyright (c) 2016-Present, Bracket Productions.\n * Licensed under the"
},
{
"path": "rltk/rltk.cpp",
"chars": 6563,
"preview": "#include \"rltk.hpp\"\n#include \"texture.hpp\"\n#include <memory>\n\nnamespace rltk {\n\nstd::unique_ptr<sf::RenderWindow> main_w"
},
{
"path": "rltk/rltk.hpp",
"chars": 4196,
"preview": "#pragma once\n/* RLTK (RogueLike Tool Kit) 1.00\n * Copyright (c) 2016-Present, Bracket Productions.\n * Licensed under the"
},
{
"path": "rltk/rng.cpp",
"chars": 904,
"preview": "#include \"rng.hpp\"\n\n#include <iostream>\n#include <time.h>\n\nnamespace rltk {\n\n int random_number_generator::fastrand()"
},
{
"path": "rltk/rng.hpp",
"chars": 507,
"preview": "#pragma once\n\n/* RLTK (RogueLike Tool Kit) 1.00\n * Copyright (c) 2016-Present, Bracket Productions.\n * Licensed under th"
},
{
"path": "rltk/scaling.cpp",
"chars": 73,
"preview": "#include \"scaling.hpp\"\n\nnamespace rltk {\n float scale_factor = 1.0f;\n}"
},
{
"path": "rltk/scaling.hpp",
"chars": 63,
"preview": "#pragma once\n\nnamespace rltk {\n extern float scale_factor;\n}"
},
{
"path": "rltk/serialization_utils.hpp",
"chars": 9622,
"preview": "#pragma once\n\n#include <fstream>\n#include <string>\n#include <vector>\n#include <zlib.h>\n#include <utility>\n#include <sstr"
},
{
"path": "rltk/texture.hpp",
"chars": 582,
"preview": "#pragma once\n/* RLTK (RogueLike Tool Kit) 1.00\n * Copyright (c) 2016-Present, Bracket Productions.\n * Licensed under the"
},
{
"path": "rltk/texture_resources.cpp",
"chars": 767,
"preview": "#include <unordered_map>\n#include <stdexcept>\n#include \"texture_resources.hpp\"\n#include \"texture.hpp\"\n\nnamespace rltk {\n"
},
{
"path": "rltk/texture_resources.hpp",
"chars": 393,
"preview": "#pragma once\n/* RLTK (RogueLike Tool Kit) 1.00\n * Copyright (c) 2016-Present, Bracket Productions.\n * Licensed under the"
},
{
"path": "rltk/vchar.hpp",
"chars": 1029,
"preview": "#pragma once\n/* RLTK (RogueLike Tool Kit) 1.00\n * Copyright (c) 2016-Present, Bracket Productions.\n * Licensed under the"
},
{
"path": "rltk/virtual_terminal.cpp",
"chars": 8845,
"preview": "#include \"virtual_terminal.hpp\"\n#include \"texture_resources.hpp\"\n#include \"scaling.hpp\"\n#include <algorithm>\n#include <s"
},
{
"path": "rltk/virtual_terminal.hpp",
"chars": 5226,
"preview": "#pragma once\n/* RLTK (RogueLike Tool Kit) 1.00\n * Copyright (c) 2016-Present, Bracket Productions.\n * Licensed under the"
},
{
"path": "rltk/virtual_terminal_sparse.cpp",
"chars": 2817,
"preview": "#include \"virtual_terminal_sparse.hpp\"\n#include \"texture_resources.hpp\"\n#include \"scaling.hpp\"\n\nnamespace rltk {\n\nvoid v"
},
{
"path": "rltk/virtual_terminal_sparse.hpp",
"chars": 2214,
"preview": "/* RLTK (RogueLike Tool Kit) 1.00\n * Copyright (c) 2016-Present, Bracket Productions.\n * Licensed under the MIT license "
},
{
"path": "rltk/visibility.hpp",
"chars": 2818,
"preview": "#pragma once\n/* RLTK (RogueLike Tool Kit) 1.00\n * Copyright (c) 2016-Present, Bracket Productions.\n * Licensed under the"
},
{
"path": "rltk/xml.cpp",
"chars": 3839,
"preview": "#include \"xml.hpp\"\n#include <stack>\n#include <algorithm> \n#include <functional> \n#include <cctype>\n#include <locale>\n#in"
},
{
"path": "rltk/xml.hpp",
"chars": 3985,
"preview": "#pragma once\n\n#include <string>\n#include <fstream>\n#include <vector>\n#include <utility>\n#include <memory>\n#include <sstr"
}
]
// ... and 1 more files (download for full content)
About this extraction
This page contains the full source code of the thebracket/rltk GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 64 files (295.8 KB), approximately 82.7k tokens, and a symbol index with 569 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.