This is my first attempt at using a visual library in C++, so for practice I decided to create the Game of Life utilizing SDL2; however, I would like help in terms of optimization and OOP.
When running the program at the current config with a 200x200 vector, the screen updates with a new image about twice a second, but I think that there is definitely room for improvement in my code.
To explain the program, the initialization of the CellVector
class creates a 2D-vector of boolean values that contains whether or not a cell on the grid is alive. Then, cellVector.generateSeed(RANDOM)
randomly assigns alive or dead values to all booleans in the array (I have an enum of patterns in CellVector.h
such as LOAF
or GLIDER
which RANDOM
is a part of). The SDL window is created and opened, and the program enters the while
loop.
I've included the main.cpp
file and the CellVector::tick()
and Window::render2DBoolVector()
functions below.
main.cpp:
#include <string>
#include "CellVector.h"
#include "Window.h"
int main(int argc, char* args[])
{
// Configuration Settings //
int worldWidth = 200;
int worldHeight = 200;
// Window size as a percentage of the world size. EX: 50x50 world with 2.0 scale = 100x100 window
double windowScale = 5;
// Percentage chance that a specific cell will be alive at world generation if RANDOM is the arg in CellVector.generateseed()
double isAliveChance = 0.5;
// Name of the program window
const char* gameTitle = "Conway's Game of Life";
// Initialize cell vector
CellVector cellVector(worldHeight, worldWidth, isAliveChance);
// Generate seed for cell vector from given seed type
cellVector.generateSeed(RANDOM);
// Initialize the window class
Window window(worldWidth, worldHeight, windowScale, "Conway's Game of Life");
// Initialize SDL within the window class
bool running = window.initSDL();
while (running)
{
// Check if the X button on the window was clicked, stop looping if so
running = (window.wasEventTriggered(SDL_QUIT)) ? false : true;
// Render the cell vector on the SDL window
window.render2DBoolVector(cellVector.getCellVector());
// Calculate one generation of The Game of Life
cellVector.tick();
// Crude delay system for the moment
SDL_Delay(static_cast<Uint32>(1 / 60 * 1e4));
}
// Deallocate and destroy all SDL variables and windows
window.closeSDL();
return 0;
}
CellVector::tick():
void CellVector::tick()
{
std::vector<std::vector<bool>> vectorCopy = cellVector;
for (int x = 0; x < height; x++)
{
for (int y = 0; y < width; y++)
{
int amountOfNeighbors = getAmountOfNeighbors(x, y);
// Alive and has 2 neighbors - Cell Lives
if (cellVector[x][y] && amountOfNeighbors == 2)
{
vectorCopy[x][y] = 1;
}
// Has 3 neighbors - Cell Lives/Is Born
else if (amountOfNeighbors == 3)
{
vectorCopy[x][y] = 1;
}
// Neither previous conditions satisfied - Cell Dies
else
{
vectorCopy[x][y] = 0;
}
}
}
cellVector.swap(vectorCopy);
}
Window::render2DBoolVector():
void Window::render2DBoolVector(std::vector<std::vector<bool>> boolVector)
{
std::cout << "Rendering cell vector...\n";
SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
SDL_RenderClear(renderer);
int vectorWidth = boolVector.size();
int vectorHeight = boolVector[0].size();
for (int x = 0; x < vectorWidth; x++)
{
for (int y = 0; y < vectorHeight; y++)
{
// Renderer draws in black if the cell is alive, white if it is dead
(boolVector[x][y]) ? SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255)
: SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
SDL_Rect cell;
cell.x = static_cast<int>(ceil(x * (windowWidth / vectorWidth)));
cell.w = static_cast<int>(ceil(windowWidth / vectorWidth));
cell.y = static_cast<int>(ceil(y * (windowHeight / vectorHeight)));
cell.h = static_cast<int>(ceil(windowHeight / vectorHeight));
SDL_RenderFillRect(renderer, &cell);
}
}
SDL_RenderPresent(renderer);
std::cout << "Cell vector rendered...\n";
}