Line data Source code
1 : /**
2 : Copyright (c) 2023 Stappler LLC <admin@stappler.dev>
3 :
4 : Permission is hereby granted, free of charge, to any person obtaining a copy
5 : of this software and associated documentation files (the "Software"), to deal
6 : in the Software without restriction, including without limitation the rights
7 : to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 : copies of the Software, and to permit persons to whom the Software is
9 : furnished to do so, subject to the following conditions:
10 :
11 : The above copyright notice and this permission notice shall be included in
12 : all copies or substantial portions of the Software.
13 :
14 : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 : IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 : FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 : AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 : LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 : OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 : THE SOFTWARE.
21 : **/
22 :
23 : #include "XL2dActionAcceleratedMove.h"
24 : #include "XLNode.h"
25 :
26 : #define XL_ACCELERATED_LOG(...)
27 : //#define XL_ACCELERATED_LOG(...) stappler::log::format("ActionAcceleratedMove", __VA_ARGS__)
28 :
29 : namespace STAPPLER_VERSIONIZED stappler::xenolith::basic2d {
30 :
31 0 : Rc<ActionInterval> ActionAcceleratedMove::createBounce(float acceleration, Vec2 from, Vec2 to, Vec2 velocity,
32 : float bounceAcceleration, Function<void(Node *)> &&callback) {
33 0 : Vec2 diff = to - from;
34 0 : float distance = diff.length();
35 :
36 0 : if (std::fabs(distance) < std::numeric_limits<float>::epsilon()) {
37 0 : return Rc<DelayTime>::create(0.0f);
38 : }
39 :
40 0 : Vec2 normal = diff.getNormalized();
41 0 : normal.normalize();
42 :
43 0 : Vec2 velProject = velocity.project(normal);
44 :
45 : float startSpeed;
46 0 : if (std::fabs(normal.getAngle(velProject)) < M_PI_2) {
47 0 : startSpeed = velProject.length();
48 : } else {
49 0 : startSpeed = -velProject.length();
50 : }
51 :
52 0 : return ActionAcceleratedMove::createBounce(acceleration, from, to, startSpeed, bounceAcceleration, move(callback));
53 : }
54 :
55 0 : Rc<ActionInterval> ActionAcceleratedMove::createBounce(float acceleration, Vec2 from, Vec2 to, float velocity,
56 : float bounceAcceleration, Function<void(Node *)> &&callback) {
57 0 : Vec2 diff = to - from;
58 0 : float distance = diff.length();
59 :
60 0 : if (std::fabs(distance) < std::numeric_limits<float>::epsilon()) {
61 0 : return Rc<DelayTime>::create(0.0f);
62 : }
63 :
64 0 : Vec2 normal = diff.getNormalized();
65 0 : normal.normalize();
66 :
67 0 : float startSpeed = velocity;
68 :
69 0 : if (startSpeed == 0) {
70 0 : float duration = std::sqrt(distance / acceleration);
71 :
72 0 : auto a = ActionAcceleratedMove::createWithDuration(duration, normal, from, startSpeed, acceleration);
73 0 : auto b = ActionAcceleratedMove::createWithDuration(duration, normal, a->getEndPosition(), a->getEndVelocity(), -acceleration);
74 :
75 0 : a->setCallback(Function<void(Node *)>(callback));
76 0 : b->setCallback(move(callback));
77 :
78 0 : return Rc<Sequence>::create(a, b);
79 0 : } else {
80 0 : float t = startSpeed / acceleration;
81 0 : float result = (startSpeed * t) - (acceleration * t * t * 0.5);
82 :
83 0 : if (startSpeed > 0 && distance > result) {
84 0 : float pseudoDistance = distance + acceleration * t * t * 0.5;
85 0 : float pseudoDuration = std::sqrt(pseudoDistance / acceleration);
86 :
87 0 : auto a = ActionAcceleratedMove::createAccelerationTo(normal, from, startSpeed, acceleration * pseudoDuration, acceleration);
88 0 : auto b = ActionAcceleratedMove::createWithDuration(pseudoDuration, normal, a->getEndPosition(), a->getEndVelocity(), -acceleration);
89 :
90 0 : a->setCallback(Function<void(Node *)>(callback));
91 0 : b->setCallback(move(callback));
92 :
93 0 : return Rc<Sequence>::create(a, b);
94 0 : } else if (startSpeed > 0 && distance <= result) {
95 0 : if (bounceAcceleration == 0) {
96 0 : acceleration = -acceleration;
97 0 : float pseudoDistance = distance - result; // < 0
98 0 : float pseudoDuration = std::sqrt(pseudoDistance / acceleration); // > 0
99 :
100 0 : auto a = ActionAcceleratedMove::createAccelerationTo(normal, from, startSpeed, acceleration * pseudoDuration, acceleration);
101 0 : auto b = ActionAcceleratedMove::createWithDuration(pseudoDuration, normal, a->getEndPosition(), a->getEndVelocity(), -acceleration);
102 :
103 0 : a->setCallback(Function<void(Node *)>(callback));
104 0 : b->setCallback(move(callback));
105 :
106 0 : return Rc<Sequence>::create(a, b);
107 0 : } else {
108 0 : auto a0 = ActionAcceleratedMove::createAccelerationTo(from, to, startSpeed, -acceleration);
109 0 : auto a1 = ActionAcceleratedMove::createDecceleration(normal, a0->getEndPosition(), a0->getEndVelocity(), bounceAcceleration);
110 :
111 0 : Vec2 tmpFrom = a1->getEndPosition();
112 0 : diff = to - tmpFrom;
113 0 : distance = diff.length();
114 0 : normal = diff.getNormalized();
115 0 : float duration = std::sqrt(distance / acceleration);
116 :
117 0 : auto a = ActionAcceleratedMove::createWithDuration(duration, normal, tmpFrom, 0, acceleration);
118 0 : auto b = ActionAcceleratedMove::createWithDuration(duration, normal, a->getEndPosition(), a->getEndVelocity(), -acceleration);
119 :
120 0 : a0->setCallback(Function<void(Node *)>(callback));
121 0 : a1->setCallback(Function<void(Node *)>(callback));
122 0 : a->setCallback(Function<void(Node *)>(callback));
123 0 : b->setCallback(move(callback));
124 :
125 0 : return Rc<Sequence>::create(a0, a1, a, b);
126 0 : }
127 : } else {
128 0 : float pseudoDistance = 0;
129 :
130 0 : if (bounceAcceleration) {
131 0 : t = startSpeed / bounceAcceleration;
132 0 : pseudoDistance = distance + std::fabs((startSpeed * t) - bounceAcceleration * t * t * 0.5);
133 : } else {
134 0 : pseudoDistance = distance + std::fabs((startSpeed * t) - acceleration * t * t * 0.5);
135 : }
136 :
137 0 : float pseudoDuration = std::sqrt(pseudoDistance / acceleration);
138 :
139 0 : Rc<ActionAcceleratedMove> a1;
140 0 : Rc<ActionAcceleratedMove> a2;
141 0 : if (bounceAcceleration) {
142 0 : a1 = ActionAcceleratedMove::createDecceleration(-normal, from, -startSpeed, bounceAcceleration);
143 0 : a2 = ActionAcceleratedMove::createAccelerationTo(normal, a1->getEndPosition(), 0, acceleration * pseudoDuration, acceleration);
144 : } else {
145 0 : a2 = ActionAcceleratedMove::createAccelerationTo(normal, from, startSpeed, acceleration * pseudoDuration, acceleration);
146 : }
147 :
148 0 : auto b = ActionAcceleratedMove::createDecceleration(normal, a2->getEndPosition(), a2->getEndVelocity(), acceleration);
149 :
150 0 : if (a1) {
151 0 : a2->setCallback(Function<void(Node *)>(callback));
152 0 : b->setCallback(Function<void(Node *)>(callback));
153 0 : a1->setCallback(move(callback));
154 0 : return Rc<Sequence>::create(a1, a2, b);
155 : } else {
156 0 : a2->setCallback(Function<void(Node *)>(callback));
157 0 : b->setCallback(move(callback));
158 0 : return Rc<Sequence>::create(a2, b);
159 : }
160 0 : }
161 : }
162 : }
163 :
164 0 : Rc<ActionInterval> ActionAcceleratedMove::createFreeBounce(float acceleration, Vec2 from, Vec2 to, Vec2 velocity,
165 : float bounceAcceleration, Function<void(Node *)> &&callback) {
166 :
167 0 : Vec2 diff = to - from;
168 0 : float distance = diff.length();
169 0 : Vec2 normal = diff.getNormalized();
170 0 : Vec2 velProject = velocity.project(normal);
171 :
172 : float startSpeed;
173 0 : if (std::fabs(normal.getAngle(velProject)) < M_PI_2) {
174 0 : startSpeed = velProject.length();
175 : } else {
176 0 : startSpeed = -velProject.length();
177 : }
178 :
179 0 : if (startSpeed < 0) {
180 0 : return createBounce(acceleration, from, to, velocity, bounceAcceleration, move(callback));
181 : } else {
182 0 : float duration = startSpeed / acceleration;
183 0 : float deccelerationPath = startSpeed * duration - acceleration * duration * duration * 0.5;
184 0 : if (deccelerationPath < distance) {
185 0 : auto a = createWithDuration(duration, normal, from, startSpeed, -acceleration);
186 0 : a->setCallback(move(callback));
187 0 : return a;
188 0 : } else {
189 0 : return createBounce(acceleration, from, to, velocity, bounceAcceleration, move(callback));
190 : }
191 : }
192 : }
193 :
194 0 : Rc<ActionInterval> ActionAcceleratedMove::createWithBounds(float acceleration, Vec2 from, Vec2 velocity,
195 : const Rect &bounds, Function<void(Node *)> &&callback) {
196 0 : Vec2 normal = velocity.getNormalized();
197 :
198 0 : float angle = normal.getAngle();
199 :
200 : float start, end, pos, v, t, dist;
201 0 : Vec2 x, y, z, a, b, i;
202 :
203 0 : if (bounds.size.width == 0 && bounds.size.height == 0) {
204 0 : return nullptr;
205 : }
206 :
207 0 : if (bounds.size.width == 0) {
208 0 : start = bounds.origin.y;
209 0 : end = bounds.origin.y + bounds.size.height;
210 0 : pos = from.y;
211 :
212 0 : v = velocity.y;
213 0 : t = std::fabs(v) / std::fabs(acceleration);
214 0 : dist = std::fabs(v) * t - std::fabs(acceleration) * t * t * 0.5;
215 :
216 0 : if (velocity.y > 0) {
217 0 : if (std::fabs(pos - end) < std::numeric_limits<float>::epsilon()) {
218 0 : return Rc<DelayTime>::create(0.0f);
219 0 : } else if (pos + dist < end) {
220 0 : return createDecceleration(Vec2(0, 1), from, velocity.y, -acceleration, move(callback));
221 : } else {
222 0 : return createAccelerationTo(from, Vec2(from.x, end), v, -acceleration, move(callback));
223 : }
224 : } else {
225 0 : if (std::fabs(pos - start) < std::numeric_limits<float>::epsilon()) {
226 0 : return Rc<DelayTime>::create(0.0f);
227 0 : } else if (pos - dist > start) {
228 0 : return createDecceleration(Vec2(0, -1), from, velocity.y, -acceleration, move(callback));
229 : } else {
230 0 : return createAccelerationTo(from, Vec2(from.x, start), std::fabs(v), -acceleration, move(callback));
231 : }
232 : }
233 : }
234 :
235 0 : if (bounds.size.height == 0) {
236 0 : start = bounds.origin.x;
237 0 : end = bounds.origin.x + bounds.size.width;
238 0 : pos = from.x;
239 :
240 0 : v = std::fabs(velocity.x);
241 0 : t = v / std::fabs(acceleration);
242 0 : dist = v * t - std::fabs(acceleration) * t * t * 0.5;
243 :
244 0 : if (velocity.x > 0) {
245 0 : if (std::fabs(pos - end) < std::numeric_limits<float>::epsilon()) {
246 0 : return Rc<DelayTime>::create(0.0f);
247 0 : } else if (pos + dist < end) {
248 0 : return createDecceleration(Vec2(1, 0), from, v, -acceleration, move(callback));
249 : } else {
250 0 : return createAccelerationTo(from, Vec2(end, from.y), v, -acceleration, move(callback));
251 : }
252 : } else {
253 0 : if (std::fabs(pos - start) < std::numeric_limits<float>::epsilon()) {
254 0 : return nullptr;
255 0 : } else if (pos - dist > start) {
256 0 : return createDecceleration(Vec2(-1, 0), from, v, -acceleration, move(callback));
257 : } else {
258 0 : return createAccelerationTo(from, Vec2(start, from.y), v, -acceleration, move(callback));
259 : }
260 : }
261 : }
262 :
263 0 : if (angle < -M_PI_2) {
264 0 : x = Vec2(bounds.getMinX(), bounds.getMaxY());
265 0 : y = Vec2(bounds.getMinX(), bounds.getMinY());
266 0 : z = Vec2(bounds.getMaxX(), bounds.getMinY());
267 :
268 0 : a = (normal.x == 0)?from:Vec2::getIntersectPoint(from, from + normal, x, y);
269 0 : b = (normal.y == 0)?from:Vec2::getIntersectPoint(from, from + normal, y, z);
270 0 : } else if (angle < 0) {
271 0 : x = Vec2(bounds.getMinX(), bounds.getMinY());
272 0 : y = Vec2(bounds.getMaxX(), bounds.getMinY());
273 0 : z = Vec2(bounds.getMaxX(), bounds.getMaxY());
274 :
275 0 : a = (normal.x == 0)?from:Vec2::getIntersectPoint(from, from + normal, x, y);
276 0 : b = (normal.y == 0)?from:Vec2::getIntersectPoint(from, from + normal, y, z);
277 0 : } else if (angle < M_PI_2) {
278 0 : x = Vec2(bounds.getMaxX(), bounds.getMinY());
279 0 : y = Vec2(bounds.getMaxX(), bounds.getMaxY());
280 0 : z = Vec2(bounds.getMinX(), bounds.getMaxY());
281 :
282 0 : a = (normal.y == 0)?from:Vec2::getIntersectPoint(from, from + normal, x, y);
283 0 : b = (normal.x == 0)?from:Vec2::getIntersectPoint(from, from + normal, y, z);
284 : } else {
285 0 : x = Vec2(bounds.getMaxX(), bounds.getMaxY());
286 0 : y = Vec2(bounds.getMinX(), bounds.getMaxY());
287 0 : z = Vec2(bounds.getMinX(), bounds.getMinY());
288 :
289 0 : a = (normal.y == 0)?from:Vec2::getIntersectPoint(from, from + normal, x, y);
290 0 : b = (normal.x == 0)?from:Vec2::getIntersectPoint(from, from + normal, y, z);
291 : }
292 :
293 0 : float a_len = from.distance(a);
294 0 : float b_len = from.distance(b);
295 : float i_len, s_len;
296 :
297 0 : if (a_len < b_len) {
298 0 : i = a; i_len = a_len; s_len = b_len;
299 : } else {
300 0 : i = b; i_len = b_len; s_len = a_len;
301 : }
302 :
303 0 : v = velocity.length();
304 0 : t = v / acceleration;
305 0 : float path = v * t - acceleration * t * t * 0.5;
306 :
307 0 : if (path < i_len) {
308 0 : return createDecceleration(normal, from, v, acceleration, move(callback));
309 : } else {
310 0 : auto a1 = createAccelerationTo(from, i, v, -acceleration);
311 :
312 0 : if (s_len > 0) {
313 0 : a1->setCallback(Function<void(Node *)>(callback));
314 0 : Vec2 diff = y - i;
315 0 : if (diff.length() < std::numeric_limits<float>::epsilon()) {
316 0 : return a1;
317 : }
318 0 : Vec2 newNormal = diff.getNormalized();
319 :
320 0 : i_len = diff.length();
321 :
322 0 : acceleration = (normal * acceleration).project(newNormal).length();
323 0 : if (acceleration == 0.0f) {
324 0 : return a1;
325 : }
326 0 : v = (normal * a1->getEndVelocity()).project(newNormal).length();
327 0 : t = v / acceleration;
328 0 : path = v * t - acceleration * t * t * 0.5;
329 :
330 0 : if (path < i_len) {
331 0 : auto a2 = createDecceleration(newNormal, i, v, acceleration);
332 0 : a2->setCallback(move(callback));
333 0 : return Rc<Sequence>::create(a1, a2);
334 0 : } else {
335 0 : auto a2 = createAccelerationTo(i, y, v, -acceleration);
336 0 : a2->setCallback(move(callback));
337 0 : return Rc<Sequence>::create(a1, a2);
338 0 : }
339 : } else {
340 0 : if (a1) {
341 0 : a1->setCallback(move(callback));
342 : }
343 0 : return a1;
344 : }
345 0 : }
346 : }
347 :
348 14 : Vec2 ActionAcceleratedMove::computeEndPoint() {
349 14 : return _startPoint + (_normalPoint * ((_startVelocity * _accDuration) + (_acceleration * _accDuration * _accDuration * 0.5)));
350 : }
351 :
352 0 : Vec2 ActionAcceleratedMove::computeNormalPoint() {
353 0 : return (_endPoint - _startPoint).getNormalized();
354 : }
355 :
356 0 : float ActionAcceleratedMove::computeEndVelocity() {
357 0 : return _startVelocity + _acceleration * _accDuration;
358 : }
359 :
360 14 : Rc<ActionAcceleratedMove> ActionAcceleratedMove::createDecceleration(Vec2 normal, Vec2 startPoint, float startVelocity,
361 : float acceleration, Function<void(Node *)> &&callback) {
362 14 : auto pRet = Rc<ActionAcceleratedMove>::alloc();
363 14 : if (pRet->initDecceleration(normal, startPoint, startVelocity, acceleration, move(callback))) {
364 14 : return pRet;
365 : }
366 0 : return nullptr;
367 14 : }
368 :
369 0 : Rc<ActionAcceleratedMove> ActionAcceleratedMove::createDecceleration(Vec2 startPoint, Vec2 endPoint,
370 : float acceleration, Function<void(Node *)> &&callback) {
371 0 : auto pRet = Rc<ActionAcceleratedMove>::alloc();
372 0 : if (pRet->initDecceleration(startPoint, endPoint, acceleration, move(callback))) {
373 0 : return pRet;
374 : }
375 0 : return nullptr;
376 0 : }
377 :
378 0 : Rc<ActionAcceleratedMove> ActionAcceleratedMove::createAccelerationTo(Vec2 normal, Vec2 startPoint, float startVelocity, float endVelocity,
379 : float acceleration, Function<void(Node *)> &&callback) {
380 0 : auto pRet = Rc<ActionAcceleratedMove>::alloc();
381 0 : if (pRet->initAccelerationTo(normal, startPoint, startVelocity, endVelocity, acceleration, move(callback))) {
382 0 : return pRet;
383 : }
384 0 : return nullptr;
385 0 : }
386 :
387 0 : Rc<ActionAcceleratedMove> ActionAcceleratedMove::createAccelerationTo(Vec2 startPoint, Vec2 endPoint, float startVelocity,
388 : float acceleration, Function<void(Node *)> &&callback) {
389 0 : auto pRet = Rc<ActionAcceleratedMove>::alloc();
390 0 : if (pRet->initAccelerationTo(startPoint, endPoint, startVelocity, acceleration, move(callback))) {
391 0 : return pRet;
392 : }
393 0 : return nullptr;
394 0 : }
395 :
396 0 : Rc<ActionAcceleratedMove> ActionAcceleratedMove::createWithDuration(float duration, Vec2 normal, Vec2 startPoint, float startVelocity,
397 : float acceleration, Function<void(Node *)> &&callback) {
398 0 : auto pRet = Rc<ActionAcceleratedMove>::alloc();
399 0 : if (pRet->initWithDuration(duration, normal, startPoint, startVelocity, acceleration, move(callback))) {
400 0 : return pRet;
401 : }
402 0 : return nullptr;
403 0 : }
404 :
405 14 : bool ActionAcceleratedMove::initDecceleration(Vec2 normal, Vec2 startPoint, float startVelocity,
406 : float acceleration, Function<void(Node *)> &&callback) {
407 14 : acceleration = std::fabs(acceleration);
408 14 : startVelocity = std::fabs(startVelocity);
409 14 : if (startVelocity < 0 || acceleration < 0) {
410 : XL_ACCELERATED_LOG("Deceleration failed: velocity:%f acceleration:%f", startVelocity, acceleration);
411 0 : return false;
412 : }
413 :
414 14 : _accDuration = startVelocity / acceleration;
415 :
416 14 : if (!ActionInterval::init(_accDuration)) {
417 0 : return false;
418 : }
419 :
420 14 : _acceleration = -acceleration;
421 14 : _startVelocity = startVelocity;
422 14 : _endVelocity = 0;
423 :
424 14 : _normalPoint = normal;
425 14 : _startPoint = startPoint;
426 :
427 14 : _endPoint = computeEndPoint();
428 :
429 : XL_ACCELERATED_LOG("%s %d Acceleration:%f velocity:%f->%f duration:%f position:(%f %f)->(%f %f)",
430 : __FUNCTION__, __LINE__,
431 : _acceleration, _startVelocity, _endVelocity, _accDuration,
432 : _startPoint.x, _startPoint.y, _endPoint.x, _endPoint.y);
433 :
434 14 : if (isnan(_endPoint.x) || isnan(_endPoint.y) || isnan(_accDuration)) {
435 : XL_ACCELERATED_LOG("Failed!");
436 0 : return false;
437 : }
438 :
439 14 : _callback = move(callback);
440 14 : return true;
441 : }
442 :
443 0 : bool ActionAcceleratedMove::initDecceleration(Vec2 startPoint, Vec2 endPoint, float acceleration, Function<void(Node *)> &&callback) {
444 0 : float distance = startPoint.distance(endPoint);
445 0 : acceleration = std::fabs(acceleration);
446 :
447 0 : if (std::fabs(distance) < std::numeric_limits<float>::epsilon()) {
448 0 : _accDuration = 0.0f;
449 : } else {
450 0 : _accDuration = std::sqrt((distance * 2.0f) / acceleration);
451 : }
452 :
453 0 : if (!ActionInterval::init(_accDuration)) {
454 0 : return false;
455 : }
456 :
457 0 : _acceleration = -acceleration;
458 0 : _startVelocity = _accDuration * acceleration;
459 0 : _endVelocity = 0;
460 :
461 0 : _startPoint = startPoint;
462 0 : _endPoint = endPoint;
463 0 : _normalPoint = computeNormalPoint();
464 :
465 : XL_ACCELERATED_LOG("%s %d Acceleration:%f velocity:%f->%f duration:%f position:(%f %f)->(%f %f)",
466 : __FUNCTION__, __LINE__,
467 : _acceleration, _startVelocity, _endVelocity, _accDuration,
468 : _startPoint.x, _startPoint.y, _endPoint.x, _endPoint.y);
469 :
470 0 : if (isnan(_endPoint.x) || isnan(_endPoint.y) || isnan(_accDuration)) {
471 : XL_ACCELERATED_LOG("Failed!");
472 0 : return false;
473 : }
474 :
475 0 : _callback = move(callback);
476 0 : return true;
477 : }
478 :
479 0 : bool ActionAcceleratedMove::initAccelerationTo(Vec2 normal, Vec2 startPoint, float startVelocity, float endVelocity,
480 : float acceleration, Function<void(Node *)> &&callback) {
481 :
482 0 : _accDuration = (endVelocity - startVelocity) / acceleration;
483 :
484 0 : if (_accDuration < 0) {
485 : XL_ACCELERATED_LOG("AccelerationTo failed: velocity:(%f:%f) acceleration:%f", startVelocity, endVelocity, acceleration);
486 0 : return false;
487 : }
488 :
489 0 : if (!ActionInterval::init(_accDuration)) {
490 0 : return false;
491 : }
492 :
493 0 : _acceleration = acceleration;
494 0 : _startVelocity = startVelocity;
495 0 : _endVelocity = endVelocity;
496 :
497 0 : _normalPoint = normal;
498 0 : _startPoint = startPoint;
499 :
500 0 : _endPoint = computeEndPoint();
501 :
502 : XL_ACCELERATED_LOG("%s %d Acceleration:%f velocity:%f->%f duration:%f position:(%f %f)->(%f %f)",
503 : __FUNCTION__, __LINE__,
504 : _acceleration, _startVelocity, _endVelocity, _accDuration,
505 : _startPoint.x, _startPoint.y, _endPoint.x, _endPoint.y);
506 :
507 0 : if (isnan(_endPoint.x) || isnan(_endPoint.y) || isnan(_accDuration)) {
508 : XL_ACCELERATED_LOG("Failed!");
509 0 : return false;
510 : }
511 :
512 0 : _callback = move(callback);
513 0 : return true;
514 : }
515 :
516 0 : bool ActionAcceleratedMove::initAccelerationTo(Vec2 startPoint, Vec2 endPoint, float startVelocity,
517 : float acceleration, Function<void(Node *)> &&callback) {
518 :
519 0 : float distance = - endPoint.distance(startPoint);
520 0 : float d = startVelocity * startVelocity - 2 * acceleration * distance;
521 :
522 0 : if (std::fabs(distance) < std::numeric_limits<float>::epsilon()) {
523 : XL_ACCELERATED_LOG("zero distance");
524 : }
525 :
526 0 : if (d < 0) {
527 : XL_ACCELERATED_LOG("AccelerationTo failed: acceleration:%f velocity:%f D:%f", acceleration, startVelocity, d);
528 0 : return false;
529 : }
530 :
531 0 : float t1 = (-startVelocity + std::sqrt(d)) / acceleration;
532 0 : float t2 = (-startVelocity - std::sqrt(d)) / acceleration;
533 :
534 0 : if (distance != 0.0f) {
535 0 : _accDuration = t1 < 0 ? t2 : (t2 < 0 ? t1 : std::min(t1, t2));
536 0 : if (isnan(_accDuration)) {
537 0 : _accDuration = 0.0f;
538 : }
539 : } else {
540 0 : _accDuration = 0.0f;
541 : }
542 :
543 0 : if (_accDuration < 0) {
544 0 : if (d < 0) {
545 : XL_ACCELERATED_LOG("AccelerationTo failed: acceleration:%f velocity:%f duration:%f", acceleration, startVelocity, _accDuration);
546 0 : return false;
547 : }
548 : }
549 :
550 0 : if (!ActionInterval::init(_accDuration)) {
551 0 : return false;
552 : }
553 :
554 0 : _startPoint = startPoint;
555 0 : _endPoint = endPoint;
556 0 : _normalPoint = computeNormalPoint();
557 :
558 0 : _acceleration = acceleration;
559 0 : _startVelocity = startVelocity;
560 0 : _endVelocity = computeEndVelocity();
561 :
562 : XL_ACCELERATED_LOG("%s %d Acceleration:%f velocity:%f->%f duration:%f position:(%f %f)->(%f %f)",
563 : __FUNCTION__, __LINE__,
564 : _acceleration, _startVelocity, _endVelocity, _accDuration,
565 : _startPoint.x, _startPoint.y, _endPoint.x, _endPoint.y);
566 :
567 0 : if (isnan(_endPoint.x) || isnan(_endPoint.y) || isnan(_accDuration)) {
568 : XL_ACCELERATED_LOG("Failed!");
569 0 : return false;
570 : }
571 :
572 0 : _callback = move(callback);
573 0 : return true;
574 : }
575 :
576 0 : bool ActionAcceleratedMove::initWithDuration(float duration, Vec2 normal, Vec2 startPoint, float startVelocity,
577 : float acceleration, Function<void(Node *)> &&callback) {
578 :
579 0 : _accDuration = duration;
580 :
581 0 : if (!ActionInterval::init(_accDuration)) {
582 0 : return false;
583 : }
584 :
585 0 : _normalPoint = normal;
586 0 : _startPoint = startPoint;
587 :
588 0 : _acceleration = acceleration;
589 0 : _startVelocity = startVelocity;
590 :
591 0 : _endVelocity = computeEndVelocity();
592 0 : _endPoint = computeEndPoint();
593 :
594 : XL_ACCELERATED_LOG("%s %d Acceleration:%f velocity:%f->%f duration:%f position:(%f %f)->(%f %f)",
595 : __FUNCTION__, __LINE__,
596 : _acceleration, _startVelocity, _endVelocity, _accDuration,
597 : _startPoint.x, _startPoint.y, _endPoint.x, _endPoint.y);
598 :
599 0 : if (isnan(_endPoint.x) || isnan(_endPoint.y) || isnan(_accDuration)) {
600 : XL_ACCELERATED_LOG("Failed!");
601 0 : return false;
602 : }
603 :
604 0 : _callback = move(callback);
605 0 : return true;
606 : }
607 :
608 0 : float ActionAcceleratedMove::getDuration() const {
609 0 : return _accDuration;
610 : }
611 :
612 338 : Vec2 ActionAcceleratedMove::getPosition(float timePercent) const {
613 338 : float t = timePercent * _accDuration;
614 338 : return _startPoint + _normalPoint * ((_startVelocity * t) + (_acceleration * t * t * 0.5));
615 : }
616 :
617 0 : float ActionAcceleratedMove::getCurrentVelocity() const {
618 0 : return _startVelocity + _acceleration * _elapsed;
619 : }
620 :
621 14 : void ActionAcceleratedMove::startWithTarget(Node *target) {
622 14 : ActionInterval::startWithTarget(target);
623 : XL_ACCELERATED_LOG("Acceleration:%f velocity:%f->%f duration:%f position:(%f %f)->(%f %f)",
624 : _acceleration, _startVelocity, _endVelocity, _accDuration,
625 : _startPoint.x, _startPoint.y, _endPoint.x, _endPoint.y);
626 14 : }
627 :
628 338 : void ActionAcceleratedMove::update(float t) {
629 338 : if (_target) {
630 338 : Vec2 pos = getPosition(t);
631 338 : _target->setPosition(pos);
632 338 : if (_callback) {
633 0 : _callback(_target);
634 : }
635 : }
636 338 : }
637 :
638 0 : void ActionAcceleratedMove::setCallback(Function<void(Node *)> &&callback) {
639 0 : _callback = move(callback);
640 0 : }
641 :
642 : }
|