From 6875cb5fe12061e50ac7fcd156cbca497c7ea9b5 Mon Sep 17 00:00:00 2001 From: John McCardle Date: Wed, 8 Mar 2023 23:30:00 -0500 Subject: [PATCH] Spawning & drawing entities from Python API --- README.md | 2 +- src/Components.h | 59 +++++++++++++++++++++++++++++++++++++++++++++ src/Entity.h | 13 ++++++---- src/Grid.cpp | 11 +++++++++ src/Grid.h | 3 +++ src/Item.cpp | 3 +++ src/Item.h | 13 ++++++++++ src/McRFPy_API.cpp | 57 +++++++++++++++++++++++++++++++++++++++++++ src/McRFPy_API.h | 22 +++++++++++++++-- src/PythonScene.cpp | 1 + 10 files changed, 176 insertions(+), 8 deletions(-) create mode 100644 src/Item.cpp create mode 100644 src/Item.h diff --git a/README.md b/README.md index ce0bf46..58b71e5 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ I did the r/RoguelikeDev TCOD tutorial in Python. I loved it, but I did not want * ✅ Windows / Visual Studio project * ✅ Draw Sprites * ✅ Play Sounds -* ❌ Draw UI, spawn entity from Python code +* ✅ Draw UI, spawn entity from Python code * ❌ Python AI for entities (NPCs on set paths, enemies towards player) * ❌ Walking / Collision; "Boards" (stairs / doors / walk off edge of screen) * ❌ Cutscenes - interrupt normal controls, text scroll, character portraits diff --git a/src/Components.h b/src/Components.h index 4f0603f..16aa657 100644 --- a/src/Components.h +++ b/src/Components.h @@ -1,6 +1,63 @@ #pragma once #include "Common.h" +#include "IndexSprite.h" +#include "Grid.h" +#include "Item.h" +#include "Python.h" +#include + +class CGrid +{ +public: + bool visible; + int x, y; + IndexSprite indexsprite; + Grid* grid; + CGrid(Grid* _g, int _ti, int _si, int _x, int _y, bool _v) + : visible(_v), x(_x), y(_y), grid(_g), indexsprite(_ti, _si, _x, _y, 1.0) {} +}; + +class CInventory +{ +public: + //std::list>; + int x; +}; + +class CBehavior +{ +public: + PyObject* object; + CBehavior(PyObject* p): object(p) {} +}; + +/* +class CCombatant +{ +public: + int hp; + int maxhp; +} + +class CCaster +{ +public: + int mp; + int maxmp; +} + +class CLevel +{ + int constitution; // +HP, resist effects + int strength; // +damage, block/parry + int dexterity; // +speed, dodge + int intelligence; // +MP, spell resist + int wisdom; // +damage, deflect + int luck; // crit, loot +} +*/ + /* class CTransform @@ -15,6 +72,7 @@ public: }; */ +/* class CShape { public: @@ -77,3 +135,4 @@ public: float theta_max; float dtheta_max; }; +*/ diff --git a/src/Entity.h b/src/Entity.h index d6b3c8f..9043d44 100644 --- a/src/Entity.h +++ b/src/Entity.h @@ -18,11 +18,14 @@ class Entity public: // component pointers //std::shared_ptr cTransform; - std::shared_ptr cShape; - std::shared_ptr cCollision; - std::shared_ptr cInput; - std::shared_ptr cScore; - std::shared_ptr cLifespan; + //std::shared_ptr cShape; + //std::shared_ptr cCollision; + //std::shared_ptr cInput; + //std::shared_ptr cScore; + //std::shared_ptr cLifespan; + std::shared_ptr cGrid; + std::shared_ptr cInventory; + std::shared_ptr cBehavior; //private member access functions bool isActive() const; diff --git a/src/Grid.cpp b/src/Grid.cpp index 344e264..9ed50dc 100644 --- a/src/Grid.cpp +++ b/src/Grid.cpp @@ -1,5 +1,6 @@ #include "Grid.h" #include +#include "Entity.h" GridPoint::GridPoint(): color(0, 0, 0, 0), walkable(true), tilesprite(-1), transparent(true), visible(false), discovered(false), color_overlay(0,0,0,255), tile_overlay(-1), uisprite(-1) @@ -236,6 +237,16 @@ void Grid::render(sf::RenderWindow & window) } } + + for (auto e : entities) { + auto drawent = e->cGrid->indexsprite.drawable(); + drawent.setScale(zoom, zoom); + auto pixel_pos = sf::Vector2f( + (drawent.getPosition().x*grid_size - left_spritepixels) * zoom, + (drawent.getPosition().y*grid_size - top_spritepixels) * zoom ); + drawent.setPosition(pixel_pos); + renderTexture.draw(drawent); + } // grid lines for testing & validation /* diff --git a/src/Grid.h b/src/Grid.h index 283d0aa..e23e257 100644 --- a/src/Grid.h +++ b/src/Grid.h @@ -1,5 +1,7 @@ #pragma once #include "Common.h" +//#include "Entity.h" +class Entity; // forward declare class GridPoint { @@ -35,6 +37,7 @@ public: int center_x, center_y; // center in 1.0x Pixels std::vector points; // grid visible contents + std::vector> entities; void render(sf::RenderWindow&); // draw to screen GridPoint& at(int, int); bool inBounds(int, int); diff --git a/src/Item.cpp b/src/Item.cpp new file mode 100644 index 0000000..6de77be --- /dev/null +++ b/src/Item.cpp @@ -0,0 +1,3 @@ +#include "Item.h" + +int Item::next_id; diff --git a/src/Item.h b/src/Item.h new file mode 100644 index 0000000..054df6b --- /dev/null +++ b/src/Item.h @@ -0,0 +1,13 @@ +#pragma once +#include "Common.h" +#include "Components.h" +#include "Python.h" + +class Item +{ +public: + bool stackable; + static int next_id; + std::string name; + PyObject* object; +}; diff --git a/src/McRFPy_API.cpp b/src/McRFPy_API.cpp index e0caa20..d60a1b1 100644 --- a/src/McRFPy_API.cpp +++ b/src/McRFPy_API.cpp @@ -11,6 +11,9 @@ std::list McRFPy_API::animations; std::vector McRFPy_API::soundbuffers; sf::Music McRFPy_API::music; sf::Sound McRFPy_API::sfx; +std::string McRFPy_API::input_mode; +int McRFPy_API::turn_number; +std::string McRFPy_API::active_grid; EntityManager McRFPy_API::entities; @@ -79,6 +82,15 @@ static PyMethodDef mcrfpyMethods[] = { {"playSound", McRFPy_API::_playSound, METH_VARARGS, "(int)"}, {"getMusicVolume", McRFPy_API::_getMusicVolume, METH_VARARGS, ""}, {"getSoundVolume", McRFPy_API::_getSoundVolume, METH_VARARGS, ""}, + + {"unlockPlayerInput", McRFPy_API::_unlockPlayerInput, METH_VARARGS, ""}, + {"lockPlayerInput", McRFPy_API::_lockPlayerInput, METH_VARARGS, ""}, + {"requestGridTarget", McRFPy_API::_requestGridTarget, METH_VARARGS, ""}, + {"activeGrid", McRFPy_API::_activeGrid, METH_VARARGS, ""}, + {"inputMode", McRFPy_API::_inputMode, METH_VARARGS, ""}, + {"turnNumber", McRFPy_API::_turnNumber, METH_VARARGS, ""}, + {"createEntity", McRFPy_API::_createEntity, METH_VARARGS, ""}, + {"listEntities", McRFPy_API::_listEntities, METH_VARARGS, ""}, {NULL, NULL, 0, NULL} }; @@ -851,3 +863,48 @@ PyObject* McRFPy_API::_getMusicVolume(PyObject* self, PyObject* args) { PyObject* McRFPy_API::_getSoundVolume(PyObject* self, PyObject* args) { return Py_BuildValue("f", McRFPy_API::sfx.getVolume()); } + +PyObject* McRFPy_API::_unlockPlayerInput(PyObject* self, PyObject* args) { + McRFPy_API::input_mode = "playerturn"; + Py_INCREF(Py_None); + return Py_None; +} +PyObject* McRFPy_API::_lockPlayerInput(PyObject* self, PyObject* args) { + McRFPy_API::input_mode = "computerturn"; + Py_INCREF(Py_None); + return Py_None; +} +PyObject* McRFPy_API::_requestGridTarget(PyObject* self, PyObject* args) { + const char* requestmode; + if (!PyArg_ParseTuple(args, "s", &requestmode)) return NULL; + McRFPy_API::input_mode = requestmode; + Py_INCREF(Py_None); + return Py_None; +} +PyObject* McRFPy_API::_activeGrid(PyObject* self, PyObject* args) { + return Py_BuildValue("s", McRFPy_API::active_grid.c_str()); +} +PyObject* McRFPy_API::_inputMode(PyObject* self, PyObject* args) { + return Py_BuildValue("s", McRFPy_API::input_mode.c_str()); +} +PyObject* McRFPy_API::_turnNumber(PyObject* self, PyObject* args) { + return Py_BuildValue("i", McRFPy_API::turn_number); +} +PyObject* McRFPy_API::_createEntity(PyObject* self, PyObject* args) { + const char * grid_cstr, *entity_tag; + int ti, si, x, y; + PyObject* behavior_obj; + if (!PyArg_ParseTuple(args, "ssiiii|O", &grid_cstr, &entity_tag, &ti, &si, &x, &y, &behavior_obj)) return NULL; + auto e = entities.addEntity(std::string(entity_tag)); + Grid* grid_ptr = grids[grid_cstr]; + grid_ptr->entities.push_back(e); + e->cGrid = std::make_shared(grid_ptr, ti, si, x, y, true); + e->cBehavior = std::make_shared(behavior_obj); + Py_INCREF(behavior_obj); + Py_INCREF(Py_None); + return Py_None; +} +PyObject* McRFPy_API::_listEntities(PyObject* self, PyObject* args) { + Py_INCREF(Py_None); + return Py_None; +} diff --git a/src/McRFPy_API.h b/src/McRFPy_API.h index a0d9643..e08acd9 100644 --- a/src/McRFPy_API.h +++ b/src/McRFPy_API.h @@ -52,6 +52,8 @@ public: static std::vector soundbuffers; static sf::Music music; static sf::Sound sfx; + + static std::shared_ptr player; static std::map callbacks; @@ -70,8 +72,8 @@ public: //static PyObject* _listCaptions(PyObject*, PyObject*); //static PyObject* _listButtons(PyObject*, PyObject*); - //static PyObject* _createEntity(PyObject*, PyObject*); - //static PyObject* _listEntities(PyObject*, PyObject*); + static PyObject* _createEntity(PyObject*, PyObject*); + static PyObject* _listEntities(PyObject*, PyObject*); static PyObject* _createGrid(PyObject*, PyObject*); static PyObject* _listGrids(PyObject*, PyObject*); @@ -88,6 +90,22 @@ public: static PyObject* _playSound(PyObject*, PyObject*); static PyObject* _getMusicVolume(PyObject*, PyObject*); static PyObject* _getSoundVolume(PyObject*, PyObject*); + + // allow all player actions (items, menus, movement, combat) + static PyObject* _unlockPlayerInput(PyObject*, PyObject*); + // disallow player actions (animating enemy actions) + static PyObject* _lockPlayerInput(PyObject*, PyObject*); + // prompt C++/Grid Objects to callback with a target Entity or grid space + static PyObject* _requestGridTarget(PyObject*, PyObject*); + // string for labeling the map + static std::string active_grid; + static PyObject* _activeGrid(PyObject*, PyObject*); + // string for prompting input + static std::string input_mode; + static PyObject* _inputMode(PyObject*, PyObject*); + // turn cycle + static int turn_number; + static PyObject* _turnNumber(PyObject*, PyObject*); // Jank Functionality static UIMenu* createMenu(int posx, int posy, int sizex, int sizey); diff --git a/src/PythonScene.cpp b/src/PythonScene.cpp index d6ad2ce..315aac5 100644 --- a/src/PythonScene.cpp +++ b/src/PythonScene.cpp @@ -41,6 +41,7 @@ PythonScene::PythonScene(GameEngine* g, std::string pymodule) // import pymodule and call start() McRFPy_API::executePyString("import " + pymodule); McRFPy_API::executePyString(pymodule + ".start()"); + } void PythonScene::animate() {