1 // SuperTux - BicyclePlatform
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
17 #include "object/bicycle_platform.hpp"
18
19 #include <algorithm>
20 #include <math.h>
21
22 #include "math/util.hpp"
23 #include "object/player.hpp"
24 #include "object/portable.hpp"
25 #include "supertux/debug.hpp"
26 #include "supertux/sector.hpp"
27 #include "util/log.hpp"
28 #include "util/reader_mapping.hpp"
29
BicyclePlatformChild(const ReaderMapping & reader,float angle_offset,BicyclePlatform & parent)30 BicyclePlatformChild::BicyclePlatformChild(const ReaderMapping& reader, float angle_offset, BicyclePlatform& parent) :
31 MovingSprite(reader, "images/objects/platforms/small.sprite", LAYER_OBJECTS, COLGROUP_STATIC),
32 m_parent(parent),
33 m_angle_offset(angle_offset),
34 m_momentum(),
35 m_contacts()
36 {
37 }
38
39 void
update(float dt_sec)40 BicyclePlatformChild::update(float dt_sec)
41 {
42 float angle = m_parent.m_angle + m_angle_offset;
43 angle = math::positive_fmodf(angle, math::TAU);
44
45 Vector dest = m_parent.m_center + Vector(cosf(angle), sinf(angle)) * m_parent.m_radius - (m_col.m_bbox.get_size().as_vector() * 0.5f);
46 Vector movement = dest - get_pos();
47 m_col.set_movement(movement);
48 m_col.propagate_movement(movement);
49 }
50
51 HitResponse
collision(GameObject & other,const CollisionHit &)52 BicyclePlatformChild::collision(GameObject& other, const CollisionHit& )
53 {
54 const float gravity = Sector::get().get_gravity();
55
56 // somehow the hit parameter does not get filled in, so to determine (hit.top == true) we do this:
57 auto mo = dynamic_cast<MovingObject*>(&other);
58 if (!mo) return FORCE_MOVE;
59 if ((mo->get_bbox().get_bottom()) > (m_col.m_bbox.get_top() + 2)) return FORCE_MOVE;
60
61 auto pl = dynamic_cast<Player*>(mo);
62 if (pl) {
63 if (pl->is_big()) m_momentum += m_parent.m_momentum_change_rate * gravity;
64 auto po = pl->get_grabbed_object();
65 auto pomo = dynamic_cast<MovingObject*>(po);
66 if (m_contacts.insert(pomo).second) {
67 m_momentum += m_parent.m_momentum_change_rate * gravity;
68 }
69 }
70
71 if (m_contacts.insert(&other).second) {
72 m_momentum += m_parent.m_momentum_change_rate * Sector::get().get_gravity();
73 }
74
75 return FORCE_MOVE;
76 }
77
editor_delete()78 void BicyclePlatformChild::editor_delete()
79 {
80 // removing a child removes the whole platform
81 m_parent.editor_delete();
82 }
83
BicyclePlatform(const ReaderMapping & reader)84 BicyclePlatform::BicyclePlatform(const ReaderMapping& reader) :
85 GameObject(reader),
86 m_center(0.0f, 0.0f),
87 m_radius(128),
88 m_angle(0),
89 m_angular_speed(0.0f),
90 m_momentum_change_rate(0.1f),
91 m_children(),
92 m_walker(),
93 m_platforms(2)
94 {
95 reader.get("x", m_center.x);
96 reader.get("y", m_center.y);
97 reader.get("radius", m_radius, 128.0f);
98 reader.get("momentum-change-rate", m_momentum_change_rate, 0.1f);
99
100 reader.get("platforms", m_platforms);
101 m_platforms = std::max(1, m_platforms);
102
103 for (int i = 0; i < m_platforms; ++i) {
104 const float offset = static_cast<float>(i) * (math::TAU / static_cast<float>(m_platforms));
105 m_children.push_back(&d_sector->add<BicyclePlatformChild>(reader, offset, *this));
106 }
107
108 std::string path_ref;
109 if (reader.get("path-ref", path_ref))
110 {
111 d_sector->request_name_resolve(path_ref, [this](UID uid){
112 if (!uid) {
113 log_fatal << "no path-ref entry for BicyclePlatform" << std::endl;
114 } else {
115 m_walker.reset(new PathWalker(uid, true));
116 }
117 });
118 }
119 }
120
~BicyclePlatform()121 BicyclePlatform::~BicyclePlatform()
122 {
123 }
124
125 void
draw(DrawingContext & context)126 BicyclePlatform::draw(DrawingContext& context)
127 {
128 if (g_debug.show_collision_rects) {
129 context.color().draw_filled_rect(Rectf::from_center(m_center, Sizef(16, 16)), Color::MAGENTA, LAYER_OBJECTS);
130 }
131 }
132
133 void
update(float dt_sec)134 BicyclePlatform::update(float dt_sec)
135 {
136 float total_angular_momentum = 0.0f;
137 for (auto& child : m_children)
138 {
139 const float child_angle = m_angle + child->m_angle_offset;
140 const float angular_momentum = cosf(child_angle) * child->m_momentum;
141 total_angular_momentum += angular_momentum;
142 child->m_momentum = 0.0f;
143 child->m_contacts.clear();
144 }
145
146 m_angular_speed += (total_angular_momentum * dt_sec) * math::PI;
147 m_angular_speed *= 1.0f - dt_sec * 0.2f;
148 m_angle += m_angular_speed * dt_sec;
149 m_angle = math::positive_fmodf(m_angle, math::TAU);
150
151 m_angular_speed = std::min(std::max(m_angular_speed, -128.0f * math::PI * dt_sec),
152 128.0f * math::PI * dt_sec);
153
154 if (m_walker)
155 {
156 m_walker->update(std::max(0.0f, dt_sec * m_angular_speed * 0.1f));
157 m_center = m_walker->get_pos();
158 }
159 else
160 {
161 m_center += Vector(m_angular_speed, 0) * dt_sec * 32.0f;
162 }
163 }
164
165 void
on_flip(float height)166 BicyclePlatform::on_flip(float height)
167 {
168 m_center.y = height - m_center.y;
169 }
170
171 void
editor_delete()172 BicyclePlatform::editor_delete()
173 {
174 // remove children
175 for (auto& child : m_children)
176 {
177 child->remove_me();
178 }
179
180 // remove self
181 remove_me();
182 }
183
184 void
after_editor_set()185 BicyclePlatform::after_editor_set()
186 {
187 GameObject::after_editor_set();
188 }
189
190 ObjectSettings
get_settings()191 BicyclePlatform::get_settings()
192 {
193 auto result = GameObject::get_settings();
194
195 result.add_float(_("X"), &m_center.x, "x", 0.0f, OPTION_HIDDEN);
196 result.add_float(_("Y"), &m_center.y, "y", 0.0f, OPTION_HIDDEN);
197
198 result.add_int(_("Platforms"), &m_platforms, "platforms", 2);
199 result.add_float(_("Radius"), &m_radius, "radius", 128.0f);
200 result.add_float(_("Momentum change rate"), &m_momentum_change_rate, "momentum-change-rate", 0.1f);
201
202 result.reorder({"platforms", "x", "y"});
203
204 return result;
205 }
206
207 /* EOF */
208