move chunk loading into world class
This commit is contained in:
parent
6a001c4840
commit
4f83af1857
4 changed files with 156 additions and 74 deletions
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
|
@ -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
98
src/world.cpp
Normal 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
43
src/world.hpp
Normal 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;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in a new issue