Scene subclasses can now define on_key(self, key, state) methods that
receive keyboard events, matching the existing on_enter, on_exit, and
update lifecycle callbacks.
Changes:
- Rename call_on_keypress to call_on_key (consistent naming with property)
- Add triggerKeyEvent helper in McRFPy_API
- Call triggerKeyEvent from GameEngine when key_callable is not set
- Fix condition to check key_callable.isNone() (not just pointer existence)
- Handle both bound methods and instance-assigned callables
Usage:
class GameScene(mcrfpy.Scene):
def on_key(self, key, state):
if key == "Escape" and state == "end":
quit_game()
Property assignment (scene.on_key = callable) still works and takes
precedence when key_callable is set via the property setter.
Includes comprehensive test: tests/unit/scene_subclass_on_key_test.py
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
98 lines
3.4 KiB
C++
98 lines
3.4 KiB
C++
#pragma once
|
|
#include "Common.h"
|
|
#include "Python.h"
|
|
#include <list>
|
|
#include <atomic>
|
|
|
|
#include "PyFont.h"
|
|
#include "PyTexture.h"
|
|
#include "McRogueFaceConfig.h"
|
|
|
|
class GameEngine; // forward declared (circular members)
|
|
|
|
class McRFPy_API
|
|
{
|
|
private:
|
|
static const int texture_size = 16, // w & h (pixels) of one sprite in the tex
|
|
texture_width = 12, texture_height = 11, // w & h sprite/frame count
|
|
texture_sprite_count = 11 * 12; // t_width * t_height, minus blanks?
|
|
|
|
McRFPy_API();
|
|
|
|
|
|
public:
|
|
static PyObject* mcrf_module;
|
|
static std::shared_ptr<PyFont> default_font;
|
|
static std::shared_ptr<PyTexture> default_texture;
|
|
//inline static sf::Sprite sprite;
|
|
//inline static sf::Texture texture;
|
|
//static void setSpriteTexture(int);
|
|
inline static GameEngine* game;
|
|
static void api_init();
|
|
static void api_init(const McRogueFaceConfig& config);
|
|
static PyStatus init_python_with_config(const McRogueFaceConfig& config);
|
|
static void api_shutdown();
|
|
// Python API functionality - use mcrfpy.* in scripts
|
|
//static PyObject* _drawSprite(PyObject*, PyObject*);
|
|
static void REPL_device(FILE * fp, const char *filename);
|
|
static void REPL();
|
|
|
|
// Internal - used by PySceneClass_get_children()
|
|
static PyObject* _sceneUI(PyObject*, PyObject*);
|
|
|
|
// Internal - used by PySceneObject::activate()
|
|
static PyObject* _setScene(PyObject*, PyObject*);
|
|
|
|
// Note: setTimer/delTimer removed in #173 - use Timer objects instead
|
|
|
|
// #153 - Headless simulation control
|
|
static PyObject* _step(PyObject*, PyObject*);
|
|
|
|
static PyObject* _exit(PyObject*, PyObject*);
|
|
static PyObject* _setScale(PyObject*, PyObject*);
|
|
|
|
// accept keyboard input from scene
|
|
static sf::Vector2i cursor_position;
|
|
|
|
|
|
static void executeScript(std::string);
|
|
static void executePyString(std::string);
|
|
|
|
// Helper to mark scenes as needing z_index resort
|
|
static void markSceneNeedsSort();
|
|
|
|
// Name-based finding methods
|
|
static PyObject* _find(PyObject*, PyObject*);
|
|
static PyObject* _findAll(PyObject*, PyObject*);
|
|
|
|
// Profiling/metrics
|
|
static PyObject* _getMetrics(PyObject*, PyObject*);
|
|
|
|
// Benchmark logging (#104)
|
|
static PyObject* _startBenchmark(PyObject*, PyObject*);
|
|
static PyObject* _endBenchmark(PyObject*, PyObject*);
|
|
static PyObject* _logBenchmark(PyObject*, PyObject*);
|
|
|
|
// Developer console
|
|
static PyObject* _setDevConsole(PyObject*, PyObject*);
|
|
|
|
// Scene lifecycle management for Python Scene objects
|
|
static void triggerSceneChange(const std::string& from_scene, const std::string& to_scene);
|
|
static void updatePythonScenes(float dt);
|
|
static void triggerResize(int width, int height);
|
|
static void triggerKeyEvent(const std::string& key, const std::string& action);
|
|
|
|
// #151: Module-level scene property accessors
|
|
static PyObject* api_get_current_scene();
|
|
static int api_set_current_scene(PyObject* value);
|
|
static PyObject* api_get_scenes();
|
|
|
|
// #173: Module-level timer collection accessor
|
|
static PyObject* api_get_timers();
|
|
|
|
// Exception handling - signal game loop to exit on unhandled Python exceptions
|
|
static std::atomic<bool> exception_occurred;
|
|
static std::atomic<int> exit_code;
|
|
static void signalPythonException(); // Called by exception handlers
|
|
static bool shouldExit(); // Checked by game loop
|
|
};
|