- Introduction to Sprite Sheets
- Using Zwoptex
- The SpriteSheet Class
- PackedSpriteSheet Class
- Summary
- Exercise
PackedSpriteSheet Class
As mentioned earlier, the PackedSpriteSheet class is responsible for dealing with complex sprite sheets. These sprite sheets contain many variably sized images to which we want to get access. This often includes other sprite sheets. This class can be found in the same group within the CH06_SLQTSOR project, as before.
Initialization
This class uses the same caching technique as the SpriteSheet class. There is, however, only one initializer, which is shown in Listing 6.6.
Listing 6.6. PackedSpriteSheet initWithImageNamed:controlFile:filter Method
- (id
)initWithImageNamed:(NSString
*)aImageFileName controlFile:(NSString
*)aControlFile filter:(GLenum
)aFilter {if
(self
= [super
init
]) {NSString
*fileName = [[aImageFileNamelastPathComponent
]stringByDeletingPathExtension
];image
= [[[Image
alloc
]initWithImageNamed
:fileNamefilter
:aFilter]retain
];sprites
= [[NSMutableDictionary
alloc
]init
];controlFile
= [[NSDictionary
alloc
]initWithContentsOfFile
:[[NSBundle
mainBundle
]pathForResource
:aControlFileofType
:@"plist"
]]; [self
parseControlFile
:controlFile
]; [controlFile
release
]; }return self
; }
Once inside the initializer, we create a new Image instance from the details passed in and allocate an NSMutableDictionary instance called sprites that will hold the details of the sprites in our packed sprite sheet.
The last section of the initializer grabs the contents of the control file that were passed in and loads it into an NSDictionary called controlFile. It is always assumed that the type of file is a plist, so the file type is hard coded. After we have the controlFile dictionary populated, we then parse the information inside that dictionary using the private parseControlFile method shown in Listing 6.7.
Listing 6.7. PackedSpriteSheet parseControlFile: Method
- (void
)parseControlFile:(NSDictionary
*)aControlFile {NSDictionary
*framesDictionary = [controlFile
objectForKey
:@"frames"
];for
(NSString
*frameDictionaryKeyin
framesDictionary) {NSDictionary
*frameDictionary = [framesDictionaryobjectForKey
:frameDictionaryKey];float
x
= [[frameDictionaryobjectForKey
:@"x"
]floatValue
];float
y
= [[frameDictionaryobjectForKey
:@"y"
]floatValue
];float
w = [[frameDictionaryobjectForKey
:@"width"
]floatValue
];float
h = [[frameDictionaryobjectForKey
:@"height"
]floatValue
];Image
*subImage = [image
subImageInRect
:CGRectMake
(x
,y
, w, h)]; [sprites
setObject
:subImageforKey
:frameDictionaryKey]; } }
Parsing the Control File
The parseControlFile method creates a dictionary from all the frames objects within the dictionary we passed in. There are several objects inside the plist file, as follows:
- Texture, which holds the dimensions of the texture.
- Frames, which hold objects keyed on the image's filename for each image in the sprite sheet.
An example of the plist file inside the Plist Editor can be seen in Figure 6.8.
Figure 6.8 Sprite sheet plist control file.
The details we want for the sprites are therefore held in the frame's objects.
Now that we have a dictionary called frames, we loop through each of them, extracting the information we need. For each frame we find, we assign another NSDictionary that contains the objects for the key we are dealing with. Remember that the key is a string that contains the name of the original image file that was embedded into the larger sprite sheet. This makes it easy later on to reference the image we need.
Once we have the information for the frame, we then add a new object to our sprites dictionary. The key is the name of the image file we have just read from the control file, and the object is an Image instance.
Getting a sub-image from the full sprite sheet image creates the Image instance. Again, we are just making use of functionality we have already built.
This process is repeated for each image in the sprite sheet control file, and we end up with a dictionary that contains an image representing each image in our packed sprite sheet.
Retrieving a Sprite
Having all our sprites in a dictionary now makes retrieving a sprite from our PackedSpriteSheet very simple. This is done using the imageForKey method. Listing 6.8 shows this method.
Listing 6.8. PackedSpriteSheet imageForKey Method
- (Image
*)imageForKey:(NSString
*)aKey {Image
*spriteImage = [sprites
objectForKey
:aKey];if
(spriteImage) {return
[sprites
objectForKey
:aKey]; }NSLog
(@"ERROR - PackedSpriteSheet: Sprite could not be found for key
'%@'"
, aKey);return nil
; }
We pass an NSString into this method containing the key to the sprite's dictionary that we created earlier. If you remember, the key is the filename of the image that was placed inside the packed sprite sheet. If an image is found for the key supplied, a reference to this image is returned. Otherwise, an error is logged, so we know that the sprite we wanted could not be found.