@@ -3,6 +3,7 @@ core_mod = shared_library('mod', | |||
'src/DefaultWorldGen.cc', | |||
'src/entities/PlayerEntity.cc', | |||
'src/entities/ItemStackEntity.cc', | |||
'src/world/tree.cc', | |||
name_prefix: '', | |||
name_suffix: 'so', | |||
install: true, |
@@ -1,6 +1,7 @@ | |||
#include "DefaultWorldGen.h" | |||
#include <algorithm> | |||
#include <cstdint> | |||
#include "entities/PlayerEntity.h" | |||
@@ -54,6 +55,25 @@ Swan::Tile::ID DefaultWorldGen::genTile(Swan::TilePos pos) { | |||
if (pos.y > grassLevel + 7 && perlin_.noise(pos.x / 43.37, pos.y / 16.37) > 0.2) | |||
return tAir_; | |||
// Trees | |||
if (pos.y == grassLevel - 1) { | |||
constexpr int treeProb = 4; | |||
bool spawnTree = Swan::random(pos.x) % treeProb == 0; | |||
if (spawnTree) { | |||
// Avoid trees which are too close | |||
for (int rx = 1; rx <= 5; ++rx) { | |||
if (Swan::random(pos.x + rx) % treeProb == 0) { | |||
spawnTree = false; | |||
break; | |||
} | |||
} | |||
if (spawnTree) { | |||
return tTreeSeeder_; | |||
} | |||
} | |||
} | |||
if (pos.y > stoneLevel) | |||
return tStone_; | |||
else if (pos.y > grassLevel) |
@@ -10,9 +10,8 @@ public: | |||
tGrass_(world.getTileID("core::grass")), | |||
tDirt_(world.getTileID("core::dirt")), | |||
tStone_(world.getTileID("core::stone")), | |||
tTreeSeeder_(world.getTileID("core::tree-seeder")), | |||
tAir_(world.getTileID("@::air")), | |||
tTreeTrunk_(world.getTileID("core::tree-trunk")), | |||
tLeaves_(world.getTileID("core::leaves")), | |||
bgCave_(world.getSprite("core::misc/background-cave")) {} | |||
void drawBackground( | |||
@@ -23,7 +22,9 @@ public: | |||
private: | |||
Swan::Tile::ID genTile(Swan::TilePos pos); | |||
Swan::Tile::ID tGrass_, tDirt_, tStone_, tAir_, tTreeTrunk_, tLeaves_; | |||
const uint32_t seed_ = 100; | |||
Swan::Tile::ID tGrass_, tDirt_, tStone_, tTreeSeeder_, tAir_; | |||
Cygnet::RenderSprite bgCave_; | |||
siv::PerlinNoise perlin_ = siv::PerlinNoise(100); | |||
siv::PerlinNoise perlin_{seed_}; | |||
}; |
@@ -3,6 +3,7 @@ | |||
#include "DefaultWorldGen.h" | |||
#include "entities/PlayerEntity.h" | |||
#include "entities/ItemStackEntity.h" | |||
#include "world/tree.h" | |||
#include <functional> | |||
@@ -34,11 +35,18 @@ public: | |||
registerTile({ | |||
.name = "tree-trunk", | |||
.image = "core::tile/tree-trunk", | |||
.isSolid = false, | |||
.droppedItem = "core::tree-trunk", | |||
}); | |||
registerTile({ | |||
.name = "leaves", | |||
.name = "tree-leaves", | |||
.image = "core::tile/leaves", | |||
.isSolid = false, | |||
}); | |||
registerTile({ | |||
.name = "tree-seeder", | |||
.image = "core::tile/leaves", | |||
.onSpawn = spawnTree, | |||
}); | |||
registerTile({ | |||
.name = "torch", |
@@ -0,0 +1,31 @@ | |||
#include "tree.h" | |||
#include <algorithm> | |||
void spawnTree(const Swan::Context &ctx, Swan::TilePos pos) { | |||
Swan::Tile::ID logID = ctx.world.getTileID("core::tree-trunk"); | |||
Swan::Tile::ID leavesID = ctx.world.getTileID("core::tree-leaves"); | |||
int height = 4 + Swan::random(pos.x) % 3; | |||
for (int y = pos.y; y >= pos.y - height; --y) { | |||
ctx.plane.setTileID({pos.x, y}, logID); | |||
} | |||
int radius = 2 + Swan::random(pos.x) % 2; | |||
int radius2 = radius * radius; | |||
Swan::TilePos top = pos - Swan::Vec2i{0, height}; | |||
for (int ry = -radius; ry <= radius + 2; ++ry) { | |||
for (int rx = -radius; rx <= radius; ++rx) { | |||
if (rx == 0 && ry <= -radius / 2) { | |||
continue; | |||
} | |||
int d2 = std::max( | |||
ry * ry + rx * rx, | |||
(ry + 1) * (ry + 1) + rx * rx); | |||
if (d2 <= radius2) { | |||
ctx.plane.setTileID(top - Swan::Vec2i{rx, ry}, leavesID); | |||
} | |||
} | |||
} | |||
} |
@@ -0,0 +1,5 @@ | |||
#pragma once | |||
#include "swan/swan.h" | |||
void spawnTree(const Swan::Context &ctx, Swan::TilePos pos); |