From 257aa3c3d2b5e700baa99ff999740a3c395073bf Mon Sep 17 00:00:00 2001 From: John McCardle Date: Sat, 4 Mar 2023 23:04:16 -0500 Subject: [PATCH] Fully python-driven scene. Lots of interaction needs testing but the broad strokes are there for mouse pan/zoom on multiple grids and any number of UIs --- src/GameEngine.cpp | 6 +- src/Grid.cpp | 2 +- src/Grid.h | 2 + src/McRFPy_API.cpp | 1 + src/McRFPy_API.h | 2 +- src/PythonScene.cpp | 159 ++++++++++++++++++++++++++++++++++++++++++++ src/PythonScene.h | 21 ++++++ src/Scene.h | 1 + 8 files changed, 191 insertions(+), 3 deletions(-) create mode 100644 src/PythonScene.cpp create mode 100644 src/PythonScene.h diff --git a/src/GameEngine.cpp b/src/GameEngine.cpp index 1599438..ea28547 100644 --- a/src/GameEngine.cpp +++ b/src/GameEngine.cpp @@ -3,6 +3,7 @@ #include "UITestScene.h" #include "ActionCode.h" #include "McRFPy_API.h" +#include "PythonScene.h" GameEngine::GameEngine() { @@ -10,18 +11,21 @@ GameEngine::GameEngine() window.create(sf::VideoMode(1024, 768), "McRogueFace Engine by John McCardle"); visible = window.getDefaultView(); window.setFramerateLimit(30); - scene = "menu"; + scene = "py"; //std::cout << "Constructing MenuScene" << std::endl; scenes["menu"] = new MenuScene(this); //std::cout << "Constructed MenuScene" < McRFPy_API::menus; std::map McRFPy_API::grids; std::map McRFPy_API::callbacks; +EntityManager McRFPy_API::entities; static PyMethodDef mcrfpyMethods[] = { {"drawSprite", McRFPy_API::_drawSprite, METH_VARARGS, diff --git a/src/McRFPy_API.h b/src/McRFPy_API.h index dc558f3..c6c896d 100644 --- a/src/McRFPy_API.h +++ b/src/McRFPy_API.h @@ -42,7 +42,7 @@ public: // Jank mode engage: let the API hold data for Python to hack on static std::map menus; - EntityManager entities; // this is also kinda good, entities not on the current grid can still act (like monsters following you through doors??) + static EntityManager entities; // this is also kinda good, entities not on the current grid can still act (like monsters following you through doors??) static std::map grids; static std::map callbacks; diff --git a/src/PythonScene.cpp b/src/PythonScene.cpp new file mode 100644 index 0000000..73edcaa --- /dev/null +++ b/src/PythonScene.cpp @@ -0,0 +1,159 @@ +#include "PythonScene.h" +#include "ActionCode.h" +#include "McRFPy_API.h" + +PythonScene::PythonScene(GameEngine* g, std::string pymodule) +: Scene(g) { + // mouse events + registerAction(ActionCode::MOUSEBUTTON + sf::Mouse::Left, "click"); + registerAction(ActionCode::MOUSEBUTTON + sf::Mouse::Left, "rclick"); + registerAction(ActionCode::MOUSEWHEEL + ActionCode::WHEEL_DEL, "wheel_up"); + registerAction(ActionCode::MOUSEWHEEL + ActionCode::WHEEL_NEG + ActionCode::WHEEL_DEL, "wheel_down"); + + // keyboard events + registerAction(ActionCode::KEY + sf::Keyboard::Q, "upleft"); + registerAction(ActionCode::KEY + sf::Keyboard::W, "up"); + registerAction(ActionCode::KEY + sf::Keyboard::E, "upright"); + registerAction(ActionCode::KEY + sf::Keyboard::A, "left"); + registerAction(ActionCode::KEY + sf::Keyboard::S, "down"); + registerAction(ActionCode::KEY + sf::Keyboard::D, "right"); + registerAction(ActionCode::KEY + sf::Keyboard::Z, "downleft"); + registerAction(ActionCode::KEY + sf::Keyboard::X, "wait"); + registerAction(ActionCode::KEY + sf::Keyboard::C, "downright"); + + registerAction(ActionCode::KEY + sf::Keyboard::Numpad7, "upleft"); + registerAction(ActionCode::KEY + sf::Keyboard::Numpad8, "up"); + registerAction(ActionCode::KEY + sf::Keyboard::Numpad9, "upright"); + registerAction(ActionCode::KEY + sf::Keyboard::Numpad4, "left"); + registerAction(ActionCode::KEY + sf::Keyboard::Numpad5, "wait"); + registerAction(ActionCode::KEY + sf::Keyboard::Numpad6, "right"); + registerAction(ActionCode::KEY + sf::Keyboard::Numpad1, "downleft"); + registerAction(ActionCode::KEY + sf::Keyboard::Numpad2, "down"); + registerAction(ActionCode::KEY + sf::Keyboard::Numpad3, "downright"); + + // window resize + registerAction(0, "event"); + + dragging = false; + + // import pymodule and call start() + McRFPy_API::executePyString("import " + pymodule); + McRFPy_API::executePyString(pymodule + ".start()"); +} + +void PythonScene::update() { + McRFPy_API::entities.update(); + + // check if left click is still down & mouse has moved + // continue the drag motion + if (dragging && drag_grid) { + auto mousepos = sf::Mouse::getPosition(game->getWindow()); + auto dx = mousepos.x - mouseprev.x, + dy = mousepos.y - mouseprev.y; + drag_grid->center_x += (dx / drag_grid->zoom); + drag_grid->center_y += (dy / drag_grid->zoom); + } + +} + +void PythonScene::doLClick(sf::Vector2i mousepos) { + // UI buttons get first chance + for (auto pair : McRFPy_API::menus) { + if (!pair.second->visible) continue; + for (auto b : pair.second->buttons) { + if (b.contains(mousepos)) { + McRFPy_API::doAction(b.getAction()); + return; + } + } + } + // left clicking a grid to select a square + for (auto pair : McRFPy_API::grids) { + if (!pair.second->visible) continue; + if (pair.second->contains(mousepos)) { + // grid was clicked + return; + } + } +} + +void PythonScene::doRClick(sf::Vector2i mousepos) { + // just grids for right click + for (auto pair : McRFPy_API::grids) { + if (!pair.second->visible) continue; + if (pair.second->contains(mousepos)) { + // grid was clicked + return; + } + } +} + +void PythonScene::doZoom(sf::Vector2i mousepos, int value) { + // just grids for right click + for (auto pair : McRFPy_API::grids) { + if (!pair.second->visible) continue; + if (pair.second->contains(mousepos)) { + // grid was zoomed + float new_zoom = pair.second->zoom + (value * 0.25); + if (new_zoom >= 0.5 && new_zoom <= 5.0) { + pair.second->zoom = new_zoom; + } + } + } +} + +void PythonScene::doAction(std::string name, std::string type) { + auto mousepos = sf::Mouse::getPosition(game->getWindow()); + if (ACTIONONCE("click")) { + // left click start + dragstart = mousepos; + mouseprev = mousepos; + dragging = true; + // determine the grid that contains the cursor + for (auto pair : McRFPy_API::grids) { + if (!pair.second->visible) continue; + if (pair.second->contains(mousepos)) { + // grid was clicked + drag_grid = pair.second; + } + } + } + else if (ACTIONAFTER("click")) { + // left click end + // if click ended without starting a drag event, try lclick? + if (dragstart == mousepos) { + // mouse did not move, do click + doLClick(mousepos); + } + dragging = false; + drag_grid = NULL; + } + else if (ACTIONONCE("rclick")) { + // not going to test for right click drag - just rclick + doRClick(mousepos); + } + else if (ACTIONONCE("wheel_up")) { + // try zoom in + doZoom(mousepos, 1); + } + else if (ACTIONONCE("wheel_down")) { + // try zoom out + doZoom(mousepos, -1); + } +} + +void PythonScene::sRender() { + game->getWindow().clear(); + + for (auto pair: McRFPy_API::grids) { + if (!pair.second->visible) continue; + pair.second->render(game->getWindow()); + } + + for (auto pair: McRFPy_API::menus) { + if (!pair.second->visible) continue; + pair.second->render(game->getWindow()); + } + + game->getWindow().display(); +} diff --git a/src/PythonScene.h b/src/PythonScene.h new file mode 100644 index 0000000..7bf236d --- /dev/null +++ b/src/PythonScene.h @@ -0,0 +1,21 @@ +#pragma once + +#include "Common.h" +#include "Scene.h" +#include "GameEngine.h" +#include "Grid.h" + +class PythonScene: public Scene +{ + sf::Vector2i dragstart, mouseprev; + bool dragging; + Grid* drag_grid; + void doLClick(sf::Vector2i); + void doRClick(sf::Vector2i); + void doZoom(sf::Vector2i, int); +public: + PythonScene(GameEngine*, std::string); + void update() override final; + void doAction(std::string, std::string) override final; + void sRender() override final; +}; diff --git a/src/Scene.h b/src/Scene.h index 0eec797..19a663f 100644 --- a/src/Scene.h +++ b/src/Scene.h @@ -3,6 +3,7 @@ // macros for scene input #define ACTION(X, Y) (name.compare(X) == 0 && type.compare(Y) == 0) #define ACTIONONCE(X) ((name.compare(X) == 0 && type.compare("start") == 0 && !actionState[name])) +#define ACTIONAFTER(X) ((name.compare(X) == 0 && type.compare("end") == 0 && actionState[name])) #include "Common.h" //#include "GameEngine.h"