#include "WormCaveGenerator.h" #include "FastNoiseWrapper.h" #include "Game.h" #include "RandNoise.h" NoiseWorm3D::NoiseWorm3D() : ReferenceCounter() {} NoiseWorm3D::NoiseWorm3D(Noise* pitch, Noise* yaw, Noise* size, Framework::Vec3 startPos, int distant, int minRad, int maxRad) : ReferenceCounter(), startChunk(Game::INSTANCE->getChunkCenter(startPos.x, startPos.y)) { Vec3 lastPos = (Vec3)startPos; keyPoints.add(lastPos); this->size.add((float)minRad); minAffected.x = (int)lastPos.x - minRad; minAffected.y = (int)lastPos.y - minRad; maxAffected.x = (int)lastPos.x + minRad; maxAffected.y = (int)lastPos.y + minRad; while (keyPoints.getEintragAnzahl() < distant * 20) { Vec3 defaultDir(1.f, 0.f, 0.f); if (keyPoints.getEintragAnzahl() > 1) { defaultDir = keyPoints.get(keyPoints.getEintragAnzahl() - 1) - keyPoints.get(keyPoints.getEintragAnzahl() - 2); } float n = (float)yaw->getNoise(lastPos.x, lastPos.y, lastPos.z); defaultDir.rotateZ((n - 0.5f) / 2.f); defaultDir.normalize(); n = (float)pitch->getNoise(lastPos.x, lastPos.y, lastPos.z); defaultDir.z = ((float)n - 0.3f) * 2.f; lastPos = lastPos + defaultDir; if ((Vec2(lastPos.x, lastPos.y) - (Vec2((float)startPos.x, (float)startPos.y))) .getLengthSq() >= (float)(distant * distant)) break; keyPoints.add(lastPos); float rad = (float)size->getNoise(lastPos.x, lastPos.y, lastPos.z) * (float)(maxRad - minRad) + (float)minRad; this->size.add(rad); minAffected.x = MIN(minAffected.x, (int)(lastPos.x - rad)); minAffected.y = MIN(minAffected.y, (int)(lastPos.y - rad)); maxAffected.x = MAX(maxAffected.x, (int)(lastPos.x + rad)); maxAffected.y = MAX(maxAffected.y, (int)(lastPos.y + rad)); } } Framework::Punkt NoiseWorm3D::getStartChunkCenter() { return startChunk; } NoiseWorm3D* NoiseWorm3D::getPartAffectedByChunk(int x, int y) { NoiseWorm3D* result = 0; if (x - CHUNK_SIZE / 2 <= maxAffected.x && x + CHUNK_SIZE / 2 >= minAffected.x && y - CHUNK_SIZE / 2 <= maxAffected.y && y + CHUNK_SIZE / 2 >= minAffected.y) { auto pi = keyPoints.begin(); auto si = size.begin(); while (pi && si) { if ((Vec2((float)x, (float)y) - Vec2(pi.val().x, pi.val().y)) .getLengthSq() < (si.val() + CHUNK_SIZE / 2) * (si.val() + CHUNK_SIZE / 2)) { if (result == 0) { result = new NoiseWorm3D(); } result->keyPoints.add(pi.val()); result->size.add(si.val()); } ++pi; ++si; } } return result; } bool NoiseWorm3D::isInside(int x, int y, int z) { auto pi = keyPoints.begin(); auto si = size.begin(); while (pi && si) { if (Vec3((float)x, (float)y, (float)z).abstandSq(pi.val()) < si.val() * si.val()) return 1; ++pi; ++si; } return 0; } WormCaveChunkGenerator::WormCaveChunkGenerator( Framework::RCArray worms) : CaveChunkGenerator(), worms(worms) {} bool WormCaveChunkGenerator::isInCave(int x, int y, int z) { for (NoiseWorm3D* w : worms) { if (w->isInside(x, y, z)) return 1; } return 0; } WormCaveGenerator::WormCaveGenerator(int minDistant, int maxDistant, int minRadius, int maxRadius, float cavePosibillityPerChunk, int seed) : CaveGenerator(seed), maxDistant(maxDistant), minDistant(minDistant), maxRadius(maxRadius), minRadius(minRadius), cavePosibillity(cavePosibillityPerChunk), wormStartNoise(new RandNoise(seed)) {} WormCaveGenerator::~WormCaveGenerator() { wormStartNoise->release(); } NoiseWorm3D* WormCaveGenerator::zWormOfChunk(int x, int y) { for (NoiseWorm3D* worm : cache) { if (worm->getStartChunkCenter().x == x && worm->getStartChunkCenter().y == y) { return worm; } } for (Punkt p : noWormChunks) { if (p.x == x && p.y == y) return 0; } float cNoise = (float)wormStartNoise->getNoise(x, y, 0); if (cNoise < cavePosibillity) { FastNoiseLite* noise = new FastNoiseLite(seed + x * y + y + x); noise->SetNoiseType(FastNoiseLite::NoiseType::NoiseType_Perlin); noise->SetFrequency(0.05f); FastNoiseWrapper* pitch = new FastNoiseWrapper(noise, seed + x * y + y + x); noise = new FastNoiseLite(seed + x * y + y + x); noise->SetNoiseType(FastNoiseLite::NoiseType::NoiseType_Perlin); noise->SetFrequency(0.005f); FastNoiseWrapper* yaw = new FastNoiseWrapper(noise, seed - x * y - y - x); Vec3 start( (int)(cNoise / cavePosibillity * CHUNK_SIZE) + x - CHUNK_SIZE / 2, (int)(cNoise / cavePosibillity * CHUNK_SIZE) + y - CHUNK_SIZE / 2, (int)(cNoise / cavePosibillity * 200)); noise = new FastNoiseLite( seed + start.getLengthSq() + start.x + start.y + start.z); noise->SetNoiseType(FastNoiseLite::NoiseType::NoiseType_Perlin); noise->SetFrequency(0.005f); FastNoiseWrapper* size = new FastNoiseWrapper( noise, seed + start.getLengthSq() + start.x + start.y + start.z); NoiseWorm3D* worm = new NoiseWorm3D(pitch, yaw, size, start, (int)(wormStartNoise->getNoise(start.x, start.y, start.z) * (maxDistant - minDistant) + minDistant), minRadius, maxRadius); if (cache.getEintragAnzahl() > (maxDistant * 2) / CHUNK_SIZE * (maxDistant * 2) / CHUNK_SIZE * 3) cache.remove(0); cache.add(worm); return worm; } else { if (noWormChunks.getEintragAnzahl() > (maxDistant * 2) / CHUNK_SIZE * (maxDistant * 2) / CHUNK_SIZE * 3) noWormChunks.remove(0); noWormChunks.add(Punkt(x, y)); } return 0; } CaveChunkGenerator* WormCaveGenerator::getGeneratorForChunk(int x, int y) { Framework::RCArray affected; Punkt center = Game::getChunkCenter(x, y); int offset = (int)ceil((float)maxDistant / CHUNK_SIZE); for (int cx = -offset; cx <= offset; cx++) { for (int cy = -offset; cy <= offset; cy++) { NoiseWorm3D* worm = zWormOfChunk( center.x + cx * CHUNK_SIZE, center.y + cy * CHUNK_SIZE); if (worm) { NoiseWorm3D* cuttedWorm = worm->getPartAffectedByChunk(x, y); if (cuttedWorm) affected.add(cuttedWorm); } } } return new WormCaveChunkGenerator(affected); }