home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 1999 Spring / macformat-077.iso / Shareware Plus / Development / SpriteWorld 2.2 / Documentation / Add-On Docs / Multi-Screen Scrolling < prev    next >
Encoding:
Text File  |  1998-08-05  |  15.2 KB  |  173 lines  |  [TEXT/ttxt]

  1. Since releasing SpriteWorld 2.0, several people have expressed interest in making scrolling games that have more than one window, each window showing a different area of the same scrolling SpriteWorld. I hadn't even considered this when I made the scrolling routines, so there was no easy way to do this. I have now added a new file to SpriteWorld called  "Multi-Screen Scrolling.c", which has several routines that will enable you to write a scrolling game that has more than one view of the same world.
  2.  
  3. These routines are designed to run as quickly as possible. In order to accomplish that goal, each separate view gets its own offscreen areas. If all the views shared the same offscreen areas, the entire background would have to be redrawn each time one of the views were animated, which would slow things down considerably. Of course, giving each view its own offscreen areas takes up more memory, but since multi-screen scrolling games generally have smaller views than a normal scrolling game, this shouldn't be a problem.
  4.  
  5. These routines were designed for tiling games only. They weren't designed for games where the offscreen areas are as large as the "virtual world", since it would be impractical to create new offscreen areas for each view if this method were used. It probably wouldn't be too hard to make new routines for these types of games, but for right now I don't see that there is a need for it, since generally people will want to use tiling.
  6.  
  7.  
  8. Setting Up
  9.  
  10. First of all you need to add the file "Multi-Screen Scrolling.c" to your project, which is in the Utils folder of the SpriteWorld Files folder. You must still include Tiling.c and Scrolling.c in your project as well. Also #include the header file, "Multi-Screen Scrolling.h", in your source code.
  11.  
  12. In order to make a scrolling game with more than one view of the same world, you should create a separate SpriteWorld for each view, and then "share" certain information between each SpriteWorld. To do this, you should first set up your "master" SpriteWorld by adding to it all the layers that you are going to use, setting the drawProcs, initializing the tiling, etc. You then create the other SpriteWorld(s) just as you would normally, and then copy the information that must be shared to each of the other SpriteWorlds by calling SWSetUpDuplicateSpriteWorld. This will copy certain information from the master SpriteWorld into the other SpriteWorld, such as the spriteLayerPtrs, tileLayerArray, and tileFrameArray. Then the second SpriteWorld will have access to the same TileMaps, tile images, and sprites as the first SpriteWorld. In other words, once you install a TileMap, add a Sprites, or add a new tile image to the master SpriteWorld, that same TileMap, Sprite, or Tile will automatically be available to all duplicate SpriteWorlds as well.
  13.  
  14.  
  15. Setting Up Tiling
  16.  
  17. Call SWInitTiling for the master SpriteWorld before calling SWSetUpDuplicateSpiteWorld, since SWSetUpDuplicateSpiteWorld copies certain tiling variables from the master SpriteWorld that must have already been initialized by SWInitTiling. Do not call SWInitTiling for any of the other SpriteWorlds, but instead use SWInitTilingForDuplicateSpriteWorld. Also make sure not to make any Tiling calls for any clone SpriteWorld (such as SWDrawTile) until after calling SWSetUpDuplicateSpriteWorld for that clone SpriteWorld.
  18.  
  19.  
  20. Performing the Animation
  21.  
  22. To perform the animation, first call SWProcessSpriteWorld (not SWProcessScrollingSpriteWorld) once to process all of the sprites, passing it the masterSpriteWorldP. Then call SWProcessMultiScreenSpriteWorld for each SpriteWorld, including the master SpriteWorld. This will not process the sprites, but will simply call the scrollingWorldMoveProc and move the visScrollRect for each SpriteWorld. Then call SWAnimateMultiScreenSpriteWorld for each SpriteWorld (including the master). Finally, call SWFinishMultiScreenAnimation once. This will reset certain variables in each sprite, such as the needsToBeDrawn and needsToBeErased flags.
  23.  
  24. The reason SWProcessSpriteWorld is called only once and then SWProcessMultiScreenSpriteWorld is called for each SpriteWorld after the first is because the sprites, which are shared by all the SpriteWorlds, should be processed only once. SWProcessMultiScreenSpriteWorld does not process the sprites, but only calls the SpriteWorld's scrollingWorldMoveProc, and moves the visScrollRect.
  25.  
  26. Here's an example of the main loop of an animation that has three views of the same world:
  27.  
  28. while (!done)
  29. {
  30.         // Process the sprites
  31.     SWProcessSpriteWorld(gMasterSpriteWorldP);
  32.  
  33.     if (gMasterSpriteWorldP->frameHasOccurred)
  34.     {
  35.             // Call the worldMoveProcs
  36.         SWProcessMultiScreenSpriteWorld(gMasterSpriteWorldP);
  37.         SWProcessMultiScreenSpriteWorld(gClone1SpriteWorldP);
  38.         SWProcessMultiScreenSpriteWorld(gClone2SpriteWorldP);
  39.   
  40.             // Animate it
  41.         SWAnimateMultiScreenSpriteWorld(gMasterSpriteWorldP);
  42.         SWAnimateMultiScreenSpriteWorld(gClone1SpriteWorldP);
  43.         SWAnimateMultiScreenSpriteWorld(gClone2SpriteWorldP);
  44.         SWFinishMultiScreenAnimation(gMasterSpriteWorldP);
  45.     }
  46. }
  47.  
  48.  
  49. Controlling the Animation Rate
  50.  
  51. The animation speed is controlled by the masterSpriteWorldP. When setting a MaxFPS value (if you decide to use one), call SWSetSpriteWorldMaxFPS for the masterSpriteWorld only. Then check the masterSpriteWorldP->frameHasOccurred variable before making all the other Process/Animate calls. See the code above for an example. This will ensure that all the SpriteWorlds run the same speed. Also, if you want to sync to the VBL, it is advised that you only call SWSyncSpriteWorldToVBL only for the master SpriteWorld. You could call it for each SpriteWorld if you want, but that could make it really slow, since each SpriteWorld would have to wait for the VBL before they could update the screen.
  52.  
  53.  
  54. Using SWChangeTileImage
  55.  
  56. Any time that you use SWChangeTileImage, you must call it once for each SpriteWorld. Below is an example of a TileChangeProc that does this:
  57.  
  58. SW_FUNC void TileChangeProc(
  59.     SpriteWorldPtr spriteWorldP)
  60. {
  61.     short            curImage;
  62.     
  63.         // Animate kWallTile
  64.     curImage = spriteWorldP->curTileImage[kWallTile];
  65.     if (curImage < kLastWallTile)
  66.         curImage++;
  67.     else
  68.         curImage = kWallTile;
  69.     
  70.     SWChangeTileImage(gMasterSpriteWorldP, kWallTile, curImage);
  71.     SWChangeTileImage(gClone1SpriteWorldP, kWallTile, curImage);
  72.     SWChangeTileImage(gClone2SpriteWorldP, kWallTile, curImage);
  73. }
  74.  
  75. The TileChangeProc will only be called once, when the master SpriteWorld is processed (when you call SWProcessSpriteWorld). Any TileChangeProcs that are installed in any of the other SpriteWorlds will be ignored.
  76.  
  77.  
  78. Installing TileMaps
  79.  
  80. While installing a TileMap in one SpriteWorld will affect all of the other SpriteWorlds that share data with that SpriteWorld, it won't update the lastActiveTileLayer variable stored in each SpriteWorld. This variable keeps track of the number of tile layers in use. So if you have 3 tile layers in use in each SpriteWorld, then install a TileMap in a fourth layer in one of the SpriteWorlds, that TileMap will be installed in the other SpriteWorlds as well, but they won't know that more than 3 tile layers are in use.
  81.  
  82. To rememdy this, whenever you call SWInstallTileMap to install or remove a TileMap from a tile layer, you should:
  83.  
  84. A) Call SWInstallTileMap for every SpriteWorld you have (the master and all of its duplicates), or
  85.  
  86. B) Install the TileMap in your master SpriteWorld, and then call SWSetUpDuplicateSpriteWorld for each clone SpriteWorld, just as you would have to before starting the animation.
  87.  
  88.  
  89. Shared Information
  90.  
  91. When working with multiple SpriteWorlds that share information, it is important to realize that some actions will affect all of the SpriteWorlds, while some actions only affect the SpriteWorld you are performing them on. Actions that affect all of the SpriteWorlds are those actions that act on any of the information that is "shared"  between the SpriteWorlds. There are four things that are "shared" between SpriteWorlds when you call SWSetUpDuplicateSpriteWorld; they are the sprite layers, the tileLayerArray (which stores the tileMaps in each tile layer), the tileFrameArray (containing the tile images), and the curTileImage array. This means that if you add a sprite to a layer in one SpriteWorld, it will appear in each SpriteWorld, since that layer is shared by all the SpriteWorlds. Likewise, if you change a value in the TileMap of one SpriteWorld, it will affect all the other SpriteWorlds that use that TileMap. And if you add a TileMap to one SpriteWorld, it will appear in the others as well. The curTileImage array is also shared, although you still must call SWChangeTileImage for each SpriteWorld in your tileChangeProc, since that function not only changes the value in the curTileImage array, but must also redraw those tiles that have been changed in the offscreen area of each SpriteWorld. And since the tileFrameArray is shared, loading tiles into one SpriteWorld will make them available to the others as well.
  92.  
  93. However, whenever you make any changes to a part of a SpriteWorld that is not shared, you must make the same changes to each of the other SpriteWorlds. So if, for instance, you change the screenDrawProc of one of the SpriteWorlds, you must change if for each of the other SpriteWorlds as well, if you want them all to use the same screenDrawProc. Or if you install a new TileMap in a SpriteWorld, you must call SWDrawTilesInBackground and SWUpdateSpriteWorld for each SpriteWorld. Another example is that if you add or remove a Sprite Layer from a SpriteWorld, your changes will not affect the other SpriteWorlds. To remedy this, simply call SWSetUpDuplicateSpriteWorld again, to update the other SpriteWorlds in regard to the change you just made in the one SpriteWorld. Here's an example:
  94.  
  95. SWAddSpriteLayer(gMasterSpriteWorldP, newSpriteLayerP);
  96. SWSetUpDuplicateSpriteWorld(gMasterSpriteWorldP, gClone1SpriteWorldP);
  97. SWSetUpDuplicateSpriteWorld(gMasterSpriteWorldP, gClone2SpriteWorldP);
  98.  
  99. This process can be used whenever you make changes to one of the SpriteWorlds that does not automatically affect the other SpriteWorlds, but should. This can be done because SWSetUpDuplicateSpriteWorld simply copies certain variables from the one SpriteWorld to the other.
  100.  
  101. Other SpriteWorld Functions
  102.  
  103. You may wonder which SpriteWorldPtr should be passed to certain SpriteWorld functions that require a SpriteWorldPtr, such as SWMarkSpriteForRemoval. The answer is that although sometimes any SpriteWorld will work, you should use the masterSpriteWorldP, not only to be consistent, but because some functions won't work unless the masterSpriteWorldP is used, such as SWMarkSpriteForRemoval. Of course, this only applies to functions that affect "shared" data, such as Sprites. When calling functions that only affect the specified SpriteWorld (such as SWChangeTileImage), you should call the function several times, passing each SpriteWorldPtr to the function.
  104.  
  105.  
  106. Function Reference
  107.  
  108. SWSetUpDuplicateSpriteWorld
  109.  
  110. SW_FUNC OSErr SWSetUpDuplicateSpriteWorld(
  111.     SpriteWorldPtr masterSpriteWorldP,
  112.     SpriteWorldPtr duplicateSpriteWorldP)
  113.  
  114. Call this function after completely setting up the masterSpriteWorldP by adding the sprite layers, calling SWInitTiling, and setting the various drawProcs and scrollingWorldMoveProc. This will then copy the information that must be "shared" from the masterSpriteWorldP to the duplicateSpriteWorldP, such as the head and tail spriteLayerPtrs. Since the layer pointers themselves, and not the sprites, are copied, it doesn't matter whether you have added any sprites to the master SpriteWorld or not before this function is called. Since the layers themselves are shared, any sprites you add or remove from those layers (even after calling SWSetUpDuplicateSpriteWorld) will affect all the SpriteWorlds.
  115.  
  116. This function copies the following vairables from one SpriteWorld to the other:
  117. headSpriteLayerP, tailSpriteLayerP, offscreenDrawProc, screenDrawProc, scrollRectMoveBounds, tileLayerArray, tileFrameArray, curTileImage, maxNumTiles, tileWidth, tileHeight, and tileMaskDrawProc.
  118.  
  119. Some of the variables, such as the drawProcs, are copied for your convenience only, even though these variables are not "shared" between the SpriteWorlds, meaning that if you later change the drawProc for one of the SpriteWorlds, it will not automatically be changed for all of the other SpriteWorlds as well.
  120.  
  121. Since the release of SpriteWorld 2.2, installing a TileMap in a tile layer in one SpriteWorld will affect all of the other SpriteWorlds as well. This is because just one tileLayerArray is shared between the master SpriteWorld and all of its clones.
  122.  
  123.  
  124. SWDisposeDuplicateSpriteWorld
  125.  
  126. SW_FUNC void SWDisposeDuplicateSpriteWorld(
  127.     SpriteWorldPtr    spriteWorldP)
  128.  
  129. You should call this function instead of SWDisposeSpriteWorld when disposing a "duplicate" SpriteWorld, or one that "shares" some of the variables that the master SpriteWorld uses. This is necessary since, if you used SWDisposeSpriteWorld to dispose a duplicate SpriteWorld, it would dispose some of the "shared" variables that the master SpriteWorld uses, which would cause problems if you tried to continue running the animation for the master SpriteWorld.
  130.  
  131. When you only have one SpriteWorld left, you should call SWDisposeSpriteWorld to dispose it.
  132.  
  133.  
  134. SWInitTilingForDuplicateSpriteWorld
  135.  
  136. SW_FUNC void SWInitTilingForDuplicateSpriteWorld(
  137.     SpriteWorldPtr    spriteWorldP
  138.     short  tileHeight,
  139.     short  tileWidth)
  140.  
  141. Call this function to prepare a duplicate SpriteWorld (not the master) for an animation that uses tiling. This function does not have the maxNumTiles parameter that the normal SWInitTiling does, since that variable is automatically copied from the master SpriteWorld when you call SWSetUpDuplicateSpriteWorld. While it currently doesn't matter whether you call this function before or after SWSetUpDuplicateSpriteWorld, it is recommended that you call it beforehand, since this flexibility may change in a future version.
  142.  
  143.  
  144. SWExitTilingForDuplicateSpriteWorld
  145.  
  146. SW_FUNC void SWExitTilingForDuplicateSpriteWorld(
  147.     SpriteWorldPtr    spriteWorldP)
  148.  
  149. Call this function instead of SWExitTiling when acting on a duplicate SpriteWorld. Normally you won't need to call this function, since SWDisposeDuplicateSpriteWorld automatically calls it for you.
  150.  
  151.  
  152. SWProcessMultiScreenSpriteWorld
  153.  
  154. SW_FUNC void SWProcessMultiScreenSpriteWorld(
  155.     SpriteWorldPtr spriteWorldP)
  156.  
  157. Call this function for each of your SpriteWorlds, including the master, in order to call that SpriteWorld's worldMoveProc and move its visScrollRect. You must do this in addition to calling SWProcessSpriteWorld for the master SpriteWorld, which does the processing of the sprites and calls the tileChangeProc.
  158.  
  159.  
  160. SWAnimateMultiScreenSpriteWorld
  161.  
  162. SW_FUNC void SWAnimateMultiScreenSpriteWorld(
  163.     SpriteWorldPtr spriteWorldP)
  164.  
  165. Call this for each of your SpriteWorlds, including the master, to render the animation for that SpriteWorld.
  166.  
  167.  
  168. SWFinishMultiScreenAnimation
  169.  
  170. SW_FUNC void SWFinishMultiScreenAnimation(
  171.     SpriteWorldPtr spriteWorldP);
  172.  
  173. Call this once in your main animation loop after making the calls to SWAnimateMultiScreenSpriteWorld. This function simply resets a few of the variables in each sprite in the SpriteWorld, such as the needsToBeDrawn flag, the needsToBeErased flag, and the oldFrameRect. Normally these would be done at the end of SWAnimateScrollingSpriteWorld, but when the same sprites are used in multiple SpriteWorlds, it is important not to change these variables until the last SpriteWorld using them has been rendered.