2 Copyright (c) 2006 Paolo Capriotti <p.capriotti@gmail.com>
3 (c) 2006 Maurizio Monge <maurizio.monge@kdemail.net>
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 2 of the License, or
8 (at your option) any later version.
15 #include <boost/scoped_ptr.hpp>
18 #include "animation.h"
19 #include <core/point.h>
24 using namespace boost
;
26 #undef ANIMATION_DEBUG
28 //BEGIN ConcreteAnimation
30 ConcreteAnimation::ConcreteAnimation(const SpritePtr
& piece
)
33 //END ConcreteAnimation
35 //BEGIN MovementAnimation
37 MovementAnimation::MovementAnimation(const SpritePtr
& piece
,
38 const QPoint
& destination
,
39 bool rotate
, double speed
)
40 : ConcreteAnimation(piece
)
43 , m_destination(destination
)
47 #ifdef ANIMATION_DEBUG
48 cout
<< "creating animation " << this << " for piece " << piece
.get() << endl
;
52 MovementAnimation::~MovementAnimation() {
53 #ifdef ANIMATION_DEBUG
54 cout
<< "destroying animation " << this << " for piece " << m_piece
.get() << endl
;
55 if (m_piece
->movementAnimation().lock())
56 cout
<< " *********** BUG **************" << endl
;
58 // m_piece->setMovementAnimation(0);
61 void MovementAnimation::setTarget(const SpritePtr
& target
) {
65 void MovementAnimation::setSource(const SpritePtr
& source
) {
69 boost::shared_ptr
<Movement
>
70 MovementAnimation::createMovement(const QPoint
& from
, const QPoint
& to
) const {
71 return boost::shared_ptr
<Movement
>(new SigmoidalMovement
<LinearMovement
>(from
, to
, m_rotate
));
74 void MovementAnimation::start() {
75 #ifdef ANIMATION_DEBUG
76 cout
<< "starting movement animation " << this
77 << " on piece " << m_piece
.get() << endl
;
81 if (shared_ptr
<Animation
> animation
= m_source
->movementAnimation().lock()) {
82 #ifdef ANIMATION_DEBUG
83 cout
<< "aborting movement animation " << animation
84 << " on piece " << m_source
.get() << endl
;
90 m_source
->setMovementAnimation(shared_ptr
<Animation
>());
91 m_target
->setMovementAnimation(shared_from_this());
94 m_movement
= createMovement(m_piece
->pos(), m_destination
);
96 // The total time of the animation is proportional to the square root
97 // of the distance and to the inverse of the speed factor.
98 double distance
= Point(m_destination
- m_piece
->pos()).norm();
100 Q_ASSERT(m_speed
> 0.0);
101 m_time
= 35 * sqrt(distance
) / m_speed
;
102 m_state
= m_time
> 0 ? Active
: Inactive
;
105 Animation::State
MovementAnimation::animationAdvance(int msec
) {
110 if (m_state
== Inactive
) abort();
116 // reparameterize the time variable in [0,1]
117 Q_ASSERT(m_time
> 0);
118 double t
= (msec
- m_start
) / m_time
;
121 #ifdef ANIMATION_DEBUG
122 cout
<< "active: t = " << t
<< endl
;
128 QPoint to
= m_movement
->pos(t
);
130 m_piece
->setRotation(m_movement
->rotation(t
));
137 #ifdef ANIMATION_DEBUG
138 cout
<< "advance (" << this << ") state = " << m_state
<< endl
;
143 void MovementAnimation::stop() {
144 #ifdef ANIMATION_DEBUG
145 cout
<< "stopping animation " << this
146 << " on piece " << m_piece
.get() << endl
;
148 m_piece
->moveTo(m_destination
);
149 m_piece
->setRotation(0);
154 void MovementAnimation::abort() {
155 #ifdef ANIMATION_DEBUG
156 cout
<< "aborting animation " << this
157 << " on piece " << m_piece
.get() << endl
;
160 m_target
->setMovementAnimation(shared_ptr
<MovementAnimation
>());
163 //END MovementAnimation
165 //BEGIN KnightMovementAnimation
167 KnightMovementAnimation::KnightMovementAnimation(const SpritePtr
& piece
, const QPoint
& destination
,
168 bool rotate
, double speed
)
169 : MovementAnimation(piece
, destination
, rotate
, speed
){
172 boost::shared_ptr
<Movement
>
173 KnightMovementAnimation::createMovement(const QPoint
& from
, const QPoint
& to
) const {
174 return boost::shared_ptr
<Movement
>(new SigmoidalMovement
<LMovement
>(from
, to
, m_rotate
));
177 //END KnightMovementAnimation
179 //BEGIN OneShotAnimation
181 OneShotAnimation::OneShotAnimation(const SpritePtr
& piece
)
182 : ConcreteAnimation(piece
) { }
184 Animation::State
OneShotAnimation::animationAdvance(int) {
189 //END OneShotAnimation
191 //BEGIN InstantAnimation
193 InstantAnimation::InstantAnimation(const SpritePtr
& piece
, const QPoint
& destination
)
194 : OneShotAnimation(piece
)
195 , m_destination(destination
) { }
197 void InstantAnimation::shoot() {
198 m_piece
->moveTo(m_destination
);
200 if (shared_ptr
<Animation
> animation
= m_piece
->movementAnimation().lock()) {
202 m_piece
->setMovementAnimation(shared_ptr
<Animation
>());
206 //END InstantAnimation
208 //BEGIN CaptureAnimation
210 CaptureAnimation::CaptureAnimation(const SpritePtr
& piece
)
211 : OneShotAnimation(piece
) { }
213 void CaptureAnimation::shoot() {
216 if (shared_ptr
<Animation
> animation
= m_piece
->movementAnimation().lock()) {
218 m_piece
->setMovementAnimation(shared_ptr
<Animation
>());
223 //END CaptureAnimation
225 //BEGIN DropAnimation
227 DropAnimation::DropAnimation(const SpritePtr
& piece
)
228 : OneShotAnimation(piece
)
229 , m_valid_position(false) { }
231 DropAnimation::DropAnimation(const SpritePtr
& piece
, const QPoint
& pos
)
232 : OneShotAnimation(piece
)
233 , m_valid_position(true)
234 , m_position(pos
) { }
236 void DropAnimation::shoot() {
237 if (m_valid_position
)
238 m_piece
->moveTo(m_position
);
244 //BEGIN PromotionAnimation
246 PromotionAnimation::PromotionAnimation(const SpritePtr
& piece
,
247 const SpritePtr
& promoted
)
248 : OneShotAnimation(piece
)
249 , m_promoted(promoted
) { }
251 void PromotionAnimation::shoot() {
256 //END PromotionAnimation
258 //BEGIN CrossFadingAnimation
260 CrossFadingAnimation::CrossFadingAnimation(const SpritePtr
& piece
,
261 const SpritePtr
& promoted
)
263 addPreAnimation(shared_ptr
<FadeAnimation
>(new FadeAnimation(piece
, 255, 0)));
264 addPreAnimation(shared_ptr
<FadeAnimation
>(new FadeAnimation(promoted
, 0, 255)));
267 void CrossFadingAnimation::start() {
268 AnimationGroup::start();
271 //END CrossFadingAnimation
275 //BEGIN DelayAnimation
277 DelayAnimation::DelayAnimation(int secs
)
282 void DelayAnimation::start() {
286 Animation::State
DelayAnimation::animationAdvance(int msec
) {
295 if(msec
> m_start
+ m_msecs
)
303 void DelayAnimation::stop() {
307 void DelayAnimation::abort() {
315 //BEGIN FadeAnimation
317 FadeAnimation::FadeAnimation(const SpritePtr
& sprite
, const QPoint
& to
,
318 int fadeFrom
, int fadeTo
)
319 : ConcreteAnimation(sprite
)
320 , m_fadeFrom(fadeFrom
)
323 , m_state(Inactive
) { }
325 FadeAnimation::FadeAnimation(const SpritePtr
& sprite
, int fadeFrom
, int fadeTo
)
326 : ConcreteAnimation(sprite
)
327 , m_fadeFrom(fadeFrom
)
329 , m_to(Point::invalid())
330 , m_state(Inactive
) { }
332 void FadeAnimation::start() {
335 if (m_to
!= Point::invalid()) {
336 m_piece
->moveTo(m_to
);
339 m_piece
->setOpacity(m_fadeFrom
);
343 Animation::State
FadeAnimation::animationAdvance(int msec
) {
353 double t
= (msec
- m_start
) / 400.0;
359 int op
= static_cast<int>(m_fadeTo
* t
+ m_fadeFrom
* (1 - t
));
360 m_piece
->setOpacity(op
);
369 void FadeAnimation::stop() {
370 m_piece
->setOpacity(m_fadeTo
);
374 void FadeAnimation::abort() {
383 //BEGIN GrowAnimation
385 GrowAnimation::GrowAnimation(const SpritePtr
& sprite
)
386 : ConcreteAnimation(sprite
)
387 , m_state(Inactive
) { }
389 void GrowAnimation::start() {
393 m_piece
->setScale(0.0);
396 Animation::State
GrowAnimation::animationAdvance(int msec
) {
406 double t
= (msec
- m_start
) / 700.0;
413 m_piece
->setScale(t
);
422 void GrowAnimation::stop() {
423 m_piece
->setScale(1.0);
427 void GrowAnimation::abort() {
435 //BEGIN ExplodeAnimation
437 ExplodeAnimation::ExplodeAnimation(const SpritePtr
& sprite
, Random
& random
)
438 : ConcreteAnimation(sprite
)
440 , m_random(random
) { }
442 void ExplodeAnimation::start() {
446 m_piece
->setupExplosion(m_random
);
449 Animation::State
ExplodeAnimation::animationAdvance(int msec
) {
459 double t
= (msec
- m_start
) / 700.0;
466 m_piece
->setExplosionStep(sin(t
*M_PI
/2)*0.7);
467 //m_piece->setScale(1.0+t*0.2);
468 m_piece
->setOpacity(int(cos(t
*M_PI
/2)*255));
477 void ExplodeAnimation::stop() {
478 m_piece
->setExplosionStep(0.7);
479 //m_piece->setScale(1.2);
483 void ExplodeAnimation::abort() {
488 //END ExplodeAnimation
490 //BEGIN AnimationGroup
492 AnimationGroup::AnimationGroup(bool persistent
)
495 , m_persistent(persistent
)
496 , m_chain_abortions(!persistent
) {
499 void AnimationGroup::start() {
503 bool AnimationGroup::empty() const {
504 return pre
.empty() && post
.empty();
507 Animation::State
AnimationGroup::animationAdvance(int msec
) {
514 // advance pre-animations
515 for (Iterator i
= pre
.begin(); i
!= pre
.end(); ) {
516 State animation_state
= (*i
)->animationAdvance(msec
);
517 switch (animation_state
) {
520 if (m_chain_abortions
) {
521 for (Iterator j
= pre
.begin(); j
!= pre
.end(); ) {
530 // the animation ended or has been aborted,
531 // remove it from the list
535 // handle next animation
541 // if there are still pre-animations, we're done
546 // no pre-animations: handle post animations
547 for (Iterator i
= post
.begin(); i
!= post
.end(); ) {
548 State animation_state
= (*i
)->animationAdvance(msec
);
549 switch (animation_state
) {
552 if (m_chain_abortions
) {
557 // the animation ended or has been aborted,
558 // remove it from the list
562 // handle next animation
569 // go on animating if there are still animations left
570 // or the group is persistent
571 m_active
= m_persistent
|| !post
.empty();
572 return m_active
? Active
: Inactive
;
575 void AnimationGroup::addPreAnimation(AnimationPtr anim
) {
579 // cannot dynamically add pre-animations
580 // adding it as a post-animation, instead
581 addPostAnimation(anim
);
586 void AnimationGroup::addPostAnimation(AnimationPtr anim
) {
588 post
.push_back(anim
);
591 void AnimationGroup::stop() {
592 // stop all animations
593 for (Iterator i
= pre
.begin(); i
!= pre
.end(); ) {
597 for (Iterator i
= post
.begin(); i
!= post
.end(); ) {
608 //BEGIN TeleportAnimation
610 TeleportAnimation::TeleportAnimation(const SpritePtr
& sprite
,
611 const QPoint
& from
, const QPoint
& to
)
612 : AnimationGroup(1.0) {
614 SpritePtr
copy(sprite
->duplicate());
617 addPreAnimation(AnimationPtr(new FadeAnimation(copy
, from
, 255, 0)));
618 addPreAnimation(AnimationPtr(new FadeAnimation(sprite
, to
, 0, 255)));
621 TeleportAnimation::TeleportAnimation(const SpritePtr
& sprite
,
623 : AnimationGroup(1.0) {
625 SpritePtr
copy(sprite
->duplicate());
628 addPreAnimation(AnimationPtr(new FadeAnimation(copy
, copy
->pos(), 255, 0)));
629 addPreAnimation(AnimationPtr(new FadeAnimation(sprite
, to
, 0, 255)));
633 //END TeleportAnimation
635 //BEGIN DelayedAnimationSet
637 DelayedAnimationSet::DelayedAnimationSet(Random
& random
)
639 , m_state(Inactive
) { }
641 void DelayedAnimationSet::addAnimation(const shared_ptr
<Animation
>& animation
) {
642 if (animation
&& m_state
== Inactive
)
643 m_animations
.push_back(animation
);
646 void DelayedAnimationSet::start() {
647 const int n
= m_animations
.size();
652 // animation time is proportional to the
653 // number of animations
656 // one animation starts immediately
657 int immediate
= m_random
.rand(0, n
- 1)();
658 m_events
.push_back(Event(immediate
, m_start
));
660 // generate event times
661 Random::IntegerGenerator event_time
= m_random
.rand(m_start
, m_start
+ m_time
);
662 for (int i
= 0; i
< n
; i
++) {
663 if (i
== immediate
) continue;
664 m_events
.push_back(Event(i
, event_time()));
668 sort(m_events
.begin(), m_events
.end());
671 m_next_event
= m_events
.begin();
677 Animation::State
DelayedAnimationSet::animationAdvance(int msec
) {
682 if (m_state
== Inactive
) abort();
688 // if there are still events left
689 if (m_next_event
!= m_events
.end()) {
691 // if the event period is elapsed
692 if (msec
>= m_start
+ m_time
) {
693 // execute all remaining animations
694 while (m_next_event
!= m_events
.end())
695 execute((m_next_event
++)->index());
699 // if the event time has elapsed
700 while (m_next_event
!= m_events
.end() && msec
>= m_next_event
->time()) {
701 // run the corresponding animation
702 execute((m_next_event
++)->index());
707 // step all active animations
708 // continue animating until m_group is over
709 m_state
= m_group
.animationAdvance(msec
);
718 void DelayedAnimationSet::execute(int index
) {
719 // start animation adding it to m_group
720 m_group
.addPostAnimation(m_animations
[index
]);
722 // remove it from the animation vector
723 m_animations
[index
] = shared_ptr
<Animation
>();
726 void DelayedAnimationSet::stop() {
728 m_animations
.clear();
732 void DelayedAnimationSet::abort() {
734 m_animations
.clear();
737 //END DelayedAnimationSet