00001 #ifndef CSSPRITE_H 00002 #define CSSPRITE_H 00003 00004 // USES SDL_Surface 00005 00006 #include <string> 00007 #include <vector> 00008 #include <map> 00009 #include "CSTypes.h" 00010 #include "CSLoadable.h" 00011 #include "CSMessageListener.h" 00012 #include "CSMessage.h" 00013 #include "CSAction.h" //!< for ActionState 00014 #include "CSLog.h" 00015 00016 class CSTileMap; 00017 class CSTile; 00018 class CSNavigator; 00019 00020 class CSSpriteLoader; 00021 class CSSprite; 00022 class StateData; 00023 class ActionBundle; 00024 00025 typedef std::vector<CSSprite*> CSSprites; 00026 typedef std::vector<StateData *> StateDatas; 00027 typedef std::map<int, ActionBundle *> ActionBundleMap; 00028 00029 class StateData 00030 { 00031 public: 00032 StringVector actionNames; //!< filenames (xml) of all action belonging to sprite 00033 char *defaultActionName; //!< default action (id) 00034 int stateId; 00035 00036 StateData() 00037 { 00038 defaultActionName = 0; 00039 stateId = 0; 00040 } 00041 00042 ~StateData() 00043 { 00044 for (StringVector::iterator iter = actionNames.begin(); iter != actionNames.end(); iter++) 00045 { 00046 delete *iter; 00047 } 00048 actionNames.clear(); 00049 00050 if (defaultActionName != 0) 00051 { 00052 free(defaultActionName); 00053 defaultActionName = 0; 00054 } 00055 stateId = 0; 00056 } 00057 }; 00058 00059 //! data classes are used for loading a loadable class 00060 //! first the data is loaded via xml into this "DATA"-class 00061 //! from this data - the actual sprite is created 00062 //! the data can be reused to create another instance of an 00063 //! sprite class - though probably not needed... 00064 class CSSpriteData 00065 { 00066 public: 00067 char *id; //!< id of sprite (unique) 00068 StateDatas stateDatas; 00069 int layer_position; //!< sprite lies above layer (and under each higher layer) 00070 int type; 00071 int defaultBundle; 00072 int subtype; 00073 int y_position; //!< within that layer a sprite can have a y position 00074 //!< so that one sprite can be above another within one layer 00075 //!< TODO: right now the squence of the sprite 00076 //!< is used, this parameter is still ignored! 00077 CSSpriteData() 00078 { 00079 type = 0; 00080 subtype = 0; 00081 defaultBundle = 0; 00082 id = 0; 00083 layer_position = 0; 00084 y_position = 0; 00085 } 00086 00087 ~CSSpriteData() 00088 { 00089 if (id != 0) 00090 { 00091 free (id); 00092 id = 0; 00093 } 00094 for (StateDatas::iterator iter = stateDatas.begin(); iter != stateDatas.end(); iter++) 00095 { 00096 delete *iter; 00097 } 00098 stateDatas.clear(); 00099 } 00100 }; 00101 00102 //! the states hold all variable parts needed for printing the 00103 //! sprite on screen 00104 //! putting these in a state class, enables us to 00105 //! reuse the memory expensive sprite class! 00106 class SpriteState 00107 { 00108 public: 00109 ActionState mActionState; //!< each sprite must have actions -> so each 00110 //!< sprite state needs an action state! 00111 00112 //!< current active action 00113 CSAction *mCurrentAction; 00114 ActionBundle *mCurrentBundle; 00115 int mCurrentBundleId; 00116 int mUserState; 00117 00118 SpriteState() 00119 { 00120 mUserState = 0; 00121 mCurrentAction = 0; 00122 mCurrentBundleId = 0; 00123 mCurrentBundle = 0; 00124 } 00125 virtual ~SpriteState() {} 00126 }; 00127 00128 class ActionBundle 00129 { 00130 public: 00131 CSActions *mActions; //!< all actions belonging to this sprite 00132 CSAction *mDefaultAction; //!< default action 00133 int stateId; 00134 00135 ActionBundle() 00136 { 00137 mActions = 0; //!< all actions belonging to this sprite 00138 mDefaultAction = 0; //!< default action 00139 stateId = 0; 00140 } 00141 00142 ~ActionBundle() 00143 { 00144 if (mActions != 0) 00145 { 00146 //!< Actions are singletons -> do not delete them 00147 delete mActions; 00148 mActions = 0; 00149 } 00150 mDefaultAction = 0; 00151 } 00152 }; 00153 00154 /** 00155 This file defines CSSprite: 00156 00157 CSSprite can only be created thru a loader (CSSpriteLoader). 00158 CSSprite are defined by (now ONLY thru) an xml-File, like: 00159 DTD: 00160 \verbatim 00161 <!ELEMENT SPRITE (ID,(ACTION)+,DEFAULT_ACTION,LAYER_POSITION,Y_POSITION)> 00162 <!ELEMENT ID (#PCDATA)> 00163 <!ELEMENT ACTION (#PCDATA)> 00164 <!ELEMENT DEFAULT_ACTION (#PCDATA)> 00165 <!ELEMENT LAYER_POSITION (#PCDATA)> 00166 <!ELEMENT Y_POSITION (#PCDATA)> 00167 \endverbatim 00168 Example: 00169 00170 \verbatim 00171 <SPRITE> 00172 <ID>PACMAN_SPRITE</ID> 00173 <ACTION>action\\pac_down.xml</ACTION> 00174 <ACTION>action\\pac_up.xml</ACTION> 00175 <ACTION>action\\pac_left.xml</ACTION> 00176 <ACTION>action\\pac_right.xml</ACTION> 00177 <ACTION>action\\pac_down_stay.xml</ACTION> 00178 <ACTION>action\\pac_up_stay.xml</ACTION> 00179 <ACTION>action\\pac_right_stay.xml</ACTION> 00180 <ACTION>action\\pac_left_stay.xml</ACTION> 00181 <ACTION>action\\pac_death.xml</ACTION> 00182 <DEFAULT_ACTION>action\\pac_right.xml</DEFAULT_ACTION> 00183 <LAYER_POSITION>0</LAYER_POSITION> 00184 <Y_POSITION>0</Y_POSITION> 00185 </SPRITE> 00186 \endverbatim 00187 <PRE> 00188 ID - supposed a unique identifier 00189 00190 ACTION - many actions are possible! 00191 describes the action to be loaded, 00192 parameter gives the ini-file for a CSAction 00193 00194 DEFAULT_ACTION - an action that is used as a default, if another actions 00195 ends. 00196 This default is overriden by the DEFAULT_NEXT_ACTION 00197 setting of the current active action. 00198 The default action should not appear listed in the 00199 'normal' action setting. (no double entries) 00200 00201 LAYER_POSITION - sprite lies above layer (and under each higher layer) 00202 Y_POSITION - within that layer a sprite can have a y position 00203 so that one sprite can be above another within one layer 00204 TODO: right now the squence of the sprite 00205 is used, this parameter is still ignored! 00206 00207 Methods: 00208 virtual void next(); 00209 virtual void display(); 00210 SpriteState buildState(); // only for compatibility issues 00211 void resetState(SpriteState &state); 00212 virtual void reactOnMessage(CSMessage *message);// MessageListener implementation 00213 void setSecPerFrame(float secPerFrame); 00214 void setDisplayOffset(int xOffset, int yOffset);// where on the screen is 0,0 of our displaying 00215 void setWorldPosition(int x, int y); // where in the world will we start drawing the screen 00216 unsigned int checkCollisionPixels(CSSprite *other); // Collision detection, returns # of pixels 00217 unsigned int checkCollisionPixels(CSTileMap *map); // Collision detection, returns # of pixels 00218 unsigned int checkCollisionPixels(CSTile *tile); // Collision detection, returns # of pixels 00219 bool checkCollision(CSSprite *other); // Collision detection, returns boolean 00220 bool checkCollision(CSTileMap *map); // Collision detection, returns boolean 00221 bool checkCollision(CSTile *tile); // Collision detection, returns boolean 00222 std::vector<CSTile*> getCollidingTiles(CSTileMap *map); // return all tiles, that have pixels colliding with sprite 00223 void setSpeedY(int speed); // overrides values in animation 00224 void setSpeedX(int speed); // overrides values in animation 00225 void resetSpeed(); // returns to speed values of animation (default) 00226 SpriteState getState() 00227 void setState(const SpriteState &state) 00228 int getLayer() 00229 int getLayerY() 00230 void clearNavigator() 00231 void setNavigator(CSNavigator *navigator) 00232 unsigned int getDisplayXLower() 00233 unsigned int getDisplayYLower() 00234 unsigned int getDisplayXUpper() // pos + width of sprite 00235 unsigned int getDisplayYUpper() // pos + height of sprite 00236 unsigned int getXPos() 00237 unsigned int getYPos() 00238 00239 Supported messages: 00240 (see Message.h) 00241 Messages of type; ACTION_MESSAGE 00242 00243 CSSprite also implements: 00244 CSMessageListener 00245 </PRE> 00246 the sprite class has (in opposite to action an aniamtion) state 00247 dependent data -> the sprite state 00248 should at some point it be neccessary to have state information outside of 00249 sprites - than we must remove it here, than the sprite class will 00250 (as action and aniamtion) behave as a local singleton... (and change next(), display()) 00251 */ 00252 class CSSprite : public CSMessageListener, public CSMessageDispatchable 00253 { 00254 friend CSSpriteLoader; 00255 private: 00256 SpriteMessage MESSAGE_SPRITE_ACTION_CHANGE; 00257 SpriteState mState; //!< the only state dependent data within this class 00258 00259 bool mActive; 00260 ActionBundleMap actionMap; 00261 int mDefaultBundle; 00262 CSNavigator *mNavigator; //!< this class can 'navigate' our sprite (if set) 00263 //!< called within (at first chance) next() 00264 int mType; 00265 int mSubtype; 00266 int layer_position; //!< sprite lies above layer (and under each higher layer) 00267 int y_position; //!< within that layer a sprite can have a y position 00268 //!< so that one sprite can be above another within one layer 00269 //!< TODO: right now the squence of the sprite 00270 //!< is used, this parameter is still ignored! 00271 00272 unsigned int mWidth; //!< max Width of this sprite 00273 unsigned int mHeight; //!< max Height of this sprite 00274 unsigned int mWorldPos; //!< current on world # 00275 std::string mFilename; 00276 char *mId; 00277 //!< constructor using "*.xml" file 00278 CSSprite(const std::string &filename); 00279 static void loadSpriteData(const std::string &filename, CSSpriteData &data); 00280 bool changeStateTo(int state); 00281 00282 void initialize(const CSSpriteData &data); 00283 void initialize(); 00284 00285 public: 00286 CSSprite(const CSSprite &Sprite); 00287 virtual ~CSSprite(); 00288 00289 static const char *CLASS; 00290 virtual std::string getType() {return (std::string) CLASS;} 00291 00292 virtual void next(); 00293 virtual void display(); 00294 00295 SpriteState buildState(); //!< only for compatibility issues 00296 void resetState(SpriteState &state); 00297 00298 virtual void reactOnMessage(CSMessage *message);//!< MessageListener implementation 00299 00300 void setSecPerFrame(float secPerFrame); 00301 00302 void setDisplayOffset(int xOffset, int yOffset);//!< where on the screen is 0,0 of our displaying 00303 void setWorldPosition(int x, int y); //!< where in the world will we start drawing the screen 00304 unsigned int checkCollisionPixels(CSSprite *other); //!< Collision detection, returns # of pixels 00305 unsigned int checkCollisionPixels(CSTileMap *map); //!< Collision detection, returns # of pixels 00306 unsigned int checkCollisionPixels(CSTile *tile); //!< Collision detection, returns # of pixels 00307 bool checkCollision(CSSprite *other); //!< Collision detection, returns boolean 00308 bool checkCollision(CSTileMap *map); //!< Collision detection, returns boolean 00309 bool checkCollision(CSTile *tile); //!< Collision detection, returns boolean 00310 std::vector<CSTile*> getCollidingTiles(CSTileMap *map); //!< return all tiles, that have pixels colliding with sprite 00311 void setSpeedY(int speed); //!< overrides values in animation 00312 void setSpeedX(int speed); //!< overrides values in animation 00313 void adjustSpeed(int speed); //!< overrides values in animation 00314 void resetSpeed(); //!< returns to speed values of animation (default) 00315 void setNavigator(CSNavigator *navigator); 00316 CSNavigator *getNavigator() {return mNavigator;} 00317 void setAlpha(int alpha); 00318 00319 //!< inlines 00320 unsigned int getWorldPos() {return mWorldPos;} 00321 SpriteState getState() {return mState;} 00322 void setState(const SpriteState &state) {mState = state;} 00323 void setLayer(int z) {layer_position = z;} 00324 int getLayer() {return layer_position;} 00325 int getLayerY() {return y_position;} 00326 void clearNavigator() {mNavigator = 0;} 00327 void resetNavigator(); 00328 int getMaxWidth() {return mWidth;} 00329 int getMaxHeight() {return mHeight;} 00330 int getSpriteType() {return mType;} 00331 int getSubtype() {return mSubtype;} 00332 int getCurrentStateId() {return mState.mCurrentBundleId;} 00333 std::string getFilename() {return mFilename;} 00334 std::string getId() {return mId;} 00335 void setPosition(int x, int y, unsigned int z); 00336 00337 int getUserState(void) {return mState.mUserState;} 00338 void setUserState(int userState) {mState.mUserState = userState;} 00339 00340 SDL_Surface *getScaledSprite(double factor) 00341 { 00342 return mState.mActionState.mAnimation->getScaledAnimation(mState.mActionState.mAnimationState, factor); 00343 } 00344 00345 const char *getCurrentActionId() 00346 { 00347 return mState.mCurrentAction->getId(); 00348 } 00349 int getCurrentActionType() 00350 { 00351 return mState.mCurrentAction->getActionType(); 00352 } 00353 00354 00355 //!< return x start of surface coordinates of where the 00356 //!< the sprite will be drawn during next display 00357 unsigned int getDisplayXLower() 00358 { 00359 int x = 00360 mState.mActionState.mAnimationState.mDisplayParams.mXDisplayStart + 00361 mState.mActionState.mAnimationState.mDisplayParams.mXPos - 00362 mState.mActionState.mAnimationState.mDisplayParams.mXWorldStart; 00363 return x; 00364 } 00365 00366 //!< return y start of surface coordinates of where the 00367 //!< the sprite will be drawn during next display 00368 unsigned int getDisplayYLower() 00369 { 00370 int y = 00371 mState.mActionState.mAnimationState.mDisplayParams.mYDisplayStart + 00372 mState.mActionState.mAnimationState.mDisplayParams.mYPos - 00373 mState.mActionState.mAnimationState.mDisplayParams.mYWorldStart; 00374 return y; 00375 } 00376 00377 //!< return x end of surface coordinates of where the 00378 //!< the sprite will be drawn during next display 00379 unsigned int getDisplayXUpper() //!< pos + width of sprite 00380 { 00381 int x = getDisplayXLower(); 00382 x += mWidth; 00383 return x; 00384 } 00385 00386 //!< return y end of surface coordinates of where the 00387 //!< the sprite will be drawn during next display 00388 unsigned int getDisplayYUpper() //!< pos + height of sprite 00389 { 00390 int y = getDisplayYLower(); 00391 y += mHeight; 00392 return y; 00393 } 00394 00395 //!< return the world x-coordinate of sprite that will be used during 00396 //!< the next display 00397 int getXPos() 00398 { 00399 return mState.mActionState.mAnimationState.mDisplayParams.mXPos; 00400 } 00401 00402 //!< return the world y-coordinate of sprite that will be used during 00403 //!< the next display 00404 int getYPos() 00405 { 00406 return mState.mActionState.mAnimationState.mDisplayParams.mYPos; 00407 } 00408 void setActive(bool active) 00409 { 00410 mActive = active; 00411 } 00412 }; 00413 00414 //! factory - class 00415 //! that is used to create CSSprite 00416 //! uses xml - data-files, produces NOT "singletons"!!! 00417 //! than means the result sprite must be freed by the caller (or whoever)!!! 00418 class CSSpriteLoader : public Loadable<CSSprite> 00419 { 00420 protected: 00421 //! not a singleton created! 00422 virtual bool isSingleCreate(void) const 00423 { 00424 return false; 00425 } 00426 00427 virtual CSSprite *create(const std::string &filename) 00428 { 00429 return new CSSprite(filename); 00430 } 00431 00432 public: 00433 static CSSpriteLoader INSTANCE; 00434 }; 00435 00436 #endif // CSSPRITE_H 00437