A Grid class whereby you can set the screen width, screen height and the # of rows and columns. Uses SDL.
simpleLevel |
testingGridClass |
|---|---|
![]() |
![]() |
The two demo programs in test/, built from this repository and run unchanged: a textured level whose ground row is solid, and the default outlined 20x20 grid.
- A C++ compiler (the sources are C++11-compatible)
- SDL2 and SDL2_image development headers
src/GridClass.h includes <SDL.h> and <SDL_image.h> directly, so the SDL2 include directory must be on the include path for any translation unit that uses the library.
SDLGrid is not built as a library. The two files in src/ are vendored directly into a consuming project:
src/GridClass.hsrc/GridClass.cpp
A grid is set up once, then drawn each frame. The call order below is the one used by test/testingGridClass.cpp:
#include "GridClass.h"
const int COLUMNS = 20;
const int ROWS = 20;
const int SCREEN_WIDTH = 500; // must be a multiple of COLUMNS
const int SCREEN_HEIGHT = 500; // must be a multiple of ROWS
GridClass theGrid;
// after the SDL renderer has been created:
theGrid.init(COLUMNS, ROWS, SCREEN_WIDTH, SCREEN_HEIGHT);
theGrid.setRenderer(gRenderer);
theGrid.createGrid();
// each frame:
theGrid.drawGrid();setRenderer must be called before createGrid, because createGrid copies the renderer into each slot as the slots are constructed.
Individual slots are reached by column and row, and a slot with no texture set is drawn as an outlined rectangle:
theGrid.getGridSlot(column, row).setTexture(grassTexture);
theGrid.getGridSlot(column, row).setSolidFlag(true);Drawing a slot with no texture sets the renderer's draw colour to opaque black with SDL_SetRenderDrawColor and does not restore it, so once drawGrid has drawn any untextured slot, the renderer is left drawing in black. A consumer that depends on the draw colour — for example before SDL_RenderClear — must set it again, as both demos do at the start of each frame.
Slot dimensions are computed as screenWidth / columns and screenHeight / rows using integer division, which is why the screen dimensions should be exact multiples of the column and row counts — otherwise the grid does not reach the right and bottom edges of the window. The screen width and height are stored without being checked, so a screen width smaller than the column count, or a screen height smaller than the row count — including zero or any negative value — gives slots a width or height of zero or less.
A non-positive column or row count is rejected: init reports the rejected values on std::cerr and returns without storing anything. On a grid that has not yet been initialized, this leaves it at its constructed state of zero columns and zero rows, and a subsequent createGrid then builds no slots rather than dividing by zero. On a grid that has already been initialized, the dimensions and slot sizes from the previous successful init are kept, and a subsequent createGrid rebuilds the grid at those dimensions.
createGrid may be called again after a further init to rebuild the grid at new dimensions. Each call discards the slots built by the previous call, along with any texture or flag set on them, and invalidates any reference previously returned by getGridSlot. The public solidSlots and buttonSlots vectors are not touched, because they hold copies placed there by the consumer.
GridClass:
| Member | Description |
|---|---|
GridClass() |
Constructs a grid with zero columns and rows, zero screen and slot dimensions, no renderer and no slots |
init(int c, int r, int sW, int sH) |
Stores the column count, row count, screen width and screen height, and computes the slot dimensions. A non-positive c or r is rejected and nothing is stored, so the grid keeps its previous dimensions. sW and sH are not checked |
setRenderer(SDL_Renderer* rendererToSet) |
Sets the renderer handed to each slot by createGrid. Slots that already exist keep the renderer they were built with, so a renderer set after createGrid reaches them only when createGrid is called again or when GridSlot::setRenderer is called on each slot |
createGrid() |
Discards any existing slots, then constructs and positions c * r new ones |
drawGrid() |
Renders every slot |
getGridSlot(int x, int y) |
Returns a reference to the slot at column x, row y. No bounds check is performed: x must lie in 0 to getColumns() - 1, y in 0 to getRows() - 1, and createGrid must have been called since the last successful init, otherwise the behaviour is undefined |
getColumns() / getRows() |
Return the configured column and row counts |
solidSlots / buttonSlots |
Public vectors a consumer may populate to track slots of interest |
GridSlot:
| Member | Description |
|---|---|
GridSlot() |
Constructs a slot at position (0, 0) with zero width and height, no renderer, no texture, an outlined rectangle, and both flags false |
init(int x, int y, int w, int h) |
Sets the slot's position, size and collider |
setRenderer(SDL_Renderer* rendererToSet) |
Sets the renderer used to draw the slot |
setTexture(SDL_Texture* textureToSet) |
Sets the texture drawn in place of the outline; ownership is not taken |
render() |
Draws the texture if one is set, otherwise draws a rectangle. Does nothing while the slot has no renderer |
drawRectangle(int x, int y, int w, int h) |
Draws an opaque black rectangle at the given position and size, filled or outlined according to the slot's fill state. Does nothing while the slot has no renderer |
fillBlack() / clear() |
Switch the rectangle between filled and outlined. While a texture is set, render draws the texture and never the rectangle, so neither call changes what render or drawGrid draws until the texture is cleared with setTexture(NULL) |
setSolidFlag(bool setter) / setButtonFlag(bool setter) |
Set the slot's solid and button flags. Neither flag has a getter, and nothing in GridClass or GridSlot reads them, so setting one changes no behaviour on its own; collision in simpleLevel.cpp is checked against the copies placed in solidSlots |
collider |
Public SDL_Rect matching the slot's position and size, for collision checks. render draws from the slot's private position and size, not from collider, so changing collider moves the slot for collision only; the next init overwrites it |
test/ contains two standalone SDL programs:
testingGridClass.cpp— draws a 20x20 grid of outlined slots in a 500x500 windowsimpleLevel.cpp— draws a textured level and drops a sprite that comes to rest on the ground row, whose slots are copied intosolidSlotsfor collision checks
Both load their PNGs by relative path, so both must be run from inside test/:
cd test
g++ -std=c++11 -I../src ../src/GridClass.cpp testingGridClass.cpp $(sdl2-config --cflags --libs) -lSDL2_image -o testingGridClass
./testingGridClass
g++ -std=c++11 -I../src ../src/GridClass.cpp simpleLevel.cpp $(sdl2-config --cflags --libs) -lSDL2_image -o simpleLevel
./simpleLevelIf SDL or SDL_image fails to initialize, the window or renderer cannot be created, or a PNG cannot be loaded (for example because the demo was started from outside test/), the demo prints the failing call and the SDL_GetError() / IMG_GetError() message on stderr and exits with status 1.
The screenshots at the top of this README were taken from these two programs
under a virtual X display. docs/capture.sh, run from the repository root,
compiles both with the commands above and regenerates docs/images/; it needs
Xvfb, xdotool and ImageMagick in addition to SDL2 and SDL2_image.
test/checkGridClass.cpp exercises the parts of GridClass and GridSlot that need no window: the column and row counts stored by init, the rejection of non-positive counts by init on both a fresh and an already-initialized grid, the position and size of the slots laid out by createGrid on both a square grid and a grid with more rows than columns, the replacement of those slots by a second createGrid, the truncated slot size and the uncovered right and bottom edges when the screen dimensions are not multiples of the column and row counts, and the signatures of setSolidFlag, setButtonFlag and the public tracking vectors. Drawing is checked by reading pixels back from a software renderer over an in-memory surface: an outlined slot, fillBlack and clear, a texture hiding the fill state until it is removed, the black draw colour left behind by drawGrid, a renderer set after createGrid, the fill state and texture dropped by a second createGrid, drawRectangle drawing at its arguments rather than at the slot's position, render ignoring a moved collider, and the pixels left undrawn by a grid that does not reach the right and bottom edges. It never calls SDL_Init, so it runs on a machine with no display. Each failed expectation is reported on stderr, and the process exits non-zero if any failed:
cd test
g++ -std=c++11 -I../src ../src/GridClass.cpp checkGridClass.cpp $(sdl2-config --cflags --libs) -o checkGridClass
./checkGridClassSDLGrid is made available under the terms of the MIT License. See COPYRIGHT.md.

