From 4d661e4a3ea534ed0244d124baa673ea7aa179cf Mon Sep 17 00:00:00 2001 From: Andrew Pamment Date: Sun, 20 Apr 2025 10:05:21 +1000 Subject: [PATCH] Initial Commit --- ADG5.cpp | 38 +++++++++++++++ ADG5.h | 8 +++ Actor.cpp | 10 ++++ Actor.h | 13 +++++ CMakeLists.txt | 28 +++++++++++ CMakePresets.json | 69 ++++++++++++++++++++++++++ CMakeUserPresets.json | 12 +++++ Engine.cpp | 74 ++++++++++++++++++++++++++++ Engine.h | 21 ++++++++ Map.cpp | 102 +++++++++++++++++++++++++++++++++++++++ Map.h | 26 ++++++++++ vcpkg-configuration.json | 14 ++++++ vcpkg.json | 5 ++ 13 files changed, 420 insertions(+) create mode 100644 ADG5.cpp create mode 100644 ADG5.h create mode 100644 Actor.cpp create mode 100644 Actor.h create mode 100644 CMakeLists.txt create mode 100644 CMakePresets.json create mode 100644 CMakeUserPresets.json create mode 100644 Engine.cpp create mode 100644 Engine.h create mode 100644 Map.cpp create mode 100644 Map.h create mode 100644 vcpkg-configuration.json create mode 100644 vcpkg.json diff --git a/ADG5.cpp b/ADG5.cpp new file mode 100644 index 0000000..555cb47 --- /dev/null +++ b/ADG5.cpp @@ -0,0 +1,38 @@ +// ADG5.cpp : Defines the entry point for the application. +// +#include +#include +#include "libtcod.hpp" +#include "Engine.h" +#include "ADG5.h" + +using namespace std; + +Engine *engine; + +int main(int argc, char **argv) +{ + auto console = tcod::Console(80, 50); + auto params = TCOD_ContextParams{}; + + int playerx = 40, playery = 25; + + params.console = console.get(); + params.window_title = "Andrew's Dungeon Game 5"; + params.sdl_window_flags = SDL_WINDOW_RESIZABLE; + params.vsync = true; + params.argc = argc; + params.argv = argv; + + auto context = tcod::Context(params); + engine = new Engine(&context, &console); + engine->init(); + + while (engine->update()) { + engine->render(); + } + + delete engine; + + return 0; +} diff --git a/ADG5.h b/ADG5.h new file mode 100644 index 0000000..a20e344 --- /dev/null +++ b/ADG5.h @@ -0,0 +1,8 @@ +// ADG5.h : Include file for standard system include files, +// or project specific include files. + +#pragma once + +#include + +// TODO: Reference additional headers your program requires here. diff --git a/Actor.cpp b/Actor.cpp new file mode 100644 index 0000000..4e503b1 --- /dev/null +++ b/Actor.cpp @@ -0,0 +1,10 @@ +#include "libtcod.hpp" +#include "Actor.h" + +Actor::Actor(int x, int y, std::string_view ch, const TCOD_ColorRGB& col) : + x(x), y(y), ch(ch), col(col) { +} + +void Actor::render(TCOD_Console& cons) const { + tcod::print(cons, { x, y }, ch, col, std::nullopt); +} \ No newline at end of file diff --git a/Actor.h b/Actor.h new file mode 100644 index 0000000..dbb61c1 --- /dev/null +++ b/Actor.h @@ -0,0 +1,13 @@ +#pragma once + +#include "libtcod.hpp" + +class Actor { +public: + int x, y; // position on map + std::string_view ch; // ascii code + TCOD_ColorRGB col; // color + + Actor(int x, int y, std::string_view ch, const TCOD_ColorRGB& col); + void render(TCOD_Console& cons) const; +}; \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..d81d478 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,28 @@ +# CMakeList.txt : CMake project for ADG5, include source and define +# project specific logic here. +# +cmake_minimum_required (VERSION 3.8) + +# Enable Hot Reload for MSVC compilers if supported. +if (POLICY CMP0141) + cmake_policy(SET CMP0141 NEW) + set(CMAKE_MSVC_DEBUG_INFORMATION_FORMAT "$,$>,$<$:EditAndContinue>,$<$:ProgramDatabase>>") +endif() + +project ("ADG5") + +find_package(libtcod CONFIG REQUIRED) + +# Add source to this project's executable. +add_executable (ADG5 "ADG5.cpp" "ADG5.h" "Actor.cpp" "Actor.h" "Map.h" "Map.cpp" "Engine.h" "Engine.cpp" ) + +target_link_libraries(ADG5 + PRIVATE + libtcod::libtcod +) + +if (CMAKE_VERSION VERSION_GREATER 3.12) + set_property(TARGET ADG5 PROPERTY CXX_STANDARD 20) +endif() + +# TODO: Add tests and install targets if needed. diff --git a/CMakePresets.json b/CMakePresets.json new file mode 100644 index 0000000..955bb0b --- /dev/null +++ b/CMakePresets.json @@ -0,0 +1,69 @@ +{ + "version": 3, + "configurePresets": [ + { + "name": "windows-base", + "hidden": true, + "generator": "Ninja", + "binaryDir": "${sourceDir}/out/build/${presetName}", + "installDir": "${sourceDir}/out/install/${presetName}", + "cacheVariables": { + "CMAKE_C_COMPILER": "cl.exe", + "CMAKE_CXX_COMPILER": "cl.exe" + }, + "condition": { + "type": "equals", + "lhs": "${hostSystemName}", + "rhs": "Windows" + } + }, + { + "name": "vcpkg", + "generator": "Ninja", + "binaryDir": "${sourceDir}/build", + "cacheVariables": { + "CMAKE_TOOLCHAIN_FILE": "$env{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake" + } + }, + { + "name": "x64-debug", + "displayName": "x64 Debug", + "inherits": "windows-base", + "architecture": { + "value": "x64", + "strategy": "external" + }, + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Debug" + } + }, + { + "name": "x64-release", + "displayName": "x64 Release", + "inherits": "x64-debug", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Release" + } + }, + { + "name": "x86-debug", + "displayName": "x86 Debug", + "inherits": "windows-base", + "architecture": { + "value": "x86", + "strategy": "external" + }, + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Debug" + } + }, + { + "name": "x86-release", + "displayName": "x86 Release", + "inherits": "x86-debug", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Release" + } + } + ] +} diff --git a/CMakeUserPresets.json b/CMakeUserPresets.json new file mode 100644 index 0000000..36896a1 --- /dev/null +++ b/CMakeUserPresets.json @@ -0,0 +1,12 @@ +{ + "version": 3, + "configurePresets": [ + { + "name": "default", + "inherits": "vcpkg", + "environment": { + "VCPKG_ROOT": "C:/Users/apamm/Projects/vcpkg" + } + } + ] +} \ No newline at end of file diff --git a/Engine.cpp b/Engine.cpp new file mode 100644 index 0000000..a3cb582 --- /dev/null +++ b/Engine.cpp @@ -0,0 +1,74 @@ +#include +#include "libtcod.hpp" +#include "Actor.h" +#include "Map.h" +#include "Engine.h" + + + +Engine::Engine(tcod::Context *context, tcod::Console *console) { + this->context = context; + this->console = console; + map = nullptr; + player = nullptr; +} + +void Engine::init() { + player = new Actor(40, 25, "@", TCOD_ColorRGB(255, 255, 255)); + actors.push(player); + map = new Map(80, 45); +} + +Engine::~Engine() { + actors.clearAndDelete(); + delete map; +} + +bool Engine::update() { + SDL_Event event; + while (SDL_PollEvent(&event)) { + context->convert_event_coordinates(event); + switch (event.type) { + case SDL_EVENT_KEY_DOWN: + switch (event.key.key) { + case SDLK_UP: + if (!map->isWall(player->x, player->y - 1)) + player->y--; + break; + case SDLK_DOWN: + if (!map->isWall(player->x, player->y + 1)) + player->y++; + break; + case SDLK_LEFT: + if (!map->isWall(player->x - 1, player->y)) + player->x--; + break; + case SDLK_RIGHT: + if (!map->isWall(player->x + 1, player->y)) + player->x++; + break; + default: + break; + } + break; + case SDL_EVENT_QUIT: + return false; + default: + break; + } + } + return true; +} + +void Engine::render() { + console->clear(); + // draw the map + map->render(*console); + + // draw the actors + for (Actor** iterator = actors.begin(); + iterator != actors.end(); iterator++) { + (*iterator)->render(*console); + } + context->present(*console); +} diff --git a/Engine.h b/Engine.h new file mode 100644 index 0000000..f7fe96a --- /dev/null +++ b/Engine.h @@ -0,0 +1,21 @@ +#pragma once +class Actor; +class Map; + +#include "libtcod.hpp" + +class Engine { +public: + TCODList actors; + Actor* player; + Map* map; + tcod::Context *context; + tcod::Console* console; + Engine(tcod::Context *context, tcod::Console *console); + void init(); + ~Engine(); + bool update(); + void render(); +}; + +extern Engine *engine; \ No newline at end of file diff --git a/Map.cpp b/Map.cpp new file mode 100644 index 0000000..7d350b3 --- /dev/null +++ b/Map.cpp @@ -0,0 +1,102 @@ +#include "libtcod.hpp" +#include "Map.h" +#include "Actor.h" +#include "Engine.h" + +static const int ROOM_MAX_SIZE = 12; +static const int ROOM_MIN_SIZE = 6; + +class BspListener : public ITCODBspCallback { +private: + Map& map; // a map to dig + int roomNum; // room number + int lastx = 0, lasty = 0; // center of the last room + +public: + BspListener(Map& map) : map(map), roomNum(0) {} + bool visitNode(TCODBsp* node, void* userData) { + if (node->isLeaf()) { + int x, y, w, h; + // dig a room + TCODRandom* rng = TCODRandom::getInstance(); + w = rng->getInt(ROOM_MIN_SIZE, node->w - 2); + h = rng->getInt(ROOM_MIN_SIZE, node->h - 2); + x = rng->getInt(node->x + 1, node->x + node->w - w - 1); + y = rng->getInt(node->y + 1, node->y + node->h - h - 1); + map.createRoom(roomNum == 0, x, y, x + w - 1, y + h - 1); + if (roomNum != 0) { + // dig a corridor from last room + map.dig(lastx, lasty, x + w / 2, lasty); + map.dig(x + w / 2, lasty, x + w / 2, y + h / 2); + } + lastx = x + w / 2; + lasty = y + h / 2; + roomNum++; + } + return true; + } +}; + +Map::Map(int width, int height) : width(width), height(height) { + tiles = new Tile[width * height]; + TCODBsp bsp(0, 0, width, height); + bsp.splitRecursive(NULL, 8, ROOM_MAX_SIZE, ROOM_MAX_SIZE, 1.5f, 1.5f); + BspListener listener(*this); + bsp.traverseInvertedLevelOrder(&listener, NULL); +} + +Map::~Map() { + delete[] tiles; +} + +bool Map::isWall(int x, int y) const { + return !tiles[x + y * width].canWalk; +} + +void Map::setWall(int x, int y) { + tiles[x + y * width].canWalk = false; +} + +void Map::render(TCOD_Console& cons) const { + static const TCOD_ColorRGB darkWall(0, 0, 100); + static const TCOD_ColorRGB darkGround(50, 50, 150); + for (int x = 0; x < width; x++) { + for (int y = 0; y < height; y++) { + tcod::print(cons, { x, y }, " ", std::nullopt, isWall(x, y) ? darkWall : darkGround); + } + } +} + +void Map::dig(int x1, int y1, int x2, int y2) { + if (x2 < x1) { + int tmp = x2; + x2 = x1; + x1 = tmp; + } + if (y2 < y1) { + int tmp = y2; + y2 = y1; + y1 = tmp; + } + for (int tilex = x1; tilex <= x2; tilex++) { + for (int tiley = y1; tiley <= y2; tiley++) { + tiles[tilex + tiley * width].canWalk = true; + } + } +} + +void Map::createRoom(bool first, int x1, int y1, int x2, int y2) { + dig(x1, y1, x2, y2); + if (first) { + // put the player in the first room + engine->player->x = (x1 + x2) / 2; + engine->player->y = (y1 + y2) / 2; + } + else { + TCODRandom* rng = TCODRandom::getInstance(); + if (rng->getInt(0, 3) == 0) { + engine->actors.push(new Actor((x1 + x2) / 2, (y1 + y2) / 2, "@", + TCOD_ColorRGB(255, 255, 0))); + } + } +} \ No newline at end of file diff --git a/Map.h b/Map.h new file mode 100644 index 0000000..510b98a --- /dev/null +++ b/Map.h @@ -0,0 +1,26 @@ +#pragma once +struct Tile { + bool explored; // has the player already seen this tile ? + Tile() : explored(false) {} +}; + +class Map { +public: + int width, height; + + Map(int width, int height); + ~Map(); + bool isWall(int x, int y) const; + bool isInFov(int x, int y) const; + bool isExplored(int x, int y) const; + void computeFov(); + void render(TCOD_Console& cons) const; +protected: + Tile* tiles; + friend class BspListener; + TCODMap* map; + void dig(int x1, int y1, int x2, int y2); + void createRoom(bool first, int x1, int y1, int x2, int y2); + + void setWall(int x, int y); +}; \ No newline at end of file diff --git a/vcpkg-configuration.json b/vcpkg-configuration.json new file mode 100644 index 0000000..c8a7759 --- /dev/null +++ b/vcpkg-configuration.json @@ -0,0 +1,14 @@ +{ + "default-registry": { + "kind": "git", + "baseline": "0d5cae153065957df7f382de7c1549ccc88027e5", + "repository": "https://github.com/microsoft/vcpkg" + }, + "registries": [ + { + "kind": "artifact", + "location": "https://github.com/microsoft/vcpkg-ce-catalog/archive/refs/heads/main.zip", + "name": "microsoft" + } + ] +} diff --git a/vcpkg.json b/vcpkg.json new file mode 100644 index 0000000..768eab2 --- /dev/null +++ b/vcpkg.json @@ -0,0 +1,5 @@ +{ + "dependencies": [ + "libtcod" + ] +}