ambient_sound.cpp 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. // SuperTux
  2. // Copyright (C) 2006 Matthias Braun <matze@braunis.de>
  3. // 2023 mrkubax10 <mrkubax10@onet.pl>
  4. //
  5. // This program is free software: you can redistribute it and/or modify
  6. // it under the terms of the GNU General Public License as published by
  7. // the Free Software Foundation, either version 3 of the License, or
  8. // (at your option) any later version.
  9. //
  10. // This program is distributed in the hope that it will be useful,
  11. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. // GNU General Public License for more details.
  14. //
  15. // You should have received a copy of the GNU General Public License
  16. // along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. #include "object/ambient_sound.hpp"
  18. #include <limits>
  19. #include "audio/sound_manager.hpp"
  20. #include "audio/sound_source.hpp"
  21. #include "editor/editor.hpp"
  22. #include "object/player.hpp"
  23. #include "supertux/sector.hpp"
  24. #include "util/reader_mapping.hpp"
  25. #include "video/drawing_context.hpp"
  26. AmbientSound::AmbientSound(const ReaderMapping& mapping) :
  27. MovingObject(mapping),
  28. ExposedObject<AmbientSound, scripting::AmbientSound>(this),
  29. m_sample(),
  30. m_sound_source(),
  31. m_radius(),
  32. m_radius_in_px(),
  33. m_volume(),
  34. m_has_played_sound(false)
  35. {
  36. m_col.m_group = COLGROUP_DISABLED;
  37. float w, h;
  38. mapping.get("x", m_col.m_bbox.get_left(), 0.0f);
  39. mapping.get("y", m_col.m_bbox.get_top(), 0.0f);
  40. mapping.get("width" , w, 32.0f);
  41. mapping.get("height", h, 32.0f);
  42. m_col.m_bbox.set_size(w, h);
  43. mapping.get("radius", m_radius, 1.0f);
  44. mapping.get("sample", m_sample, "");
  45. mapping.get("volume", m_volume, 1.0f);
  46. m_radius_in_px = m_radius*32.0f;
  47. prepare_sound_source();
  48. }
  49. AmbientSound::AmbientSound(const Vector& pos, float radius, float vol, const std::string& file) :
  50. ExposedObject<AmbientSound, scripting::AmbientSound>(this),
  51. m_sample(file),
  52. m_sound_source(),
  53. m_radius(radius),
  54. m_radius_in_px(m_radius*32.0f),
  55. m_volume(vol),
  56. m_has_played_sound(false)
  57. {
  58. m_col.m_group = COLGROUP_DISABLED;
  59. m_col.m_bbox.set_pos(pos);
  60. m_col.m_bbox.set_size(32, 32);
  61. prepare_sound_source();
  62. }
  63. AmbientSound::~AmbientSound()
  64. {
  65. stop_looping_sounds();
  66. }
  67. ObjectSettings
  68. AmbientSound::get_settings()
  69. {
  70. ObjectSettings result = MovingObject::get_settings();
  71. result.add_sound(_("Sound"), &m_sample, "sample");
  72. result.add_float(_("Radius (in tiles)"), &m_radius, "radius");
  73. result.add_float(_("Volume"), &m_volume, "volume");
  74. result.reorder({"sample", "radius", "volume", "region", "name", "x", "y", "width", "height"});
  75. return result;
  76. }
  77. #ifndef SCRIPTING_API
  78. void
  79. AmbientSound::set_pos(const Vector& pos)
  80. {
  81. MovingObject::set_pos(pos);
  82. }
  83. #endif
  84. void
  85. AmbientSound::set_pos(float x, float y)
  86. {
  87. m_col.m_bbox.set_pos(Vector(x, y));
  88. }
  89. float
  90. AmbientSound::get_pos_x() const
  91. {
  92. return m_col.m_bbox.get_left();
  93. }
  94. float
  95. AmbientSound::get_pos_y() const
  96. {
  97. return m_col.m_bbox.get_top();
  98. }
  99. HitResponse
  100. AmbientSound::collision(GameObject& other, const CollisionHit& hit_)
  101. {
  102. return ABORT_MOVE;
  103. }
  104. void
  105. AmbientSound::draw(DrawingContext& context)
  106. {
  107. if (Editor::is_active())
  108. context.color().draw_filled_rect(m_col.m_bbox, Color(0.0f, 0.0f, 1.0f, 0.6f),
  109. 0.0f, LAYER_OBJECTS);
  110. }
  111. void
  112. AmbientSound::stop_looping_sounds()
  113. {
  114. if (m_sound_source)
  115. m_sound_source->stop(false);
  116. }
  117. void
  118. AmbientSound::play_looping_sounds()
  119. {
  120. if (Editor::is_active())
  121. return;
  122. m_sound_source->play();
  123. }
  124. void
  125. AmbientSound::update(float dt_sec)
  126. {
  127. const Player* const nearest_player = Sector::get().get_nearest_player(get_bbox().get_middle());
  128. if (!nearest_player)
  129. return;
  130. const Rectf& player_bbox = nearest_player->get_bbox();
  131. const Vector player_center = player_bbox.get_middle();
  132. if (get_bbox().overlaps(player_bbox))
  133. m_sound_source->set_gain(m_volume);
  134. else
  135. {
  136. float player_distance = m_radius+1;
  137. if (player_center.x >= get_bbox().get_left() && player_center.x <= get_bbox().get_right())
  138. player_distance = player_center.y < get_bbox().get_top() ? get_bbox().get_top() - player_center.y : player_center.y - get_bbox().get_bottom();
  139. else if (player_center.y >= get_bbox().get_top() && player_center.y <= get_bbox().get_bottom())
  140. player_distance = player_center.x < get_bbox().get_left() ? get_bbox().get_left() - player_center.x : player_center.x - get_bbox().get_right();
  141. else if (player_center.x <= get_bbox().get_left() && player_center.y <= get_bbox().get_top())
  142. player_distance = glm::distance(player_center, get_bbox().p1());
  143. else if (player_center.x >= get_bbox().get_right() && player_center.y <= get_bbox().get_top())
  144. player_distance = glm::distance(player_center, get_bbox().p1() + Vector(get_bbox().get_width(), 0));
  145. else if (player_center.x <= get_bbox().get_left() && player_center.y >= get_bbox().get_bottom())
  146. player_distance = glm::distance(player_center, get_bbox().p1() + Vector(0, get_bbox().get_height()));
  147. else if (player_center.x >= get_bbox().get_right() && player_center.y >= get_bbox().get_bottom())
  148. player_distance = glm::distance(player_center, get_bbox().p2());
  149. m_sound_source->set_gain(std::max(m_radius_in_px - player_distance, 0.0f) / m_radius_in_px * m_volume);
  150. }
  151. if (!m_has_played_sound)
  152. {
  153. m_sound_source->play();
  154. m_has_played_sound = true;
  155. }
  156. }
  157. void
  158. AmbientSound::prepare_sound_source()
  159. {
  160. if (Editor::is_active())
  161. return;
  162. if (m_sample.empty())
  163. {
  164. remove_me();
  165. return;
  166. }
  167. try
  168. {
  169. m_sound_source = SoundManager::current()->create_sound_source(m_sample);
  170. if (!m_sound_source)
  171. throw std::runtime_error("file not found");
  172. m_sound_source->set_gain(0);
  173. m_sound_source->set_looping(true);
  174. m_sound_source->set_relative(true);
  175. }
  176. catch(const std::exception& e)
  177. {
  178. log_warning << "Couldn't load '" << m_sample << "': " << e.what() << std::endl;
  179. m_sound_source.reset();
  180. remove_me();
  181. }
  182. }
  183. /* EOF */