refactor: Remove layer-related GridPoint properties, fix layer z-index
- Remove color, color_overlay, tilesprite, tile_overlay, uisprite from UIGridPoint - these are now accessed through named layers - Keep only walkable and transparent as protected GridPoint properties - Update isProtectedLayerName() to only protect walkable/transparent - Fix default layer z-index to -1 (below entities) instead of 0 - Remove dead rendering code from GridChunk (layers handle rendering) - Update cos_level.py demo to use explicit layer definitions - Update UITestScene.cpp to use layer API instead of GridPoint properties Part of #150 - Grid layer system migration 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
a258613faa
commit
42fcd3417e
|
|
@ -14,7 +14,7 @@ GridChunk::GridChunk(int chunk_x, int chunk_y, int width, int height,
|
|||
width(width), height(height),
|
||||
world_x(world_x), world_y(world_y),
|
||||
cells(width * height),
|
||||
dirty(true), texture_initialized(false),
|
||||
dirty(true),
|
||||
parent_grid(parent)
|
||||
{}
|
||||
|
||||
|
|
@ -30,60 +30,8 @@ void GridChunk::markDirty() {
|
|||
dirty = true;
|
||||
}
|
||||
|
||||
void GridChunk::ensureTexture(int cell_width, int cell_height) {
|
||||
unsigned int required_width = width * cell_width;
|
||||
unsigned int required_height = height * cell_height;
|
||||
|
||||
if (texture_initialized &&
|
||||
cached_texture.getSize().x == required_width &&
|
||||
cached_texture.getSize().y == required_height) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!cached_texture.create(required_width, required_height)) {
|
||||
texture_initialized = false;
|
||||
return;
|
||||
}
|
||||
|
||||
texture_initialized = true;
|
||||
dirty = true; // Force re-render after resize
|
||||
cached_sprite.setTexture(cached_texture.getTexture());
|
||||
}
|
||||
|
||||
void GridChunk::renderToTexture(int cell_width, int cell_height,
|
||||
std::shared_ptr<PyTexture> texture) {
|
||||
ensureTexture(cell_width, cell_height);
|
||||
if (!texture_initialized) return;
|
||||
|
||||
cached_texture.clear(sf::Color::Transparent);
|
||||
|
||||
sf::RectangleShape rect;
|
||||
rect.setSize(sf::Vector2f(cell_width, cell_height));
|
||||
rect.setOutlineThickness(0);
|
||||
|
||||
// Render all cells in this chunk
|
||||
for (int y = 0; y < height; ++y) {
|
||||
for (int x = 0; x < width; ++x) {
|
||||
const auto& cell = at(x, y);
|
||||
sf::Vector2f pixel_pos(x * cell_width, y * cell_height);
|
||||
|
||||
// Draw background color
|
||||
rect.setPosition(pixel_pos);
|
||||
rect.setFillColor(cell.color);
|
||||
cached_texture.draw(rect);
|
||||
|
||||
// Draw tile sprite if available
|
||||
if (texture && cell.tilesprite != -1) {
|
||||
sf::Sprite sprite = texture->sprite(cell.tilesprite, pixel_pos,
|
||||
sf::Vector2f(1.0f, 1.0f));
|
||||
cached_texture.draw(sprite);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cached_texture.display();
|
||||
dirty = false;
|
||||
}
|
||||
// #150 - Removed ensureTexture/renderToTexture - base layer rendering removed
|
||||
// GridChunk now only provides data storage for GridPoints
|
||||
|
||||
sf::FloatRect GridChunk::getWorldBounds(int cell_width, int cell_height) const {
|
||||
return sf::FloatRect(
|
||||
|
|
|
|||
|
|
@ -10,11 +10,11 @@ class UIGrid;
|
|||
class PyTexture;
|
||||
|
||||
/**
|
||||
* #123 - Grid chunk for sub-grid rendering system
|
||||
* #123 - Grid chunk for sub-grid data storage
|
||||
* #150 - Rendering removed; layers now handle all rendering
|
||||
*
|
||||
* Each chunk represents a CHUNK_SIZE x CHUNK_SIZE portion of the grid.
|
||||
* Chunks have their own RenderTexture and dirty flag for efficient
|
||||
* incremental rendering - only dirty chunks are re-rendered.
|
||||
* Chunks store GridPoint data for pathfinding and game logic.
|
||||
*/
|
||||
class GridChunk {
|
||||
public:
|
||||
|
|
@ -30,16 +30,13 @@ public:
|
|||
// World position (in cell coordinates)
|
||||
int world_x, world_y;
|
||||
|
||||
// Cell data for this chunk
|
||||
// Cell data for this chunk (pathfinding properties only)
|
||||
std::vector<UIGridPoint> cells;
|
||||
|
||||
// Cached rendering
|
||||
sf::RenderTexture cached_texture;
|
||||
sf::Sprite cached_sprite;
|
||||
// Dirty flag (for layer sync if needed)
|
||||
bool dirty;
|
||||
bool texture_initialized;
|
||||
|
||||
// Parent grid reference (for texture access)
|
||||
// Parent grid reference
|
||||
UIGrid* parent_grid;
|
||||
|
||||
// Constructor
|
||||
|
|
@ -50,16 +47,9 @@ public:
|
|||
UIGridPoint& at(int local_x, int local_y);
|
||||
const UIGridPoint& at(int local_x, int local_y) const;
|
||||
|
||||
// Mark chunk as needing re-render
|
||||
// Mark chunk as dirty
|
||||
void markDirty();
|
||||
|
||||
// Ensure texture is properly sized
|
||||
void ensureTexture(int cell_width, int cell_height);
|
||||
|
||||
// Render chunk content to cached texture
|
||||
void renderToTexture(int cell_width, int cell_height,
|
||||
std::shared_ptr<PyTexture> texture);
|
||||
|
||||
// Get pixel bounds of this chunk in world coordinates
|
||||
sf::FloatRect getWorldBounds(int cell_width, int cell_height) const;
|
||||
|
||||
|
|
|
|||
|
|
@ -407,9 +407,9 @@ std::shared_ptr<GridLayer> UIGrid::getLayerByName(const std::string& name) {
|
|||
}
|
||||
|
||||
bool UIGrid::isProtectedLayerName(const std::string& name) {
|
||||
// #150 - These names are reserved for GridPoint properties
|
||||
// #150 - These names are reserved for GridPoint pathfinding properties
|
||||
static const std::vector<std::string> protected_names = {
|
||||
"walkable", "transparent", "color", "color_overlay"
|
||||
"walkable", "transparent"
|
||||
};
|
||||
for (const auto& pn : protected_names) {
|
||||
if (name == pn) return true;
|
||||
|
|
@ -896,8 +896,8 @@ int UIGrid::init(PyUIGridObject* self, PyObject* args, PyObject* kwds) {
|
|||
// Default: {"tilesprite": "tile"} when layers not provided
|
||||
// Empty dict: no rendering layers (entity storage + pathfinding only)
|
||||
if (layers_obj == nullptr) {
|
||||
// Default layer: single TileLayer named "tilesprite"
|
||||
self->data->addTileLayer(0, texture_ptr, "tilesprite");
|
||||
// Default layer: single TileLayer named "tilesprite" (z_index -1 = below entities)
|
||||
self->data->addTileLayer(-1, texture_ptr, "tilesprite");
|
||||
} else if (layers_obj != Py_None) {
|
||||
if (!PyDict_Check(layers_obj)) {
|
||||
PyErr_SetString(PyExc_TypeError, "layers must be a dict mapping names to types ('color' or 'tile')");
|
||||
|
|
@ -907,7 +907,7 @@ int UIGrid::init(PyUIGridObject* self, PyObject* args, PyObject* kwds) {
|
|||
PyObject* key;
|
||||
PyObject* value;
|
||||
Py_ssize_t pos = 0;
|
||||
int layer_z = 0; // Auto-increment z_index for each layer
|
||||
int layer_z = -1; // Start at -1 (below entities), decrement for each layer
|
||||
|
||||
while (PyDict_Next(layers_obj, &pos, &key, &value)) {
|
||||
if (!PyUnicode_Check(key)) {
|
||||
|
|
@ -929,9 +929,9 @@ int UIGrid::init(PyUIGridObject* self, PyObject* args, PyObject* kwds) {
|
|||
}
|
||||
|
||||
if (strcmp(layer_type, "color") == 0) {
|
||||
self->data->addColorLayer(layer_z++, layer_name);
|
||||
self->data->addColorLayer(layer_z--, layer_name);
|
||||
} else if (strcmp(layer_type, "tile") == 0) {
|
||||
self->data->addTileLayer(layer_z++, texture_ptr, layer_name);
|
||||
self->data->addTileLayer(layer_z--, texture_ptr, layer_name);
|
||||
} else {
|
||||
PyErr_Format(PyExc_ValueError, "Unknown layer type '%s' (expected 'color' or 'tile')", layer_type);
|
||||
return -1;
|
||||
|
|
|
|||
|
|
@ -4,8 +4,7 @@
|
|||
#include <cstring> // #150 - for strcmp
|
||||
|
||||
UIGridPoint::UIGridPoint()
|
||||
: color(1.0f, 1.0f, 1.0f), color_overlay(0.0f, 0.0f, 0.0f), walkable(false), transparent(false),
|
||||
tilesprite(-1), tile_overlay(-1), uisprite(-1), grid_x(-1), grid_y(-1), parent_grid(nullptr)
|
||||
: walkable(false), transparent(false), grid_x(-1), grid_y(-1), parent_grid(nullptr)
|
||||
{}
|
||||
|
||||
// Utility function to convert sf::Color to PyObject*
|
||||
|
|
@ -53,28 +52,7 @@ sf::Color PyObject_to_sfColor(PyObject* obj) {
|
|||
return sf::Color(r, g, b, a);
|
||||
}
|
||||
|
||||
PyObject* UIGridPoint::get_color(PyUIGridPointObject* self, void* closure) {
|
||||
if (reinterpret_cast<long>(closure) == 0) { // color
|
||||
return sfColor_to_PyObject(self->data->color);
|
||||
} else { // color_overlay
|
||||
return sfColor_to_PyObject(self->data->color_overlay);
|
||||
}
|
||||
}
|
||||
|
||||
int UIGridPoint::set_color(PyUIGridPointObject* self, PyObject* value, void* closure) {
|
||||
sf::Color color = PyObject_to_sfColor(value);
|
||||
// Check if an error occurred during conversion
|
||||
if (PyErr_Occurred()) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (reinterpret_cast<long>(closure) == 0) { // color
|
||||
self->data->color = color;
|
||||
} else { // color_overlay
|
||||
self->data->color_overlay = color;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
// #150 - Removed get_color/set_color - now handled by layers
|
||||
|
||||
PyObject* UIGridPoint::get_bool_member(PyUIGridPointObject* self, void* closure) {
|
||||
if (reinterpret_cast<long>(closure) == 0) { // walkable
|
||||
|
|
@ -110,36 +88,11 @@ int UIGridPoint::set_bool_member(PyUIGridPointObject* self, PyObject* value, voi
|
|||
return 0;
|
||||
}
|
||||
|
||||
PyObject* UIGridPoint::get_int_member(PyUIGridPointObject* self, void* closure) {
|
||||
switch(reinterpret_cast<long>(closure)) {
|
||||
case 0: return PyLong_FromLong(self->data->tilesprite);
|
||||
case 1: return PyLong_FromLong(self->data->tile_overlay);
|
||||
case 2: return PyLong_FromLong(self->data->uisprite);
|
||||
default: PyErr_SetString(PyExc_RuntimeError, "Invalid closure"); return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
int UIGridPoint::set_int_member(PyUIGridPointObject* self, PyObject* value, void* closure) {
|
||||
long val = PyLong_AsLong(value);
|
||||
if (PyErr_Occurred()) return -1;
|
||||
|
||||
switch(reinterpret_cast<long>(closure)) {
|
||||
case 0: self->data->tilesprite = val; break;
|
||||
case 1: self->data->tile_overlay = val; break;
|
||||
case 2: self->data->uisprite = val; break;
|
||||
default: PyErr_SetString(PyExc_RuntimeError, "Invalid closure"); return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
// #150 - Removed get_int_member/set_int_member - now handled by layers
|
||||
|
||||
PyGetSetDef UIGridPoint::getsetters[] = {
|
||||
{"color", (getter)UIGridPoint::get_color, (setter)UIGridPoint::set_color, "GridPoint color", (void*)0},
|
||||
{"color_overlay", (getter)UIGridPoint::get_color, (setter)UIGridPoint::set_color, "GridPoint color overlay", (void*)1},
|
||||
{"walkable", (getter)UIGridPoint::get_bool_member, (setter)UIGridPoint::set_bool_member, "Is the GridPoint walkable", (void*)0},
|
||||
{"transparent", (getter)UIGridPoint::get_bool_member, (setter)UIGridPoint::set_bool_member, "Is the GridPoint transparent", (void*)1},
|
||||
{"tilesprite", (getter)UIGridPoint::get_int_member, (setter)UIGridPoint::set_int_member, "Tile sprite index", (void*)0},
|
||||
{"tile_overlay", (getter)UIGridPoint::get_int_member, (setter)UIGridPoint::set_int_member, "Tile overlay sprite index", (void*)1},
|
||||
{"uisprite", (getter)UIGridPoint::get_int_member, (setter)UIGridPoint::set_int_member, "UI sprite index", (void*)2},
|
||||
{NULL} /* Sentinel */
|
||||
};
|
||||
|
||||
|
|
@ -148,9 +101,9 @@ PyObject* UIGridPoint::repr(PyUIGridPointObject* self) {
|
|||
if (!self->data) ss << "<GridPoint (invalid internal object)>";
|
||||
else {
|
||||
auto gp = self->data;
|
||||
ss << "<GridPoint (walkable=" << (gp->walkable ? "True" : "False") << ", transparent=" << (gp->transparent ? "True" : "False") <<
|
||||
", tilesprite=" << gp->tilesprite << ", tile_overlay=" << gp->tile_overlay << ", uisprite=" << gp->uisprite <<
|
||||
")>";
|
||||
ss << "<GridPoint (walkable=" << (gp->walkable ? "True" : "False")
|
||||
<< ", transparent=" << (gp->transparent ? "True" : "False")
|
||||
<< ") at (" << gp->grid_x << ", " << gp->grid_y << ")>";
|
||||
}
|
||||
std::string repr_str = ss.str();
|
||||
return PyUnicode_DecodeUTF8(repr_str.c_str(), repr_str.size(), "replace");
|
||||
|
|
|
|||
|
|
@ -33,24 +33,20 @@ typedef struct {
|
|||
std::shared_ptr<UIEntity> entity;
|
||||
} PyUIGridPointStateObject;
|
||||
|
||||
// UIGridPoint - revised grid data for each point
|
||||
// UIGridPoint - grid cell data for pathfinding and layer access
|
||||
// #150 - Layer-related properties (color, tilesprite, etc.) removed; now handled by layers
|
||||
class UIGridPoint
|
||||
{
|
||||
public:
|
||||
sf::Color color, color_overlay;
|
||||
bool walkable, transparent;
|
||||
int tilesprite, tile_overlay, uisprite;
|
||||
int grid_x, grid_y; // Position in parent grid
|
||||
UIGrid* parent_grid; // Parent grid reference for TCOD sync
|
||||
bool walkable, transparent; // Pathfinding/FOV properties
|
||||
int grid_x, grid_y; // Position in parent grid
|
||||
UIGrid* parent_grid; // Parent grid reference for TCOD sync
|
||||
UIGridPoint();
|
||||
|
||||
static int set_int_member(PyUIGridPointObject* self, PyObject* value, void* closure);
|
||||
// Built-in property accessors (walkable, transparent only)
|
||||
static PyGetSetDef getsetters[];
|
||||
static PyObject* get_color(PyUIGridPointObject* self, void* closure);
|
||||
static PyObject* get_int_member(PyUIGridPointObject* self, void* closure);
|
||||
static int set_bool_member(PyUIGridPointObject* self, PyObject* value, void* closure);
|
||||
static PyObject* get_bool_member(PyUIGridPointObject* self, void* closure);
|
||||
static int set_color(PyUIGridPointObject* self, PyObject* value, void* closure);
|
||||
static PyObject* repr(PyUIGridPointObject* self);
|
||||
|
||||
// #150 - Dynamic property access for named layers
|
||||
|
|
|
|||
|
|
@ -105,16 +105,16 @@ UITestScene::UITestScene(GameEngine* g) : Scene(g)
|
|||
*/
|
||||
|
||||
// UIGrid test: (in grid cells) ( in screen pixels )
|
||||
// constructor args: w h texture x y w h
|
||||
// constructor args: w h texture x y w h
|
||||
auto e5 = std::make_shared<UIGrid>(4, 4, ptex, sf::Vector2f(550, 150), sf::Vector2f(200, 200));
|
||||
e5->zoom=2.0;
|
||||
e5->points[0].color = sf::Color(255, 0, 0);
|
||||
e5->points[1].tilesprite = 1;
|
||||
e5->points[5].color = sf::Color(0, 255, 0);
|
||||
e5->points[6].tilesprite = 2;
|
||||
e5->points[10].color = sf::Color(0, 0, 255);
|
||||
e5->points[11].tilesprite = 3;
|
||||
e5->points[15].color = sf::Color(255, 255, 255);
|
||||
|
||||
// #150 - GridPoint no longer has color/tilesprite properties
|
||||
// Use layers for visual rendering; GridPoint only has walkable/transparent
|
||||
// The default "tilesprite" TileLayer is created automatically
|
||||
// Example: e5->layers[0]->at(x, y) = tile_index for TileLayer
|
||||
e5->points[0].walkable = true;
|
||||
e5->points[0].transparent = true;
|
||||
|
||||
ui_elements->push_back(e5);
|
||||
|
||||
|
|
|
|||
|
|
@ -105,7 +105,9 @@ class Level:
|
|||
self.height = height
|
||||
#self.graph = [(0, 0, width, height)]
|
||||
self.graph = RoomGraph( (0, 0, width, height) )
|
||||
self.grid = mcrfpy.Grid(grid_size=(width, height), texture=t, pos=(10, 5), size=(1014, 700))
|
||||
# #150 - Create grid with explicit layers for color and tilesprite
|
||||
self.grid = mcrfpy.Grid(grid_size=(width, height), texture=t, pos=(10, 5), size=(1014, 700),
|
||||
layers={"color": "color", "tilesprite": "tile"})
|
||||
self.highlighted = -1 #debug view feature
|
||||
self.walled_rooms = [] # for tracking "hallway rooms" vs "walled rooms"
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue