diff --git a/main.cpp b/main.cpp index 6d75ba0..2293a06 100644 --- a/main.cpp +++ b/main.cpp @@ -7,6 +7,7 @@ #include "stats.hpp" #include "levelmanager.hpp" #include "components.hpp" +#include using namespace components; @@ -38,6 +39,100 @@ void draw_weapon(sf::RenderWindow &window, sf::Sprite &weapon, float rotation) { window.draw(weapon); } +enum MoveState { + MOVE, + ROTATE, + STRAFE, + IDLE +}; + +struct CameraLOL { + double t = 0.0; + double moveSpeed = 0.1; + double rotSpeed = 0.1; + double targetX = 0.0; + double targetY = 0.0; + int targetDir = 0; + double targetDirX = 0.0; + double targetDirY = 0.0; + double targetPlaneX = 0.0; + double targetPlaneY = 0.0; + + void plan_run(Raycaster &rayview, int dir) { + t = 0.0; + targetX = rayview.$posX + int(rayview.$dirX * 1.5 * dir); + targetY = rayview.$posY + int(rayview.$dirY * 1.5 * dir); + targetDir = dir; + } + + bool lerp_run(Raycaster &rayview) { + t += moveSpeed; + rayview.$posX = std::lerp(rayview.$posX, targetX, t); + rayview.$posY = std::lerp(rayview.$posY, targetY, t); + return t >= 1.0; + } + + void plan_rotate(Raycaster &rayview, int dir) { + t = 0.0; + double angle_dir = std::numbers::pi * 0.5 * dir; + + targetDirX = rayview.$dirX * cos(angle_dir) - rayview.$dirY * sin(angle_dir); + targetDirY = rayview.$dirX * sin(angle_dir) + rayview.$dirY * cos(angle_dir); + + targetPlaneX = rayview.$planeX * cos(angle_dir) - rayview.$planeY * sin(angle_dir); + targetPlaneY = rayview.$planeX * sin(angle_dir) + rayview.$planeY * cos(angle_dir); + + targetDir = dir; + } + + bool lerp_rotate(Raycaster &rayview) { + t += rotSpeed; + rayview.$dirX = std::lerp(rayview.$dirX, targetDirX, t); + rayview.$dirY = std::lerp(rayview.$dirY, targetDirY, t); + rayview.$planeX = std::lerp(rayview.$planeX, targetPlaneX, t); + rayview.$planeY = std::lerp(rayview.$planeY, targetPlaneY, t); + + return t > 1.0; + } +}; + + +inline void handle_window_events(sf::RenderWindow &window, Raycaster &rayview, + MoveState &state, CameraLOL &camera) +{ + while(const auto event = window.pollEvent()) { + if(event->is()) { + window.close(); + } + + if(const auto* key = event->getIf()) { + if(key->scancode == sf::Keyboard::Scan::W) { + camera.plan_run(rayview, 1); + state = MOVE; + } else if(key->scancode == sf::Keyboard::Scan::S) { + camera.plan_run(rayview, -1); + state = MOVE; + } + + if(key->scancode == sf::Keyboard::Scan::D) { + camera.plan_rotate(rayview, -1); + state = ROTATE; + } else if(key->scancode == sf::Keyboard::Scan::A) { + camera.plan_rotate(rayview, 1); + state = ROTATE; + } + } + } + + if(sf::Keyboard::isKeyPressed(sf::Keyboard::Key::P)) { + if(rayview.$active_shader == nullptr) { + rayview.$active_shader = &rayview.$paused; + } else { + rayview.$active_shader = nullptr; + } + } +} + int main() { sf::RenderWindow window(sf::VideoMode({SCREEN_WIDTH, SCREEN_HEIGHT}), "Zed's Ray Caster Game Thing"); @@ -56,21 +151,18 @@ int main() { auto map = generate_map(textures, cur_level, player); - Point evil_eye_pos{player.x+1, player.y+1}; + 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.set_position(RAY_VIEW_X, RAY_VIEW_Y); - rayview.position_camera(player.x, player.y); rayview.init_shaders(); - DinkyECS::Entity evil_ent = rayview.position_sprite(evil_eye_pos, "evil_eye"); - double moveSpeed = 0.1; - double rotSpeed = 0.1; + rayview.set_position(RAY_VIEW_X, RAY_VIEW_Y); + rayview.position_camera(player.x + 0.5, player.y + 0.5); - const auto onClose = [&window](const sf::Event::Closed&) - { - window.close(); - }; + rayview.position_sprite(evil_eye_1, "evil_eye"); + rayview.position_sprite(evil_eye_2, "evil_eye"); float rotation = -30.0f; Stats stats; @@ -78,8 +170,8 @@ int main() { window.setVerticalSyncEnabled(VSYNC); window.setFramerateLimit(FRAME_LIMIT); - double new_x = evil_eye_pos.x+0.1; - double new_y = evil_eye_pos.y+0.1; + MoveState state = IDLE; + CameraLOL camera; while(window.isOpen()) { auto start = std::chrono::high_resolution_clock::now(); @@ -93,45 +185,32 @@ int main() { draw_weapon(window, *weapon_sprite_ptr, rotation); window.display(); - if(sf::Keyboard::isKeyPressed(sf::Keyboard::Key::W)) { - rayview.run(moveSpeed, 1); - } else if(sf::Keyboard::isKeyPressed(sf::Keyboard::Key::S)) { - rayview.run(moveSpeed, -1); - } - - if(sf::Keyboard::isKeyPressed(sf::Keyboard::Key::D)) { - rayview.rotate(rotSpeed, -1); - } else if(sf::Keyboard::isKeyPressed(sf::Keyboard::Key::A)) { - rayview.rotate(rotSpeed, 1); + if(state == IDLE) { + handle_window_events(window, rayview, state, camera); + } else if(state == MOVE) { + if(camera.lerp_run(rayview)) { + state = IDLE; + } + } else if(state == ROTATE) { + if(camera.lerp_rotate(rayview)) { + state = IDLE; + } + } else if(state == STRAFE) { + state = IDLE; + } else { + dbc::sentinel("invalid move state."); } if(sf::Keyboard::isKeyPressed(sf::Keyboard::Key::R)) { stats.reset(); } - 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::Mouse::isButtonPressed(sf::Mouse::Button::Left)) { - new_x += 0.1; - new_y += 0.1; - rayview.$collision.move(evil_eye_pos, {size_t(new_x), size_t(new_y)}, evil_ent); - evil_eye_pos = {size_t(new_x), size_t(new_y)}; - rayview.$sprites[evil_ent].x = new_x; - rayview.$sprites[evil_ent].y = new_y; - rayview.$anim.play(false); rotation = -30.0f; } else { rotation = -10.0f; } - - window.handleEvents(onClose); } return 0; diff --git a/raycaster.cpp b/raycaster.cpp index ecf8c40..1606296 100644 --- a/raycaster.cpp +++ b/raycaster.cpp @@ -345,33 +345,9 @@ bool Raycaster::empty_space(int new_x, int new_y) { return $map[new_y][new_x] == 0; } - -void Raycaster::run(double speed, int dir) { - double speed_and_dir = speed * dir; - if(empty_space(int($posX + $dirX * speed_and_dir), int($posY))) { - $posX += $dirX * speed_and_dir; - } - - if(empty_space(int($posX), int($posY + $dirY * speed_and_dir))) { - $posY += $dirY * speed_and_dir; - } -} - -void Raycaster::rotate(double speed, int dir) { - double speed_and_dir = speed * dir; - double oldDirX = $dirX; - $dirX = $dirX * cos(speed_and_dir) - $dirY * sin(speed_and_dir); - $dirY = oldDirX * sin(speed_and_dir) + $dirY * cos(speed_and_dir); - - double oldPlaneX = $planeX; - $planeX = $planeX * cos(speed_and_dir) - $planeY * sin(speed_and_dir); - $planeY = oldPlaneX * sin(speed_and_dir) + $planeY * cos(speed_and_dir); -} - - DinkyECS::Entity Raycaster::position_sprite(Point pos, string name) { auto sprite_txt = $textures.sprite_textures[name]; - $sprites.emplace_back(pos.x, pos.y, sprite_txt); + $sprites.emplace_back(pos.x + 0.5, pos.y + 0.5, sprite_txt); DinkyECS::Entity ent = $sprites.size() - 1; $collision.insert({pos.x, pos.y}, ent); return ent; diff --git a/raycaster.hpp b/raycaster.hpp index b92b2f5..2a013ae 100644 --- a/raycaster.hpp +++ b/raycaster.hpp @@ -60,9 +60,6 @@ struct Raycaster { void render(); bool empty_space(int new_x, int new_y); - - void run(double speed, int dir); - void rotate(double speed, int dir); void position_camera(float player_x, float player_y); void set_position(int x, int y);