基于SFML的康威生命游戏细胞网格创建及交互实现咨询
康威生命游戏开发问题
我有Java开发背景,现在用C++结合SFML库开发首个图形化程序,目标是实现康威生命游戏。目前的思路是创建基础细胞网格,每个细胞包含x、y坐标与状态(初始为死亡)。但因为SFML和Java布局机制不同,不清楚如何创建带有独立数据的细胞网格,同时需要实现点击细胞时控制台输出响应的功能。以下是我写的不完整代码,请求指导完成:
main.cpp
#include <iostream> #include "Include/Grid.h" const int32_t windowWidth = 1000; // 窗口像素宽度 const int32_t windowHeight = 800; // 窗口像素高度 int main() { // 测试需求:运行程序后弹出网格,可点击放置黑色方块 Grid gameOfLife(windowWidth, windowHeight); gameOfLife.run(); return 0; }
cell.h
#ifndef CELLULARAUTOMATA2D_CELL_H #define CELLULARAUTOMATA2D_CELL_H #include <iostream> #include <vector> #include <cstdio> #include <SFML/Graphics.hpp> #include <SFML/Window.hpp> // 用枚举记录细胞状态,初始为死亡,点击后可切换为存活 class Cell { public: enum State { ALIVE, DEAD }; private: std::int32_t xCell; std::int32_t yCell; State cellState; public: sf::RectangleShape cell; [[nodiscard]] int getX() const; [[nodiscard]] int getY() const; State getState(); void toggleState(); // 新增:切换细胞状态并更新视觉表现 void setPosition(int xPos, int yPos); Cell(int xPos, int yPos, Cell::State state); }; #endif //CELLULARAUTOMATA2D_CELL_H
cell.cpp
#include "Include/Cell.h" #include <SFML/Graphics.hpp> #include <SFML/Window.hpp> Cell::Cell(int xPos, int yPos, Cell::State state) { this->xCell = xPos; this->yCell = yPos; this->cellState = state; this->cell = sf::RectangleShape(sf::Vector2f(10,10)); cell.setFillColor(sf::Color::White); cell.setOutlineColor(sf::Color::Black); cell.setOutlineThickness(1); // 新增:设置轮廓厚度,让网格边界更清晰 // 将细胞坐标转换为窗口像素位置 cell.setPosition(static_cast<float>(xPos * 10), static_cast<float>(yPos * 10)); } int Cell::getX() const { return xCell; } int Cell::getY() const { return yCell; } Cell::State Cell::getState() { return cellState; } void Cell::setPosition(int xPos, int yPos) { xCell = xPos; yCell = yPos; cell.setPosition(static_cast<float>(xPos * 10), static_cast<float>(yPos * 10)); } // 新增:切换细胞状态并同步颜色 void Cell::toggleState() { cellState = (cellState == DEAD) ? ALIVE : DEAD; cell.setFillColor(cellState == ALIVE ? sf::Color::Black : sf::Color::White); }
grid.h
#ifndef CELLULARAUTOMATA2D_GRID_H #define CELLULARAUTOMATA2D_GRID_H #include <iostream> #include <vector> #include <cstdio> #include "Cell.h" class Grid { private: std::vector<std::vector<Cell>> gridVector; int32_t cellRows; // 细胞行数 int32_t cellCols; // 细胞列数 bool isRunning; const int CELL_SIZE = 10; // 单个细胞的像素尺寸 public: void initGridVector(); void setWidth(int pixelWidth); void setHeight(int pixelHeight); void toggleCell(int x, int y); // 新增:切换指定位置细胞状态 void gridCopy(); void update(); void run(); void display(int pixelWidth, int pixelHeight); // 去掉const,因为需要修改细胞状态 Grid(int pixelWidth, int pixelHeight); }; #endif //CELLULARAUTOMATA2D_GRID_H
grid.cpp
#include "Include/Grid.h" #include "Include/Cell.h" #include <iostream> #include <vector> #include <SFML/Graphics.hpp> #include <SFML/Window.hpp> Grid::Grid(int pixelWidth, int pixelHeight) { // 将窗口像素尺寸转换为细胞行列数 this->cellRows = pixelHeight / CELL_SIZE; this->cellCols = pixelWidth / CELL_SIZE; this->isRunning = false; } void Grid::initGridVector() { gridVector.clear(); // 初始化前清空,避免重复创建 for(int i = 0; i < cellRows; i++){ std::vector<Cell> cellVec; for(int j = 0; j < cellCols; j++){ // 直接构造Cell对象,避免new导致的内存泄漏 cellVec.emplace_back(j, i, Cell::DEAD); } gridVector.push_back(cellVec); } } void Grid::display(int pixelWidth, int pixelHeight) { sf::RenderWindow window(sf::VideoMode(pixelWidth,pixelHeight), "Cellular Automata"); while (window.isOpen() && isRunning) { sf::Event event; while (window.pollEvent(event)) { if (event.type == sf::Event::Closed) { window.close(); } // 处理鼠标左键点击事件 if (event.type == sf::Event::MouseButtonPressed && event.mouseButton.button == sf::Mouse::Left) { // 将鼠标像素位置转换为细胞坐标 int cellX = event.mouseButton.x / CELL_SIZE; int cellY = event.mouseButton.y / CELL_SIZE; // 检查坐标是否在网格范围内 if (cellX >= 0 && cellX < cellCols && cellY >=0 && cellY < cellRows) { toggleCell(cellX, cellY); // 控制台输出点击响应 std::cout << "点击细胞 (" << cellX << ", " << cellY << "),当前状态:" << (gridVector[cellY][cellX].getState() == Cell::ALIVE ? "存活" : "死亡") << std::endl; } } } window.clear(sf::Color::White); // 设置窗口背景为白色 for (auto & row : gridVector){ for (auto & cell : row){ window.draw(cell.cell); } } window.display(); } } void Grid::setWidth(int pixelWidth) { this->cellCols = pixelWidth / CELL_SIZE; } void Grid::setHeight(int pixelHeight) { this->cellRows = pixelHeight / CELL_SIZE; } void Grid::toggleCell(int x, int y) { gridVector[y][x].toggleState(); } void Grid::gridCopy() { // 后续实现生命游戏状态复制逻辑 } void Grid::update() { // 后续实现生命游戏规则更新逻辑 } void Grid::run() { std::cout << "Automata is running" << std::endl; isRunning = true; initGridVector(); display(cellCols * CELL_SIZE, cellRows * CELL_SIZE); // 传递窗口像素尺寸 }
关键修正与实现说明
- 修复内存泄漏:原
initGridVector中使用*new Cell(...)会导致内存泄漏,改为直接用emplace_back构造Cell对象,避免手动分配内存。 - 统一坐标映射:定义
CELL_SIZE常量,将窗口像素尺寸转换为细胞行列数,同时在Cell构造时将细胞坐标转换为窗口像素位置,确保网格正确显示。 - 实现点击交互:在
display的事件循环中处理鼠标点击事件,将像素坐标转换为细胞坐标,调用toggleCell切换状态,并在控制台输出点击信息。 - 完善状态视觉反馈:新增
toggleState方法,切换细胞生死状态的同时更新填充颜色,让操作反馈更直观。 - 调整尺寸逻辑:将Grid构造函数中的像素宽高转换为细胞行列数,避免生成超出窗口范围的无效细胞。
内容的提问来源于stack exchange,提问作者Cr3
相关产品推荐
相关产品推荐

