From 36d4f4741cd2559362de7e64820ca4b29b022121 Mon Sep 17 00:00:00 2001 From: Cara Salter Date: Sat, 7 Jan 2023 23:24:04 -0500 Subject: Initial commit --- .gitignore | 68 ++++++++++++++++++ SConstruct | 9 +++ src/frame.cpp | 216 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/frame.hpp | 76 ++++++++++++++++++++ src/main.cpp | 71 +++++++++++++++++++ src/mob.cpp | 43 ++++++++++++ src/mob.hpp | 34 +++++++++ src/noise.cpp | 100 ++++++++++++++++++++++++++ src/noise.hpp | 32 +++++++++ src/screen.cpp | 49 +++++++++++++ src/screen.hpp | 33 +++++++++ 11 files changed, 731 insertions(+) create mode 100644 .gitignore create mode 100644 SConstruct create mode 100644 src/frame.cpp create mode 100644 src/frame.hpp create mode 100644 src/main.cpp create mode 100644 src/mob.cpp create mode 100644 src/mob.hpp create mode 100644 src/noise.cpp create mode 100644 src/noise.hpp create mode 100644 src/screen.cpp create mode 100644 src/screen.hpp diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e596c2b --- /dev/null +++ b/.gitignore @@ -0,0 +1,68 @@ +# Created by https://www.toptal.com/developers/gitignore/api/scons,vim,c++ +# Edit at https://www.toptal.com/developers/gitignore?templates=scons,vim,c++ + +### C++ ### +# Prerequisites +*.d + +# Compiled Object files +*.slo +*.lo +*.o +*.obj + +# Precompiled Headers +*.gch +*.pch + +# Compiled Dynamic libraries +*.so +*.dylib +*.dll + +# Fortran module files +*.mod +*.smod + +# Compiled Static libraries +*.lai +*.la +*.a +*.lib + +# Executables +*.exe +*.out +*.app + +### SCons ### +# for projects that use SCons for building: http://http://www.scons.org/ +.sconsign.dblite + +# When configure fails, SCons outputs these +config.log +.sconf_temp + +### Vim ### +# Swap +[._]*.s[a-v][a-z] +!*.svg # comment out if you don't need vector files +[._]*.sw[a-p] +[._]s[a-rt-v][a-z] +[._]ss[a-gi-z] +[._]sw[a-p] + +# Session +Session.vim +Sessionx.vim + +# Temporary +.netrwhist +*~ +# Auto-generated tag files +tags +# Persistent undo +[._]*.un~ + +# End of https://www.toptal.com/developers/gitignore/api/scons,vim,c++ +cpp-rl* diff --git a/SConstruct b/SConstruct new file mode 100644 index 0000000..38474cf --- /dev/null +++ b/SConstruct @@ -0,0 +1,9 @@ + +envDebug = Environment(CXXFLAGS='-g') + + + +targetDebug = envDebug.Program(target = 'cpp-rl-dbg', source=Glob('src/*.cpp'), LIBS=['ncurses', 'tinfo']) + +envDebug.Default(targetDebug) + diff --git a/src/frame.cpp b/src/frame.cpp new file mode 100644 index 0000000..48b5687 --- /dev/null +++ b/src/frame.cpp @@ -0,0 +1,216 @@ +/* + * ===================================================================================== + * + * Filename: frame.cpp + * + * Description: Implementation of frames + * + * Version: 1.0 + * Created: 01/07/2023 10:11:54 PM + * Revision: none + * Compiler: gcc + * + * Author: Cara Salter (muirrum), cara@devcara.com + * Organization: + * + * ===================================================================================== + */ + +#include +#include "frame.hpp" +#include "noise.hpp" +#include + +Frame::Frame(int nr_rows, int nr_cols, int row_0, int col_0) { + _has_super = FALSE; + _super = NULL; + _w = newwin(nr_rows, nr_cols, row_0, col_0); + _height = nr_rows; + _width = nr_cols; + _row = row_0; + _col = col_0; +} + +Frame::Frame(Frame &sw, int nr_rows, int nr_cols, int row_0, int col_0) { + _has_super = TRUE; + _super = sw.win(); + + _w = derwin(sw.win(), nr_rows, nr_cols, row_0, col_0); + _height = nr_rows; + _width = nr_cols; + _row = row_0; + _col = col_0; +} + +Frame::~Frame() { + delwin(_w); +} + +// Place a mob in the window +void Frame::place_mob(Mob &x) { + mvwaddch(_w, x.row(), x.col(), x.symbol()); +} + +void Frame::place_mob(Mob &x, int row_0, int col_0) { + if ((row_0 >= 0 && row_0 < _height) && (col_0 >= 0 && col_0 < _width)) { + // Get element at target position + char target = mvwinch(_w, row_0, col_0); + if (target == '~' || target == '#' || target == 'S') { + return; + } + erase(x); + mvwaddch(_w, row_0, col_0, x.symbol()); + x.move(row_0, col_0); + } +} + +void Frame::erase(Mob &x) { + mvwaddch(_w, x.row(), x.col(), ' '); +} + +void Frame::center(Mob &x) { + if(_has_super) { + int rr = _row, cc = _col, hh, ww; + int _r = x.row() - _height/2; + int _c = x.col() - _width/2; + + getmaxyx(_super, hh, ww); + + if(_c + _width >= ww) { + int delta = ww - (_c + _width); + cc = _c + delta; + } + else { + cc = _c; + } + + if(_r +_height >= hh) { + int delta = hh - (_r +_height); + rr = _r + delta; + } + else { + rr = _r; + } + + if (_r < 0) { + rr = 0; + } + + if (_c < 0) { + cc = 0; + } + + + move(rr, cc); + } +} + +// Refresh window +void Frame::refresh() { + if (_has_super) { + touchwin(_super); + } + wrefresh(_w); +} + +// Move a window to a new position +void Frame::move(int r, int c) { + if (_has_super) { + mvderwin(_w, r, c); + _row = r; + _col = c; + ::refresh(); + } +} + +void Frame::fill_window() { + int mid_x = _width/2; + int mid_y = _height/2; + + // first region w 0s + for (int y = 0; y < mid_y; ++y) { + for(int x = 0; x < mid_x; ++x) { + mvwaddch(_w, y, x, '0'); + } + } + for (int y = 0; y < mid_y; ++y) { + for(int x = mid_x; x < _width; ++x) { + mvwaddch(_w, y, x, '1'); + } + } + for (int y = mid_y; y < _height; ++y) { + for(int x = 0; x < mid_x; ++x) { + mvwaddch(_w, y, x, '2'); + } + } + for (int y = mid_y; y < _height; ++y) { + for(int x = mid_x; x < _width; ++x) { + mvwaddch(_w, y, x, '3'); + } + } + + for (int y = 0; y < _height; ++y) { + mvwaddch(_w, y, 0, '|'); + mvwaddch(_w, y, _width - 1, '|'); + } + + for (int x = 0; x < _width; ++ x) { + mvwaddch(_w, 0, x, '-'); + mvwaddch(_w, _height - 1, x, '-'); + } +} + +void Frame::gen_Perlin(const unsigned int &seed) { + PerlinNoise pn(seed); + + for (int i = 0; i < _height; ++i) { + for (int j = 0; j < _width; ++j) { + double x = (double)j/((double)_width); + double y = (double)i/((double) _height); + + double n = pn.noise(10 * x, 10 * y, 0.8); + + // Water + if (n < 0.35) { + mvwaddch(_w, i, j, '~'); + } else if (n >= 0.35 && n < 0.6) { + // Floors + mvwaddch(_w, i, j, '.'); + } else if (n >= 0.6 && n < 0.8) { + // Walls + mvwaddch(_w, i, j, '#'); + } else { + // Ice + mvwaddch(_w, i, j, 'S'); + } + } + } +} + +WINDOW* Frame::win() { + return _w; +} + +WINDOW* Frame::super() { + return _super; +} + +bool Frame::has_super() { + return _has_super; +} + +int Frame::height() { + return _height; +} + +int Frame::width() { + return _width; +} + +int Frame::row() { + return _row; +} + +int Frame::col() { + return _col; +} diff --git a/src/frame.hpp b/src/frame.hpp new file mode 100644 index 0000000..378619e --- /dev/null +++ b/src/frame.hpp @@ -0,0 +1,76 @@ +/* + * ===================================================================================== + * + * Filename: frame.hpp + * + * Description: Abstractions around NCurses windows + * + * Version: 1.0 + * Created: 01/07/2023 09:55:52 PM + * Revision: none + * Compiler: gcc + * + * Author: Cara Salter (muirrum), cara@devcara.com + * Organization: + * + * ===================================================================================== + */ + +#pragma once + +#include + +#include "mob.hpp" + +class Frame { + // dimensions + int _height, _width; + // Position + int _row, _col; + // FALSE when root window and TRUE for a subwindow + bool _has_super; + // Pointer to an ncurses window + WINDOW* _w; + // The super-window, if exists + WINDOW* _super; + + public: + // Init with no parent + Frame(int nr_rows, int nr_cols, int row_0, int col_0); + // Init with parent window + Frame(Frame &super, int nr_rows, int nr_cols, int row_0, int col_0); + ~Frame(); + + // Get window type + bool has_super(); + + WINDOW* win(); + WINDOW *super(); + + // Get height of window + int height(); + int width(); + int row(); + int col(); + + void refresh(); + void move(int r, int c); + + // Fill a window with numbers, for debugging + // Will look like this: + // 0 | 1 + // ----- + // 2 | 3 + void fill_window(); + + void move_window(int r, int c); + + void erase(Mob &x); + // Add a mob to the window + void place_mob(Mob &x); + void place_mob(Mob &x, int row_0, int col_0); + // Center viewport around mob + void center(Mob &x); + + void gen_Perlin(const unsigned int &seed); +}; diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..7a27f82 --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,71 @@ +/* + * ===================================================================================== + * + * Filename: main.cpp + * + * Description: Entrypoint + * + * Version: 1.0 + * Created: 01/07/2023 09:36:42 PM + * Revision: none + * Compiler: gcc + * + * Author: Cara Salter (muirrum), cara@devcara.com + * Organization: + * + * ===================================================================================== + */ +#include +#include + +#include "screen.hpp" +#include "mob.hpp" +#include "frame.hpp" + +void game_loop(Frame &map, Frame &viewport, Mob &character, int ch); + +int main() { + Screen scr; + + scr.add("Welcome to the game!\nPress any key to start."); + + int ch = getch(); + + Frame game_map(2*scr.height(), 2*scr.width(), 0, 0); + + Frame viewport(game_map, scr.height(), scr.width(), 0, 0); + + Mob character('@', game_map.height()/2, game_map.width()/2); + + game_map.gen_Perlin(237); + + game_loop(game_map, viewport, character, ch); + + return 0; +} + +void game_loop(Frame &map, Frame &viewport, Mob &character, int ch) { + if (ch == 'q' || ch == 'Q') return; + + map.place_mob(character); + viewport.center(character); + viewport.refresh(); + + for(;;) { + ch = getch(); + + if (ch == 'h') { + map.place_mob(character, character.row(), character.col() -1); + } else if (ch == 'j') { + map.place_mob(character, character.row() + 1, character.col()); + } else if (ch == 'k') { + map.place_mob(character, character.row() - 1, character.col()); + } else if (ch == 'l') { + map.place_mob(character, character.row(), character.col() + 1); + } else if (ch == 'q') { + break; + } + viewport.center(character); + viewport.refresh(); + } +} diff --git a/src/mob.cpp b/src/mob.cpp new file mode 100644 index 0000000..0da7b34 --- /dev/null +++ b/src/mob.cpp @@ -0,0 +1,43 @@ +/* + * ===================================================================================== + * + * Filename: mob.cpp + * + * Description: Implements a mobile entity + * + * Version: 1.0 + * Created: 01/07/2023 10:02:44 PM + * Revision: none + * Compiler: gcc + * + * Author: Cara Salter (muirrum), cara@devcara.com + * Organization: + * + * ===================================================================================== + */ +#include +#include +#include "mob.hpp" + +Mob::Mob(char symbol, int row_0, int col_0) { + _symbol = symbol; + _row = row_0; + _col = col_0; +} + +void Mob::move(int row_0, int col_0) { + _row = row_0; + _col = col_0; +} + +int Mob::row() { + return _row; +} + +int Mob::col() { + return _col; +} + +char Mob::symbol() { + return _symbol; +} diff --git a/src/mob.hpp b/src/mob.hpp new file mode 100644 index 0000000..496a7bd --- /dev/null +++ b/src/mob.hpp @@ -0,0 +1,34 @@ +/* + * ===================================================================================== + * + * Filename: mob.hpp + * + * Description: Defines a mobile entity + * + * Version: 1.0 + * Created: 01/07/2023 09:54:14 PM + * Revision: none + * Compiler: gcc + * + * Author: Cara Salter (muirrum), cara@devcara.com + * Organization: + * + * ===================================================================================== + */ + +#pragma once +class Mob { + int _row, _col; + char _symbol; + public: + // Create a mob + Mob(char symbol, int row_0, int col_0); + // Change mob position + void move(int row_0, int col_0); + // Get character's row (y) position + int row(); + // Get mob's col (x) position + int col(); + // Get the symbol that represents this mob + char symbol(); +}; diff --git a/src/noise.cpp b/src/noise.cpp new file mode 100644 index 0000000..d91345b --- /dev/null +++ b/src/noise.cpp @@ -0,0 +1,100 @@ +/* + * ===================================================================================== + * + * Filename: noise.cpp + * + * Description: Implementation of Perlin Noise + * + * Version: 1.0 + * Created: 01/07/2023 10:55:49 PM + * Revision: none + * Compiler: gcc + * + * Author: Cara Salter (muirrum), cara@devcara.com + * Organization: + * + * ===================================================================================== + */ +#include +#include +#include +#include +#include +#include "noise.hpp" + +PerlinNoise::PerlinNoise() { + // Magic numbers... magic numbers everywhere + p = { + 151,160,137,91,90,15,131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142, + 8,99,37,240,21,10,23,190, 6,148,247,120,234,75,0,26,197,62,94,252,219,203,117, + 35,11,32,57,177,33,88,237,149,56,87,174,20,125,136,171,168, 68,175,74,165,71, + 134,139,48,27,166,77,146,158,231,83,111,229,122,60,211,133,230,220,105,92,41, + 55,46,245,40,244,102,143,54, 65,25,63,161,1,216,80,73,209,76,132,187,208, 89, + 18,169,200,196,135,130,116,188,159,86,164,100,109,198,173,186, 3,64,52,217,226, + 250,124,123,5,202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182, + 189,28,42,223,183,170,213,119,248,152, 2,44,154,163, 70,221,153,101,155,167, + 43,172,9,129,22,39,253, 19,98,108,110,79,113,224,232,178,185, 112,104,218,246, + 97,228,251,34,242,193,238,210,144,12,191,179,162,241, 81,51,145,235,249,14,239, + 107,49,192,214, 31,181,199,106,157,184, 84,204,176,115,121,50,45,127, 4,150,254, + 138,236,205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180 }; + + // Duplicate + p.insert(p.end(), p.begin(), p.end()); +} + +PerlinNoise::PerlinNoise(unsigned int seed) { + p.resize(256); + + // fill p with values from 0 to 255 + std::iota(p.begin(), p.end(), 0); + + std::default_random_engine engine(seed); + + std::shuffle(p.begin(), p.end(), engine); + + p.insert(p.end(), p.begin(), p.end()); +} + +double PerlinNoise::noise(double x, double y, double z) { + // Find the unit cube that contains the input + int X = (int) floor(x) & 255; + int Y = (int) floor(y) & 255; + int Z = (int) floor(z) & 255; + + // find relative x, y, z in cube + x -= floor(x); + y -= floor(y); + z -= floor(z); + + // Fade curves! + double u = fade(x); + double v = fade(y); + double w = fade(z); + + // hash coordinates + int A = p[X] + Y; + int AA = p[A] + Z; + int AB = p[A + 1] + Z; + int B = p[X + 1] + Y; + int BA = p[B] + Z; + int BB = p[B + 1] + Z; + + // Blend! + double res = lerp(w, lerp(v, lerp(u, grad(p[AA], x, y, z), grad(p[BA], x-1, y, z)), lerp(u, grad(p[AB], x, y-1, z), grad(p[BB], x-1, y-1, z))), lerp(v, lerp(u, grad(p[AA+1], x, y, z-1), grad(p[BA+1], x-1, y, z-1)), lerp(u, grad(p[AB+1], x, y-1, z-1), grad(p[BB+1], x-1, y-1, z-1)))); + return (res + 1.0)/2.0; +} + +double PerlinNoise::fade(double t) { + return t * t * t * (t * (t * 6 - 15) + 10); +} + +double PerlinNoise::lerp(double t, double a, double b) { + return a + t * (b - a); +} + +double PerlinNoise::grad(int hash, double x, double y, double z) { + int h = hash & 15; + double u = h < 8 ? x : y, + v = h < 4 ? y : h == 12 || h == 14 ? x : z; + return ((h & 1) == 0 ? u : -u) + ((h & 2) == 0 ? v : -v); +} diff --git a/src/noise.hpp b/src/noise.hpp new file mode 100644 index 0000000..c127e7f --- /dev/null +++ b/src/noise.hpp @@ -0,0 +1,32 @@ +/* + * ===================================================================================== + * + * Filename: noise.hpp + * + * Description: Defining Perlin Noise + * + * Version: 1.0 + * Created: 01/07/2023 10:52:51 PM + * Revision: none + * Compiler: gcc + * + * Author: Cara Salter (muirrum), cara@devcara.com + * Organization: + * + * ===================================================================================== + */ +#include +#include + +class PerlinNoise { + // permutation vector + std::vector p; + public: + PerlinNoise(); + PerlinNoise(unsigned int seed); + double noise(double x, double y, double z); + private: + double fade(double t); + double lerp(double t, double a, double b); + double grad(int hash, double x, double y, double z); +}; diff --git a/src/screen.cpp b/src/screen.cpp new file mode 100644 index 0000000..9bff98f --- /dev/null +++ b/src/screen.cpp @@ -0,0 +1,49 @@ +/* + * ===================================================================================== + * + * Filename: screen.cpp + * + * Description: Defines an NCurses screen + * + * Version: 1.0 + * Created: 01/07/2023 09:52:27 PM + * Revision: none + * Compiler: gcc + * + * Author: Cara Salter (muirrum), cara@devcara.com + * Organization: + * + * ===================================================================================== + */ + +#include +#include +#include "screen.hpp" + +Screen::Screen() { + initscr(); + clear(); + noecho(); + cbreak(); + keypad(stdscr, TRUE); + curs_set(0); + + getmaxyx(stdscr, _height, _width); +} + +Screen::~Screen() { + endwin(); +} + +// Print a message +void Screen::add(const char* message) { + printw(message); +} + +int Screen::height() { + return _height; +} + +int Screen::width() { + return _width; +} diff --git a/src/screen.hpp b/src/screen.hpp new file mode 100644 index 0000000..d9324a2 --- /dev/null +++ b/src/screen.hpp @@ -0,0 +1,33 @@ +/* + * ===================================================================================== + * + * Filename: screen.hpp + * + * Description: NCurses screen + * + * Version: 1.0 + * Created: 01/07/2023 09:52:54 PM + * Revision: none + * Compiler: gcc + * + * Author: Cara Salter (muirrum), cara@devcara.com + * Organization: + * + * ===================================================================================== + */ + + +class Screen { + int _height, _width; + public: + // Initialize NCurses + Screen(); + // Clear NCurses + ~Screen(); + // Print a message on the screen + void add(const char* message); + // Get the screen height + int height(); + // Get the screen width + int width(); +}; -- cgit v1.2.3