diff --git a/camera.hpp b/camera.hpp index a1380cd..b91dd2f 100644 --- a/camera.hpp +++ b/camera.hpp @@ -4,7 +4,7 @@ struct CameraLOL { double t = 0.0; double moveSpeed = 0.1; - double rotSpeed = 0.1; + double rotSpeed = 0.06; double targetX = 0.0; double targetY = 0.0; double targetDirX = 0.0; diff --git a/constants.hpp b/constants.hpp index 858eefb..26ec1d9 100644 --- a/constants.hpp +++ b/constants.hpp @@ -1,5 +1,7 @@ #pragma once +#include + constexpr const int TEXTURE_WIDTH=256; constexpr const int TEXTURE_HEIGHT=256; constexpr const int RAY_VIEW_WIDTH=960; @@ -21,7 +23,6 @@ constexpr const bool DEBUG_BUILD=true; ////////// copied from roguish - constexpr int INV_WALL = 0; constexpr int INV_SPACE = 1; constexpr int WALL_VALUE = 1; diff --git a/gui.cpp b/gui.cpp new file mode 100644 index 0000000..d145c05 --- /dev/null +++ b/gui.cpp @@ -0,0 +1,216 @@ +#include "gui.hpp" +#include "raycaster.hpp" +#include +#include +#include +#include +#include "constants.hpp" +#include "stats.hpp" +#include "levelmanager.hpp" +#include "components.hpp" +#include "camera.hpp" +#include +#include "fsm.hpp" + +using namespace components; + +namespace gui { + FSM::FSM() : + $window(sf::VideoMode({SCREEN_WIDTH, SCREEN_HEIGHT}), "Zed's Raycaster Thing"), + $font{"./assets/text.otf"}, + $text{$font}, + $rayview($window, $textures, RAY_VIEW_WIDTH, RAY_VIEW_HEIGHT) + { + $text.setFillColor({255,255,255}); + $text.setPosition({10,10}); + $window.setVerticalSyncEnabled(VSYNC); + $window.setFramerateLimit(FRAME_LIMIT); + $textures.load_tiles(); + $textures.load_sprites(); + $rayview.init_shaders(); + } + + void FSM::event(Event ev) { + switch($state) { + FSM_STATE(State, START, ev); + FSM_STATE(State, MOVING, ev); + FSM_STATE(State, ROTATING, ev); + FSM_STATE(State, IDLE, ev); + FSM_STATE(State, END, ev); + } + } + + void FSM::START(Event ) { + // ZED: this must die + $rayview.$map = generate_map(); + $rayview.set_position(RAY_VIEW_X, RAY_VIEW_Y); + $rayview.position_camera($player.x + 0.5, $player.y + 0.5); + state(State::IDLE); + } + + void FSM::MOVING(Event ) { + if($camera.play_move($rayview)) { + state(State::IDLE); + } + } + + void FSM::ROTATING(Event ) { + if($camera.play_rotate($rayview)) { + state(State::IDLE); + } + } + + void FSM::IDLE(Event ev) { + using FU = Event; + + switch(ev) { + case FU::QUIT: + $window.close(); + state(State::END); + break; + case FU::MOVE_FORWARD: + $camera.plan_run($rayview, 1); + state(State::MOVING); + break; + case FU::MOVE_BACK: + $camera.plan_run($rayview, -1); + state(State::MOVING); + break; + case FU::MOVE_LEFT: + $camera.plan_strafe($rayview, 1); + state(State::MOVING); + break; + case FU::MOVE_RIGHT: + $camera.plan_strafe($rayview, -1); + state(State::MOVING); + break; + case FU::ROTATE_LEFT: + $camera.plan_rotate($rayview, 1); + state(State::ROTATING); + break; + case FU::ROTATE_RIGHT: + $camera.plan_rotate($rayview, -1); + state(State::ROTATING); + break; + default: + dbc::sentinel("unhandled event in IDLE"); + } + } + + void FSM::END(Event ev) { + fmt::println("END: received event after done: {}", int(ev)); + } + + void FSM::keyboard() { + while(const auto keyev = $window.pollEvent()) { + if(keyev->is()) { + event(Event::QUIT); + } + + if(const auto* key = keyev->getIf()) { + using KEY = sf::Keyboard::Scan; + switch(key->scancode) { + case KEY::W: + event(Event::MOVE_FORWARD); + break; + case KEY::S: + event(Event::MOVE_BACK); + break; + case KEY::Q: + event(Event::ROTATE_LEFT); + break; + case KEY::E: + event(Event::ROTATE_RIGHT); + break; + case KEY::D: + event(Event::MOVE_RIGHT); + break; + case KEY::A: + event(Event::MOVE_LEFT); + break; + case KEY::R: + $stats.reset(); + break; + case KEY::P: + if($rayview.$active_shader == nullptr) { + $rayview.$active_shader = &$rayview.$paused; + } else { + $rayview.$active_shader = nullptr; + } + break; + default: + break; // ignored + } + } + } + } + + void FSM::draw_weapon() { + auto weapon = $rayview.$textures.sword.sprite; + weapon->setPosition({SCREEN_WIDTH/2, SCREEN_HEIGHT/2}); + weapon->setRotation(sf::degrees($rotation)); + $window.draw(*weapon); + } + + void FSM::draw_gui() { + sf::RectangleShape rect({SCREEN_WIDTH - RAY_VIEW_WIDTH, SCREEN_HEIGHT}); + + rect.setPosition({0,0}); + rect.setFillColor({50, 50, 50}); + $window.draw(rect); + + $text.setString( + fmt::format("FPS\n" + "mean:{:>8.5}\n" + "sdev: {:>8.5}\n" + "min: {:>8.5}\n" + "max: {:>8.5}\n" + "count:{:<10}\n\n" + "VSync? {}\n" + "FR Limit: {}\n" + "Debug? {}\n\n" + "Hit R to reset.\n\n" + "dir: {:>2.02},{:>2.02}\n" + "pos: {:>2.02},{:>2.02}", + $stats.mean(), $stats.stddev(), $stats.min, + $stats.max, $stats.n, VSYNC, + FRAME_LIMIT, DEBUG_BUILD, $rayview.$dirX, + $rayview.$dirY, $rayview.$posX, $rayview.$posY)); + $window.draw($text); + } + + void FSM::render() { + auto start = std::chrono::high_resolution_clock::now(); + $rayview.render(); + auto end = std::chrono::high_resolution_clock::now(); + auto elapsed = std::chrono::duration(end - start); + $stats.sample(1/elapsed.count()); + + draw_gui(); + draw_weapon(); + $window.display(); + } + + void FSM::mouse() { + if(sf::Mouse::isButtonPressed(sf::Mouse::Button::Left)) { + $rayview.$anim.play(false); + $rotation = -30.0f; + } else { + $rotation = -10.0f; + } + } + + Matrix FSM::generate_map() { + auto& level = $levels.current(); + auto& tiles = level.map->tiles(); + auto& player = level.world->get_the(); + auto& player_position = level.world->get(player.entity); + $player = player_position.location; + + return $textures.convert_char_to_texture(tiles.$tile_ids); + } + + bool FSM::active() { + return !in_state(State::END); + } +} diff --git a/gui.hpp b/gui.hpp new file mode 100644 index 0000000..8f70a43 --- /dev/null +++ b/gui.hpp @@ -0,0 +1,67 @@ +#pragma once +#include "raycaster.hpp" +#include +#include +#include +#include +#include "constants.hpp" +#include "stats.hpp" +#include "levelmanager.hpp" +#include "components.hpp" +#include "camera.hpp" +#include +#include "fsm.hpp" + +namespace gui { + enum class State { + START, + MOVING, + ROTATING, + IDLE, + END + }; + + enum class Event { + STARTED, + TICK, + MOVE_FORWARD, + MOVE_BACK, + MOVE_LEFT, + MOVE_RIGHT, + ROTATE_LEFT, + ROTATE_RIGHT, + QUIT + }; + + class FSM : public DeadSimpleFSM { + public: + float $rotation = -30.0f; + Point $player{0,0}; + LevelManager $levels; + sf::RenderWindow $window; + CameraLOL $camera; + sf::Font $font; + sf::Text $text; + Stats $stats; + TexturePack $textures; + Raycaster $rayview; + + FSM(); + + void event(Event ev); + + void START(Event ); + void MOVING(Event ); + void ROTATING(Event ); + void IDLE(Event ev); + void END(Event ev); + + void keyboard(); + void draw_weapon(); + void draw_gui(); + void render(); + void mouse(); + Matrix generate_map(); + bool active(); + }; +} diff --git a/main.cpp b/main.cpp index ce40c2c..a42eaa9 100644 --- a/main.cpp +++ b/main.cpp @@ -1,264 +1,20 @@ -#include "raycaster.hpp" -#include -#include -#include -#include -#include "constants.hpp" -#include "stats.hpp" -#include "levelmanager.hpp" -#include "components.hpp" -#include "camera.hpp" -#include -#define FSM_DEBUG 1 -#include "fsm.hpp" - -using namespace components; - -void draw_gui(sf::RenderWindow &window, Raycaster &rayview, sf::Text &text, Stats &stats) { - sf::RectangleShape rect({SCREEN_WIDTH - RAY_VIEW_WIDTH, SCREEN_HEIGHT}); - - rect.setPosition({0,0}); - rect.setFillColor({50, 50, 50}); - window.draw(rect); - - text.setString( - fmt::format("FPS\n" - "mean:{:>8.5}\n" - "sdev: {:>8.5}\n" - "min: {:>8.5}\n" - "max: {:>8.5}\n" - "count:{:<10}\n\n" - "VSync? {}\n" - "FR Limit: {}\n" - "Debug? {}\n\n" - "Hit R to reset.\n\n" - "dir: {:>2.02},{:>2.02}\n" - "pos: {:>2.02},{:>2.02}", - stats.mean(), stats.stddev(), stats.min, - stats.max, stats.n, VSYNC, - FRAME_LIMIT, DEBUG_BUILD, rayview.$dirX, - rayview.$dirY, rayview.$posX, rayview.$posY)); - window.draw(text); -} - -Matrix generate_map(TexturePack &textures, GameLevel &level, Point &player_out) { - auto &tiles = level.map->tiles(); - auto &player = level.world->get_the(); - auto &player_position = level.world->get(player.entity); - player_out = player_position.location; - - return textures.convert_char_to_texture(tiles.$tile_ids); -} - -void draw_weapon(sf::RenderWindow &window, sf::Sprite &weapon, float rotation) { - weapon.setPosition({SCREEN_WIDTH/2,SCREEN_HEIGHT/2}); - weapon.setRotation(sf::degrees(rotation)); - window.draw(weapon); -} - -enum class MainState { - START, - MOVING, - ROTATING, - IDLE -}; - -enum class MainEvent { - STARTED, - TICK, - MOVE_FORWARD, - MOVE_BACK, - MOVE_LEFT, - MOVE_RIGHT, - ROTATE_LEFT, - ROTATE_RIGHT, - QUIT -}; - -class MainFSM : public DeadSimpleFSM { - public: - sf::RenderWindow& $window; - Raycaster& $rayview; - CameraLOL $camera; - - MainFSM(sf::RenderWindow &window, Raycaster &rayview) : - $window(window), - $rayview(rayview) { } - - void event(MainEvent ev) { - switch($state) { - FSM_STATE(MainState, START, ev); - FSM_STATE(MainState, MOVING, ev); - FSM_STATE(MainState, ROTATING, ev); - FSM_STATE(MainState, IDLE, ev); - } - } - - void START(MainEvent ) { - state(MainState::IDLE); - } - - void MOVING(MainEvent ) { - if($camera.play_move($rayview)) { - state(MainState::IDLE); - } - } - - void ROTATING(MainEvent ) { - if($camera.play_rotate($rayview)) { - state(MainState::IDLE); - } - } - - void IDLE(MainEvent ev) { - using FU = MainEvent; - - switch(ev) { - case FU::QUIT: - $window.close(); - break; - case FU::MOVE_FORWARD: - $camera.plan_run($rayview, 1); - state(MainState::MOVING); - break; - case FU::MOVE_BACK: - $camera.plan_run($rayview, -1); - state(MainState::MOVING); - break; - case FU::MOVE_LEFT: - $camera.plan_strafe($rayview, 1); - state(MainState::MOVING); - break; - case FU::MOVE_RIGHT: - $camera.plan_strafe($rayview, -1); - state(MainState::MOVING); - break; - case FU::ROTATE_LEFT: - $camera.plan_rotate($rayview, 1); - state(MainState::ROTATING); - break; - case FU::ROTATE_RIGHT: - $camera.plan_rotate($rayview, -1); - state(MainState::ROTATING); - break; - default: - dbc::sentinel("unhandled event in IDLE"); - } - } - - void keyboard() { - while(const auto keyev = $window.pollEvent()) { - if(keyev->is()) { - event(MainEvent::QUIT); - } - - if(const auto* key = keyev->getIf()) { - using KEY = sf::Keyboard::Scan; - switch(key->scancode) { - case KEY::W: - event(MainEvent::MOVE_FORWARD); - break; - case KEY::S: - event(MainEvent::MOVE_BACK); - break; - case KEY::Q: - event(MainEvent::ROTATE_LEFT); - break; - case KEY::E: - event(MainEvent::ROTATE_RIGHT); - break; - case KEY::D: - event(MainEvent::MOVE_RIGHT); - break; - case KEY::A: - event(MainEvent::MOVE_LEFT); - break; - default: - break; // ignored - } - } - } - } -}; - +#include "gui.hpp" int main() { - sf::RenderWindow window(sf::VideoMode({SCREEN_WIDTH, SCREEN_HEIGHT}), "Zed's Ray Caster Game Thing"); - - sf::Font font{"./assets/text.otf"}; - sf::Text text{font}; - text.setFillColor({255,255,255}); - text.setPosition({10,10}); - - Point player{0, 0}; - LevelManager levels; - GameLevel &cur_level = levels.current(); - - TexturePack textures; - textures.load_tiles(); - textures.load_sprites(); - - auto map = generate_map(textures, cur_level, player); - - Point evil_eye_1, evil_eye_2; - dbc::check(cur_level.map->place_entity(1, evil_eye_1), "failed to place enemy 1"); - dbc::check(cur_level.map->place_entity(2, evil_eye_2), "failed to place enemy 2"); - - Raycaster rayview(window, textures, map, RAY_VIEW_WIDTH, RAY_VIEW_HEIGHT); - rayview.init_shaders(); + gui::FSM main; + main.event(gui::Event::STARTED); - rayview.set_position(RAY_VIEW_X, RAY_VIEW_Y); - rayview.position_camera(player.x + 0.5, player.y + 0.5); + while(main.active()) { + main.render(); - rayview.position_sprite(evil_eye_1, "evil_eye"); - rayview.position_sprite(evil_eye_2, "evil_eye"); - - float rotation = -30.0f; - Stats stats; - - window.setVerticalSyncEnabled(VSYNC); - window.setFramerateLimit(FRAME_LIMIT); - - MainFSM fsm(window, rayview); - fsm.event(MainEvent::STARTED); - - while(window.isOpen()) { - auto start = std::chrono::high_resolution_clock::now(); - rayview.render(); - auto end = std::chrono::high_resolution_clock::now(); - auto elapsed = std::chrono::duration(end - start); - stats.sample(1/elapsed.count()); - - auto weapon_sprite_ptr = rayview.$textures.sword.sprite; - draw_gui(window, rayview, text, stats); - draw_weapon(window, *weapon_sprite_ptr, rotation); - window.display(); - - if(fsm.in_state(MainState::IDLE)) { - fsm.keyboard(); + // ZED: need to sort out how to deal with this in the FSM + if(main.in_state(gui::State::IDLE)) { + main.keyboard(); } else{ - fsm.event(MainEvent::TICK); + main.event(gui::Event::TICK); } - if(sf::Keyboard::isKeyPressed(sf::Keyboard::Key::P)) { - if(rayview.$active_shader == nullptr) { - rayview.$active_shader = &rayview.$paused; - } else { - rayview.$active_shader = nullptr; - } - } - - if(sf::Keyboard::isKeyPressed(sf::Keyboard::Key::R)) { - rayview.position_camera(player.x + 0.5, player.y + 0.5); - stats.reset(); - } - - if(sf::Mouse::isButtonPressed(sf::Mouse::Button::Left)) { - rayview.$anim.play(false); - rotation = -30.0f; - } else { - rotation = -10.0f; - } + main.mouse(); } return 0; diff --git a/meson.build b/meson.build index cbf6132..5324b24 100644 --- a/meson.build +++ b/meson.build @@ -47,6 +47,7 @@ sources = [ 'config.cpp', 'dbc.cpp', 'devices.cpp', + 'gui.cpp', 'inventory.cpp', 'levelmanager.cpp', 'lights.cpp', diff --git a/raycaster.cpp b/raycaster.cpp index 1606296..6c5ba38 100644 --- a/raycaster.cpp +++ b/raycaster.cpp @@ -27,13 +27,12 @@ inline uint32_t dumb_lighting(uint32_t pixel, double distance) { return conv.as_int; } -Raycaster::Raycaster(sf::RenderWindow& window, TexturePack &textures, Matrix &map, int width, int height) : +Raycaster::Raycaster(sf::RenderWindow& window, TexturePack &textures, int width, int height) : $textures(textures), $view_texture({(unsigned int)width, (unsigned int)height}), $view_sprite($view_texture), $width(width), $height(height), $window(window), - $map(map), ZBuffer(width), $anim(256, 256, 10, "assets/monster-1.ogg") { diff --git a/raycaster.hpp b/raycaster.hpp index 2a013ae..c1a7056 100644 --- a/raycaster.hpp +++ b/raycaster.hpp @@ -41,7 +41,7 @@ struct Raycaster { int $width; int $height; sf::RenderWindow& $window; - Matrix& $map; + Matrix $map; SpatialMap $collision; std::vector $sprites; std::vector ZBuffer; // width @@ -49,7 +49,7 @@ struct Raycaster { sf::Shader $paused; sf::Shader* $active_shader = nullptr; - Raycaster(sf::RenderWindow& window, TexturePack &textures, Matrix &map, int width, int height); + Raycaster(sf::RenderWindow& window, TexturePack &textures, int width, int height); void draw_pixel_buffer(); void clear();