A 2D tile-based sandbox game.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

WorldPlane.cc 3.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. #include "WorldPlane.h"
  2. #include <math.h>
  3. #include <SFML/System/Clock.hpp>
  4. #include <iostream>
  5. #include "World.h"
  6. #include "Game.h"
  7. #include "Timer.h"
  8. namespace Swan {
  9. static ChunkPos chunkPos(TilePos pos) {
  10. int chx = pos.x_ / CHUNK_WIDTH;
  11. if (pos.x_ < 0 && pos.x_ % CHUNK_WIDTH != 0) chx -= 1;
  12. int chy = pos.y_ / CHUNK_HEIGHT;
  13. if (pos.y_ < 0 && pos.y_ % CHUNK_HEIGHT != 0) chy -= 1;
  14. return ChunkPos(chx, chy);
  15. }
  16. static Chunk::RelPos relPos(TilePos pos) {
  17. int rx = pos.x_ % CHUNK_WIDTH;
  18. if (rx < 0) rx += CHUNK_WIDTH;
  19. int ry = pos.y_ % CHUNK_HEIGHT;
  20. if (ry < 0) ry += CHUNK_HEIGHT;
  21. return Chunk::RelPos(rx, ry);
  22. }
  23. Context WorldPlane::getContext() {
  24. return { .game = *world_->game_, .world = *world_, .plane = *this };
  25. }
  26. Entity &WorldPlane::spawnEntity(const std::string &name, const SRF &params) {
  27. if (world_->ents_.find(name) == world_->ents_.end()) {
  28. fprintf(stderr, "Tried to spawn non-existant entity %s!", name.c_str());
  29. abort();
  30. }
  31. Entity *ent = world_->ents_[name]->create(getContext(), params);
  32. entities_.push_back(std::unique_ptr<Entity>(ent));
  33. fprintf(stderr, "Spawned %s. SRF: ", name.c_str());
  34. params.pretty(std::cerr) << '\n';
  35. return *ent;
  36. }
  37. bool WorldPlane::hasChunk(ChunkPos pos) {
  38. return chunks_.find(pos) != chunks_.end();
  39. }
  40. Chunk &WorldPlane::getChunk(ChunkPos pos) {
  41. auto iter = chunks_.find(pos);
  42. if (iter == chunks_.end()) {
  43. iter = chunks_.emplace(pos, Chunk(pos)).first;
  44. gen_->genChunk(*this, iter->second);
  45. active_chunks_.insert(&iter->second);
  46. iter->second.render(getContext());
  47. } else if (iter->second.keepActive()) {
  48. active_chunks_.insert(&iter->second);
  49. }
  50. return iter->second;
  51. }
  52. void WorldPlane::setTileID(TilePos pos, Tile::ID id) {
  53. Chunk &chunk = getChunk(chunkPos(pos));
  54. Chunk::RelPos rp = relPos(pos);
  55. chunk.setTileID(rp, id);
  56. chunk.drawBlock(rp, world_->getTileByID(id));
  57. if (active_chunks_.find(&chunk) == active_chunks_.end())
  58. active_chunks_.insert(&chunk);
  59. }
  60. void WorldPlane::setTile(TilePos pos, const std::string &name) {
  61. setTileID(pos, world_->getTileID(name));
  62. }
  63. Tile::ID WorldPlane::getTileID(TilePos pos) {
  64. Chunk &chunk = getChunk(chunkPos(pos));
  65. if (active_chunks_.find(&chunk) == active_chunks_.end())
  66. active_chunks_.insert(&chunk);
  67. return chunk.getTileID(relPos(pos));
  68. }
  69. Tile &WorldPlane::getTile(TilePos pos) {
  70. return world_->getTileByID(getTileID(pos));
  71. }
  72. Entity &WorldPlane::spawnPlayer() {
  73. return gen_->spawnPlayer(*this);
  74. }
  75. void WorldPlane::breakBlock(TilePos pos) {
  76. Tile &t = getTile(pos);
  77. setTile(pos, "core::air");
  78. if (t.dropped_item != "") {
  79. spawnEntity("core::item-stack", SRFArray{
  80. new SRFFloatArray{ (float)pos.x_, (float)pos.y_ },
  81. new SRFString{ t.dropped_item },
  82. });
  83. }
  84. }
  85. void WorldPlane::draw(Win &win) {
  86. const Vec2 &ppos = world_->player_->getPos();
  87. ChunkPos pcpos = ChunkPos(
  88. (int)floor(ppos.x_ / CHUNK_WIDTH),
  89. (int)floor(ppos.y_ / CHUNK_HEIGHT));
  90. for (int x = -1; x <= 1; ++x) {
  91. for (int y = -1; y <= 1; ++y) {
  92. auto iter = chunks_.find(pcpos + ChunkPos(x, y));
  93. if (iter != chunks_.end())
  94. iter->second.draw(getContext(), win);
  95. }
  96. }
  97. for (auto &ent: entities_)
  98. ent->draw(getContext(), win);
  99. if (debug_boxes_.size() > 0) {
  100. sf::RectangleShape rect(Vec2(TILE_SIZE, TILE_SIZE));
  101. rect.setFillColor(sf::Color(60, 70, 200, 100));
  102. rect.setOutlineThickness(1);
  103. rect.setOutlineColor(sf::Color(50, 65, 170, 200));
  104. for (auto &pos: debug_boxes_) {
  105. win.setPos(pos);
  106. win.draw(rect);
  107. }
  108. }
  109. }
  110. void WorldPlane::update(float dt) {
  111. debug_boxes_.clear();
  112. // Don't use iterators, because an entity's update method might push_back to entities
  113. for (size_t len = entities_.size(), i = 0; i < len; ++i)
  114. entities_[i]->update(getContext(), dt);
  115. }
  116. void WorldPlane::tick() {
  117. for (auto &ent: entities_)
  118. ent->tick();
  119. for (auto &chunk: active_chunks_) {
  120. chunk->tick();
  121. if (!chunk->isActive())
  122. active_chunks_.erase(chunk);
  123. }
  124. }
  125. void WorldPlane::debugBox(TilePos pos) {
  126. debug_boxes_.push_back(pos);
  127. }
  128. }