move chunk loading into world class

This commit is contained in:
tylermurphy534 2022-10-01 16:28:38 -04:00
parent 6a001c4840
commit 4f83af1857
4 changed files with 156 additions and 74 deletions

View file

@ -5,7 +5,7 @@ using namespace std::chrono;
namespace app { namespace app {
Minecraft::Minecraft() : xeEngine{WIDTH, HEIGHT, "Minecraft Vulkan", "res/image/icon.png"} {}; Minecraft::Minecraft() : engine{WIDTH, HEIGHT, "Minecraft Vulkan", "res/image/icon.png"} {};
Minecraft::~Minecraft() {} Minecraft::~Minecraft() {}
@ -13,83 +13,35 @@ void Minecraft::run() {
Chunk::load(); Chunk::load();
auto viewerObject = xe::GameObject::createGameObject(); auto viewer = xe::GameObject::createGameObject();
viewerObject.transform.translation = {0.f, 40.f, 0.f}; viewer.transform.translation = {0.f, 40.f, 0.f};
viewerObject.transform.rotation.y = glm::radians(45.f); viewer.transform.rotation.y = glm::radians(45.f);
createGameObjects(viewerObject); World world {viewer, 10, 12345};
ChunkRenderer renderer{Chunk::getTextures()};
xe::Sound sound{"res/sound/when_the_world_ends.wav"}; xe::Sound sound{"res/sound/when_the_world_ends.wav"};
sound.setLooping(true); sound.setLooping(true);
sound.play(); sound.play();
PlayerController cameraController{xeEngine.getInput(), viewerObject}; PlayerController playerController{engine.getInput(), viewer};
while (xeEngine.poll()) { while (engine.poll()) {
float frameTime = xeEngine.getFrameTime(); playerController.update(engine.getFrameTime());
cameraController.update(frameTime); world.reloadChunks();
xeEngine.getCamera().setViewYXZ(viewerObject.transform.translation, viewerObject.transform.rotation);
if(xeEngine.beginFrame()) { if(engine.beginFrame()) {
renderer.render(loadedChunks, xeEngine.getCamera()); world.render(engine.getCamera());
xeEngine.endFrame(); engine.endFrame();
} }
reloadLoadedChunks(viewerObject);
} }
xeEngine.close(); engine.close();
Chunk::unload(); Chunk::unload();
} }
void Minecraft::createGameObjects(xe::GameObject& viewer) {
int width = 2*RENDER_DISTANCE+1;
loadedChunks.clear();
for(int32_t x = 0; x < width; x++) {
for(int32_t z = 0; z < width; z++) {
auto gameObject = xe::GameObject::createGameObject();
gameObject.transform.translation = glm::vec3(0.f);
loadedChunks.push_back(std::move(gameObject));
}
}
}
void Minecraft::reloadLoadedChunks(xe::GameObject& viewer) {
viewX = static_cast<int>(floor(viewer.transform.translation.x / Chunk::CHUNK_SIZE.x));
viewZ = static_cast<int>(floor(viewer.transform.translation.z / Chunk::CHUNK_SIZE.z));
int width = 2*RENDER_DISTANCE+1;
int minX = viewX - RENDER_DISTANCE;
int minZ = viewZ - RENDER_DISTANCE;
int maxX = viewX + RENDER_DISTANCE;
int maxZ = viewZ + RENDER_DISTANCE;
for(int32_t x = 0; x < width; x++) {
for(int32_t z = 0; z < width; z++) {
auto& gameObject = loadedChunks[x + z * width];
int gridX = static_cast<int>(floor(gameObject.transform.translation.x / Chunk::CHUNK_SIZE.x));
int gridZ = static_cast<int>(floor(gameObject.transform.translation.z / Chunk::CHUNK_SIZE.z));
int newGridX = minX + x;
int newGridZ = minZ + z;
if(gridX < minX || gridZ < minZ || gridX > maxX || gridZ > maxZ)
Chunk::deleteChunk(gridX, gridZ);
Chunk* chunk = Chunk::getChunk(newGridX, newGridZ);
if(chunk == nullptr) {
chunk = Chunk::newChunk(newGridX, newGridZ, 12345);
Chunk::generateAsync(chunk);
}
if(chunk->getMesh() == nullptr){
Chunk::createMeshAsync(chunk);
}
gameObject.model = chunk->getMesh();
gameObject.transform.translation = glm::vec3(newGridX * Chunk::CHUNK_SIZE.x, 0, newGridZ * Chunk::CHUNK_SIZE.z);
}
}
}
} }

View file

@ -3,8 +3,8 @@
#include "xe_engine.hpp" #include "xe_engine.hpp"
#include "player_controller.hpp" #include "player_controller.hpp"
#include "chunk_renderer.hpp"
#include "chunk.hpp" #include "chunk.hpp"
#include "world.hpp"
#define GLM_FORCE_RADIANS #define GLM_FORCE_RADIANS
#define GLM_FORCE_DEPTH_ZERO_TO_ONE #define GLM_FORCE_DEPTH_ZERO_TO_ONE
@ -23,24 +23,13 @@ class Minecraft {
Minecraft(); Minecraft();
~Minecraft(); ~Minecraft();
Minecraft(const Minecraft &) = delete;
Minecraft operator=(const Minecraft &) = delete;
void run(); void run();
private: private:
static constexpr int WIDTH = 800; static constexpr int WIDTH = 800;
static constexpr int HEIGHT = 600; static constexpr int HEIGHT = 600;
static constexpr int RENDER_DISTANCE = 10;
void createGameObjects(xe::GameObject& viewer); xe::Engine engine;
void reloadLoadedChunks(xe::GameObject& viewer);
int viewX, viewZ;
xe::Engine xeEngine;
std::vector<xe::GameObject> loadedChunks;
}; };
} }

98
src/world.cpp Normal file
View file

@ -0,0 +1,98 @@
#include "world.hpp"
namespace app {
World::World(xe::GameObject& viewer, int renderDistance, int worldSeed)
: viewer{viewer},
renderDistance{renderDistance},
worldSeed{worldSeed},
chunkRenderer{Chunk::getTextures()} {
reloadChunks(renderDistance);
}
World::~World() {}
void World::reloadChunks() {
int currentViewX = static_cast<int>(floor(viewer.transform.translation.x / Chunk::CHUNK_SIZE.x));
int currentViewZ = static_cast<int>(floor(viewer.transform.translation.z / Chunk::CHUNK_SIZE.z));
if(currentViewX != viewX || currentViewZ != viewZ) {
viewX = currentViewX;
viewZ = currentViewZ;
unloadOldChunks();
loadNewChunks();
}
updateChunkMeshs();
}
void World::reloadChunks(int newRenderDistance) {
renderDistance = newRenderDistance;
viewX = static_cast<int>(floor(viewer.transform.translation.x / Chunk::CHUNK_SIZE.x));
viewZ = static_cast<int>(floor(viewer.transform.translation.z / Chunk::CHUNK_SIZE.z));
resetChunks();
loadNewChunks();
updateChunkMeshs();
}
void World::resetChunks() {
unloadOldChunks();
loadedChunks.clear();
int width = 2*renderDistance+1;
for(int i = 0; i < width*width; i++) {
auto gameObject = xe::GameObject::createGameObject();
loadedChunks.push_back(std::move(gameObject));
}
}
void World::unloadOldChunks() {
int minX = viewX - renderDistance;
int minZ = viewZ - renderDistance;
int maxX = viewX + renderDistance;
int maxZ = viewZ + renderDistance;
for(auto &object : loadedChunks) {
int gridX = static_cast<int>(floor(object.transform.translation.x / Chunk::CHUNK_SIZE.x));
int gridZ = static_cast<int>(floor(object.transform.translation.z / Chunk::CHUNK_SIZE.z));
if(gridX < minX || gridZ < minZ || gridX > maxX || gridZ > maxZ){
Chunk::deleteChunk(gridX, gridZ);
object.model = nullptr;
}
}
}
void World::loadNewChunks() {
int width = 2*renderDistance+1;
int minX = viewX - renderDistance;
int minZ = viewZ - renderDistance;
int maxX = viewX + renderDistance;
int maxZ = viewZ + renderDistance;
int i = 0;
for(auto &object : loadedChunks) {
int gridX = minX + i % width;
int gridZ = minZ + i / width;
Chunk* chunk = Chunk::getChunk(gridX, gridZ);
if(chunk == nullptr) {
chunk = Chunk::newChunk(gridX, gridZ, worldSeed);
Chunk::generateAsync(chunk);
}
object.transform.translation = glm::vec3(gridX * Chunk::CHUNK_SIZE.x, 0, gridZ * Chunk::CHUNK_SIZE.z);
i++;
}
}
void World::updateChunkMeshs() {
for(auto &object : loadedChunks) {
int gridX = static_cast<int>(floor(object.transform.translation.x / Chunk::CHUNK_SIZE.x));
int gridZ = static_cast<int>(floor(object.transform.translation.z / Chunk::CHUNK_SIZE.z));
Chunk* chunk = Chunk::getChunk(gridX, gridZ);
if(chunk == nullptr) continue;
if(chunk->getMesh() == nullptr)
Chunk::createMeshAsync(chunk);
object.model = chunk->getMesh();
}
}
void World::render(xe::Camera& camera) {
camera.setViewYXZ(viewer.transform.translation, viewer.transform.rotation);
chunkRenderer.render(loadedChunks, camera);
}
}

43
src/world.hpp Normal file
View file

@ -0,0 +1,43 @@
#pragma once
#include "xe_game_object.hpp"
#include "chunk_renderer.hpp"
#include "chunk.hpp"
#include <vector>
namespace app {
class World {
public:
World(xe::GameObject& viewer, int renderDistance, int worldSeed);
~World();
void reloadChunks();
void reloadChunks(int newRenderDistance);
void render(xe::Camera& camera);
private:
void resetChunks();
void unloadOldChunks();
void loadNewChunks();
void updateChunkMeshs();
int viewX, viewZ;
int worldSeed;
int renderDistance;
const xe::GameObject& viewer;
std::vector<xe::GameObject> loadedChunks;
ChunkRenderer chunkRenderer;
};
}