climbable.cpp 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. // SuperTux - Climbable area
  2. // Copyright (C) 2007 Christoph Sommer <christoph.sommer@2007.expires.deltadevelopment.de>
  3. //
  4. // This program is free software: you can redistribute it and/or modify
  5. // it under the terms of the GNU General Public License as published by
  6. // the Free Software Foundation, either version 3 of the License, or
  7. // (at your option) any later version.
  8. //
  9. // This program is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU General Public License for more details.
  13. //
  14. // You should have received a copy of the GNU General Public License
  15. // along with this program. If not, see <http://www.gnu.org/licenses/>.
  16. #include "trigger/climbable.hpp"
  17. #include "editor/editor.hpp"
  18. #include "object/player.hpp"
  19. #include "supertux/debug.hpp"
  20. #include "supertux/resources.hpp"
  21. #include "util/reader_mapping.hpp"
  22. #include "video/drawing_context.hpp"
  23. #include "video/video_system.hpp"
  24. #include "video/viewport.hpp"
  25. namespace {
  26. const float GRACE_DX = 8; // How far off may the player's bounding-box be x-wise.
  27. const float GRACE_DY = 8; // How far off may the player's bounding-box be y-wise.
  28. const float ACTIVATE_TRY_FOR = 1; // How long to try correcting mis-alignment of player and climbable before giving up.
  29. const float POSITION_FIX_AX = 30; // X-wise acceleration applied to player when trying to align player and Climbable.
  30. const float POSITION_FIX_AY = 50; // Y-wise acceleration applied to player when trying to align player and Climbable.
  31. }
  32. Climbable::Climbable(const ReaderMapping& reader) :
  33. Trigger(reader),
  34. climbed_by(),
  35. trying_to_climb(),
  36. message()
  37. {
  38. reader.get("message", message);
  39. }
  40. Climbable::~Climbable()
  41. {
  42. for (auto* player : climbed_by)
  43. player->stop_climbing(*this);
  44. climbed_by.clear();
  45. trying_to_climb.clear();
  46. }
  47. ObjectSettings
  48. Climbable::get_settings()
  49. {
  50. ObjectSettings result = Trigger::get_settings();
  51. result.add_translatable_text(_("Message"), &message, "message");
  52. result.reorder({"message", "region", "x", "y"});
  53. return result;
  54. }
  55. void
  56. Climbable::update(float dt_sec)
  57. {
  58. Trigger::update(dt_sec);
  59. auto it = climbed_by.begin();
  60. while (it != climbed_by.end())
  61. {
  62. if (!may_climb(**it))
  63. {
  64. (*it)->stop_climbing(*this);
  65. it = climbed_by.erase(it);
  66. continue;
  67. }
  68. it++;
  69. }
  70. auto it2 = trying_to_climb.begin();
  71. while (it2 != trying_to_climb.end())
  72. {
  73. if (it2->m_activate_try_timer->started())
  74. {
  75. // The "-20" to y velocity prevents Tux from walking in place on the ground for horizonal adjustments.
  76. if (it2->m_player->get_bbox().get_left() < m_col.m_bbox.get_left() - GRACE_DX) it2->m_player->add_velocity(Vector(POSITION_FIX_AX,-20));
  77. if (it2->m_player->get_bbox().get_right() > m_col.m_bbox.get_right() + GRACE_DX) it2->m_player->add_velocity(Vector(-POSITION_FIX_AX,-20));
  78. if (it2->m_player->get_bbox().get_top() < m_col.m_bbox.get_top() - GRACE_DY) it2->m_player->add_velocity(Vector(0,POSITION_FIX_AY));
  79. if (it2->m_player->get_bbox().get_bottom() > m_col.m_bbox.get_bottom() + GRACE_DY) it2->m_player->add_velocity(Vector(0,-POSITION_FIX_AY));
  80. }
  81. if (may_climb(*(it2->m_player)))
  82. {
  83. climbed_by.push_back(it2->m_player);
  84. it2->m_player->start_climbing(*this);
  85. it2 = trying_to_climb.erase(it2);
  86. continue;
  87. }
  88. it2++;
  89. }
  90. }
  91. void
  92. Climbable::draw(DrawingContext& context)
  93. {
  94. if (!climbed_by.empty() && !message.empty()) {
  95. context.push_transform();
  96. context.set_translation(Vector(0, 0));
  97. context.transform().scale = 1.f;
  98. Vector pos = Vector(0, static_cast<float>(SCREEN_HEIGHT) / 2.0f - Resources::normal_font->get_height() / 2.0f);
  99. context.color().draw_center_text(Resources::normal_font, _(message), pos, LAYER_HUD, Climbable::text_color);
  100. context.pop_transform();
  101. }
  102. if (Editor::is_active() || g_debug.show_collision_rects) {
  103. context.color().draw_filled_rect(m_col.m_bbox, Color(1.0f, 1.0f, 0.0f, 0.6f),
  104. 0.0f, LAYER_OBJECTS);
  105. }
  106. }
  107. void
  108. Climbable::event(Player& player, EventType type)
  109. {
  110. if (type == EVENT_ACTIVATE || (type == EVENT_TOUCH && player.get_controller().hold(Control::UP))) {
  111. if (player.get_grabbed_object() == nullptr){
  112. auto it = std::find_if(trying_to_climb.begin(), trying_to_climb.end(),
  113. [&player](const ClimbPlayer& element)
  114. {
  115. return element.m_player == &player;
  116. });
  117. if (it == trying_to_climb.end()) {
  118. trying_to_climb.push_back(ClimbPlayer{&player, std::make_unique<Timer>()});
  119. it = trying_to_climb.begin() + (trying_to_climb.size() - 1);
  120. }
  121. if (!may_climb(player))
  122. it->m_activate_try_timer->start(ACTIVATE_TRY_FOR);
  123. }
  124. }
  125. if (type == EVENT_LOSETOUCH) {
  126. player.stop_climbing(*this);
  127. auto it = climbed_by.begin();
  128. while (it != climbed_by.end())
  129. {
  130. if (*it == &player)
  131. it = climbed_by.erase(it);
  132. else
  133. it++;
  134. }
  135. auto it2 = trying_to_climb.begin();
  136. while (it2 != trying_to_climb.end())
  137. {
  138. if (it2->m_player == &player)
  139. it2 = trying_to_climb.erase(it2);
  140. else
  141. it2++;
  142. }
  143. }
  144. }
  145. bool
  146. Climbable::may_climb(const Player& player) const
  147. {
  148. if (player.get_bbox().get_left() < m_col.m_bbox.get_left() - GRACE_DX) return false;
  149. if (player.get_bbox().get_right() > m_col.m_bbox.get_right() + GRACE_DX) return false;
  150. if (player.get_bbox().get_top() < m_col.m_bbox.get_top() - GRACE_DY) return false;
  151. if (player.get_bbox().get_bottom() > m_col.m_bbox.get_bottom() + GRACE_DY) return false;
  152. return true;
  153. }
  154. /* EOF */