Extract all grid data members and methods into GridData base class. UIGrid now inherits from both UIDrawable (rendering) and GridData (state). - GridData holds: grid dimensions, cell storage (flat/chunked), entities, spatial hash, TCOD map, FOV state, Dijkstra caches, layers, cell callbacks, children collection - GridData provides: at(), syncTCODMap/Cell(), computeFOV(), isInFOV(), layer management (add/remove/sort/getByName), initStorage() - UIGrid retains: texture, box, sprites, renderTexture, camera (center, zoom, rotation), fill_color, perspective, cell hover/click dispatch, all Python API static methods, render() Fix dangling parent_grid pointers: change UIGrid* to GridData* in GridLayer, UIGridPoint, GridChunk, ChunkManager (closes #270, closes #271, closes #277). All 258 tests pass unchanged. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
700c21ce96
commit
13d5512a41
9 changed files with 379 additions and 340 deletions
|
|
@ -9,7 +9,7 @@
|
|||
// =============================================================================
|
||||
|
||||
GridChunk::GridChunk(int chunk_x, int chunk_y, int width, int height,
|
||||
int world_x, int world_y, UIGrid* parent)
|
||||
int world_x, int world_y, GridData* parent)
|
||||
: chunk_x(chunk_x), chunk_y(chunk_y),
|
||||
width(width), height(height),
|
||||
world_x(world_x), world_y(world_y),
|
||||
|
|
@ -47,7 +47,7 @@ bool GridChunk::isVisible(float left_edge, float top_edge,
|
|||
// ChunkManager implementation
|
||||
// =============================================================================
|
||||
|
||||
ChunkManager::ChunkManager(int grid_x, int grid_y, UIGrid* parent)
|
||||
ChunkManager::ChunkManager(int grid_x, int grid_y, GridData* parent)
|
||||
: grid_x(grid_x), grid_y(grid_y), parent_grid(parent)
|
||||
{
|
||||
// Calculate number of chunks needed
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
// Forward declarations
|
||||
class UIGrid;
|
||||
class GridData;
|
||||
class PyTexture;
|
||||
|
||||
/**
|
||||
|
|
@ -36,11 +37,11 @@ public:
|
|||
bool dirty;
|
||||
|
||||
// Parent grid reference
|
||||
UIGrid* parent_grid;
|
||||
GridData* parent_grid;
|
||||
|
||||
// Constructor
|
||||
GridChunk(int chunk_x, int chunk_y, int width, int height,
|
||||
int world_x, int world_y, UIGrid* parent);
|
||||
int world_x, int world_y, GridData* parent);
|
||||
|
||||
// Access cell at local chunk coordinates
|
||||
UIGridPoint& at(int local_x, int local_y);
|
||||
|
|
@ -69,10 +70,10 @@ public:
|
|||
std::vector<std::unique_ptr<GridChunk>> chunks;
|
||||
|
||||
// Parent grid
|
||||
UIGrid* parent_grid;
|
||||
GridData* parent_grid;
|
||||
|
||||
// Constructor - creates chunks for given grid dimensions
|
||||
ChunkManager(int grid_x, int grid_y, UIGrid* parent);
|
||||
ChunkManager(int grid_x, int grid_y, GridData* parent);
|
||||
|
||||
// Get chunk containing cell (x, y)
|
||||
GridChunk* getChunkForCell(int x, int y);
|
||||
|
|
|
|||
184
src/GridData.cpp
Normal file
184
src/GridData.cpp
Normal file
|
|
@ -0,0 +1,184 @@
|
|||
// GridData.cpp - Pure data layer implementation (#252)
|
||||
#include "GridData.h"
|
||||
#include "UIEntity.h"
|
||||
#include "PyTexture.h"
|
||||
#include <algorithm>
|
||||
|
||||
GridData::GridData()
|
||||
{
|
||||
entities = std::make_shared<std::list<std::shared_ptr<UIEntity>>>();
|
||||
children = std::make_shared<std::vector<std::shared_ptr<UIDrawable>>>();
|
||||
}
|
||||
|
||||
GridData::~GridData()
|
||||
{
|
||||
cleanupTCOD();
|
||||
}
|
||||
|
||||
void GridData::cleanupTCOD()
|
||||
{
|
||||
dijkstra_maps.clear();
|
||||
if (tcod_map) {
|
||||
delete tcod_map;
|
||||
tcod_map = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void GridData::initStorage(int gx, int gy, GridData* parent_ref)
|
||||
{
|
||||
grid_w = gx;
|
||||
grid_h = gy;
|
||||
use_chunks = (gx > CHUNK_THRESHOLD || gy > CHUNK_THRESHOLD);
|
||||
|
||||
if (tcod_map) delete tcod_map;
|
||||
tcod_map = new TCODMap(gx, gy);
|
||||
|
||||
if (use_chunks) {
|
||||
chunk_manager = std::make_unique<ChunkManager>(gx, gy, parent_ref);
|
||||
for (int cy = 0; cy < chunk_manager->chunks_y; ++cy) {
|
||||
for (int cx = 0; cx < chunk_manager->chunks_x; ++cx) {
|
||||
GridChunk* chunk = chunk_manager->getChunk(cx, cy);
|
||||
if (!chunk) continue;
|
||||
for (int ly = 0; ly < chunk->height; ++ly) {
|
||||
for (int lx = 0; lx < chunk->width; ++lx) {
|
||||
auto& cell = chunk->at(lx, ly);
|
||||
cell.grid_x = chunk->world_x + lx;
|
||||
cell.grid_y = chunk->world_y + ly;
|
||||
cell.parent_grid = parent_ref;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
points.resize(gx * gy);
|
||||
for (int y = 0; y < gy; y++) {
|
||||
for (int x = 0; x < gx; x++) {
|
||||
int idx = y * gx + x;
|
||||
points[idx].grid_x = x;
|
||||
points[idx].grid_y = y;
|
||||
points[idx].parent_grid = parent_ref;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
syncTCODMap();
|
||||
}
|
||||
|
||||
// Cell access
|
||||
UIGridPoint& GridData::at(int x, int y)
|
||||
{
|
||||
if (use_chunks && chunk_manager) {
|
||||
return chunk_manager->at(x, y);
|
||||
}
|
||||
return points[y * grid_w + x];
|
||||
}
|
||||
|
||||
// TCOD integration
|
||||
void GridData::syncTCODMap()
|
||||
{
|
||||
if (!tcod_map) return;
|
||||
for (int y = 0; y < grid_h; y++) {
|
||||
for (int x = 0; x < grid_w; x++) {
|
||||
const UIGridPoint& point = at(x, y);
|
||||
tcod_map->setProperties(x, y, point.transparent, point.walkable);
|
||||
}
|
||||
}
|
||||
fov_dirty = true;
|
||||
}
|
||||
|
||||
void GridData::syncTCODMapCell(int x, int y)
|
||||
{
|
||||
if (!tcod_map || x < 0 || x >= grid_w || y < 0 || y >= grid_h) return;
|
||||
const UIGridPoint& point = at(x, y);
|
||||
tcod_map->setProperties(x, y, point.transparent, point.walkable);
|
||||
fov_dirty = true;
|
||||
}
|
||||
|
||||
void GridData::computeFOV(int x, int y, int radius, bool light_walls, TCOD_fov_algorithm_t algo)
|
||||
{
|
||||
if (!tcod_map || x < 0 || x >= grid_w || y < 0 || y >= grid_h) return;
|
||||
|
||||
if (!fov_dirty &&
|
||||
x == fov_last_x && y == fov_last_y &&
|
||||
radius == fov_last_radius &&
|
||||
light_walls == fov_last_light_walls &&
|
||||
algo == fov_last_algo) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(fov_mutex);
|
||||
tcod_map->computeFov(x, y, radius, light_walls, algo);
|
||||
|
||||
fov_dirty = false;
|
||||
fov_last_x = x;
|
||||
fov_last_y = y;
|
||||
fov_last_radius = radius;
|
||||
fov_last_light_walls = light_walls;
|
||||
fov_last_algo = algo;
|
||||
}
|
||||
|
||||
bool GridData::isInFOV(int x, int y) const
|
||||
{
|
||||
if (!tcod_map || x < 0 || x >= grid_w || y < 0 || y >= grid_h) return false;
|
||||
std::lock_guard<std::mutex> lock(fov_mutex);
|
||||
return tcod_map->isInFov(x, y);
|
||||
}
|
||||
|
||||
// Layer management
|
||||
std::shared_ptr<ColorLayer> GridData::addColorLayer(int z_index, const std::string& name)
|
||||
{
|
||||
auto layer = std::make_shared<ColorLayer>(z_index, grid_w, grid_h, this);
|
||||
layer->name = name;
|
||||
layers.push_back(layer);
|
||||
layers_need_sort = true;
|
||||
return layer;
|
||||
}
|
||||
|
||||
std::shared_ptr<TileLayer> GridData::addTileLayer(int z_index, std::shared_ptr<PyTexture> texture, const std::string& name)
|
||||
{
|
||||
auto layer = std::make_shared<TileLayer>(z_index, grid_w, grid_h, this, texture);
|
||||
layer->name = name;
|
||||
layers.push_back(layer);
|
||||
layers_need_sort = true;
|
||||
return layer;
|
||||
}
|
||||
|
||||
void GridData::removeLayer(std::shared_ptr<GridLayer> layer)
|
||||
{
|
||||
auto it = std::find(layers.begin(), layers.end(), layer);
|
||||
if (it != layers.end()) {
|
||||
layers.erase(it);
|
||||
}
|
||||
if (layer) {
|
||||
layer->parent_grid = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void GridData::sortLayers()
|
||||
{
|
||||
if (layers_need_sort) {
|
||||
std::sort(layers.begin(), layers.end(),
|
||||
[](const auto& a, const auto& b) { return a->z_index < b->z_index; });
|
||||
layers_need_sort = false;
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<GridLayer> GridData::getLayerByName(const std::string& name)
|
||||
{
|
||||
if (name.empty()) return nullptr;
|
||||
for (auto& layer : layers) {
|
||||
if (layer->name == name) return layer;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool GridData::isProtectedLayerName(const std::string& name)
|
||||
{
|
||||
static const std::vector<std::string> protected_names = {
|
||||
"walkable", "transparent"
|
||||
};
|
||||
for (const auto& pn : protected_names) {
|
||||
if (name == pn) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
131
src/GridData.h
Normal file
131
src/GridData.h
Normal file
|
|
@ -0,0 +1,131 @@
|
|||
#pragma once
|
||||
// GridData.h - Pure data layer for grid state (#252)
|
||||
//
|
||||
// GridData holds all non-rendering grid state: cells, entities, TCOD map,
|
||||
// spatial hash, layers, FOV, pathfinding caches. UIGrid inherits from this
|
||||
// and adds rendering. GridView can also reference GridData for multi-view.
|
||||
|
||||
#include "Common.h"
|
||||
#include "Python.h"
|
||||
#include <list>
|
||||
#include <libtcod.h>
|
||||
#include <mutex>
|
||||
#include <optional>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "PyCallable.h"
|
||||
#include "UIGridPoint.h"
|
||||
#include "SpatialHash.h"
|
||||
#include "GridLayers.h"
|
||||
#include "GridChunk.h"
|
||||
|
||||
// Forward declarations
|
||||
class DijkstraMap;
|
||||
class UIEntity;
|
||||
class UIDrawable;
|
||||
class PyTexture;
|
||||
|
||||
class GridData {
|
||||
public:
|
||||
GridData();
|
||||
virtual ~GridData();
|
||||
|
||||
// =========================================================================
|
||||
// Grid dimensions and cell storage
|
||||
// =========================================================================
|
||||
int grid_w = 0, grid_h = 0;
|
||||
|
||||
// #123 - Chunk-based storage for large grid support
|
||||
std::unique_ptr<ChunkManager> chunk_manager;
|
||||
// Legacy flat storage (kept for small grids or compatibility)
|
||||
std::vector<UIGridPoint> points;
|
||||
// Use chunks for grids larger than this threshold
|
||||
static constexpr int CHUNK_THRESHOLD = 64;
|
||||
bool use_chunks = false;
|
||||
|
||||
// Cell access (handles both flat and chunked storage)
|
||||
UIGridPoint& at(int x, int y);
|
||||
|
||||
// =========================================================================
|
||||
// Entity management
|
||||
// =========================================================================
|
||||
std::shared_ptr<std::list<std::shared_ptr<UIEntity>>> entities;
|
||||
SpatialHash spatial_hash; // O(1) entity queries (#115)
|
||||
|
||||
// =========================================================================
|
||||
// TCOD integration (FOV and pathfinding base)
|
||||
// =========================================================================
|
||||
TCODMap* tcod_map = nullptr;
|
||||
mutable std::mutex fov_mutex;
|
||||
|
||||
void syncTCODMap();
|
||||
void syncTCODMapCell(int x, int y);
|
||||
void computeFOV(int x, int y, int radius, bool light_walls = true,
|
||||
TCOD_fov_algorithm_t algo = FOV_BASIC);
|
||||
bool isInFOV(int x, int y) const;
|
||||
TCODMap* getTCODMap() const { return tcod_map; }
|
||||
|
||||
// #114 - FOV algorithm and radius defaults
|
||||
TCOD_fov_algorithm_t fov_algorithm = FOV_BASIC;
|
||||
int fov_radius = 10;
|
||||
|
||||
// #292 - FOV deduplication
|
||||
bool fov_dirty = true;
|
||||
int fov_last_x = -1, fov_last_y = -1;
|
||||
int fov_last_radius = -1;
|
||||
bool fov_last_light_walls = true;
|
||||
TCOD_fov_algorithm_t fov_last_algo = FOV_BASIC;
|
||||
|
||||
// =========================================================================
|
||||
// Pathfinding caches
|
||||
// =========================================================================
|
||||
std::map<std::pair<int,int>, std::shared_ptr<DijkstraMap>> dijkstra_maps;
|
||||
|
||||
// =========================================================================
|
||||
// Layer system (#147, #150)
|
||||
// =========================================================================
|
||||
std::vector<std::shared_ptr<GridLayer>> layers;
|
||||
bool layers_need_sort = true;
|
||||
|
||||
std::shared_ptr<ColorLayer> addColorLayer(int z_index, const std::string& name = "");
|
||||
std::shared_ptr<TileLayer> addTileLayer(int z_index, std::shared_ptr<PyTexture> texture = nullptr,
|
||||
const std::string& name = "");
|
||||
void removeLayer(std::shared_ptr<GridLayer> layer);
|
||||
void sortLayers();
|
||||
std::shared_ptr<GridLayer> getLayerByName(const std::string& name);
|
||||
static bool isProtectedLayerName(const std::string& name);
|
||||
|
||||
// =========================================================================
|
||||
// Cell callbacks (#142, #230)
|
||||
// =========================================================================
|
||||
std::unique_ptr<PyCellHoverCallable> on_cell_enter_callable;
|
||||
std::unique_ptr<PyCellHoverCallable> on_cell_exit_callable;
|
||||
std::unique_ptr<PyClickCallable> on_cell_click_callable;
|
||||
std::optional<sf::Vector2i> hovered_cell;
|
||||
std::optional<sf::Vector2i> last_clicked_cell;
|
||||
|
||||
struct CellCallbackCache {
|
||||
uint32_t generation = 0;
|
||||
bool valid = false;
|
||||
bool has_on_cell_click = false;
|
||||
bool has_on_cell_enter = false;
|
||||
bool has_on_cell_exit = false;
|
||||
};
|
||||
CellCallbackCache cell_callback_cache;
|
||||
|
||||
// fireCellClick/Enter/Exit and refreshCellCallbackCache are on UIGrid
|
||||
// because they need access to UIDrawable::serial_number/is_python_subclass
|
||||
|
||||
// =========================================================================
|
||||
// UIDrawable children (speech bubbles, effects, overlays)
|
||||
// =========================================================================
|
||||
std::shared_ptr<std::vector<std::shared_ptr<UIDrawable>>> children;
|
||||
bool children_need_sort = true;
|
||||
|
||||
protected:
|
||||
// Initialize grid storage (flat or chunked) and TCOD map
|
||||
void initStorage(int gx, int gy, GridData* parent_ref);
|
||||
void cleanupTCOD();
|
||||
};
|
||||
|
|
@ -150,7 +150,7 @@ static sf::Color LerpColor(const sf::Color& a, const sf::Color& b, float t) {
|
|||
// GridLayer base class
|
||||
// =============================================================================
|
||||
|
||||
GridLayer::GridLayer(GridLayerType type, int z_index, int grid_x, int grid_y, UIGrid* parent)
|
||||
GridLayer::GridLayer(GridLayerType type, int z_index, int grid_x, int grid_y, GridData* parent)
|
||||
: type(type), z_index(z_index), grid_x(grid_x), grid_y(grid_y),
|
||||
parent_grid(parent), visible(true),
|
||||
chunks_x(0), chunks_y(0),
|
||||
|
|
@ -244,7 +244,7 @@ void GridLayer::ensureChunkTexture(int chunk_idx, int cell_width, int cell_heigh
|
|||
// ColorLayer implementation
|
||||
// =============================================================================
|
||||
|
||||
ColorLayer::ColorLayer(int z_index, int grid_x, int grid_y, UIGrid* parent)
|
||||
ColorLayer::ColorLayer(int z_index, int grid_x, int grid_y, GridData* parent)
|
||||
: GridLayer(GridLayerType::Color, z_index, grid_x, grid_y, parent),
|
||||
colors(grid_x * grid_y, sf::Color::Transparent),
|
||||
perspective_visible(255, 255, 200, 64),
|
||||
|
|
@ -515,7 +515,7 @@ void ColorLayer::render(sf::RenderTarget& target,
|
|||
// TileLayer implementation
|
||||
// =============================================================================
|
||||
|
||||
TileLayer::TileLayer(int z_index, int grid_x, int grid_y, UIGrid* parent,
|
||||
TileLayer::TileLayer(int z_index, int grid_x, int grid_y, GridData* parent,
|
||||
std::shared_ptr<PyTexture> texture)
|
||||
: GridLayer(GridLayerType::Tile, z_index, grid_x, grid_y, parent),
|
||||
tiles(grid_x * grid_y, -1), // -1 = no tile
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
// Forward declarations
|
||||
class UIGrid;
|
||||
class GridData;
|
||||
class PyTexture;
|
||||
class UIEntity;
|
||||
|
||||
|
|
@ -31,7 +32,7 @@ public:
|
|||
std::string name; // #150 - Layer name for GridPoint property access
|
||||
int z_index; // Negative = below entities, >= 0 = above entities
|
||||
int grid_x, grid_y; // Dimensions
|
||||
UIGrid* parent_grid; // Parent grid reference
|
||||
GridData* parent_grid; // Parent grid reference (#252: GridData, not UIGrid)
|
||||
bool visible; // Visibility flag
|
||||
|
||||
// Chunk dimensions
|
||||
|
|
@ -43,7 +44,7 @@ public:
|
|||
std::vector<bool> chunk_texture_initialized; // Track which textures are created
|
||||
int cached_cell_width, cached_cell_height; // Cell size used for cached textures
|
||||
|
||||
GridLayer(GridLayerType type, int z_index, int grid_x, int grid_y, UIGrid* parent);
|
||||
GridLayer(GridLayerType type, int z_index, int grid_x, int grid_y, GridData* parent);
|
||||
virtual ~GridLayer() = default;
|
||||
|
||||
// Mark entire layer as needing re-render
|
||||
|
|
@ -93,7 +94,7 @@ public:
|
|||
sf::Color perspective_unknown;
|
||||
bool has_perspective;
|
||||
|
||||
ColorLayer(int z_index, int grid_x, int grid_y, UIGrid* parent);
|
||||
ColorLayer(int z_index, int grid_x, int grid_y, GridData* parent);
|
||||
|
||||
// Access color at position
|
||||
sf::Color& at(int x, int y);
|
||||
|
|
@ -145,7 +146,7 @@ public:
|
|||
std::vector<int> tiles; // Sprite indices (-1 = no tile)
|
||||
std::shared_ptr<PyTexture> texture;
|
||||
|
||||
TileLayer(int z_index, int grid_x, int grid_y, UIGrid* parent,
|
||||
TileLayer(int z_index, int grid_x, int grid_y, GridData* parent,
|
||||
std::shared_ptr<PyTexture> texture = nullptr);
|
||||
|
||||
// Access tile index at position
|
||||
|
|
|
|||
194
src/UIGrid.cpp
194
src/UIGrid.cpp
|
|
@ -22,17 +22,11 @@
|
|||
// UIEntityCollection code moved to UIEntityCollection.cpp
|
||||
|
||||
UIGrid::UIGrid()
|
||||
: grid_w(0), grid_h(0), zoom(1.0f), center_x(0.0f), center_y(0.0f), ptex(nullptr),
|
||||
fill_color(8, 8, 8, 255), tcod_map(nullptr),
|
||||
perspective_enabled(false), fov_algorithm(FOV_BASIC), fov_radius(10),
|
||||
use_chunks(false) // Default to omniscient view
|
||||
: GridData(), // Initialize data layer (entities, children, FOV defaults)
|
||||
zoom(1.0f), center_x(0.0f), center_y(0.0f), ptex(nullptr),
|
||||
fill_color(8, 8, 8, 255),
|
||||
perspective_enabled(false)
|
||||
{
|
||||
// Initialize entities list
|
||||
entities = std::make_shared<std::list<std::shared_ptr<UIEntity>>>();
|
||||
|
||||
// Initialize children collection (for UIDrawables like speech bubbles, effects)
|
||||
children = std::make_shared<std::vector<std::shared_ptr<UIDrawable>>>();
|
||||
|
||||
// Initialize box with safe defaults
|
||||
box.setSize(sf::Vector2f(0, 0));
|
||||
position = sf::Vector2f(0, 0); // Set base class position
|
||||
|
|
@ -53,12 +47,11 @@ UIGrid::UIGrid()
|
|||
}
|
||||
|
||||
UIGrid::UIGrid(int gx, int gy, std::shared_ptr<PyTexture> _ptex, sf::Vector2f _xy, sf::Vector2f _wh)
|
||||
: grid_w(gx), grid_h(gy),
|
||||
: GridData(), // Initialize data layer
|
||||
zoom(1.0f),
|
||||
ptex(_ptex),
|
||||
fill_color(8, 8, 8, 255), tcod_map(nullptr),
|
||||
perspective_enabled(false), fov_algorithm(FOV_BASIC), fov_radius(10),
|
||||
use_chunks(gx > CHUNK_THRESHOLD || gy > CHUNK_THRESHOLD) // #123 - Use chunks for large grids
|
||||
fill_color(8, 8, 8, 255),
|
||||
perspective_enabled(false)
|
||||
{
|
||||
// Use texture dimensions if available, otherwise use defaults
|
||||
int cell_width = _ptex ? _ptex->sprite_width : DEFAULT_CELL_WIDTH;
|
||||
|
|
@ -66,10 +59,6 @@ UIGrid::UIGrid(int gx, int gy, std::shared_ptr<PyTexture> _ptex, sf::Vector2f _x
|
|||
|
||||
center_x = (gx/2) * cell_width;
|
||||
center_y = (gy/2) * cell_height;
|
||||
entities = std::make_shared<std::list<std::shared_ptr<UIEntity>>>();
|
||||
|
||||
// Initialize children collection (for UIDrawables like speech bubbles, effects)
|
||||
children = std::make_shared<std::vector<std::shared_ptr<UIDrawable>>>();
|
||||
|
||||
box.setSize(_wh);
|
||||
position = _xy; // Set base class position
|
||||
|
|
@ -91,47 +80,8 @@ UIGrid::UIGrid(int gx, int gy, std::shared_ptr<PyTexture> _ptex, sf::Vector2f _x
|
|||
// textures are upside-down inside renderTexture
|
||||
output.setTexture(renderTexture.getTexture());
|
||||
|
||||
// Create TCOD map for FOV and as source for pathfinding
|
||||
tcod_map = new TCODMap(gx, gy);
|
||||
// Note: DijkstraMap objects are created on-demand via get_dijkstra_map()
|
||||
// A* paths are computed on-demand via find_path()
|
||||
|
||||
// #123 - Initialize storage based on grid size
|
||||
if (use_chunks) {
|
||||
// Large grid: use chunk-based storage
|
||||
chunk_manager = std::make_unique<ChunkManager>(gx, gy, this);
|
||||
|
||||
// Initialize all cells with parent reference
|
||||
for (int cy = 0; cy < chunk_manager->chunks_y; ++cy) {
|
||||
for (int cx = 0; cx < chunk_manager->chunks_x; ++cx) {
|
||||
GridChunk* chunk = chunk_manager->getChunk(cx, cy);
|
||||
if (!chunk) continue;
|
||||
|
||||
for (int ly = 0; ly < chunk->height; ++ly) {
|
||||
for (int lx = 0; lx < chunk->width; ++lx) {
|
||||
auto& cell = chunk->at(lx, ly);
|
||||
cell.grid_x = chunk->world_x + lx;
|
||||
cell.grid_y = chunk->world_y + ly;
|
||||
cell.parent_grid = this;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Small grid: use flat storage (original behavior)
|
||||
points.resize(gx * gy);
|
||||
for (int y = 0; y < gy; y++) {
|
||||
for (int x = 0; x < gx; x++) {
|
||||
int idx = y * gx + x;
|
||||
points[idx].grid_x = x;
|
||||
points[idx].grid_y = y;
|
||||
points[idx].parent_grid = this;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Initial sync of TCOD map
|
||||
syncTCODMap();
|
||||
// Initialize grid storage, TCOD map, and sync (#252: delegated to GridData)
|
||||
initStorage(gx, gy, static_cast<GridData*>(this));
|
||||
}
|
||||
|
||||
void UIGrid::update() {}
|
||||
|
|
@ -467,24 +417,12 @@ void UIGrid::render(sf::Vector2f offset, sf::RenderTarget& target)
|
|||
}
|
||||
}
|
||||
|
||||
UIGridPoint& UIGrid::at(int x, int y)
|
||||
{
|
||||
// #123 - Route through chunk manager for large grids
|
||||
if (use_chunks && chunk_manager) {
|
||||
return chunk_manager->at(x, y);
|
||||
}
|
||||
return points[y * grid_w + x];
|
||||
}
|
||||
// at(), syncTCODMap(), computeFOV(), isInFOV(), layer management methods
|
||||
// are now in GridData.cpp (#252)
|
||||
|
||||
UIGrid::~UIGrid()
|
||||
{
|
||||
// Clear Dijkstra maps first (they reference tcod_map)
|
||||
dijkstra_maps.clear();
|
||||
|
||||
if (tcod_map) {
|
||||
delete tcod_map;
|
||||
tcod_map = nullptr;
|
||||
}
|
||||
// GridData destructor handles TCOD map and Dijkstra cleanup
|
||||
}
|
||||
|
||||
void UIGrid::ensureRenderTextureSize()
|
||||
|
|
@ -512,114 +450,6 @@ PyObjectsEnum UIGrid::derived_type()
|
|||
return PyObjectsEnum::UIGRID;
|
||||
}
|
||||
|
||||
// #147 - Layer management methods
|
||||
std::shared_ptr<ColorLayer> UIGrid::addColorLayer(int z_index, const std::string& name) {
|
||||
auto layer = std::make_shared<ColorLayer>(z_index, grid_w, grid_h, this);
|
||||
layer->name = name;
|
||||
layers.push_back(layer);
|
||||
layers_need_sort = true;
|
||||
return layer;
|
||||
}
|
||||
|
||||
std::shared_ptr<TileLayer> UIGrid::addTileLayer(int z_index, std::shared_ptr<PyTexture> texture, const std::string& name) {
|
||||
auto layer = std::make_shared<TileLayer>(z_index, grid_w, grid_h, this, texture);
|
||||
layer->name = name;
|
||||
layers.push_back(layer);
|
||||
layers_need_sort = true;
|
||||
return layer;
|
||||
}
|
||||
|
||||
std::shared_ptr<GridLayer> UIGrid::getLayerByName(const std::string& name) {
|
||||
for (auto& layer : layers) {
|
||||
if (layer->name == name) {
|
||||
return layer;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool UIGrid::isProtectedLayerName(const std::string& name) {
|
||||
// #150 - These names are reserved for GridPoint pathfinding properties
|
||||
static const std::vector<std::string> protected_names = {
|
||||
"walkable", "transparent"
|
||||
};
|
||||
for (const auto& pn : protected_names) {
|
||||
if (name == pn) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void UIGrid::removeLayer(std::shared_ptr<GridLayer> layer) {
|
||||
auto it = std::find(layers.begin(), layers.end(), layer);
|
||||
if (it != layers.end()) {
|
||||
layers.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
void UIGrid::sortLayers() {
|
||||
if (layers_need_sort) {
|
||||
std::sort(layers.begin(), layers.end(),
|
||||
[](const auto& a, const auto& b) { return a->z_index < b->z_index; });
|
||||
layers_need_sort = false;
|
||||
}
|
||||
}
|
||||
|
||||
// TCOD integration methods
|
||||
void UIGrid::syncTCODMap()
|
||||
{
|
||||
if (!tcod_map) return;
|
||||
|
||||
for (int y = 0; y < grid_h; y++) {
|
||||
for (int x = 0; x < grid_w; x++) {
|
||||
const UIGridPoint& point = at(x, y);
|
||||
tcod_map->setProperties(x, y, point.transparent, point.walkable);
|
||||
}
|
||||
}
|
||||
fov_dirty = true; // #292: map changed, FOV needs recomputation
|
||||
}
|
||||
|
||||
void UIGrid::syncTCODMapCell(int x, int y)
|
||||
{
|
||||
if (!tcod_map || x < 0 || x >= grid_w || y < 0 || y >= grid_h) return;
|
||||
|
||||
const UIGridPoint& point = at(x, y);
|
||||
tcod_map->setProperties(x, y, point.transparent, point.walkable);
|
||||
fov_dirty = true; // #292: cell changed, FOV needs recomputation
|
||||
}
|
||||
|
||||
void UIGrid::computeFOV(int x, int y, int radius, bool light_walls, TCOD_fov_algorithm_t algo)
|
||||
{
|
||||
if (!tcod_map || x < 0 || x >= grid_w || y < 0 || y >= grid_h) return;
|
||||
|
||||
// #292: Skip redundant FOV computation if map hasn't changed and params match
|
||||
if (!fov_dirty &&
|
||||
x == fov_last_x && y == fov_last_y &&
|
||||
radius == fov_last_radius &&
|
||||
light_walls == fov_last_light_walls &&
|
||||
algo == fov_last_algo) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(fov_mutex);
|
||||
tcod_map->computeFov(x, y, radius, light_walls, algo);
|
||||
|
||||
// Cache parameters for deduplication
|
||||
fov_dirty = false;
|
||||
fov_last_x = x;
|
||||
fov_last_y = y;
|
||||
fov_last_radius = radius;
|
||||
fov_last_light_walls = light_walls;
|
||||
fov_last_algo = algo;
|
||||
}
|
||||
|
||||
bool UIGrid::isInFOV(int x, int y) const
|
||||
{
|
||||
if (!tcod_map || x < 0 || x >= grid_w || y < 0 || y >= grid_h) return false;
|
||||
|
||||
std::lock_guard<std::mutex> lock(fov_mutex);
|
||||
return tcod_map->isInFov(x, y);
|
||||
}
|
||||
|
||||
// Pathfinding methods moved to UIGridPathfinding.cpp
|
||||
// - Grid.find_path() returns AStarPath objects
|
||||
// - Grid.get_dijkstra_map() returns DijkstraMap objects (cached)
|
||||
|
|
|
|||
179
src/UIGrid.h
179
src/UIGrid.h
|
|
@ -26,169 +26,82 @@
|
|||
#include "GridChunk.h"
|
||||
#include "SpatialHash.h"
|
||||
#include "UIEntityCollection.h" // EntityCollection types (extracted from UIGrid)
|
||||
#include "GridData.h" // #252 - Data layer base class
|
||||
|
||||
// Forward declaration for pathfinding
|
||||
class DijkstraMap;
|
||||
|
||||
class UIGrid: public UIDrawable
|
||||
// UIGrid inherits both UIDrawable (rendering) and GridData (state).
|
||||
// This allows GridData to be shared with GridView for multi-view support (#252).
|
||||
class UIGrid: public UIDrawable, public GridData
|
||||
{
|
||||
private:
|
||||
std::shared_ptr<PyTexture> ptex;
|
||||
// Default cell dimensions when no texture is provided
|
||||
static constexpr int DEFAULT_CELL_WIDTH = 16;
|
||||
static constexpr int DEFAULT_CELL_HEIGHT = 16;
|
||||
TCODMap* tcod_map; // TCOD map for FOV and pathfinding
|
||||
mutable std::mutex fov_mutex; // Mutex for thread-safe FOV operations
|
||||
|
||||
public:
|
||||
// Dijkstra map cache - keyed by root position
|
||||
// Public so UIGridPathfinding can access it
|
||||
std::map<std::pair<int,int>, std::shared_ptr<DijkstraMap>> dijkstra_maps;
|
||||
|
||||
public:
|
||||
UIGrid();
|
||||
//UIGrid(int, int, IndexTexture*, float, float, float, float);
|
||||
UIGrid(int, int, std::shared_ptr<PyTexture>, sf::Vector2f, sf::Vector2f);
|
||||
~UIGrid(); // Destructor to clean up TCOD map
|
||||
~UIGrid();
|
||||
void update();
|
||||
void render(sf::Vector2f, sf::RenderTarget&) override final;
|
||||
UIGridPoint& at(int, int);
|
||||
PyObjectsEnum derived_type() override final;
|
||||
//void setSprite(int);
|
||||
virtual UIDrawable* click_at(sf::Vector2f point) override final;
|
||||
|
||||
// TCOD integration methods
|
||||
void syncTCODMap(); // Sync entire map with current grid state
|
||||
void syncTCODMapCell(int x, int y); // Sync a single cell to TCOD map
|
||||
void computeFOV(int x, int y, int radius, bool light_walls = true, TCOD_fov_algorithm_t algo = FOV_BASIC);
|
||||
bool isInFOV(int x, int y) const;
|
||||
TCODMap* getTCODMap() const { return tcod_map; } // Access for pathfinding
|
||||
|
||||
// Pathfinding - new API creates AStarPath/DijkstraMap objects
|
||||
// See UIGridPathfinding.h for the new pathfinding API
|
||||
// Grid.find_path() now returns AStarPath objects
|
||||
// Grid.get_dijkstra_map() returns DijkstraMap objects (cached by root position)
|
||||
|
||||
|
||||
// Phase 1 virtual method implementations
|
||||
sf::FloatRect get_bounds() const override;
|
||||
void move(float dx, float dy) override;
|
||||
void resize(float w, float h) override;
|
||||
void onPositionChanged() override;
|
||||
|
||||
int grid_w, grid_h;
|
||||
//int grid_size; // grid sizes are implied by IndexTexture now
|
||||
// =========================================================================
|
||||
// Rendering-only members (NOT in GridData)
|
||||
// =========================================================================
|
||||
sf::RectangleShape box;
|
||||
float center_x, center_y, zoom;
|
||||
float camera_rotation = 0.0f; // Rotation of grid contents around camera center (degrees)
|
||||
//IndexTexture* itex;
|
||||
float camera_rotation = 0.0f;
|
||||
std::shared_ptr<PyTexture> getTexture();
|
||||
sf::Sprite sprite, output;
|
||||
sf::RenderTexture renderTexture;
|
||||
sf::Vector2u renderTextureSize{0, 0}; // Track current allocation for resize detection
|
||||
|
||||
// Helper to ensure renderTexture matches game resolution
|
||||
sf::Vector2u renderTextureSize{0, 0};
|
||||
void ensureRenderTextureSize();
|
||||
|
||||
// Intermediate texture for camera_rotation (larger than viewport to hold rotated content)
|
||||
sf::RenderTexture rotationTexture;
|
||||
unsigned int rotationTextureSize = 0; // Track current allocation size
|
||||
|
||||
// #123 - Chunk-based storage for large grid support
|
||||
std::unique_ptr<ChunkManager> chunk_manager;
|
||||
// Legacy flat storage (kept for small grids or compatibility)
|
||||
std::vector<UIGridPoint> points;
|
||||
// Use chunks for grids larger than this threshold
|
||||
static constexpr int CHUNK_THRESHOLD = 64;
|
||||
bool use_chunks;
|
||||
|
||||
std::shared_ptr<std::list<std::shared_ptr<UIEntity>>> entities;
|
||||
|
||||
// Spatial hash for O(1) entity queries (#115)
|
||||
SpatialHash spatial_hash;
|
||||
|
||||
// UIDrawable children collection (speech bubbles, effects, overlays, etc.)
|
||||
std::shared_ptr<std::vector<std::shared_ptr<UIDrawable>>> children;
|
||||
bool children_need_sort = true; // Dirty flag for z_index sorting
|
||||
|
||||
// Dynamic layer system (#147)
|
||||
std::vector<std::shared_ptr<GridLayer>> layers;
|
||||
bool layers_need_sort = true; // Dirty flag for z_index sorting
|
||||
|
||||
// Layer management (#150 - extended with names)
|
||||
std::shared_ptr<ColorLayer> addColorLayer(int z_index, const std::string& name = "");
|
||||
std::shared_ptr<TileLayer> addTileLayer(int z_index, std::shared_ptr<PyTexture> texture = nullptr, const std::string& name = "");
|
||||
void removeLayer(std::shared_ptr<GridLayer> layer);
|
||||
void sortLayers();
|
||||
std::shared_ptr<GridLayer> getLayerByName(const std::string& name);
|
||||
|
||||
// #150 - Protected layer names (reserved for GridPoint properties)
|
||||
static bool isProtectedLayerName(const std::string& name);
|
||||
unsigned int rotationTextureSize = 0;
|
||||
|
||||
// Background rendering
|
||||
sf::Color fill_color;
|
||||
|
||||
// Perspective system - entity whose view to render
|
||||
std::weak_ptr<UIEntity> perspective_entity; // Weak reference to perspective entity
|
||||
bool perspective_enabled; // Whether to use perspective rendering
|
||||
// Perspective system
|
||||
std::weak_ptr<UIEntity> perspective_entity;
|
||||
bool perspective_enabled;
|
||||
|
||||
// #114 - FOV algorithm and radius for this grid
|
||||
TCOD_fov_algorithm_t fov_algorithm; // Default FOV algorithm (from mcrfpy.default_fov)
|
||||
int fov_radius; // Default FOV radius
|
||||
|
||||
// #292 - FOV deduplication: skip redundant computations
|
||||
bool fov_dirty = true; // Set true when TCOD map changes
|
||||
int fov_last_x = -1, fov_last_y = -1; // Last FOV computation parameters
|
||||
int fov_last_radius = -1;
|
||||
bool fov_last_light_walls = true;
|
||||
TCOD_fov_algorithm_t fov_last_algo = FOV_BASIC;
|
||||
|
||||
// #142, #230 - Grid cell mouse events
|
||||
// Cell hover callbacks take only (cell_pos); cell click still takes (cell_pos, button, action)
|
||||
std::unique_ptr<PyCellHoverCallable> on_cell_enter_callable;
|
||||
std::unique_ptr<PyCellHoverCallable> on_cell_exit_callable;
|
||||
std::unique_ptr<PyClickCallable> on_cell_click_callable;
|
||||
std::optional<sf::Vector2i> hovered_cell; // Currently hovered cell or nullopt
|
||||
std::optional<sf::Vector2i> last_clicked_cell; // Cell clicked during click_at
|
||||
|
||||
// Grid-specific cell callback cache (separate from UIDrawable::CallbackCache)
|
||||
struct CellCallbackCache {
|
||||
uint32_t generation = 0;
|
||||
bool valid = false;
|
||||
bool has_on_cell_click = false;
|
||||
bool has_on_cell_enter = false;
|
||||
bool has_on_cell_exit = false;
|
||||
};
|
||||
CellCallbackCache cell_callback_cache;
|
||||
|
||||
// #142 - Cell coordinate conversion (screen pos -> cell coords)
|
||||
std::optional<sf::Vector2i> screenToCell(sf::Vector2f screen_pos) const;
|
||||
|
||||
// #221 - Get effective cell size (texture size * zoom)
|
||||
sf::Vector2f getEffectiveCellSize() const;
|
||||
|
||||
// #142 - Update cell hover state (called from PyScene)
|
||||
// Now takes button/action for consistent callback signatures
|
||||
void updateCellHover(sf::Vector2f mousepos, const std::string& button, const std::string& action);
|
||||
|
||||
// Fire cell callbacks
|
||||
// #230: Cell hover callbacks (enter/exit) now take only (cell_pos)
|
||||
// Cell click still takes (cell_pos, button, action)
|
||||
// Returns true if a callback was fired
|
||||
// Cell callback firing (needs UIDrawable::is_python_subclass, serial_number)
|
||||
bool fireCellClick(sf::Vector2i cell, const std::string& button, const std::string& action);
|
||||
bool fireCellEnter(sf::Vector2i cell);
|
||||
bool fireCellExit(sf::Vector2i cell);
|
||||
|
||||
// Refresh cell callback cache for subclass method support
|
||||
void refreshCellCallbackCache(PyObject* pyObj);
|
||||
|
||||
|
||||
// #142 - Cell coordinate conversion (needs texture for cell size)
|
||||
std::optional<sf::Vector2i> screenToCell(sf::Vector2f screen_pos) const;
|
||||
sf::Vector2f getEffectiveCellSize() const;
|
||||
void updateCellHover(sf::Vector2f mousepos, const std::string& button, const std::string& action);
|
||||
|
||||
// Property system for animations
|
||||
bool setProperty(const std::string& name, float value) override;
|
||||
bool setProperty(const std::string& name, const sf::Vector2f& value) override;
|
||||
bool getProperty(const std::string& name, float& value) const override;
|
||||
bool getProperty(const std::string& name, sf::Vector2f& value) const override;
|
||||
|
||||
bool hasProperty(const std::string& name) const override;
|
||||
|
||||
// #169 - Camera positioning
|
||||
void center_camera();
|
||||
void center_camera(float tile_x, float tile_y);
|
||||
|
||||
// =========================================================================
|
||||
// Python API (static methods)
|
||||
// =========================================================================
|
||||
static int init(PyUIGridObject* self, PyObject* args, PyObject* kwds);
|
||||
static PyObject* get_grid_size(PyUIGridObject* self, void* closure);
|
||||
static PyObject* get_grid_w(PyUIGridObject* self, void* closure);
|
||||
|
|
@ -215,35 +128,22 @@ public:
|
|||
static PyObject* py_at(PyUIGridObject* self, PyObject* args, PyObject* kwds);
|
||||
static PyObject* py_compute_fov(PyUIGridObject* self, PyObject* args, PyObject* kwds);
|
||||
static PyObject* py_is_in_fov(PyUIGridObject* self, PyObject* args, PyObject* kwds);
|
||||
// Pathfinding methods moved to UIGridPathfinding.cpp
|
||||
// py_find_path -> UIGridPathfinding::Grid_find_path (returns AStarPath)
|
||||
// py_get_dijkstra_map -> UIGridPathfinding::Grid_get_dijkstra_map (returns DijkstraMap)
|
||||
// py_clear_dijkstra_maps -> UIGridPathfinding::Grid_clear_dijkstra_maps
|
||||
static PyObject* py_entities_in_radius(PyUIGridObject* self, PyObject* args, PyObject* kwds); // #115
|
||||
static PyObject* py_center_camera(PyUIGridObject* self, PyObject* args); // #169
|
||||
static PyObject* py_entities_in_radius(PyUIGridObject* self, PyObject* args, PyObject* kwds);
|
||||
static PyObject* py_center_camera(PyUIGridObject* self, PyObject* args);
|
||||
static PyObject* get_camera_rotation(PyUIGridObject* self, void* closure);
|
||||
static int set_camera_rotation(PyUIGridObject* self, PyObject* value, void* closure);
|
||||
|
||||
// #199 - HeightMap application methods
|
||||
static PyObject* py_apply_threshold(PyUIGridObject* self, PyObject* args, PyObject* kwds);
|
||||
static PyObject* py_apply_ranges(PyUIGridObject* self, PyObject* args);
|
||||
|
||||
// #169 - Camera positioning
|
||||
void center_camera(); // Center on grid's middle tile
|
||||
void center_camera(float tile_x, float tile_y); // Center on specific tile
|
||||
|
||||
// #301 - Turn management
|
||||
static PyObject* py_step(PyUIGridObject* self, PyObject* args, PyObject* kwds);
|
||||
|
||||
static PyMethodDef methods[];
|
||||
static PyGetSetDef getsetters[];
|
||||
static PyMappingMethods mpmethods; // For grid[x, y] subscript access
|
||||
static PyObject* subscript(PyUIGridObject* self, PyObject* key); // __getitem__
|
||||
static PyMappingMethods mpmethods;
|
||||
static PyObject* subscript(PyUIGridObject* self, PyObject* key);
|
||||
static PyObject* get_entities(PyUIGridObject* self, void* closure);
|
||||
static PyObject* get_children(PyUIGridObject* self, void* closure);
|
||||
static PyObject* repr(PyUIGridObject* self);
|
||||
|
||||
// #142 - Grid cell mouse event Python API
|
||||
static PyObject* get_on_cell_enter(PyUIGridObject* self, void* closure);
|
||||
static int set_on_cell_enter(PyUIGridObject* self, PyObject* value, void* closure);
|
||||
static PyObject* get_on_cell_exit(PyUIGridObject* self, void* closure);
|
||||
|
|
@ -252,7 +152,6 @@ public:
|
|||
static int set_on_cell_click(PyUIGridObject* self, PyObject* value, void* closure);
|
||||
static PyObject* get_hovered_cell(PyUIGridObject* self, void* closure);
|
||||
|
||||
// #147 - Layer system Python API
|
||||
static PyObject* py_add_layer(PyUIGridObject* self, PyObject* args);
|
||||
static PyObject* py_remove_layer(PyUIGridObject* self, PyObject* args);
|
||||
static PyObject* get_layers(PyUIGridObject* self, void* closure);
|
||||
|
|
@ -285,7 +184,7 @@ namespace mcrfpydef {
|
|||
obj->data->on_enter_unregister();
|
||||
obj->data->on_exit_unregister();
|
||||
obj->data->on_move_unregister();
|
||||
// Grid-specific cell callbacks
|
||||
// Grid-specific cell callbacks (now on GridData base)
|
||||
obj->data->on_cell_enter_callable.reset();
|
||||
obj->data->on_cell_exit_callable.reset();
|
||||
obj->data->on_cell_click_callable.reset();
|
||||
|
|
@ -294,7 +193,7 @@ namespace mcrfpydef {
|
|||
Py_TYPE(self)->tp_free(self);
|
||||
},
|
||||
.tp_repr = (reprfunc)UIGrid::repr,
|
||||
.tp_as_mapping = &UIGrid::mpmethods, // Enable grid[x, y] subscript access
|
||||
.tp_as_mapping = &UIGrid::mpmethods,
|
||||
.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC,
|
||||
.tp_doc = PyDoc_STR("Grid(pos=None, size=None, grid_size=None, texture=None, **kwargs)\n\n"
|
||||
"A grid-based UI element for tile-based rendering and entity management.\n\n"
|
||||
|
|
@ -347,11 +246,9 @@ namespace mcrfpydef {
|
|||
" margin (float): General margin for alignment\n"
|
||||
" horiz_margin (float): Horizontal margin override\n"
|
||||
" vert_margin (float): Vertical margin override"),
|
||||
// tp_traverse visits Python object references for GC cycle detection
|
||||
.tp_traverse = [](PyObject* self, visitproc visit, void* arg) -> int {
|
||||
PyUIGridObject* obj = (PyUIGridObject*)self;
|
||||
if (obj->data) {
|
||||
// Base class callbacks
|
||||
if (obj->data->click_callable) {
|
||||
PyObject* callback = obj->data->click_callable->borrow();
|
||||
if (callback && callback != Py_None) Py_VISIT(callback);
|
||||
|
|
@ -368,7 +265,6 @@ namespace mcrfpydef {
|
|||
PyObject* callback = obj->data->on_move_callable->borrow();
|
||||
if (callback && callback != Py_None) Py_VISIT(callback);
|
||||
}
|
||||
// Grid-specific cell callbacks
|
||||
if (obj->data->on_cell_enter_callable) {
|
||||
PyObject* callback = obj->data->on_cell_enter_callable->borrow();
|
||||
if (callback && callback != Py_None) Py_VISIT(callback);
|
||||
|
|
@ -384,7 +280,6 @@ namespace mcrfpydef {
|
|||
}
|
||||
return 0;
|
||||
},
|
||||
// tp_clear breaks reference cycles by clearing Python references
|
||||
.tp_clear = [](PyObject* self) -> int {
|
||||
PyUIGridObject* obj = (PyUIGridObject*)self;
|
||||
if (obj->data) {
|
||||
|
|
@ -399,7 +294,6 @@ namespace mcrfpydef {
|
|||
return 0;
|
||||
},
|
||||
.tp_methods = UIGrid_all_methods,
|
||||
//.tp_members = UIGrid::members,
|
||||
.tp_getset = UIGrid::getsetters,
|
||||
.tp_base = &mcrfpydef::PyDrawableType,
|
||||
.tp_init = (initproc)UIGrid::init,
|
||||
|
|
@ -410,7 +304,4 @@ namespace mcrfpydef {
|
|||
return (PyObject*)self;
|
||||
}
|
||||
};
|
||||
|
||||
// EntityCollection types moved to UIEntityCollection.h
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ static PyObject* sfColor_to_PyObject(sf::Color color);
|
|||
static sf::Color PyObject_to_sfColor(PyObject* obj);
|
||||
|
||||
class UIGrid;
|
||||
class GridData;
|
||||
class UIEntity;
|
||||
class UIGridPoint;
|
||||
class UIGridPointState;
|
||||
|
|
@ -40,7 +41,7 @@ class UIGridPoint
|
|||
public:
|
||||
bool walkable, transparent; // Pathfinding/FOV properties
|
||||
int grid_x, grid_y; // Position in parent grid
|
||||
UIGrid* parent_grid; // Parent grid reference for TCOD sync
|
||||
GridData* parent_grid; // Parent grid reference for TCOD sync (#252)
|
||||
UIGridPoint();
|
||||
|
||||
// Built-in property accessors (walkable, transparent only)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue