You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于Raylib的C语言生命游戏:鼠标交互版本渲染失败求助

康威生命游戏Raylib版本渲染问题排查与修复

以下是导致你的版本无法正常渲染和工作的核心问题及修复方案:

核心问题分析

  • 主循环内频繁重置网格:在while (!WindowShouldClose())开头,每次循环都会将mat数组全部置0,用户点击设置的细胞会被立刻清空,模拟状态也无法保留。
  • 鼠标坐标未转换为网格索引:直接使用鼠标的像素坐标作为mat的二维索引,像素坐标(0-600)远大于网格尺寸(20),会导致数组越界访问,行为未定义。
  • 渲染流程不完整:只有按下空格键后才会执行EndDrawing(),平时没有主动刷新屏幕,导致窗口一直无内容;同时渲染代码被嵌套在模拟逻辑内,无法实时显示用户点击的细胞。
  • 模拟状态更新条件错误:更新mat的条件是IsKeyDown(KEY_A),这不符合“按空格键启动模拟”的需求,且会导致模拟状态无法正常迭代。
  • 阻塞式模拟循环:按下空格键后会执行一个4次迭代的for循环,阻塞主循环,期间无法处理窗口关闭、鼠标输入等事件,导致程序假死。

修复后的完整代码

#include <stdlib.h>
#include <time.h>
#include <stdio.h>
#include <unistd.h>
#include "raylib.h"
#include "raymath.h"

int main()
{
    int mat[20][20] = {0}; // 初始化全为0
    int buffer[20][20] = {0};
    int up, down, left, right;
    int life;
    int i, j;
    int COLS = 20;
    int ROWS = 20;

    int screenWidth = 600;
    int screenHeight = 600;
    int cellWidth = screenWidth / COLS;
    int cellHeight = screenHeight / ROWS;

    bool isSimulating = false; // 模拟状态标记,替代阻塞循环
    SetTargetFPS(5); // 适当提高帧率,让交互更流畅
    InitWindow(screenWidth, screenHeight, "Conway's Game of Life");

    while (!WindowShouldClose())
    {
        // 1. 输入处理
        // 点击设置活细胞
        if (IsMouseButtonPressed(MOUSE_BUTTON_LEFT))
        {
            Vector2 mPos = GetMousePosition();
            // 将像素坐标转换为网格行列索引
            int gridX = mPos.x / cellWidth;
            int gridY = mPos.y / cellHeight;
            // 边界检查,避免越界
            if (gridX >= 0 && gridX < COLS && gridY >=0 && gridY < ROWS)
            {
                mat[gridX][gridY] = 1;
            }
        }
        // 按空格键切换模拟状态
        if (IsKeyPressed(KEY_SPACE))
        {
            isSimulating = !isSimulating;
        }
        // 按R键重置网格
        if (IsKeyPressed(KEY_R))
        {
            for (i = 0; i < ROWS; i++)
            {
                for (j = 0; j < COLS; j++)
                {
                    mat[i][j] = 0;
                }
            }
            isSimulating = false;
        }

        // 2. 模拟逻辑(仅在模拟状态时执行)
        if (isSimulating)
        {
            // 重置buffer
            for (i = 0; i < ROWS; i++)
            {
                for (j = 0; j < COLS; j++)
                {
                    buffer[i][j] = 0;
                }
            }

            // 计算每个细胞的下一状态
            for (i = 0; i < ROWS; i++)
            {
                for (j = 0; j < COLS; j++)
                {
                    right = (j + 1) % COLS;
                    left = ((j - 1) + COLS) % COLS;
                    up = ((i - 1) + ROWS) % ROWS;
                    down = (i + 1) % ROWS;

                    life = mat[down][j] + mat[i][left] + mat[up][left] + mat[up][j] + mat[up][right] + mat[i][right] + mat[down][right] + mat[down][left];

                    if (mat[i][j] == 1 && (life < 2 || life > 3))
                    {
                        buffer[i][j] = 0;
                    }
                    else if (mat[i][j] == 1 && (life == 2 || life == 3))
                    {
                        buffer[i][j] = 1;
                    }
                    else if (mat[i][j] == 0 && life == 3)
                    {
                        buffer[i][j] = 1;
                    }
                }
            }

            // 更新当前网格状态
            for (i = 0; i < ROWS; i++)
            {
                for (j = 0; j < COLS; j++)
                {
                    mat[i][j] = buffer[i][j];
                }
            }
        }

        // 3. 渲染流程(每次循环都执行,保证屏幕实时刷新)
        BeginDrawing();
        ClearBackground(WHITE);

        // 绘制网格
        for (i = 0; i < ROWS; i++)
        {
            for (j = 0; j < COLS; j++)
            {
                if (mat[i][j] == 1)
                {
                    DrawRectangle(i * cellWidth, j * cellHeight, cellWidth, cellHeight, BLACK);
                }
                // 绘制单元格边框
                DrawRectangleLines(i * cellWidth, j * cellHeight, cellWidth, cellHeight, GRAY);
            }
        }

        // 绘制提示文本
        DrawText("Click to place cells | SPACE to start/stop | R to reset", 10, screenHeight - 30, 20, GRAY);
        EndDrawing();
    }

    CloseWindow();
    return 0;
}

修复说明

  1. 移除主循环内的网格重置:仅在程序初始化和按R键时重置网格,保留用户设置的细胞状态。
  2. 修正鼠标坐标转换:将像素坐标除以单元格尺寸,得到网格索引,并添加边界检查避免越界。
  3. 完善渲染流程:将BeginDrawing()和EndDrawing()放在主循环固定位置,每次循环都渲染当前网格,保证屏幕实时更新。
  4. 使用状态机控制模拟:用isSimulating布尔变量替代阻塞式for循环,每次主循环执行一次模拟迭代,同时不影响输入事件处理。
  5. 添加额外交互功能:增加R键重置网格,添加操作提示文本,提升用户体验。

内容的提问来源于stack exchange,提问作者IllTime00qw

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 19:19:51