Multi-tile entities using composite sprites #237

Open
opened 2026-02-02 16:22:48 +00:00 by john · 0 comments
Owner

Summary

Support entities composed of multiple sprite indices, one per occupied tile, allowing different visual representations for different parts of a large entity.

Parent issue: #233

Use Case

A 3×2 ship entity where each tile shows a different part of the ship (bow, stern, mast, hull sections). Or a snake where each body segment is a separate sprite index.

Current Behavior

Entity has single UISprite sprite member with one sprite_index.

Proposed Changes

  1. Extend UIEntity with optional sprite grid:

    // Option A: 2D vector of sprite indices
    std::vector<std::vector<int>> sprite_grid;  // [y][x] = sprite_index, -1 = empty
    
    // Option B: Flat vector with dimensions
    std::vector<int> sprite_indices;  // Row-major, -1 = empty
    int tile_width = 1, tile_height = 1;
    
  2. Modify rendering:

    if (e->sprite_indices.empty()) {
        // Current single-sprite path
        e->sprite.render(pixel_pos, *activeTexture);
    } else {
        // Multi-sprite path
        for (int dy = 0; dy < e->tile_height; dy++) {
            for (int dx = 0; dx < e->tile_width; dx++) {
                int idx = e->sprite_indices[dy * e->tile_width + dx];
                if (idx < 0) continue;
                auto part_pos = sf::Vector2f(
                    pixel_pos.x + dx * cell_width * zoom,
                    pixel_pos.y + dy * cell_height * zoom);
                auto sprite = texture->sprite(idx, part_pos, sf::Vector2f(zoom, zoom));
                activeTexture->draw(sprite);
            }
        }
    }
    
  3. Python API:

    ship = mcrfpy.Entity(grid_pos=(5, 5), texture=ship_tex)
    ship.tile_size = (3, 2)
    ship.sprite_grid = [
        [10, 11, 12],  # Top row: bow, deck, stern
        [20, 21, 22],  # Bottom row: hull parts
    ]
    # Or flat:
    ship.sprite_indices = [10, 11, 12, 20, 21, 22]
    

Relationship to Other Issues

This builds on the work from "Multi-tile entities using oversized sprites" - the FOV, spatial hash, and frustum culling changes apply to both approaches.

Performance Impact

  • Memory: +8-64 bytes per multi-tile entity
  • Render: +1 draw call per tile vs single draw
  • Acceptable for typical use (boss enemies, vehicles, furniture)

Future Consideration

The comment in UIEntity.h:40 mentions allowing "any UIDrawable to go there" - this could eventually evolve into entities containing arbitrary UIDrawable children (frames, captions, etc.) for health bars, name tags, equipment overlays.

Files Affected

  • src/UIEntity.h/cpp - Add sprite_indices, modify property accessors
  • src/UIGrid.cpp - Modify entity rendering loop
## Summary Support entities composed of multiple sprite indices, one per occupied tile, allowing different visual representations for different parts of a large entity. **Parent issue**: #233 ## Use Case A 3×2 ship entity where each tile shows a different part of the ship (bow, stern, mast, hull sections). Or a snake where each body segment is a separate sprite index. ## Current Behavior Entity has single `UISprite sprite` member with one `sprite_index`. ## Proposed Changes 1. **Extend UIEntity with optional sprite grid**: ```cpp // Option A: 2D vector of sprite indices std::vector<std::vector<int>> sprite_grid; // [y][x] = sprite_index, -1 = empty // Option B: Flat vector with dimensions std::vector<int> sprite_indices; // Row-major, -1 = empty int tile_width = 1, tile_height = 1; ``` 2. **Modify rendering**: ```cpp if (e->sprite_indices.empty()) { // Current single-sprite path e->sprite.render(pixel_pos, *activeTexture); } else { // Multi-sprite path for (int dy = 0; dy < e->tile_height; dy++) { for (int dx = 0; dx < e->tile_width; dx++) { int idx = e->sprite_indices[dy * e->tile_width + dx]; if (idx < 0) continue; auto part_pos = sf::Vector2f( pixel_pos.x + dx * cell_width * zoom, pixel_pos.y + dy * cell_height * zoom); auto sprite = texture->sprite(idx, part_pos, sf::Vector2f(zoom, zoom)); activeTexture->draw(sprite); } } } ``` 3. **Python API**: ```python ship = mcrfpy.Entity(grid_pos=(5, 5), texture=ship_tex) ship.tile_size = (3, 2) ship.sprite_grid = [ [10, 11, 12], # Top row: bow, deck, stern [20, 21, 22], # Bottom row: hull parts ] # Or flat: ship.sprite_indices = [10, 11, 12, 20, 21, 22] ``` ## Relationship to Other Issues This builds on the work from "Multi-tile entities using oversized sprites" - the FOV, spatial hash, and frustum culling changes apply to both approaches. ## Performance Impact - Memory: +8-64 bytes per multi-tile entity - Render: +1 draw call per tile vs single draw - Acceptable for typical use (boss enemies, vehicles, furniture) ## Future Consideration The comment in UIEntity.h:40 mentions allowing "any UIDrawable to go there" - this could eventually evolve into entities containing arbitrary UIDrawable children (frames, captions, etc.) for health bars, name tags, equipment overlays. ## Files Affected - `src/UIEntity.h/cpp` - Add sprite_indices, modify property accessors - `src/UIGrid.cpp` - Modify entity rendering loop
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Reference
john/McRogueFace#237
No description provided.