AnimateSimple.pp 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269
  1. (*---------------------------------------------------------------------------------
  2. Sprite animation using two naive but common approaches to animating frames.
  3. Sprites were created by via the sprite tool at:
  4. http://charas-project.net/
  5. http://charas-project.net/charas2/index.php
  6. They were altered from their original 24x32 to 32x32 to make loading of frames simple
  7. for example purposes only. They are converted using grit via the supplied sprite.grit file.
  8. The man sprite loads new frame graphics every time the animation frame changes. This
  9. has the advantage of only consuming 32x32 bytes of data in sprite video memory and the
  10. disadvantages of having to store the rest of the frames in main memory and having the overhead
  11. of copying the data in each frame.
  12. The woman sprite loads all animation frames to sprite memory upon initialization. This
  13. has the advantage of allowing main memory to be freed, and causes the animation process
  14. to be significantly faster as only a pointer is changed each frame. The disadvantage is
  15. this single sprite is consuming nearly 10% of available sprite graphics memory for
  16. the sub display.
  17. If one of these two methods are to be employed I recommend the manly approach as the sprite memory is
  18. a scarce resource while main memory and cpu cycles are comparatively abundant.
  19. A more advanced approach is to keep track of which frames of which sprites are loaded into memory
  20. during the animation stage, load new graphics frames into memory overwriting the currently unused
  21. frames only when sprite memory is full. Decide which frame to unload by keeping track of how
  22. often they are being used and be sure to mark all a sprites frames as unused when it is "killed"
  23. This demo is using a very rigid animation engine in that it assumes that each frame of sprite
  24. graphics is the same size, that each sprite can only walk up down left or right and that
  25. each of these states is 3 frames in durration. Significantly more advance animations can be
  26. done by creating data structures to describe an animation sequence. Perhaps more advanced
  27. demos will follow this one.
  28. -- dovoto (jason rogers)
  29. ---------------------------------------------------------------------------------*)
  30. program AnimateSimple;
  31. {$L build/man.o}
  32. {$L build/woman.o}
  33. {$mode objfpc}
  34. uses
  35. ctypes, nds9;
  36. var
  37. manTiles: array [0..3071] of cuint; cvar; external;
  38. manPal: array [0..255] of cushort; cvar; external;
  39. womanTiles: array [0..3071] of cuint; cvar; external;
  40. womanPal: array [0..255] of cushort; cvar; external;
  41. const
  42. FRAMES_PER_ANIMATION = 3;
  43. type
  44. //---------------------------------------------------------------------
  45. // The man sprite
  46. // he needs a single pointer to sprite memory
  47. // and a reference to his frame graphics so they
  48. // can be loaded as needed
  49. //---------------------------------------------------------------------
  50. TMan = record
  51. x: cint;
  52. y: cint;
  53. sprite_gfx_mem: pcuint16;
  54. frame_gfx: pcuint8;
  55. state: cint;
  56. anim_frame: cint;
  57. end;
  58. PMan = ^TMan;
  59. //---------------------------------------------------------------------
  60. // The womman sprite
  61. // she needs an array of pointers to sprite memory since all
  62. // her frames are to be loaded.
  63. // she also needs to keep track of which sprite memory pointer is in use
  64. //---------------------------------------------------------------------
  65. TWoman = record
  66. x: cint;
  67. y: cint;
  68. sprite_gfx_mem: array [0..11] of pcuint16;
  69. gfx_frame: cint;
  70. state: cint;
  71. anim_frame: cint;
  72. end;
  73. PWoman = ^TWoman;
  74. const
  75. //---------------------------------------------------------------------
  76. // The state of the sprite (which way it is walking)
  77. //---------------------------------------------------------------------
  78. W_UP = 0;
  79. W_RIGHT = 1;
  80. W_DOWN = 2;
  81. W_LEFT = 3;
  82. //---------------------------------------------------------------------
  83. // Screen dimentions
  84. //---------------------------------------------------------------------
  85. SCREEN_TOP = 0;
  86. SCREEN_BOTTOM = 192;
  87. SCREEN_LEFT = 0;
  88. SCREEN_RIGHT = 256;
  89. //---------------------------------------------------------------------
  90. // Animating a man requires us to copy in a new frame of data each time
  91. //---------------------------------------------------------------------
  92. procedure animateMan(var sprite: TMan);
  93. var
  94. frame: cint;
  95. offset: pcuint8;
  96. begin
  97. frame := sprite.anim_frame + sprite.state * FRAMES_PER_ANIMATION;
  98. offset := sprite.frame_gfx + (frame * 32*32);
  99. dmaCopy(offset, sprite.sprite_gfx_mem, 32*32);
  100. end;
  101. //---------------------------------------------------------------------
  102. // Initializing a man requires little work, allocate room for one frame
  103. // and set the frame gfx pointer
  104. //---------------------------------------------------------------------
  105. procedure initMan(var sprite: TMan; gfx: pcuint8);
  106. begin
  107. sprite.sprite_gfx_mem := oamAllocateGfx(oamMain, SpriteSize_32x32, SpriteColorFormat_256Color);
  108. sprite.frame_gfx := gfx;
  109. end;
  110. //---------------------------------------------------------------------
  111. // Animating a woman only requires us to alter which sprite memory pointer
  112. // she is using
  113. //---------------------------------------------------------------------
  114. procedure animateWoman(var sprite: TWoman);
  115. begin
  116. sprite.gfx_frame := sprite.anim_frame + sprite.state * FRAMES_PER_ANIMATION;
  117. end;
  118. //---------------------------------------------------------------------
  119. // Initializing a woman requires us to load all of her graphics frames
  120. // into memory
  121. //---------------------------------------------------------------------
  122. procedure initWoman(var sprite: TWoman; gfx: pcuint8);
  123. var
  124. i: integer;
  125. begin
  126. for i := 0 to 11 do
  127. begin
  128. sprite.sprite_gfx_mem[i] := oamAllocateGfx(oamSub, SpriteSize_32x32, SpriteColorFormat_256Color);
  129. dmaCopy(gfx, sprite.sprite_gfx_mem[i], 1024);
  130. gfx := gfx + 32*32;
  131. end;
  132. end;
  133. var
  134. Man: TMan;
  135. Woman: TWoman;
  136. keys: cint;
  137. begin
  138. Man.x := 0;
  139. Man.y := 0;
  140. Man.state := 0;
  141. Man.anim_frame := 0;
  142. Woman.x := 0;
  143. Woman.y := 0;
  144. Woman.state := 0;
  145. Woman.anim_frame := 0;
  146. //-----------------------------------------------------------------
  147. // Initialize the graphics engines
  148. //-----------------------------------------------------------------
  149. videoSetMode(MODE_0_2D);
  150. videoSetModeSub(MODE_0_2D);
  151. vramSetBankA(VRAM_A_MAIN_SPRITE);
  152. vramSetBankD(VRAM_D_SUB_SPRITE);
  153. oamInit(oamMain, SpriteMapping_1D_128, false);
  154. oamInit(oamSub, SpriteMapping_1D_128, false);
  155. //-----------------------------------------------------------------
  156. // Initialize the two sprites
  157. //-----------------------------------------------------------------
  158. initMan(man, @manTiles);
  159. initWoMan(woman, @womanTiles);
  160. dmaCopy(@manPal, SPRITE_PALETTE, 512);
  161. dmaCopy(@womanPal, SPRITE_PALETTE_SUB, 512);
  162. //-----------------------------------------------------------------
  163. // main loop
  164. //-----------------------------------------------------------------
  165. while true do
  166. begin
  167. scanKeys();
  168. keys := keysHeld();
  169. if (keys and KEY_START) <> 0 then
  170. exit;
  171. if keys <> 0 then
  172. begin
  173. if (keys and KEY_UP) <> 0 then
  174. begin
  175. if man.y >= SCREEN_TOP then dec(man.y);
  176. if woman.y >= SCREEN_TOP then dec(woman.y);
  177. man.state := W_UP;
  178. woman.state := W_UP;
  179. end;
  180. if (keys and KEY_LEFT) <> 0 then
  181. begin
  182. if man.x >= SCREEN_LEFT then dec(man.x);
  183. if woman.x >= SCREEN_LEFT then dec(woman.x);
  184. man.state := W_LEFT;
  185. woman.state := W_LEFT;
  186. end;
  187. if (keys and KEY_RIGHT) <> 0 then
  188. begin
  189. if man.x <= SCREEN_RIGHT then inc(man.x);
  190. if woman.x <= SCREEN_RIGHT then inc(woman.x);
  191. man.state := W_RIGHT;
  192. woman.state := W_RIGHT;
  193. end;
  194. if (keys and KEY_DOWN) <> 0 then
  195. begin
  196. if man.y <= SCREEN_BOTTOM then inc(man.y);
  197. if woman.y <= SCREEN_BOTTOM then inc(woman.y);
  198. man.state := W_DOWN;
  199. woman.state := W_DOWN;
  200. end;
  201. inc(man.anim_frame);
  202. inc(woman.anim_frame);
  203. if man.anim_frame >= FRAMES_PER_ANIMATION then man.anim_frame := 0;
  204. if woman.anim_frame >= FRAMES_PER_ANIMATION then woman.anim_frame := 0;
  205. end;
  206. animateMan(man);
  207. animateWoman(woman);
  208. //-----------------------------------------------------------------
  209. // Set oam attributes, notice the only difference is in the sprite
  210. // graphics memory pointer argument. The man only has one pointer
  211. // while the women has an array of pointers
  212. //-----------------------------------------------------------------
  213. oamSet(oamMain, 0, man.x, man.y, 0, 0, SpriteSize_32x32, SpriteColorFormat_256Color,
  214. man.sprite_gfx_mem, -1, false, false, false, false, false);
  215. oamSet(oamSub, 0, woman.x, woman.y, 0, 0, SpriteSize_32x32, SpriteColorFormat_256Color,
  216. woman.sprite_gfx_mem[woman.gfx_frame], -1, false, false, false, false, false);
  217. swiWaitForVBlank();
  218. oamUpdate(oamMain);
  219. oamUpdate(oamSub);
  220. end;
  221. end.