unit_layer.cpp 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. #include "unit_layer.h"
  2. #include "minimap_utils.h"
  3. #include <QPainter>
  4. #include <algorithm>
  5. #include <cmath>
  6. namespace Game::Map::Minimap {
  7. void UnitLayer::init(int width, int height, float world_width,
  8. float world_height) {
  9. m_width = width;
  10. m_height = height;
  11. m_world_width = world_width;
  12. m_world_height = world_height;
  13. m_scale_x = static_cast<float>(width - 1) / world_width;
  14. m_scale_y = static_cast<float>(height - 1) / world_height;
  15. m_offset_x = world_width * 0.5F;
  16. m_offset_y = world_height * 0.5F;
  17. m_image = QImage(width, height, QImage::Format_RGBA8888);
  18. m_image.fill(Qt::transparent);
  19. }
  20. auto UnitLayer::world_to_pixel(float world_x,
  21. float world_z) const -> std::pair<float, float> {
  22. const auto &orient = MinimapOrientation::instance();
  23. const float rotated_x =
  24. world_x * orient.cos_yaw() - world_z * orient.sin_yaw();
  25. const float rotated_z =
  26. world_x * orient.sin_yaw() + world_z * orient.cos_yaw();
  27. const float px = (rotated_x + m_offset_x) * m_scale_x;
  28. const float py = (rotated_z + m_offset_y) * m_scale_y;
  29. return {px, py};
  30. }
  31. void UnitLayer::update(const std::vector<UnitMarker> &markers) {
  32. update(markers, 0, nullptr, nullptr);
  33. }
  34. void UnitLayer::update(const std::vector<UnitMarker> &markers,
  35. int local_owner_id,
  36. const VisibilityCheckFn &visibility_check,
  37. const PlayerColorFn &player_color_fn) {
  38. if (m_image.isNull()) {
  39. return;
  40. }
  41. m_image.fill(Qt::transparent);
  42. if (markers.empty()) {
  43. return;
  44. }
  45. QPainter painter(&m_image);
  46. painter.setRenderHint(QPainter::Antialiasing, true);
  47. std::vector<const UnitMarker *> buildings;
  48. std::vector<const UnitMarker *> units;
  49. std::vector<const UnitMarker *> selected;
  50. for (const auto &marker : markers) {
  51. if (visibility_check && marker.owner_id != local_owner_id &&
  52. local_owner_id > 0) {
  53. if (!visibility_check(marker.world_x, marker.world_z)) {
  54. continue;
  55. }
  56. }
  57. if (marker.is_selected) {
  58. selected.push_back(&marker);
  59. } else if (marker.is_building) {
  60. buildings.push_back(&marker);
  61. } else {
  62. units.push_back(&marker);
  63. }
  64. }
  65. for (const auto *marker : buildings) {
  66. const auto [px, py] = world_to_pixel(marker->world_x, marker->world_z);
  67. const auto colors = get_color_for_owner(marker->owner_id, player_color_fn);
  68. draw_building_marker(painter, px, py, colors, false);
  69. }
  70. for (const auto *marker : units) {
  71. const auto [px, py] = world_to_pixel(marker->world_x, marker->world_z);
  72. const auto colors = get_color_for_owner(marker->owner_id, player_color_fn);
  73. draw_unit_marker(painter, px, py, colors, false);
  74. }
  75. for (const auto *marker : selected) {
  76. const auto [px, py] = world_to_pixel(marker->world_x, marker->world_z);
  77. const auto colors = get_color_for_owner(marker->owner_id, player_color_fn);
  78. if (marker->is_building) {
  79. draw_building_marker(painter, px, py, colors, true);
  80. } else {
  81. draw_unit_marker(painter, px, py, colors, true);
  82. }
  83. }
  84. }
  85. auto UnitLayer::get_color_for_owner(int owner_id,
  86. const PlayerColorFn &player_color_fn)
  87. -> TeamColors::ColorSet {
  88. if (player_color_fn) {
  89. std::uint8_t r, g, b;
  90. if (player_color_fn(owner_id, r, g, b)) {
  91. return TeamColors::ColorSet{r,
  92. g,
  93. b,
  94. static_cast<std::uint8_t>(r / 2),
  95. static_cast<std::uint8_t>(g / 2),
  96. static_cast<std::uint8_t>(b / 2)};
  97. }
  98. }
  99. return TeamColors::get_color(owner_id);
  100. }
  101. void UnitLayer::draw_unit_marker(QPainter &painter, float px, float py,
  102. const TeamColors::ColorSet &colors,
  103. bool is_selected) {
  104. const QPointF center(static_cast<qreal>(px), static_cast<qreal>(py));
  105. if (is_selected) {
  106. painter.setBrush(Qt::NoBrush);
  107. QPen glow_pen(QColor(TeamColors::SELECT_R, TeamColors::SELECT_G,
  108. TeamColors::SELECT_B, 200));
  109. glow_pen.setWidthF(2.0);
  110. painter.setPen(glow_pen);
  111. painter.drawEllipse(center, m_unit_radius + 2.0, m_unit_radius + 2.0);
  112. }
  113. QColor fill_color(colors.r, colors.g, colors.b);
  114. QColor border_color(colors.border_r, colors.border_g, colors.border_b);
  115. painter.setBrush(fill_color);
  116. painter.setPen(QPen(border_color, 1.2));
  117. painter.drawEllipse(center, m_unit_radius, m_unit_radius);
  118. }
  119. void UnitLayer::draw_building_marker(QPainter &painter, float px, float py,
  120. const TeamColors::ColorSet &colors,
  121. bool is_selected) {
  122. const qreal half = static_cast<qreal>(m_building_half_size);
  123. const QRectF rect(px - half, py - half, half * 2.0, half * 2.0);
  124. if (is_selected) {
  125. painter.setBrush(Qt::NoBrush);
  126. QPen glow_pen(QColor(TeamColors::SELECT_R, TeamColors::SELECT_G,
  127. TeamColors::SELECT_B, 200));
  128. glow_pen.setWidthF(2.5);
  129. painter.setPen(glow_pen);
  130. painter.drawRect(rect.adjusted(-2.5, -2.5, 2.5, 2.5));
  131. }
  132. QColor fill_color(colors.r, colors.g, colors.b);
  133. QColor border_color(colors.border_r, colors.border_g, colors.border_b);
  134. painter.setBrush(fill_color);
  135. painter.setPen(QPen(border_color, 1.5));
  136. painter.drawRect(rect);
  137. const qreal inner = half * 0.4;
  138. painter.setBrush(border_color);
  139. painter.setPen(Qt::NoPen);
  140. painter.drawRect(QRectF(px - inner, py - inner, inner * 2.0, inner * 2.0));
  141. }
  142. } // namespace Game::Map::Minimap