cardsprite.cpp

Go to the documentation of this file.
00001 /*
00002    This file is part of the KDE games lskat program
00003    Copyright (c) 2006 Martin Heni <kde@heni-online.de>
00004 
00005    This library is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Library General Public
00007    License as published by the Free Software Foundation; either
00008    version 2 of the License, or (at your option) any later version.
00009 
00010    This library is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Library General Public License for more details.
00014 
00015    You should have received a copy of the GNU Library General Public License
00016    along with this library; see the file COPYING.LIB.  If not, write to
00017    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00018    Boston, MA 02110-1301, USA.
00019 */
00020 
00021 // General includes
00022 #include <math.h>
00023 
00024 // Qt includes
00025 #include <QPoint>
00026 #include <QMatrix>
00027 
00028 // KDE includes
00029 #include <kdebug.h>
00030 
00031 // Local includes
00032 #include "cardsprite.h"
00033 
00034 // Delay for card turning animation [ms]
00035 #define ANIM_CNT_TURNING          20.0 
00036 // Time in [ms] for a shuffle move
00037 #define SHUFFLEMOVE_TIME 100.0 
00038 
00039 
00040 // Theme manager stuff
00041 #define THEME_ID "card"
00042 
00043 
00044 // Constructor for the view
00045 CardSprite::CardSprite(const Suite suite, const CardType cardtype, ThemeManager* theme,
00046                        int advancePeriod, QGraphicsScene* scene)
00047           : Themable(THEME_ID, theme), QGraphicsPixmapItem(0, scene)
00048 
00049 {
00050   mAnimationState = Idle;
00051   mCurrentFrame   = 0;
00052   mAdvancePeriod  = advancePeriod;
00053   mSuite          = suite;
00054   mCardType       = cardtype;
00055   mFrames.clear();
00056 }
00057 
00058 
00059 // Main themable function. Called for any theme change. The sprites needs to
00060 // resiez and redraw here.
00061 void CardSprite::changeTheme()
00062 {
00063   // Get scaling change
00064   double oldscale = this->getScale();
00065   double scale    = thememanager()->getScale();
00066   setScale(scale);
00067 
00068   // Retrieve theme data from configuration
00069   KConfigGroup config = thememanager()->config(id());
00070   double width        = config.readEntry("width", 1.0);
00071   width *= scale;
00072   mWidth = width; // Store for later use
00073 
00074   // Z-value by program only
00075   // Nothing to do
00076 
00077   // Animation
00078   int startFrame      = config.readEntry("start-frame", 0);
00079   int endFrame        = config.readEntry("end-frame", 0);
00080 
00081   // Pos py program only
00082   setPos(x()*scale/oldscale, y()*scale/oldscale);
00083 
00084   // Frames (loaded on demand)
00085   mFrames.clear();
00086   mHotspots.clear();
00087   QPixmap nullPixmap;
00088   for (int i=startFrame;i<=endFrame;i++)
00089   {
00090     mFrames.append(nullPixmap);
00091     mHotspots.append(QPointF(0.0,0.0));
00092   }
00093 
00094   
00095   // Set pixmap to sprite
00096   setFrame(mCurrentFrame, true);
00097   update();
00098 }
00099 
00100 
00101 // Stop all movment and animation
00102 void CardSprite::stop()
00103 {
00104   mAnimationState = Idle;
00105   mTime           = 0.0;
00106   setBackside();
00107 }
00108 
00109 
00110 // Set the current aniamtion mode of this sprite
00111 void CardSprite::setTurning(bool front)
00112 {
00113   mFrontFlag      = front;
00114   mAnimationState = Turning;
00115   mTime           = 0.0;
00116 }
00117 
00118 
00119 // Set target position and calculate moving speed.
00120 void CardSprite::calcTargetAndSpeed(QPointF pos, double time)
00121 {
00122   // Convert time from [ms] to advance cycles
00123   time = time / mAdvancePeriod;
00124 
00125   double scale = getScale();
00126   mMoveTarget  = pos;
00127   // Calculate move speed so that the duration for the move
00128   // is fixed
00129   double dx    = mMoveTarget.x()-x()/scale;
00130   double dy    = mMoveTarget.y()-y()/scale;
00131   double angle = atan2(dy,dx);
00132   mMoveSpeedX  = cos(angle)* sqrt(dx*dx + dy*dy) / time;
00133   mMoveSpeedY  = sin(angle)*sqrt(dx*dx + dy*dy) / time;
00134 }
00135 
00136 
00137 // Move the sprite to the given relative position
00138 void CardSprite::setPosition(QPointF pos)
00139 {
00140   mStart          = pos;
00141   setPos(mStart.x()*getScale(), mStart.y()*getScale());
00142 }
00143 
00144 
00145 // Move the sprite slowly to the target area. Stop
00146 // movement if it arrived there.
00147 void CardSprite::setMove(QPointF pos, double time)
00148 {
00149   mAnimationState = Moving;
00150   mTime           = 0.0;
00151   calcTargetAndSpeed(pos, time);
00152 }
00153 
00154 
00155 // Move the sprite slowly to the target area. Stop
00156 // movement and remove sprite if it arrived there.
00157 void CardSprite::setRemove(QPointF pos, double time)
00158 {
00159   mAnimationState = Removing;
00160   calcTargetAndSpeed(pos, time);
00161 }
00162 
00163 
00164 // Delay before moving, then move the sprite fast to the
00165 // target area. Stop movement and depending on the last
00166 // argument turn backside/frontside sprite if it arrived there.
00167 void CardSprite::setShuffleMove(QPointF pos, double delay, bool front)
00168 {
00169   calcTargetAndSpeed(pos, SHUFFLEMOVE_TIME);
00170   mAnimationState = ShuffleMove;
00171   mTime           = delay;
00172   mFrontFlag      = front;
00173 }
00174  
00175 
00176 // Display the card front pixmap image
00177 void CardSprite::setFrontside()
00178 {
00179   // Choose card front frame
00180   setFrame(0);
00181 }
00182 
00183 
00184 // Display the card back pixmap image
00185 void CardSprite::setBackside()
00186 {
00187   // Choose card back frame (last one in the animation sequence)
00188   setFrame(mFrames.size()-1);
00189 }
00190 
00191 
00192 int CardSprite::count()
00193 {
00194   return mFrames.count();
00195 }
00196 
00197 
00198 // Set a new bitmap into the sprite. If the number is the same as the
00199 // current one, nothing is done.
00200 void CardSprite::setFrame(int no, bool force)
00201 {
00202   if (!force && no == mCurrentFrame) return;
00203   if (no<0 || no >=mFrames.count()) return;
00204 
00205   // Calulate Pixmap (only done if necessary)
00206   calcFrame(no);
00207   
00208   // Set frame pixmap
00209   QPixmap pixmap = mFrames.at(no);
00210   setPixmap(pixmap);
00211 
00212   // Translation
00213   resetMatrix();
00214   translate(mHotspots[no].x(), mHotspots[no].y());
00215 
00216   mCurrentFrame = no;
00217   update();
00218 }
00219 
00220 
00221 // Calculate a pixmap for a frame. Only calculates it if it
00222 // is not previously stored to avoid double calculations.
00223 void CardSprite::calcFrame(int no)
00224 {
00225   QPixmap pixmap = mFrames.at(no);
00226   // Check whether frame is already loaded
00227   if (pixmap.isNull())
00228   {
00229     double dx = 0.0;  
00230     double dy = 0.0; 
00231     // Frontside
00232     if (no == 0) 
00233     {
00234       pixmap = thememanager()->getCard(mSuite, mCardType, mWidth);
00235     }
00236     // Backside
00237     else if (no >= mFrames.count()-1) 
00238     {
00239       pixmap = thememanager()->getCardback(mWidth);
00240     }
00241     // Animation
00242     else
00243     {
00244       QPixmap front = thememanager()->getCard(mSuite, mCardType, mWidth);
00245       QPixmap back  = thememanager()->getCardback(mWidth);
00246       pixmap        = createCard(front, back, no, mFrames.count());
00247       dx            = (front.width()-pixmap.width())/2.0;
00248       dy            = (front.height()-pixmap.height())/2.0;
00249     }
00250     mFrames[no]   = pixmap;
00251     mHotspots[no] = QPointF(dx, dy);
00252   }
00253 }
00254 
00255 
00256 // Perform a move by a delta given by the sprites velocity.
00257 // Returns true if the target position is reached
00258 bool CardSprite::deltaMove()
00259 {
00260   // Calculate difference vector
00261   double scale = getScale();
00262   double dx    = mMoveTarget.x()-x()/scale;
00263   double dy    = mMoveTarget.y()-y()/scale;
00264 
00265   // Check arrival at target
00266   if (dx*dx + dy*dy < mMoveSpeedX*mMoveSpeedX + mMoveSpeedY*mMoveSpeedY)
00267   {
00268     setPosition(mMoveTarget);
00269     return true;
00270   }
00271   // Move towards target by given velocity
00272   else
00273   {
00274     setPosition(QPointF( x()/scale + mMoveSpeedX, y()/scale + mMoveSpeedY));
00275     return false;
00276   }
00277 }
00278 
00279 
00280 // CanvasItem advance method 
00281 void CardSprite::advance(int phase)
00282 {
00283   // Ignore phase 0 (collisions)
00284   if (phase == 0)
00285   {
00286     QGraphicsItem::advance(phase);
00287     return ;
00288   }
00289 
00290   // Turn a card
00291   if (mAnimationState == Turning)
00292   {
00293     mTime += mAdvancePeriod;
00294     // Turn delay counter
00295     if (mTime >= ANIM_CNT_TURNING)
00296     {
00297       mTime = 0.0;
00298       // Check whether animation is over
00299       if ( (mFrontFlag && frame() == 0) ||
00300            (!mFrontFlag && frame() == mFrames.size()-1) )
00301       {
00302         mAnimationState = Idle;
00303       }
00304       else
00305       {
00306         if (mFrontFlag) setFrame(frame()-1);
00307         else setFrame(frame()+1);
00308       }
00309     }
00310   }// end if Turning
00311 
00312   // Move a card
00313   else if (mAnimationState == Moving)
00314   {
00315     // Perform a move by a delta given by the sprites velocity.
00316     if (deltaMove())
00317     {
00318       mAnimationState = Idle;
00319     }
00320   }// end if Moving
00321 
00322   // Move a card
00323   else if (mAnimationState == Removing)
00324   {
00325     // Perform a move by a delta given by the sprites velocity.
00326     if (deltaMove())
00327     {
00328       // Turn to backside
00329       setTurning(false);
00330     }
00331   }// end if Removing
00332 
00333   // Shuffle move a card
00334   else if (mAnimationState == ShuffleMove)
00335   {
00336     // First delay move until counter is run down
00337     if (mTime > 0.0)
00338     {
00339       mTime -= mAdvancePeriod;
00340     }
00341     // Then move to target position
00342     else
00343     {
00344       // Perform a move by a delta given by the sprites velocity.
00345       if (deltaMove())
00346       {
00347         if (mFrontFlag) mAnimationState = Turning;
00348         else mAnimationState = Idle;
00349         mTime = 0.0;
00350       }
00351     }
00352   }// end if ShuffleMove
00353 
00354   QGraphicsItem::advance(phase);
00355 }
00356 
00357 
00358 // Create turn animation, i.e. card combined out of backside and frontside
00359 QPixmap CardSprite::createCard(const QPixmap front, const QPixmap back, int curNo, int count)
00360 {
00361   int halfCount = count/2;
00362   // Turn the frontside of the card 0..90 degree
00363   if (curNo < halfCount)  
00364   {
00365     QMatrix m;
00366     // Get an angle eps..90 deg for the values i is running
00367     double angle = (double)curNo/(double)halfCount*90.0;
00368     // Conversion to rad
00369     angle = angle/180.0*M_PI;
00370     // Scale pixmap to simulate rotating card
00371     m.scale(cos(angle), 1.0);
00372     QPixmap pm = front.transformed(m, Qt::SmoothTransformation);
00373     return pm;
00374   }
00375 
00376   // Turn the backside of the card 90..eps degree
00377   else
00378   {
00379     QMatrix m;
00380     // Get an angle 0..90 deg for the values i is running
00381     double angle = 90.0-((double)(curNo-halfCount+1)/(double)halfCount*90.0);
00382     // Conversion to rad
00383     angle = angle/180.0*M_PI;
00384     // Scale pixmap to simulate rotating card
00385     m.scale(cos(angle), 1.0);
00386     QPixmap pm = back.transformed(m, Qt::SmoothTransformation);
00387     return pm;
00388   }
00389 }
00390 
00391 

Generated on Tue May 1 09:34:40 2007 for LSkat by  doxygen 1.4.6