• 个人简介

    #include "Camera.h"

    Camera::Camera(float fov, float aspectRatio, float nearPlane, float farPlane) : position(0.0f, 0.0f, 3.0f), front(0.0f, 0.0f, -1.0f), up(0.0f, 1.0f, 0.0f), right(1.0f, 0.0f, 0.0f), worldUp(0.0f, 1.0f, 0.0f), yaw(-90.0f), pitch(0.0f), fov(fov), aspectRatio(aspectRatio), nearPlane(nearPlane), farPlane(farPlane) {

    updateVectors();
    updateMatrices();
    

    }

    void Camera::update() { updateVectors(); updateMatrices(); }

    void Camera::setPosition(const glm::vec3& position) { this->position = position; }

    void Camera::setRotation(float yaw, float pitch) { this->yaw = yaw; this->pitch = pitch;

    // 限制pitch角度,防止过度旋转
    if (pitch > 89.0f) pitch = 89.0f;
    if (pitch < -89.0f) pitch = -89.0f;
    
    updateVectors();
    

    }

    void Camera::move(const glm::vec3& offset) { position += offset; }

    void Camera::rotate(float yawOffset, float pitchOffset) { yaw += yawOffset; pitch += pitchOffset;

    // 限制pitch角度,防止过度旋转
    if (pitch > 89.0f) pitch = 89.0f;
    if (pitch < -89.0f) pitch = -89.0f;
    
    updateVectors();
    

    }

    void Camera::updateVectors() { // 计算新的front向量 glm::vec3 newFront; newFront.x = cos(glm::radians(yaw)) * cos(glm::radians(pitch)); newFront.y = sin(glm::radians(pitch)); newFront.z = sin(glm::radians(yaw)) * cos(glm::radians(pitch)); front = glm::normalize(newFront);

    // 重新计算right和up向量
    right = glm::normalize(glm::cross(front, worldUp));
    up = glm::normalize(glm::cross(right, front));
    

    }

    void Camera::updateMatrices() { // 计算视图矩阵 viewMatrix = glm::lookAt(position, position + front, up);

    // 计算投影矩阵
    projectionMatrix = glm::perspective(glm::radians(fov), aspectRatio, nearPlane, farPlane);
    

    } #pragma once #include <glm/glm.hpp> #include <glm/gtc/matrix_transform.hpp>

    class Camera { public: Camera(float fov, float aspectRatio, float nearPlane, float farPlane);

    void update();
    void setPosition(const glm::vec3& position);
    void setRotation(float yaw, float pitch);
    void move(const glm::vec3& offset);
    void rotate(float yawOffset, float pitchOffset);
    
    const glm::mat4& getViewMatrix() const { return viewMatrix; }
    const glm::mat4& getProjectionMatrix() const { return projectionMatrix; }
    const glm::vec3& getPosition() const { return position; }
    const glm::vec3& getFront() const { return front; }
    const glm::vec3& getUp() const { return up; }
    const glm::vec3& getRight() const { return right; }
    

    private: glm::vec3 position; glm::vec3 front; glm::vec3 up; glm::vec3 right; glm::vec3 worldUp;

    float yaw;
    float pitch;
    
    float fov;
    float aspectRatio;
    float nearPlane;
    float farPlane;
    
    glm::mat4 viewMatrix;
    glm::mat4 projectionMatrix;
    
    void updateVectors();
    void updateMatrices();
    

    }; #include "Input.h" #include

    Input::Input(GLFWwindow* window) : window(window), mouseX(0.0), mouseY(0.0), previousMouseX(0.0), previousMouseY(0.0), mouseDeltaX(0.0), mouseDeltaY(0.0), mouseLocked(false) {

    // 设置回调函数
    glfwSetKeyCallback(window, keyCallback);
    glfwSetMouseButtonCallback(window, mouseButtonCallback);
    
    // 存储Input实例到窗口用户指针
    glfwSetWindowUserPointer(window, this);
    
    // 获取初始鼠标位置
    glfwGetCursorPos(window, &mouseX, &mouseY);
    previousMouseX = mouseX;
    previousMouseY = mouseY;
    

    }

    void Input::update() { // 保存上一帧的按键状态 previousKeys = currentKeys; previousMouseButtons = currentMouseButtons;

    // 获取当前鼠标位置
    previousMouseX = mouseX;
    previousMouseY = mouseY;
    glfwGetCursorPos(window, &mouseX, &mouseY);
    
    // 计算鼠标移动增量
    mouseDeltaX = mouseX - previousMouseX;
    mouseDeltaY = mouseY - previousMouseY;
    

    }

    bool Input::isKeyPressed(int key) const { auto it = currentKeys.find(key); auto prevIt = previousKeys.find(key);

    return (it != currentKeys.end() && it->second) && 
           (prevIt == previousKeys.end() || !prevIt->second);
    

    }

    bool Input::isKeyDown(int key) const { auto it = currentKeys.find(key); return it != currentKeys.end() && it->second; }

    bool Input::isKeyReleased(int key) const { auto it = currentKeys.find(key); auto prevIt = previousKeys.find(key);

    return (it == currentKeys.end() || !it->second) && 
           (prevIt != previousKeys.end() && prevIt->second);
    

    }

    bool Input::isMouseButtonPressed(int button) const { auto it = currentMouseButtons.find(button); auto prevIt = previousMouseButtons.find(button);

    return (it != currentMouseButtons.end() && it->second) && 
           (prevIt == previousMouseButtons.end() || !prevIt->second);
    

    }

    bool Input::isMouseButtonDown(int button) const { auto it = currentMouseButtons.find(button); return it != currentMouseButtons.end() && it->second; }

    bool Input::isMouseButtonReleased(int button) const { auto it = currentMouseButtons.find(button); auto prevIt = previousMouseButtons.find(button);

    return (it == currentMouseButtons.end() || !it->second) && 
           (prevIt != previousMouseButtons.end() && prevIt->second);
    

    }

    void Input::setMouseLocked(bool locked) { mouseLocked = locked; if (locked) { glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); } else { glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL); } }

    void Input::keyCallback(GLFWwindow* window, int key, int scancode, int action, int mods) { Input* input = static_cast<Input*>(glfwGetWindowUserPointer(window)); if (input) { if (action == GLFW_PRESS) { input->currentKeys[key] = true; } else if (action == GLFW_RELEASE) { input->currentKeys[key] = false; } } }

    void Input::mouseButtonCallback(GLFWwindow* window, int button, int action, int mods) { Input* input = static_cast<Input*>(glfwGetWindowUserPointer(window)); if (input) { if (action == GLFW_PRESS) { input->currentMouseButtons[button] = true; } else if (action == GLFW_RELEASE) { input->currentMouseButtons[button] = false; } } } #pragma once #include <GLFW/glfw3.h> #include <unordered_map>

    class Input { public: Input(GLFWwindow* window);

    void update();
    
    bool isKeyPressed(int key) const;
    bool isKeyDown(int key) const;
    bool isKeyReleased(int key) const;
    
    bool isMouseButtonPressed(int button) const;
    bool isMouseButtonDown(int button) const;
    bool isMouseButtonReleased(int button) const;
    
    double getMouseX() const { return mouseX; }
    double getMouseY() const { return mouseY; }
    double getMouseDeltaX() const { return mouseDeltaX; }
    double getMouseDeltaY() const { return mouseDeltaY; }
    
    void setMouseLocked(bool locked);
    bool isMouseLocked() const { return mouseLocked; }
    

    private: GLFWwindow* window;

    std::unordered_map<int, bool> currentKeys;
    std::unordered_map<int, bool> previousKeys;
    
    std::unordered_map<int, bool> currentMouseButtons;
    std::unordered_map<int, bool> previousMouseButtons;
    
    double mouseX;
    double mouseY;
    double previousMouseX;
    double previousMouseY;
    double mouseDeltaX;
    double mouseDeltaY;
    
    bool mouseLocked;
    
    static void keyCallback(GLFWwindow* window, int key, int scancode, int action, int mods);
    static void mouseButtonCallback(GLFWwindow* window, int button, int action, int mods);
    

    }; #include "Window.h" #include

    Window::Window(const std::string& title, int width, int height) : title(title), width(width), height(height), window(nullptr) { init(); }

    Window::~Window() { cleanup(); }

    void Window::init() { // 初始化GLFW if (!glfwInit()) { std::cerr << "Failed to initialize GLFW" << std::endl; exit(-1); }

    // 设置OpenGL版本
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
    
    // 创建窗口
    window = glfwCreateWindow(width, height, title.c_str(), nullptr, nullptr);
    if (!window) {
        std::cerr << "Failed to create GLFW window" << std::endl;
        glfwTerminate();
        exit(-1);
    }
    
    // 设置当前上下文
    glfwMakeContextCurrent(window);
    
    // 初始化GLEW
    if (glewInit() != GLEW_OK) {
        std::cerr << "Failed to initialize GLEW" << std::endl;
        exit(-1);
    }
    
    // 设置视口
    glViewport(0, 0, width, height);
    
    // 设置窗口大小回调
    glfwSetWindowSizeCallback(window, [](GLFWwindow* window, int width, int height) {
        glViewport(0, 0, width, height);
    });
    

    }

    void Window::cleanup() { glfwDestroyWindow(window); glfwTerminate(); }

    bool Window::shouldClose() const { return glfwWindowShouldClose(window); }

    void Window::update() { glfwSwapBuffers(window); glfwPollEvents(); }

    void Window::setTitle(const std::string& title) { this->title = title; glfwSetWindowTitle(window, title.c_str()); } #pragma once #include #include <GLFW/glfw3.h>

    class Window { public: Window(const std::string& title, int width, int height); ~Window();

    bool shouldClose() const;
    void update();
    void setTitle(const std::string& title);
    
    int getWidth() const { return width; }
    int getHeight() const { return height; }
    GLFWwindow* getHandle() { return window; }
    

    private: GLFWwindow* window; std::string title; int width; int height;

    void init();
    void cleanup();
    

    }; #include "Physics.h" #include

    Physics::Physics() : gravity(0.0f, -9.81f, 0.0f), airResistance(0.05f), groundFriction(0.1f) { }

    Physics::~Physics() { }

    void Physics::applyGravity(glm::vec3& velocity, float deltaTime) const { velocity += gravity * deltaTime; }

    bool Physics::checkCollision(const AABB& aabb, const Block& block) const { // 如果方块是空气或透明的,不进行碰撞检测 if (block.getType() == BlockType::AIR || block.isTransparent()) { return false; }

    // 创建方块的碰撞箱
    AABB blockAABB = createBlockAABB(glm::vec3(0.0f), block.getType());
    
    // 检查碰撞
    return aabb.intersects(blockAABB);
    

    }

    bool Physics::resolveCollision(AABB& aabb, glm::vec3& velocity, const Block& block, float deltaTime) { // 如果方块是空气或透明的,不进行碰撞检测 if (block.getType() == BlockType::AIR || block.isTransparent()) { return false; }

    // 创建方块的碰撞箱
    AABB blockAABB = createBlockAABB(glm::vec3(0.0f), block.getType());
    
    // 检查是否碰撞
    if (!aabb.intersects(blockAABB)) {
        return false;
    }
    
    // 计算碰撞法线
    glm::vec3 aabbCenter = aabb.getCenter();
    glm::vec3 blockCenter = blockAABB.getCenter();
    glm::vec3 delta = aabbCenter - blockCenter;
    
    // 找出最小的重叠轴
    float overlapX = (aabb.getSize().x + blockAABB.getSize().x) * 0.5f - std::abs(delta.x);
    float overlapY = (aabb.getSize().y + blockAABB.getSize().y) * 0.5f - std::abs(delta.y);
    float overlapZ = (aabb.getSize().z + blockAABB.getSize().z) * 0.5f - std::abs(delta.z);
    
    if (overlapX < 0 || overlapY < 0 || overlapZ < 0) {
        return false;
    }
    
    // 找出最小的重叠
    if (overlapX < overlapY && overlapX < overlapZ) {
        // X轴碰撞
        if (delta.x > 0) {
            aabb.min.x = blockAABB.max.x;
        } else {
            aabb.max.x = blockAABB.min.x;
        }
        velocity.x = 0.0f;
    } else if (overlapY < overlapX && overlapY < overlapZ) {
        // Y轴碰撞
        if (delta.y > 0) {
            aabb.min.y = blockAABB.max.y;
        } else {
            aabb.max.y = blockAABB.min.y;
        }
        velocity.y = 0.0f;
    } else {
        // Z轴碰撞
        if (delta.z > 0) {
            aabb.min.z = blockAABB.max.z;
        } else {
            aabb.max.z = blockAABB.min.z;
        }
        velocity.z = 0.0f;
    }
    
    return true;
    

    }

    bool Physics::checkBlockCollision(const AABB& aabb, const glm::vec3& position) const { // 创建方块的碰撞箱 AABB blockAABB = createBlockAABB(position);

    // 检查碰撞
    return aabb.intersects(blockAABB);
    

    }

    AABB Physics::createBlockAABB(const glm::vec3& position) const { return AABB(position, position + glm::vec3(1.0f)); }

    AABB Physics::createBlockAABB(const glm::vec3& position, BlockType type) const { switch (type) { case BlockType::WATER: // 水方块的碰撞箱略小 return AABB(position + glm::vec3(0.0f, 0.0f, 0.0f), position + glm::vec3(1.0f, 0.9f, 1.0f)); case BlockType::LEAVES: // 树叶的碰撞箱也略小 return AABB(position + glm::vec3(0.05f, 0.05f, 0.05f), position + glm::vec3(0.95f, 0.95f, 0.95f)); default: // 普通方块的碰撞箱 return AABB(position, position + glm::vec3(1.0f)); } }

    bool Physics::checkFaceCollision(const AABB& aabb, const AABB& blockAABB, Block::Face face) const { // 根据面的方向检查碰撞 switch (face) { case Block::FRONT: return aabb.max.z >= blockAABB.min.z && aabb.min.z < blockAABB.min.z; case Block::BACK: return aabb.min.z <= blockAABB.max.z && aabb.max.z > blockAABB.max.z; case Block::LEFT: return aabb.min.x <= blockAABB.max.x && aabb.max.x > blockAABB.max.x; case Block::RIGHT: return aabb.max.x >= blockAABB.min.x && aabb.min.x < blockAABB.min.x; case Block::TOP: return aabb.max.y >= blockAABB.min.y && aabb.min.y < blockAABB.min.y; case Block::BOTTOM: return aabb.min.y <= blockAABB.max.y && aabb.max.y > blockAABB.max.y; default: return false; } }

    bool Physics::resolveFaceCollision(AABB& aabb, glm::vec3& velocity, const AABB& blockAABB, Block::Face face, float deltaTime) { // 根据面的方向解决碰撞 switch (face) { case Block::FRONT: aabb.max.z = blockAABB.min.z; velocity.z = 0.0f; return true; case Block::BACK: aabb.min.z = blockAABB.max.z; velocity.z = 0.0f; return true; case Block::LEFT: aabb.min.x = blockAABB.max.x; velocity.x = 0.0f; return true; case Block::RIGHT: aabb.max.x = blockAABB.min.x; velocity.x = 0.0f; return true; case Block::TOP: aabb.max.y = blockAABB.min.y; velocity.y = 0.0f; return true; case Block::BOTTOM: aabb.min.y = blockAABB.max.y; velocity.y = 0.0f; return true; default: return false; } } #pragma once #include <glm/glm.hpp> #include "../world/Block.h"

    // 轴对齐边界框 struct AABB { glm::vec3 min; glm::vec3 max;

    AABB() : min(0.0f), max(0.0f) {}
    AABB(const glm::vec3& min, const glm::vec3& max) : min(min), max(max) {}
    
    // 检查点是否在AABB内
    bool contains(const glm::vec3& point) const {
        return point.x >= min.x && point.x <= max.x &&
               point.y >= min.y && point.y <= max.y &&
               point.z >= min.z && point.z <= max.z;
    }
    
    // 检查两个AABB是否相交
    bool intersects(const AABB& other) const {
        return min.x < other.max.x && max.x > other.min.x &&
               min.y < other.max.y && max.y > other.min.y &&
               min.z < other.max.z && max.z > other.min.z;
    }
    
    // 获取AABB的中心点
    glm::vec3 getCenter() const {
        return (min + max) * 0.5f;
    }
    
    // 获取AABB的大小
    glm::vec3 getSize() const {
        return max - min;
    }
    

    };

    class Physics { public: Physics(); ~Physics();

    // 设置重力
    void setGravity(const glm::vec3& gravity) { this->gravity = gravity; }
    const glm::vec3& getGravity() const { return gravity; }
    
    // 应用重力
    void applyGravity(glm::vec3& velocity, float deltaTime) const;
    
    // 碰撞检测
    bool checkCollision(const AABB& aabb, const Block& block) const;
    
    // 解决碰撞
    bool resolveCollision(AABB& aabb, glm::vec3& velocity, const Block& block, float deltaTime);
    
    // 方块碰撞检测
    bool checkBlockCollision(const AABB& aabb, const glm::vec3& position) const;
    
    // 从方块位置创建碰撞箱
    AABB createBlockAABB(const glm::vec3& position) const;
    
    // 从方块位置和类型创建碰撞箱
    AABB createBlockAABB(const glm::vec3& position, BlockType type) const;
    

    private: glm::vec3 gravity; float airResistance; float groundFriction;

    // 检查AABB与方块面的碰撞
    bool checkFaceCollision(const AABB& aabb, const AABB& blockAABB, Block::Face face) const;
    
    // 解决AABB与方块面的碰撞
    bool resolveFaceCollision(AABB& aabb, glm::vec3& velocity, const AABB& blockAABB, Block::Face face, float deltaTime);
    

    }; #pragma once #include <glm/glm.hpp> #include "../core/Camera.h" #include "../core/Input.h" #include "../world/World.h" #include "Physics.h"

    class Player { public: Player(Camera* camera, World* world, Input* input); ~Player();

    void update(float deltaTime);
    void handleInput(float deltaTime);
    
    // 获取玩家位置
    const glm::vec3& getPosition() const { return position; }
    void setPosition(const glm::vec3& position);
    
    // 获取玩家视角
    float getYaw() const { return yaw; }
    float getPitch() const { return pitch; }
    void setRotation(float yaw, float pitch);
    
    // 玩家状态
    bool isFlying() const { return flying; }
    void setFlying(bool flying) { this->flying = flying; }
    
    bool isSwimming() const { return swimming; }
    bool isOnGround() const { return onGround; }
    
    // 方块交互
    void breakBlock();
    void placeBlock(BlockType type);
    
    // 获取当前选中的方块
    bool getSelectedBlock(glm::vec3& blockPosition, Block::Face& face) const;
    

    private: Camera* camera; World* world; Input* input; Physics physics;

    glm::vec3 position;
    glm::vec3 velocity;
    
    float yaw;
    float pitch;
    
    float walkSpeed;
    float sprintSpeed;
    float flySpeed;
    float jumpStrength;
    
    bool flying;
    bool swimming;
    bool onGround;
    bool sprinting;
    
    // 玩家碰撞箱
    AABB boundingBox;
    
    // 更新摄像机
    void updateCamera();
    
    // 处理移动
    void handleMovement(float deltaTime);
    
    // 处理跳跃
    void handleJump();
    
    // 检测玩家状态
    void updatePlayerState();
    
    // 更新碰撞箱
    void updateBoundingBox();
    
    // 射线检测最大距离
    static const float REACH_DISTANCE;
    

    }; #include "Renderer.h" #include #include <glm/glm.hpp> #include <glm/gtc/matrix_transform.hpp>

    Renderer::Renderer() : debugMode(false) { initShaders(); initBuffers(); initTextures(); initSkybox(); }

    Renderer::~Renderer() { // 清理VAO和VBO glDeleteVertexArrays(1, &chunkVAO); glDeleteBuffers(1, &chunkVBO); glDeleteBuffers(1, &chunkEBO);

    glDeleteVertexArrays(1, &skyboxVAO);
    glDeleteBuffers(1, &skyboxVBO);
    

    }

    void Renderer::beginFrame() { // 清除颜色和深度缓冲 glClearColor(0.529f, 0.808f, 0.922f, 1.0f); // 天空蓝 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    // 启用深度测试
    glEnable(GL_DEPTH_TEST);
    glEnable(GL_CULL_FACE);
    

    }

    void Renderer::endFrame() { // 禁用深度测试和背面剔除 glDisable(GL_DEPTH_TEST); glDisable(GL_CULL_FACE); }

    void Renderer::renderWorld(const World* world, const Camera* camera) { // 渲染天空盒 renderSkybox(camera);

    // 渲染所有加载的区块
    const auto& chunks = world->getLoadedChunks();
    for (const auto& pair : chunks) {
        const auto& chunk = pair.second;
        renderChunk(chunk.get());
    }
    
    // 使用区块着色器
    chunkShader->use();
    
    // 设置视图和投影矩阵
    chunkShader->setUniform("view", camera->getViewMatrix());
    chunkShader->setUniform("projection", camera->getProjectionMatrix());
    
    // 设置光照
    chunkShader->setUniform("lightPos", glm::vec3(100.0f, 200.0f, 100.0f));
    chunkShader->setUniform("lightColor", glm::vec3(1.0f, 1.0f, 0.9f));
    
    // 渲染所有加载的区块
    for (const auto& pair : chunks) {
        const auto& chunk = pair.second;
        renderChunk(chunk.get());
    }
    
    chunkShader->unuse();
    

    }

    void Renderer::renderChunk(const Chunk* chunk) { if (!chunk) return;

    // 检查区块是否有顶点数据
    if (chunk->getVertexCount() == 0) return;
    
    // 绑定VAO
    glBindVertexArray(chunkVAO);
    
    // 更新VBO数据
    glBindBuffer(GL_ARRAY_BUFFER, chunkVBO);
    glBufferData(GL_ARRAY_BUFFER, chunk->getVertices().size() * sizeof(float), chunk->getVertices().data(), GL_DYNAMIC_DRAW);
    
    // 更新EBO数据
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, chunkEBO);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, chunk->getIndices().size() * sizeof(unsigned int), chunk->getIndices().data(), GL_DYNAMIC_DRAW);
    
    // 绑定纹理
    Texture* texture = textureManager->getTexture("blocks");
    if (texture) {
        texture->bind(0);
        chunkShader->setUniform("textureAtlas", 0);
    }
    
    // 绘制区块
    glDrawElements(GL_TRIANGLES, chunk->getIndices().size(), GL_UNSIGNED_INT, 0);
    
    // 解绑
    glBindVertexArray(0);
    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
    

    }

    void Renderer::initShaders() { // 创建区块着色器 chunkShader = std::make_unique("resources/shaders/chunk.vert", "resources/shaders/chunk.frag");

    // 创建天空盒着色器
    skyboxShader = std::make_unique<Shader>("resources/shaders/skybox.vert", "resources/shaders/skybox.frag");
    

    }

    void Renderer::initBuffers() { // 创建区块VAO和VBO glGenVertexArrays(1, &chunkVAO); glGenBuffers(1, &chunkVBO); glGenBuffers(1, &chunkEBO);

    // 绑定VAO
    glBindVertexArray(chunkVAO);
    
    // 配置VBO
    glBindBuffer(GL_ARRAY_BUFFER, chunkVBO);
    
    // 配置顶点属性
    // 位置 (x, y, z)
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0);
    glEnableVertexAttribArray(0);
    
    // 纹理坐标 (u, v)
    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float)));
    glEnableVertexAttribArray(1);
    
    // 解绑
    glBindVertexArray(0);
    glBindBuffer(GL_ARRAY_BUFFER, 0);
    

    }

    void Renderer::initTextures() { // 创建纹理管理器 textureManager = std::make_unique();

    // 加载默认纹理
    textureManager->loadTexture("blocks", "resources/textures/blocks.png");
    textureManager->loadTexture("skybox", "resources/textures/skybox.png");
    

    }

    void Renderer::initSkybox() { // 天空盒顶点数据 float skyboxVertices[] = { // 后面 -1.0f, 1.0f, -1.0f, -1.0f, -1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, -1.0f, -1.0f, 1.0f, -1.0f, // 前面 -1.0f, -1.0f, 1.0f, -1.0f, -1.0f, -1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, -1.0f, -1.0f, 1.0f, // 右面 1.0f, -1.0f, -1.0f, 1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, -1.0f, 1.0f, -1.0f, -1.0f, // 左面 -1.0f, -1.0f, 1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, // 顶面 -1.0f, 1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f, -1.0f, // 底面 -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, 1.0f, 1.0f, -1.0f, -1.0f, 1.0f, -1.0f, -1.0f, -1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f };

    // 创建天空盒VAO和VBO
    glGenVertexArrays(1, &skyboxVAO);
    glGenBuffers(1, &skyboxVBO);
    
    // 绑定VAO
    glBindVertexArray(skyboxVAO);
    
    // 配置VBO
    glBindBuffer(GL_ARRAY_BUFFER, skyboxVBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(skyboxVertices), skyboxVertices, GL_STATIC_DRAW);
    
    // 配置顶点属性
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
    glEnableVertexAttribArray(0);
    
    // 解绑
    glBindVertexArray(0);
    glBindBuffer(GL_ARRAY_BUFFER, 0);
    

    }

    void Renderer::renderSkybox(const Camera* camera) { // 禁用深度写入 glDepthMask(GL_FALSE);

    // 使用天空盒着色器
    skyboxShader->use();
    
    // 设置视图矩阵(移除平移部分)
    glm::mat4 view = glm::mat4(glm::mat3(camera->getViewMatrix()));
    skyboxShader->setUniform("view", view);
    
    // 设置投影矩阵
    skyboxShader->setUniform("projection", camera->getProjectionMatrix());
    
    // 绑定天空盒纹理
    Texture* skyboxTexture = textureManager->getTexture("skybox");
    if (skyboxTexture) {
        skyboxTexture->bind(0);
        skyboxShader->setUniform("skybox", 0);
    }
    
    // 绑定VAO并绘制
    glBindVertexArray(skyboxVAO);
    glDrawArrays(GL_TRIANGLES, 0, 36);
    glBindVertexArray(0);
    
    // 启用深度写入
    glDepthMask(GL_TRUE);
    
    skyboxShader->unuse();
    

    }

    void Renderer::renderBlockOutline(const glm::vec3& position) { // TODO: 实现方块选择框渲染 } #pragma once #include #include <glad/glad.h> #include "../world/World.h" #include "../core/Camera.h" #include "Shader.h" #include "TextureManager.h"

    class Renderer { public: Renderer(); ~Renderer();

    void beginFrame();
    void endFrame();
    
    void renderWorld(const World* world, const Camera* camera);
    void renderChunk(const Chunk* chunk);
    
    // 设置调试模式
    void setDebugMode(bool debug) { debugMode = debug; }
    

    private: // 着色器 std::unique_ptr chunkShader; std::unique_ptr skyboxShader;

    // 纹理管理器
    std::unique_ptr<TextureManager> textureManager;
    
    // 天空盒VAO
    unsigned int skyboxVAO;
    unsigned int skyboxVBO;
    
    // 方块VAO
    unsigned int chunkVAO;
    unsigned int chunkVBO;
    unsigned int chunkEBO;
    
    // 调试模式
    bool debugMode;
    
    // 初始化
    void initShaders();
    void initBuffers();
    void initTextures();
    void initSkybox();
    
    // 渲染天空盒
    void renderSkybox(const Camera* camera);
    
    // 渲染方块选择框
    void renderBlockOutline(const glm::vec3& position);
    

    }; #include "Shader.h" #include #include #include #include <glad/glad.h>

    Shader::Shader(const std::string& vertexPath, const std::string& fragmentPath) { // 编译顶点着色器 unsigned int vertexShader = compileShader(vertexPath, GL_VERTEX_SHADER); if (vertexShader == 0) { std::cerr << "Failed to compile vertex shader" << std::endl; return; }

    // 编译片段着色器
    unsigned int fragmentShader = compileShader(fragmentPath, GL_FRAGMENT_SHADER);
    if (fragmentShader == 0) {
        std::cerr << "Failed to compile fragment shader" << std::endl;
        glDeleteShader(vertexShader);
        return;
    }
    
    // 创建着色器程序
    programID = glCreateProgram();
    glAttachShader(programID, vertexShader);
    glAttachShader(programID, fragmentShader);
    glLinkProgram(programID);
    
    // 检查链接错误
    int success;
    char infoLog[512];
    glGetProgramiv(programID, GL_LINK_STATUS, &success);
    if (!success) {
        glGetProgramInfoLog(programID, 512, NULL, infoLog);
        std::cerr << "Failed to link shader program: " << infoLog << std::endl;
        glDeleteShader(vertexShader);
        glDeleteShader(fragmentShader);
        programID = 0;
        return;
    }
    
    // 删除已链接的着色器
    glDeleteShader(vertexShader);
    glDeleteShader(fragmentShader);
    

    }

    Shader::~Shader() { if (programID != 0) { glDeleteProgram(programID); } }

    void Shader::use() const { if (programID != 0) { glUseProgram(programID); } }

    void Shader::unuse() const { glUseProgram(0); }

    void Shader::setUniform(const std::string& name, float value) const { int location = getUniformLocation(name); if (location != -1) { glUniform1f(location, value); } }

    void Shader::setUniform(const std::string& name, int value) const { int location = getUniformLocation(name); if (location != -1) { glUniform1i(location, value); } }

    void Shader::setUniform(const std::string& name, bool value) const { int location = getUniformLocation(name); if (location != -1) { glUniform1i(location, value ? 1 : 0); } }

    void Shader::setUniform(const std::string& name, const glm::vec2& value) const { int location = getUniformLocation(name); if (location != -1) { glUniform2fv(location, 1, &value[0]); } }

    void Shader::setUniform(const std::string& name, const glm::vec3& value) const { int location = getUniformLocation(name); if (location != -1) { glUniform3fv(location, 1, &value[0]); } }

    void Shader::setUniform(const std::string& name, const glm::vec4& value) const { int location = getUniformLocation(name); if (location != -1) { glUniform4fv(location, 1, &value[0]); } }

    void Shader::setUniform(const std::string& name, const glm::mat2& value) const { int location = getUniformLocation(name); if (location != -1) { glUniformMatrix2fv(location, 1, GL_FALSE, &value[0][0]); } }

    void Shader::setUniform(const std::string& name, const glm::mat3& value) const { int location = getUniformLocation(name); if (location != -1) { glUniformMatrix3fv(location, 1, GL_FALSE, &value[0][0]); } }

    void Shader::setUniform(const std::string& name, const glm::mat4& value) const { int location = getUniformLocation(name); if (location != -1) { glUniformMatrix4fv(location, 1, GL_FALSE, &value[0][0]); } }

    unsigned int Shader::compileShader(const std::string& path, unsigned int type) const { // 读取着色器文件 std::string shaderCode = readShaderFile(path); if (shaderCode.empty()) { return 0; }

    // 创建着色器
    unsigned int shader = glCreateShader(type);
    const char* codePtr = shaderCode.c_str();
    glShaderSource(shader, 1, &codePtr, NULL);
    glCompileShader(shader);
    
    // 检查编译错误
    int success;
    char infoLog[512];
    glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
    if (!success) {
        glGetShaderInfoLog(shader, 512, NULL, infoLog);
        std::cerr << "Failed to compile shader " << path << ": " << infoLog << std::endl;
        glDeleteShader(shader);
        return 0;
    }
    
    return shader;
    

    }

    int Shader::getUniformLocation(const std::string& name) const { // 检查缓存 auto it = uniformLocations.find(name); if (it != uniformLocations.end()) { return it->second; }

    // 获取位置并缓存
    int location = glGetUniformLocation(programID, name.c_str());
    if (location == -1) {
        std::cerr << "Warning: Uniform '" << name << "' not found in shader" << std::endl;
    }
    
    uniformLocations[name] = location;
    return location;
    

    }

    std::string Shader::readShaderFile(const std::string& path) const { std::ifstream file; std::stringstream stream;

    // 打开文件
    file.open(path);
    if (!file.is_open()) {
        std::cerr << "Failed to open shader file: " << path << std::endl;
        return "";
    }
    
    // 读取文件内容
    stream << file.rdbuf();
    file.close();
    
    return stream.str();
    

    }

    #pragma once #include #include <unordered_map> #include <glm/glm.hpp>

    class Shader { public: Shader(const std::string& vertexPath, const std::string& fragmentPath); ~Shader();

    void use() const;
    void unuse() const;
    
    // 设置 uniform 变量
    void setUniform(const std::string& name, float value) const;
    void setUniform(const std::string& name, int value) const;
    void setUniform(const std::string& name, bool value) const;
    void setUniform(const std::string& name, const glm::vec2& value) const;
    void setUniform(const std::string& name, const glm::vec3& value) const;
    void setUniform(const std::string& name, const glm::vec4& value) const;
    void setUniform(const std::string& name, const glm::mat2& value) const;
    void setUniform(const std::string& name, const glm::mat3& value) const;
    void setUniform(const std::string& name, const glm::mat4& value) const;
    
    unsigned int getProgramID() const { return programID; }
    

    private: unsigned int programID; std::unordered_map<std::string, int> uniformLocations;

    // 编译着色器
    unsigned int compileShader(const std::string& path, unsigned int type) const;
    
    // 获取 uniform 位置
    int getUniformLocation(const std::string& name) const;
    
    // 读取着色器文件
    std::string readShaderFile(const std::string& path) const;
    

    }; #include "Texture.h" #include #include <SOIL2/SOIL2.h>

    Texture::Texture(const std::string& path) : id(0), width(0), height(0), channels(0) { loadTexture(path); }

    Texture::~Texture() { if (id != 0) { glDeleteTextures(1, &id); } }

    void Texture::bind(unsigned int slot) const { glActiveTexture(GL_TEXTURE0 + slot); glBindTexture(GL_TEXTURE_2D, id); }

    void Texture::unbind() const { glBindTexture(GL_TEXTURE_2D, 0); }

    void Texture::loadTexture(const std::string& path) { // 生成纹理ID glGenTextures(1, &id); glBindTexture(GL_TEXTURE_2D, id);

    // 设置纹理参数
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    
    // 加载纹理图像
    unsigned char* data = SOIL_load_image(path.c_str(), &width, &height, &channels, SOIL_LOAD_RGBA);
    if (data) {
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
        glGenerateMipmap(GL_TEXTURE_2D);
    } else {
        std::cerr << "Failed to load texture: " << path << std::endl;
        std::cerr << "SOIL error: " << SOIL_last_result() << std::endl;
    }
    
    // 释放图像数据
    SOIL_free_image_data(data);
    glBindTexture(GL_TEXTURE_2D, 0);
    

    }

    TextureManager::TextureManager() : defaultTexturePath("resources/textures/") { }

    TextureManager::~TextureManager() { cleanup(); }

    Texture* TextureManager::getTexture(const std::string& name) { auto it = textures.find(name); if (it != textures.end()) { return it->second; }

    // 尝试加载纹理
    std::string path = defaultTexturePath + name + ".png";
    Texture* texture = new Texture(path);
    textures[name] = texture;
    return texture;
    

    }

    void TextureManager::loadTexture(const std::string& name, const std::string& path) { // 检查是否已存在 auto it = textures.find(name); if (it != textures.end()) { delete it->second; textures.erase(it); }

    // 加载新纹理
    Texture* texture = new Texture(path);
    textures[name] = texture;
    

    }

    void TextureManager::cleanup() { for (auto& pair : textures) { delete pair.second; } textures.clear(); } #pragma once #include #include <unordered_map> #include <glad/glad.h>

    class Texture { public: Texture(const std::string& path); ~Texture();

    void bind(unsigned int slot = 0) const;
    void unbind() const;
    
    unsigned int getID() const { return id; }
    int getWidth() const { return width; }
    int getHeight() const { return height; }
    

    private: unsigned int id; int width; int height; int channels;

    void loadTexture(const std::string& path);
    

    };

    class TextureManager { public: TextureManager(); ~TextureManager();

    // 获取或加载纹理
    Texture* getTexture(const std::string& name);
    
    // 加载纹理
    void loadTexture(const std::string& name, const std::string& path);
    
    // 清理所有纹理
    void cleanup();
    

    private: std::unordered_map<std::string, Texture*> textures;

    // 默认纹理路径
    std::string defaultTexturePath;
    

    }; #include "Block.h"

    Block::Block(BlockType type) : type(type) { }

    Block::~Block() { }

    bool Block::isSolid() const { return isSolidBlock(type); }

    bool Block::isTransparent() const { return isTransparentBlock(type); }

    std::string Block::getTextureName(int face) const { return getTextureForBlock(type, face); }

    bool Block::isSolidBlock(BlockType type) const { switch (type) { case BlockType::AIR: case BlockType::WATER: return false; case BlockType::GRASS: case BlockType::DIRT: case BlockType::STONE: case BlockType::SAND: case BlockType::WOOD: case BlockType::LEAVES: return true; default: return false; } }

    bool Block::isTransparentBlock(BlockType type) const { switch (type) { case BlockType::AIR: case BlockType::WATER: case BlockType::LEAVES: return true; case BlockType::GRASS: case BlockType::DIRT: case BlockType::STONE: case BlockType::SAND: case BlockType::WOOD: return false; default: return false; } }

    std::string Block::getTextureForBlock(BlockType type, int face) const { switch (type) { case BlockType::GRASS: if (face == TOP) return "grass_top"; if (face == BOTTOM) return "dirt"; return "grass_side"; case BlockType::DIRT: return "dirt"; case BlockType::STONE: return "stone"; case BlockType::SAND: return "sand"; case BlockType::WATER: return "water"; case BlockType::WOOD: if (face == TOP || face == BOTTOM) return "wood_top"; return "wood_side"; case BlockType::LEAVES: return "leaves"; default: return "missing"; } } #pragma once #include <glm/glm.hpp> #include

    enum class BlockType { AIR, GRASS, DIRT, STONE, SAND, WATER, WOOD, LEAVES };

    class Block { public: Block(BlockType type = BlockType::AIR); ~Block();

    BlockType getType() const { return type; }
    void setType(BlockType type) { this->type = type; }
    
    bool isSolid() const;
    bool isTransparent() const;
    
    std::string getTextureName(int face) const;
    
    static const int FACE_COUNT = 6;
    enum Face {
        FRONT,
        BACK,
        LEFT,
        RIGHT,
        TOP,
        BOTTOM
    };
    

    private: BlockType type;

    bool isSolidBlock(BlockType type) const;
    bool isTransparentBlock(BlockType type) const;
    std::string getTextureForBlock(BlockType type, int face) const;
    

    }; #include "Chunk.h" #include

    Chunk::Chunk(int chunkX, int chunkZ) : chunkX(chunkX), chunkZ(chunkZ), dirty(true) { initBlocks(); }

    Chunk::~Chunk() { }

    void Chunk::initBlocks() { blocks.resize(CHUNK_SIZE_X); for (int x = 0; x < CHUNK_SIZE_X; x++) { blocks[x].resize(CHUNK_SIZE_Y); for (int y = 0; y < CHUNK_SIZE_Y; y++) { blocks[x][y].resize(CHUNK_SIZE_Z, Block(BlockType::AIR)); } } }

    Block& Chunk::getBlock(int x, int y, int z) { if (!isBlockLoaded(x, y, z)) { static Block airBlock(BlockType::AIR); return airBlock; } return blocks[x][y][z]; }

    const Block& Chunk::getBlock(int x, int y, int z) const { if (!isBlockLoaded(x, y, z)) { static Block airBlock(BlockType::AIR); return airBlock; } return blocks[x][y][z]; }

    void Chunk::setBlock(int x, int y, int z, BlockType type) { if (!isBlockLoaded(x, y, z)) return;

    blocks[x][y][z].setType(type);
    dirty = true;
    

    }

    bool Chunk::isBlockLoaded(int x, int y, int z) const { return x >= 0 && x < CHUNK_SIZE_X && y >= 0 && y < CHUNK_SIZE_Y && z >= 0 && z < CHUNK_SIZE_Z; }

    void Chunk::generateMesh() { if (!dirty) return;

    vertices.clear();
    indices.clear();
    
    // 遍历所有方块
    for (int x = 0; x < CHUNK_SIZE_X; x++) {
        for (int y = 0; y < CHUNK_SIZE_Y; y++) {
            for (int z = 0; z < CHUNK_SIZE_Z; z++) {
                const Block& block = getBlock(x, y, z);
                
                // 跳过空气方块
                if (block.getType() == BlockType::AIR) continue;
                
                // 检查每个面是否需要渲染
                for (int face = 0; face < Block::FACE_COUNT; face++) {
                    if (shouldRenderFace(x, y, z, static_cast<Block::Face>(face))) {
                        addFaceToMesh(x, y, z, static_cast<Block::Face>(face));
                    }
                }
            }
        }
    }
    
    dirty = false;
    

    }

    bool Chunk::shouldRenderFace(int x, int y, int z, Block::Face face) const { // 根据面的方向计算相邻方块的坐标 int neighborX = x; int neighborY = y; int neighborZ = z;

    switch (face) {
        case Block::FRONT: neighborZ++; break;
        case Block::BACK: neighborZ--; break;
        case Block::LEFT: neighborX--; break;
        case Block::RIGHT: neighborX++; break;
        case Block::TOP: neighborY++; break;
        case Block::BOTTOM: neighborY--; break;
    }
    
    // 检查相邻方块是否在区块内
    if (!isBlockLoaded(neighborX, neighborY, neighborZ)) {
        // 如果相邻方块不在区块内,暂时假设它是空气方块
        return true;
    }
    
    const Block& neighborBlock = getBlock(neighborX, neighborY, neighborZ);
    
    // 如果相邻方块是透明的,则渲染当前面
    return !neighborBlock.isSolid() || neighborBlock.isTransparent();
    

    }

    void Chunk::addFaceToMesh(int x, int y, int z, Block::Face face) { const Block& block = getBlock(x, y, z);

    // 顶点位置偏移
    float offsetX = x + chunkX * CHUNK_SIZE_X;
    float offsetY = y;
    float offsetZ = z + chunkZ * CHUNK_SIZE_Z;
    
    // 每个面的4个顶点
    float faceVertices[4][5] = {
        // x, y, z, u, v
        {0.0f, 0.0f, 0.0f, 0.0f, 0.0f},
        {1.0f, 0.0f, 0.0f, 1.0f, 0.0f},
        {1.0f, 1.0f, 0.0f, 1.0f, 1.0f},
        {0.0f, 1.0f, 0.0f, 0.0f, 1.0f}
    };
    
    // 根据面的方向调整顶点位置和纹理坐标
    switch (face) {
        case Block::FRONT:
            // 已经是默认方向
            break;
        case Block::BACK:
            // 翻转Z轴
            for (int i = 0; i < 4; i++) {
                faceVertices[i][2] = 1.0f - faceVertices[i][2];
                faceVertices[i][3] = 1.0f - faceVertices[i][3];
            }
            break;
        case Block::LEFT:
            // 旋转到X轴负方向
            for (int i = 0; i < 4; i++) {
                float temp = faceVertices[i][0];
                faceVertices[i][0] = faceVertices[i][2];
                faceVertices[i][2] = 1.0f - temp;
            }
            break;
        case Block::RIGHT:
            // 旋转到X轴正方向
            for (int i = 0; i < 4; i++) {
                float temp = faceVertices[i][0];
                faceVertices[i][0] = 1.0f - faceVertices[i][2];
                faceVertices[i][2] = temp;
                faceVertices[i][3] = 1.0f - faceVertices[i][3];
            }
            break;
        case Block::TOP:
            // 旋转到Y轴正方向
            for (int i = 0; i < 4; i++) {
                float temp = faceVertices[i][1];
                faceVertices[i][1] = 1.0f - faceVertices[i][2];
                faceVertices[i][2] = temp;
                faceVertices[i][4] = 1.0f - faceVertices[i][4];
            }
            break;
        case Block::BOTTOM:
            // 旋转到Y轴负方向
            for (int i = 0; i < 4; i++) {
                float temp = faceVertices[i][1];
                faceVertices[i][1] = faceVertices[i][2];
                faceVertices[i][2] = 1.0f - temp;
                faceVertices[i][3] = 1.0f - faceVertices[i][3];
                faceVertices[i][4] = 1.0f - faceVertices[i][4];
            }
            break;
    }
    
    // 添加顶点到顶点数组
    unsigned int baseIndex = vertices.size() / 5;
    for (int i = 0; i < 4; i++) {
        vertices.push_back(faceVertices[i][0] + offsetX);
        vertices.push_back(faceVertices[i][1] + offsetY);
        vertices.push_back(faceVertices[i][2] + offsetZ);
        vertices.push_back(faceVertices[i][3]);
        vertices.push_back(faceVertices[i][4]);
    }
    
    // 添加索引到索引数组(两个三角形组成一个面)
    indices.push_back(baseIndex + 0);
    indices.push_back(baseIndex + 1);
    indices.push_back(baseIndex + 2);
    indices.push_back(baseIndex + 0);
    indices.push_back(baseIndex + 2);
    indices.push_back(baseIndex + 3);
    

    } #pragma once #include #include #include <glm/glm.hpp> #include "Block.h"

    class Chunk { public: static const int CHUNK_SIZE_X = 16; static const int CHUNK_SIZE_Y = 256; static const int CHUNK_SIZE_Z = 16;

    Chunk(int chunkX, int chunkZ);
    ~Chunk();
    
    Block& getBlock(int x, int y, int z);
    const Block& getBlock(int x, int y, int z) const;
    void setBlock(int x, int y, int z, BlockType type);
    
    bool isBlockLoaded(int x, int y, int z) const;
    
    int getChunkX() const { return chunkX; }
    int getChunkZ() const { return chunkZ; }
    
    bool isDirty() const { return dirty; }
    void setDirty(bool dirty) { this->dirty = dirty; }
    
    // 生成区块网格数据
    void generateMesh();
    
    // 获取渲染数据
    const std::vector<float>& getVertices() const { return vertices; }
    const std::vector<unsigned int>& getIndices() const { return indices; }
    int getVertexCount() const { return vertices.size() / 5; } // 5 components per vertex (x, y, z, u, v)
    

    private: int chunkX; int chunkZ; std::vector<std::vector<std::vector>> blocks;

    bool dirty;
    
    // 渲染数据
    std::vector<float> vertices;
    std::vector<unsigned int> indices;
    
    void initBlocks();
    bool shouldRenderFace(int x, int y, int z, Block::Face face) const;
    void addFaceToMesh(int x, int y, int z, Block::Face face);
    

    }; #pragma once #include #include #include <glm/glm.hpp> #include "Block.h"

    class Chunk { public: static const int CHUNK_SIZE_X = 16; static const int CHUNK_SIZE_Y = 256; static const int CHUNK_SIZE_Z = 16;

    Chunk(int chunkX, int chunkZ);
    ~Chunk();
    
    Block& getBlock(int x, int y, int z);
    const Block& getBlock(int x, int y, int z) const;
    void setBlock(int x, int y, int z, BlockType type);
    
    bool isBlockLoaded(int x, int y, int z) const;
    
    int getChunkX() const { return chunkX; }
    int getChunkZ() const { return chunkZ; }
    
    bool isDirty() const { return dirty; }
    void setDirty(bool dirty) { this->dirty = dirty; }
    
    // 生成区块网格数据
    void generateMesh();
    
    // 获取渲染数据
    const std::vector<float>& getVertices() const { return vertices; }
    const std::vector<unsigned int>& getIndices() const { return indices; }
    int getVertexCount() const { return vertices.size() / 5; } // 5 components per vertex (x, y, z, u, v)
    

    private: int chunkX; int chunkZ; std::vector<std::vector<std::vector>> blocks;

    bool dirty;
    
    // 渲染数据
    std::vector<float> vertices;
    std::vector<unsigned int> indices;
    
    void initBlocks();
    bool shouldRenderFace(int x, int y, int z, Block::Face face) const;
    void addFaceToMesh(int x, int y, int z, Block::Face face);
    

    }; #pragma once #include <unordered_map> #include #include #include <glm/glm.hpp> #include "Chunk.h" #include "WorldGenerator.h" #include "Block.h"

    // 区块位置哈希函数 struct ChunkPositionHash { std::size_t operator()(const std::pair<int, int>& k) const { return std::hash()(k.first) ^ std::hash()(k.second); } };

    class World { public: World(); ~World();

    // 获取指定位置的方块
    Block& getBlock(int x, int y, int z);
    const Block& getBlock(int x, int y, int z) const;
    
    // 设置指定位置的方块
    void setBlock(int x, int y, int z, BlockType type);
    
    // 获取或创建区块
    std::shared_ptr<Chunk> getChunk(int chunkX, int chunkZ);
    
    // 加载区块
    void loadChunk(int chunkX, int chunkZ);
    
    // 卸载区块
    void unloadChunk(int chunkX, int chunkZ);
    
    // 更新世界(加载/卸载区块)
    void update(const glm::vec3& playerPosition, int renderDistance);
    
    // 获取所有加载的区块
    const std::unordered_map<std::pair<int, int>, std::shared_ptr<Chunk>, ChunkPositionHash>& getLoadedChunks() const;
    
    // 射线检测(用于方块选择)
    bool raycast(const glm::vec3& start, const glm::vec3& direction, float maxDistance, 
                 glm::vec3& hitPosition, Block::Face& hitFace);
    
    // 设置世界生成器参数
    void setSeed(int seed) { generator.setSeed(seed); }
    

    private: // 加载的区块 std::unordered_map<std::pair<int, int>, std::shared_ptr, ChunkPositionHash> loadedChunks;

    // 世界生成器
    WorldGenerator generator;
    
    // 线程安全锁
    std::mutex worldMutex;
    
    // 计算区块坐标
    std::pair<int, int> getChunkPosition(int x, int z) const;
    
    // 计算区块内坐标
    void getBlockPositionInChunk(int x, int z, int& blockX, int& blockZ) const;
    

    }; #include "WorldGenerator.h" #include #include

    WorldGenerator::WorldGenerator() : seed(12345), amplitude(40.0f), frequency(0.01f) { initNoiseModules(); }

    WorldGenerator::~WorldGenerator() { }

    void WorldGenerator::initNoiseModules() { // 设置噪声模块参数 perlin.SetSeed(seed); perlin.SetFrequency(frequency); perlin.SetOctaveCount(6); perlin.SetPersistence(0.5f);

    ridgedNoise.SetSeed(seed + 1);
    ridgedNoise.SetFrequency(frequency * 0.5f);
    ridgedNoise.SetOctaveCount(4);
    
    detailNoise.SetSeed(seed + 2);
    detailNoise.SetFrequency(frequency * 2.0f);
    detailNoise.SetOctaveCount(3);
    detailNoise.SetPersistence(0.7f);
    
    biomeNoise.SetSeed(seed + 3);
    biomeNoise.SetFrequency(frequency * 0.25f);
    biomeNoise.SetOctaveCount(2);
    
    // 组合噪声模块
    baseTerrain.SetSourceModule(0, perlin);
    baseTerrain.SetSourceModule(1, ridgedNoise);
    
    terrainScale.SetSourceModule(0, baseTerrain);
    terrainScale.SetScale(amplitude);
    terrainScale.SetBias(64.0f); // 基础高度
    

    }

    void WorldGenerator::setSeed(int seed) { this->seed = seed; initNoiseModules(); }

    int WorldGenerator::getHeight(int x, int z) const { // 获取噪声值 double noiseValue = terrainScale.GetValue(x, 0, z);

    // 添加细节噪声
    double detailValue = detailNoise.GetValue(x, 0, z) * 5.0;
    
    // 计算最终高度
    int height = static_cast<int>(noiseValue + detailValue);
    
    // 限制高度范围
    if (height < 10) height = 10;
    if (height > 128) height = 128;
    
    return height;
    

    }

    int WorldGenerator::getBiomeType(int x, int z) const { double biomeValue = biomeNoise.GetValue(x, 0, z);

    // 根据噪声值确定生物群系
    if (biomeValue < -0.3) {
        return 0; // 沙漠
    } else if (biomeValue < 0.0) {
        return 1; // 平原
    } else if (biomeValue < 0.3) {
        return 2; // 森林
    } else {
        return 3; // 山地
    }
    

    }

    void WorldGenerator::generateBiome(int x, int z, int height, Chunk* chunk) { int biomeType = getBiomeType(x, z);

    switch (biomeType) {
        case 0: // 沙漠
            // 沙子表面
            for (int y = 0; y < height; y++) {
                if (y == height - 1) {
                    chunk->setBlock(x, y, z, BlockType::SAND);
                } else if (y > height - 4) {
                    chunk->setBlock(x, y, z, BlockType::SAND);
                } else {
                    chunk->setBlock(x, y, z, BlockType::STONE);
                }
            }
            break;
            
        case 1: // 平原
            // 草方块表面
            for (int y = 0; y < height; y++) {
                if (y == height - 1) {
                    chunk->setBlock(x, y, z, BlockType::GRASS);
                } else if (y > height - 4) {
                    chunk->setBlock(x, y, z, BlockType::DIRT);
                } else {
                    chunk->setBlock(x, y, z, BlockType::STONE);
                }
            }
            break;
            
        case 2: // 森林
            // 草方块表面,偶尔生成树木
            for (int y = 0; y < height; y++) {
                if (y == height - 1) {
                    chunk->setBlock(x, y, z, BlockType::GRASS);
                    
                    // 随机生成树木
                    if (rand() % 50 == 0) {
                        generateTree(x, y + 1, z, chunk);
                    }
                } else if (y > height - 4) {
                    chunk->setBlock(x, y, z, BlockType::DIRT);
                } else {
                    chunk->setBlock(x, y, z, BlockType::STONE);
                }
            }
            break;
            
        case 3: // 山地
            // 更多石头,更高的地形
            for (int y = 0; y < height; y++) {
                if (y == height - 1) {
                    // 山顶可能是草或石头
                    if (rand() % 3 == 0) {
                        chunk->setBlock(x, y, z, BlockType::GRASS);
                    } else {
                        chunk->setBlock(x, y, z, BlockType::STONE);
                    }
                } else if (y > height - 3) {
                    chunk->setBlock(x, y, z, BlockType::DIRT);
                } else {
                    chunk->setBlock(x, y, z, BlockType::STONE);
                }
            }
            break;
    }
    
    // 添加一些地下洞穴
    if (rand() % 100 == 0 && height > 20) {
        generateCave(x, z, height / 2, chunk);
    }
    

    }

    void WorldGenerator::generateTree(int x, int y, int z, Chunk* chunk) { int trunkHeight = 4 + rand() % 3; int leafRadius = 3;

    // 生成树干
    for (int dy = 0; dy < trunkHeight; dy++) {
        if (y + dy < 256) {
            chunk->setBlock(x, y + dy, z, BlockType::WOOD);
        }
    }
    
    // 生成树叶
    for (int dx = -leafRadius; dx <= leafRadius; dx++) {
        for (int dy = -leafRadius; dy <= leafRadius; dy++) {
            for (int dz = -leafRadius; dz <= leafRadius; dz++) {
                int distance = dx * dx + dy * dy + dz * dz;
                if (distance <= leafRadius * leafRadius) {
                    int leafX = x + dx;
                    int leafY = y + trunkHeight + dy;
                    int leafZ = z + dz;
                    
                    // 检查是否在区块范围内
                    if (leafX >= 0 && leafX < 16 && leafY >= 0 && leafY < 256 && leafZ >= 0 && leafZ < 16) {
                        // 只在空地生成树叶
                        if (chunk->getBlock(leafX, leafY, leafZ).getType() == BlockType::AIR) {
                            chunk->setBlock(leafX, leafY, leafZ, BlockType::LEAVES);
                        }
                    }
                }
            }
        }
    }
    

    }

    void WorldGenerator::generateCave(int x, int z, int startY, Chunk* chunk) { int caveLength = 20 + rand() % 30; int caveRadius = 2 + rand() % 2;

    float dirX = (rand() % 100 - 50) / 100.0f;
    float dirZ = (rand() % 100 - 50) / 100.0f;
    float dirY = (rand() % 100 - 50) / 100.0f;
    
    // 归一化方向向量
    float length = sqrt(dirX * dirX + dirY * dirY + dirZ * dirZ);
    dirX /= length;
    dirY /= length;
    dirZ /= length;
    
    float currentX = x + 0.5f;
    float currentY = startY + 0.5f;
    float currentZ = z + 0.5f;
    
    for (int i = 0; i < caveLength; i++) {
        // 挖洞
        for (int dx = -caveRadius; dx <= caveRadius; dx++) {
            for (int dy = -caveRadius; dy <= caveRadius; dy++) {
                for (int dz = -caveRadius; dz <= caveRadius; dz++) {
                    float distance = sqrt(dx * dx + dy * dy + dz * dz);
                    if (distance <= caveRadius) {
                        int caveX = static_cast<int>(currentX + dx);
                        int caveY = static_cast<int>(currentY + dy);
                        int caveZ = static_cast<int>(currentZ + dz);
                        
                        if (caveX >= 0 && caveX < 16 && caveY >= 0 && caveY < 256 && caveZ >= 0 && caveZ < 16) {
                            chunk->setBlock(caveX, caveY, caveZ, BlockType::AIR);
                        }
                    }
                }
            }
        }
        
        // 移动到下一个位置
        currentX += dirX;
        currentY += dirY;
        currentZ += dirZ;
        
        // 随机改变方向
        dirX += (rand() % 100 - 50) / 500.0f;
        dirY += (rand() % 100 - 50) / 500.0f;
        dirZ += (rand() % 100 - 50) / 500.0f;
        
        // 重新归一化方向向量
        length = sqrt(dirX * dirX + dirY * dirY + dirZ * dirZ);
        dirX /= length;
        dirY /= length;
        dirZ /= length;
    }
    

    }

    void WorldGenerator::generateChunk(int chunkX, int chunkZ, Chunk* chunk) { // 设置随机种子 srand(seed + chunkX * 1000 + chunkZ);

    // 生成区块内的每个方块
    for (int x = 0; x < 16; x++) {
        for (int z = 0; z < 16; z++) {
            // 计算世界坐标
            int worldX = chunkX * 16 + x;
            int worldZ = chunkZ * 16 + z;
            
            // 获取该位置的高度
            int height = getHeight(worldX, worldZ);
            
            // 根据生物群系生成地形
            generateBiome(x, z, height, chunk);
            
            // 在水面以下填充水
            if (height < 63) {
                for (int y = height; y < 63; y++) {
                    chunk->setBlock(x, y, z, BlockType::WATER);
                }
            }
        }
    }
    

    } #pragma once #include #include <noise/noise.h> #include "Block.h"

    class WorldGenerator { public: WorldGenerator(); ~WorldGenerator();

    // 生成区块地形
    void generateChunk(int chunkX, int chunkZ, std::vector<std::vector<std::vector<Block>>>& blocks);
    
    // 获取指定位置的高度
    int getHeight(int x, int z) const;
    
    // 设置生成器参数
    void setSeed(int seed);
    void setAmplitude(float amplitude) { this->amplitude = amplitude; }
    void setFrequency(float frequency) { this->frequency = frequency; }
    

    private: int seed; float amplitude; float frequency;

    // Perlin噪声模块
    noise::module::Perlin perlin;
    noise::module::RidgedMulti ridgedNoise;
    noise::module::Perlin detailNoise;
    
    // 噪声组合模块
    noise::module::Add baseTerrain;
    noise::module::ScaleBias terrainScale;
    
    // 生物群系相关
    noise::module::Perlin biomeNoise;
    
    // 初始化噪声模块
    void initNoiseModules();
    
    // 获取生物群系类型
    int getBiomeType(int x, int z) const;
    
    // 根据生物群系生成地形
    void generateBiome(int x, int z, int height, std::vector<std::vector<std::vector<Block>>>& blocks);
    

    }; #include #include #include "core/Window.h" #include "core/Camera.h" #include "core/Input.h" #include "world/World.h" #include "rendering/Renderer.h" #include "player/Player.h"

    int main() { // 创建窗口 std::unique_ptr window = std::make_unique("Minecraft Clone", 1280, 720);

    // 创建摄像机
    std::unique_ptr<Camera> camera = std::make_unique<Camera>(90.0f, 1280.0f / 720.0f, 0.1f, 1000.0f);
    
    // 创建输入处理器
    std::unique_ptr<Input> input = std::make_unique<Input>(window.get());
    
    // 创建渲染器
    std::unique_ptr<Renderer> renderer = std::make_unique<Renderer>();
    
    // 创建世界
    std::unique_ptr<World> world = std::make_unique<World>();
    
    // 创建玩家
    std::unique_ptr<Player> player = std::make_unique<Player>(camera.get(), world.get(), input.get());
    
    // 游戏循环
    float lastFrameTime = 0.0f;
    while (!window->shouldClose()) {
        // 计算deltaTime
        float currentTime = glfwGetTime();
        float deltaTime = currentTime - lastFrameTime;
        lastFrameTime = currentTime;
        
        // 处理输入
        input->update();
        player->handleInput(deltaTime);
        
        // 更新玩家
        player->update(deltaTime);
        
        // 更新摄像机
        camera->update();
        
        // 渲染
        renderer->beginFrame();
        renderer->renderWorld(world.get(), camera.get());
        renderer->endFrame();
        
        // 窗口更新
        window->update();
    }
    
    return 0;
    

    }

  • 通过的题目

  • 最近活动

  • 最近编写的题解

    This person is lazy and didn't write any solutions.

题目标签

初级班期中考
5
字符串
3
模拟
3
计算几何
2
排序
2
数学
2
数组
1
for循环
1
while循环
1
结构体
1
其他
1
搜索
1
枚举
1
数据结构
1
队列
1
初级期中考
1