sdlsprites.pas 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346
  1. unit sdlsprites;
  2. {************************************************************************
  3. (*
  4. $Id: sdlsprites.pas,v 1.3 2004/03/31 09:04:31 savage Exp $
  5. *)
  6. * SDLSprites.pas for JEDI-SDL *
  7. * Written by KiCHY *
  8. * Version 1.04 (04 june 2001) *
  9. * This unit is freeware, use at your own risk! *
  10. * E-mail: [email protected] *
  11. * Please send me your opinions, ideas, bugreports, etc. *
  12. * History: *
  13. * 08 aug 2001 RK: v1.0 Initial version *
  14. * 10 sept 2001 RK: v1.01 Added "SDL_DisplayFormat" for fast blitting *
  15. * 02 oct 2001 RK: v1.02 Added SDL_Image, so now can load PNG, PCX... *
  16. * 28 oct 2001 RK: v1.03 Added NumberOfFrames *
  17. * 02 nov 2001 RK: v1.04 Modifed Draw method (hint by Logan) *
  18. * 04 june 2002 RK: v1.05 Fixed memory leaks *
  19. * 19 Jan 2004 DL: v1.06 Changed ReallocMem Call to SetLength and *
  20. * Moved CompareZ function *
  21. (*
  22. $Log: sdlsprites.pas,v $
  23. Revision 1.3 2004/03/31 09:04:31 savage
  24. Added jedi-sdl.inc files for better FreePascal/multi compiler support.
  25. Revision 1.2 2004/03/30 22:21:34 savage
  26. After some prodding by Marco Van de Voort, I have made TSprite more OO by adding private and public scopes.
  27. Revision 1.1 2004/02/26 00:06:25 savage
  28. Sprite Engine first commit.
  29. *)
  30. ************************************************************************}
  31. {$I jedi-sdl.inc}
  32. interface
  33. uses
  34. {$IFDEF WIN32}
  35. Windows,
  36. {$ENDIF}
  37. Classes,
  38. SysUtils,
  39. sdl_image,
  40. sdl;
  41. type
  42. TSpriteList = class;
  43. TSprite = class
  44. private
  45. Flags : cardinal; // for SDL_BlitSurface
  46. isDead : boolean; // need to destroy ?
  47. function Remove : integer; // remove sprite from screen, result=-2 then background surface is lost
  48. public
  49. ID : byte; // we can easily determine the sprite's type
  50. ParentList : TSpriteList;
  51. AnimPhase : integer; // which image we draw
  52. NumberOfFrames : integer; // count of frames [by brombs]
  53. x, y, z : integer; // x, y coords for screen, z for sorting
  54. w, h : integer; // Width & Height of sprite
  55. Surface, Background, Image : PSDL_Surface; // Screen, Background and sprite images
  56. SrcRect : TSDL_Rect; // source rectangle what contains the image-data
  57. PrevRect : TSDL_Rect; // rectangle of previous position in the screen
  58. constructor Create( const _Image : string; Width, Height : integer );
  59. procedure GetCollisionRect( Rect : PSDL_Rect ); virtual;
  60. procedure Draw; virtual; // draw sprite on screen
  61. procedure Move; virtual; // move a sprite
  62. procedure Kill; // we will need to destroy this sprite
  63. procedure Free; virtual; // destroy sprite
  64. end;
  65. TSpriteList = class( TList )
  66. protected
  67. function Get( Index : Integer ) : TSprite;
  68. procedure Put( Index : Integer; Item : TSprite );
  69. public
  70. property Items[ Index : Integer ] : TSprite read Get write Put; default;
  71. end;
  72. TSpriteEngine = class
  73. private
  74. NeedSort : boolean; // do we need to resort sprites by Z?
  75. FSurface, FBackground : PSDL_Surface; // screen and background surface
  76. procedure SetSurface( _Surface : PSDL_Surface );
  77. procedure SetBackground( _Surface : PSDL_Surface );
  78. public
  79. Sprites : TSpriteList; // all sprites
  80. NumberOfRects : integer;
  81. UpdateRects : array of TSDL_Rect;
  82. NeedRedrawBackground : boolean; // background surface is lost?
  83. procedure Clear; // destroy all sprites from list
  84. procedure SortSprites; // that is
  85. procedure AddSprite( Item : TSprite ); // add a sprite to list
  86. procedure RemoveSprite( Item : TSprite ); // remove a sprite from list and from memory
  87. procedure Free;
  88. procedure Move; // move all sprites in the list
  89. procedure Draw; // draw all sprites in the list
  90. property Surface : PSDL_Surface read FSurface write SetSurface; // screen surface
  91. property BackgroundSurface : PSDL_Surface read FBackground write SetBackground; // background surface
  92. constructor Create( _Surface : PSDL_Surface );
  93. end;
  94. function isCollideRects( Rect1, Rect2 : PSDL_Rect ) : boolean;
  95. implementation
  96. function CompareZ( Item1, Item2 : TSprite ) : Integer;
  97. begin
  98. if Item1.z < Item2.z then
  99. Result := -1
  100. else if Item1.z > Item2.z then
  101. Result := 1
  102. else
  103. Result := 0;
  104. end;
  105. function isCollideRects( Rect1, Rect2 : PSDL_Rect ) : boolean;
  106. begin
  107. Result := true;
  108. if ( Rect1.x + Rect1.w < Rect2.x ) or
  109. ( Rect1.x > Rect2.x + Rect2.w ) or
  110. ( Rect1.y + Rect1.h < Rect2.y ) or
  111. ( Rect1.y > Rect2.y + Rect2.h ) then
  112. Result := false;
  113. end;
  114. // Create a sprite. Transparent color is $00ff00ff
  115. constructor TSprite.Create( const _Image : string; Width, Height : integer );
  116. var
  117. Temp : PSDL_Surface;
  118. begin
  119. inherited Create;
  120. ID := 0;
  121. if fileexists( _Image ) then
  122. begin
  123. Temp := IMG_Load( PChar( _Image ) );
  124. Image := SDL_DisplayFormat( Temp );
  125. SDL_FreeSurface( Temp );
  126. Flags := SDL_SRCCOLORKEY or SDL_RLEACCEL or SDL_HWACCEL;
  127. SDL_SetColorKey( Image, Flags, SDL_MapRGB( Image.format, 255, 0, 255 ) );
  128. NumberOfFrames := Image.w div Width;
  129. end
  130. else
  131. NumberOfFrames := 0;
  132. AnimPhase := 0;
  133. isDead := false;
  134. x := 0;
  135. y := 0;
  136. z := 0;
  137. w := Width;
  138. h := Height;
  139. SrcRect.y := 0;
  140. SrcRect.w := w;
  141. SrcRect.h := h;
  142. end;
  143. // we can separately determine the collision rectangle
  144. procedure TSprite.GetCollisionRect( Rect : PSDL_Rect );
  145. begin
  146. Rect.x := x;
  147. Rect.y := y;
  148. Rect.w := w;
  149. Rect.h := h;
  150. end;
  151. procedure TSprite.Free;
  152. begin
  153. if Image <> nil then
  154. SDL_FreeSurface( Image );
  155. inherited Free;
  156. end;
  157. procedure TSprite.Move;
  158. begin
  159. end;
  160. procedure TSprite.Kill;
  161. begin
  162. isDead := true;
  163. end;
  164. function TSprite.Remove : integer;
  165. begin
  166. PrevRect.w := w;
  167. PrevRect.h := h;
  168. Result := SDL_BlitSurface( Background, @PrevRect, Surface, @PrevRect );
  169. end;
  170. procedure TSprite.Draw;
  171. var
  172. DestRect : TSDL_Rect;
  173. begin
  174. SrcRect.x := AnimPhase * w; // which animation phase need to draw?
  175. DestRect.x := x; // set screen positions
  176. DestRect.y := y;
  177. SDL_BlitSurface( Image, @SrcRect, Surface, @DestRect );
  178. PrevRect := DestRect;
  179. end;
  180. // TSpriteList ---------------------------------------
  181. function TSpriteList.Get( Index : Integer ) : TSprite;
  182. begin
  183. Result := inherited Get( Index );
  184. end;
  185. procedure TSpriteList.Put( Index : Integer; Item : TSprite );
  186. begin
  187. inherited Put( Index, Item );
  188. end;
  189. // TSpriteEngine ----------------------------------------
  190. constructor TSpriteEngine.Create( _Surface : PSDL_Surface );
  191. begin
  192. inherited Create;
  193. NeedSort := false;
  194. Sprites := TSpriteList.Create;
  195. FSurface := _Surface;
  196. NeedRedrawBackground := false;
  197. NumberOfRects := 0;
  198. UpdateRects := nil;
  199. end;
  200. procedure TSpriteEngine.Free;
  201. begin
  202. Clear;
  203. Sprites.Free;
  204. inherited Free;
  205. end;
  206. procedure TSpriteEngine.AddSprite( Item : TSprite );
  207. begin
  208. Item.Surface := Surface; // setting new sprite's surfaces
  209. Item.Background := FBackground;
  210. Item.ParentList := Sprites;
  211. Sprites.Add( Item );
  212. NeedSort := true;
  213. SetLength( UpdateRects, Sprites.Count * 2 * sizeof( TSDL_Rect ) );
  214. end;
  215. procedure TSpriteEngine.RemoveSprite( Item : TSprite );
  216. begin
  217. Sprites.Remove( Item );
  218. SetLength( UpdateRects, Sprites.Count * 2 * sizeof( TSDL_Rect ) );
  219. end;
  220. procedure TSpriteEngine.Move;
  221. var
  222. i, max : integer;
  223. TempSpr : TSprite;
  224. begin
  225. if Sprites.Count > 0 then
  226. begin
  227. NeedRedrawBackground := false;
  228. i := 0; max := Sprites.Count;
  229. repeat
  230. if Sprites[ i ].Remove = -2 then
  231. NeedRedrawBackground := true;
  232. if Sprites[ i ].isDead then
  233. begin
  234. TempSpr := Sprites[ i ];
  235. RemoveSprite( TempSpr );
  236. TempSpr.Free;
  237. dec( Max );
  238. end
  239. else
  240. begin
  241. Sprites[ i ].Move;
  242. inc( i );
  243. end;
  244. until i >= Max;
  245. end;
  246. if NeedSort then
  247. begin
  248. SortSprites;
  249. NeedSort := false;
  250. end;
  251. end;
  252. procedure TSpriteEngine.Draw;
  253. var
  254. i, j, num : integer;
  255. begin
  256. num := Sprites.Count;
  257. j := 0;
  258. if num > 0 then
  259. begin
  260. for i := 0 to num - 1 do
  261. begin
  262. UpdateRects[ j ] := Sprites[ i ].PrevRect;
  263. Sprites[ i ].Draw;
  264. inc( j );
  265. if not Sprites[ i ].isDead then
  266. begin
  267. UpdateRects[ j ] := Sprites[ i ].PrevRect;
  268. inc( j );
  269. end;
  270. end;
  271. end;
  272. NumberOfRects := j;
  273. end;
  274. // set all sprites' Surface to _Surface
  275. procedure TSpriteEngine.SetSurface( _Surface : PSDL_Surface );
  276. var
  277. i : integer;
  278. begin
  279. FSurface := _Surface;
  280. if Sprites.Count > 0 then
  281. for i := 0 to Sprites.Count - 1 do
  282. Sprites[ i ].Surface := _Surface;
  283. end;
  284. // set all sprites' Background surface to _Surface
  285. procedure TSpriteEngine.SetBackground( _Surface : PSDL_Surface );
  286. var
  287. i : integer;
  288. begin
  289. FBackground := _Surface;
  290. if Sprites.Count > 0 then
  291. for i := 0 to Sprites.Count - 1 do
  292. Sprites[ i ].Background := _Surface;
  293. end;
  294. procedure TSpriteEngine.Clear;
  295. var
  296. TempSpr : TSprite;
  297. begin
  298. while Sprites.Count > 0 do
  299. begin // destroy all sprites
  300. TempSpr := Sprites[ 0 ];
  301. RemoveSprite( TempSpr );
  302. TempSpr.Free;
  303. end;
  304. Sprites.Clear;
  305. end;
  306. procedure TSpriteEngine.SortSprites;
  307. begin
  308. Sprites.Sort( @CompareZ );
  309. end;
  310. end.