Spawning & drawing entities from Python API

This commit is contained in:
John McCardle 2023-03-08 23:30:00 -05:00
parent 87483cc8ad
commit 6875cb5fe1
10 changed files with 176 additions and 8 deletions

View File

@ -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

View File

@ -1,6 +1,63 @@
#pragma once
#include "Common.h"
#include "IndexSprite.h"
#include "Grid.h"
#include "Item.h"
#include "Python.h"
#include <list>
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<std::shared_ptr<Item>>;
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;
};
*/

View File

@ -18,11 +18,14 @@ class Entity
public:
// component pointers
//std::shared_ptr<CTransform> cTransform;
std::shared_ptr<CShape> cShape;
std::shared_ptr<CCollision> cCollision;
std::shared_ptr<CInput> cInput;
std::shared_ptr<CScore> cScore;
std::shared_ptr<CLifespan> cLifespan;
//std::shared_ptr<CShape> cShape;
//std::shared_ptr<CCollision> cCollision;
//std::shared_ptr<CInput> cInput;
//std::shared_ptr<CScore> cScore;
//std::shared_ptr<CLifespan> cLifespan;
std::shared_ptr<CGrid> cGrid;
std::shared_ptr<CInventory> cInventory;
std::shared_ptr<CBehavior> cBehavior;
//private member access functions
bool isActive() const;

View File

@ -1,5 +1,6 @@
#include "Grid.h"
#include <cmath>
#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
/*

View File

@ -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<GridPoint> points; // grid visible contents
std::vector<std::shared_ptr<Entity>> entities;
void render(sf::RenderWindow&); // draw to screen
GridPoint& at(int, int);
bool inBounds(int, int);

3
src/Item.cpp Normal file
View File

@ -0,0 +1,3 @@
#include "Item.h"
int Item::next_id;

13
src/Item.h Normal file
View File

@ -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;
};

View File

@ -11,6 +11,9 @@ std::list<Animation*> McRFPy_API::animations;
std::vector<sf::SoundBuffer> 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<CGrid>(grid_ptr, ti, si, x, y, true);
e->cBehavior = std::make_shared<CBehavior>(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;
}

View File

@ -52,6 +52,8 @@ public:
static std::vector<sf::SoundBuffer> soundbuffers;
static sf::Music music;
static sf::Sound sfx;
static std::shared_ptr<Entity> player;
static std::map<std::string, PyObject*> 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);

View File

@ -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() {