Веб-сайт самохостера Lotigara

summaryrefslogtreecommitdiff
path: root/source/game/StarParticleManager.cpp
blob: 4629567e44b38bf648e0568b2728fcc151500924 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
#include "StarParticleManager.hpp"
#include "StarIterator.hpp"
#include "StarLogging.hpp"

namespace Star {

ParticleManager::ParticleManager(WorldGeometry const& worldGeometry, ClientTileSectorArrayPtr const& tileSectorArray)
  : m_worldGeometry(worldGeometry), m_undergroundLevel(0.0f), m_tileSectorArray(tileSectorArray) {}

void ParticleManager::add(Particle particle) {
  m_particles.push_back(std::move(particle));
}

void ParticleManager::addParticles(List<Particle> particles) {
  m_particles.appendAll(std::move(particles));
}

size_t ParticleManager::count() const {
  return m_particles.size();
}

void ParticleManager::clear() {
  m_particles.clear();
}

void ParticleManager::setUndergroundLevel(float undergroundLevel) {
  m_undergroundLevel = undergroundLevel;
}

void ParticleManager::update(float dt, RectF const& cullRegion, float wind) {
  if (!m_tileSectorArray)
    return;

  auto cullRects = m_worldGeometry.splitRect(cullRegion);

  for (auto& particle : m_particles) {
    bool inRegion = false;
    Vec2F worldPos = m_worldGeometry.xwrap(particle.position);
    for (auto cullRect : cullRects) {
      if (cullRect.contains(worldPos)) {
        inRegion = true;
        break;
      }
    }
    if (!inRegion)
      continue;

    particle.update(dt, Vec2F(wind, 0));
    Vec2I pos(particle.position.floor());
    TileType tiletype;
    auto const& tile = m_tileSectorArray->tile(pos);
    if (isSolidColliding(tile.getCollision()))
      tiletype = TileType::Colliding;
    else if (tile.liquid.level > 0.5f)
      tiletype = TileType::Water;
    else
      tiletype = TileType::Empty;

    if (particle.collidesForeground && tiletype == TileType::Colliding) {
      RectF colRect;
      colRect.setXMax(std::ceil(particle.position[0]));
      colRect.setXMin(std::floor(particle.position[0]));
      colRect.setYMax(std::ceil(particle.position[1]));
      colRect.setYMin(std::floor(particle.position[1]));
      Line2F colLine(particle.position, particle.position - particle.velocity);

      auto collisionPosition = colRect.edgeIntersection(colLine).point;
      if (particle.position[0] > colRect.center()[0])
        collisionPosition[0] += 0.1f;
      else if (particle.position[0] < colRect.center()[0])
        collisionPosition[0] -= 0.1f;
      if (particle.position[1] > colRect.center()[1])
        collisionPosition[1] += 0.1f;
      else if (particle.position[1] < colRect.center()[1])
        collisionPosition[1] -= 0.1f;

      particle.collide(collisionPosition);
    }

    if (particle.underwaterOnly && tiletype == TileType::Empty)
      particle.destroy(false);

    if (particle.collidesLiquid && tiletype == TileType::Water)
      particle.destroy(false);

    if (particle.trail && particle.timeToLive >= 0.0f) {
      auto trail = particle;
      trail.trail = false;
      trail.timeToLive = 0;
      trail.velocity = {};
      m_nextParticles.append(std::move(trail));
    }

    if (!particle.dead())
      m_nextParticles.append(std::move(particle));
  }

  m_particles.clear();
  swap(m_particles, m_nextParticles);
}

List<Particle> const& ParticleManager::particles() const {
  return m_particles;
}

List<pair<Vec2F, Vec3F>> ParticleManager::lightSources() const {
  List<pair<Vec2F, Vec3F>> lsources;
  for (auto const& particle : m_particles) {
    if (particle.light != Color::Clear)
      lsources.append({particle.position, particle.light.toRgbF()});
  }
  return lsources;
}

}