[MUSIC] We looked at a lot of different SK actions. Ones that moved sprites, ones that made them fade in and fade out, SK actions that played sounds, SK actions that changed the physics body. There's one particular SK action that I think is worth calling out. I want to spend this lecture talking about it a little bit. And it's one that allows you to animate textures. So at a high-level, if you have worked with digital art or digital games, something like that, you realize that not all animations are rendered. Some of them are created frame by frame. And by that I mean, it's not always the case that you model something in 3D, and then apply forces to it and shine lights on it, and in that way get the effect that you're looking for. Sometimes you do something that's more like old animations where you draw, frame by frame, different steps in the movement of a character. Maybe turning or waving their arms, swinging or jumping. The kinds of things that are maybe best done through an artistic process rather a rendering or modeling process. And these are usually drawn frame by frame. If you have such an animation or you want to include such an animation you have to figure out a way to do it. Because the way that we've talked about so far in Sprite Kit for animated things is by talking about them in terms of movements and rotations and scalings. But not in terms of changing the actual image that we're working with. iOS has a efficient way of playing multi-frame animations, and that's what we're going to talk about in this lecture. And you can do it through the SKAction infrastructure. So the motivation is, for example, from a flip book. So here's an image from Wikipedia, from someone trying to make a flip book. Now what they've done in the upper left is they've taken a bunch of pictures of their cat walking around on the floor. They've printed them out, and they've cut them into equal size squares. They've layered them on top of each other and stapled them so that now, you can pick up the book, and you can flip through it. And each picture will give you a new step in the progression of the cat around the floor. And as you flip through them, it provides the appearance of motion the way a movie on film would give you the impression of motion. You can do this in a digital environment too where you have lots of still digital images that you rotate through quickly in order to give an appearance of motion. You might want to do this for kinds of effects that don't lend themselves well to rendering. So here's an example of one that I made, that I'm going to move into my example code here. And this isn't a super great example because it is sort of something that you could probably actually render, but instead I'm representing it as multiple different frames. And you can see that as it rotates, the shape rotates but the light on the top remains shining from the top. And again, you could probably do this in a rendering mode, but I chose instead, for the purposes of displaying it to you, to show it in terms of animation. So you can see that as that blob, let me play it again. Go back a slide, then go forward. As that blob plays, it gives the appearance of motion as it's rotating and pulsing in and out. So what I'm going to do is I'm going to put this into my code, playing each one of those frames in sequence and then looping through to give the impression of a rotating cloud. How do we do that? Well, we do that with the SKAction and particularly with the animateWithTextures initializer command that creates the SKAction that does the animation. So to do this efficiently, the way that is best known practice within iOS, is to put all of your individual frames into a folder that ends with .atlas. And then when you import those into iOS, the build process will create an efficient structure of sprites for you, so that they rendered very cleanly. Basically what happens is that all of the sprites get put into one large image and the hardware knows which area on that image to highlight at a given time. So it's like having a really big image with a really small window and it's faster to move that window around that really large image than it is to load in lots of little images. So that atlas becomes a tiled sprite. And that's going to leverage the graphics hardware efficiently to load the frame, so you're not doing a bunch of memory swaps if you don't need to. All right. You don't have to think about it very much. You can treat it like it's a bunch of single files that are being played, but under the covers, it's doing something much more efficient with that automatically. So the steps in creating this are, first to design your animation. What we're seeing more and more as we go through this course is that the design part of it. The decision about the user experience and how you're going to help the user accomplish the functionality that you're looking for or have the experience that you want is really a large part is a design problem. After you design what you want to flip through, then you need to save them as a sequence of files. If you store them in a folder that ends in .atlas, you can just drag and drop them into your project and iOS will know what to do with them. All right, so here is the code and the different steps to create this. The first thing is code that we've seen before. It just creates an array to store your frames. So in this case, we're creating an NSMutable array, with the name blobNames or a pointer too it with the name blobFrames, and we're initializing an NSMutable array just from just creating a blank one. And then what we're going to do is we're going to load in the textures from our array. And the way we're going to do that is we're going to first create an SKTextureAtlas, a pointer to one called blobAnimation, and we'll initialize that by looking for that folder within our project. When we have that, we're going to go through each one of the textures that have been described in that using a loop. And we will load them into an array, so we'll pull out pointers to each one of those textures within that atlas. We're doing that here with a formatted string so we're looking for a bunch of file names that look like blob00, blob01, blob02, etc. Each one of those is a texture name, and then we'll load up a blob animation with that name and assign it to a temporary variable, so that we can add that to out blob frame's array. So our blob frame's array, as we add these objects, are going to be a sequence of textures one after another. So that's loading them into an array and that array becomes the source of the different images that we're going to sequence through in our animation. The third thing that we're going to do is that we're going to create a sprite from a texture. So we're going to take that array of textures that we have and just get the first one and we'll create a new sprite with that texture as the basis for it. Once we've set up any other properties that we have for this sprite, for example physics bodies or anything else. Then we initiate an action using the SKAction framework and in this case what we're doing is we're doing a nested action. So in the innermost loop, we have an animate with textures action that we're creating. We're pointing that to our blobFrames array that has all the textures that has all the textures that we want shown. We're saying how fast should that be shown? In this case, one frame every four 100ths of a second. Within this code, you can specify whether you want iOS to resize the images within your textures to be the same size as your initial texture. Or whether you want to allow the sprite to grow or contract with the size of the images. Then, finally, after you've done playing through these textures, you want the final image of your sprite to be the first image that you started with or the last image that you started with. So, do you want to restore it to the first image? What we're going to do then is we're going to take that action and we're going to embed it within a repeat action and forever action. And so that is sort of a nested action that's going to continue to play this animation over and over and over again. Repeat action forever also has the ability to specify a key, so that key becomes the name that we can use to access the action if we ever want to stop if for some reason. And then when we execute that sprite run action that will just start animating. So let's go to our code and add those things to our previous example code and we will see what happens as a result. So this is not our breakaway code, this is the code with the man that was moving around. And we're keeping all that code the same, so we have the make body method here, makes the same man with the pinned limbs. Come down here, and we have add sprite, and adding the sprite is the same. We create a physics body, we add it to it, we add the appropriate parameters that we want. And down here, we did move to view, this is where we're adding our new code. So we start by setting up our state that won't be necessary for this example. We name our fence the fence, name the boundary around our scene the fence. We add that fence to our world, so that the boundaries of the screen are effective. We add a vortex to the middle to keep everything moving, so we can see the effects and now this is where we're going to add our texture. Now over here on the left you can see that I dropped in the blob atlas with a bunch of different images that represent each stage in my animation. There's 36 of them, representing a 10 degree rotation for the blob. If you click on it, you can see that it cycles through each of them. We go back to our game code. What we're going to do is we're going to create an array to hold our frames in. It'll be a mutable array so that we can add stuff to it. And then we're going to look up the texture atlas that we dropped into our resources. And the way we'll do that is we will just ask for the atlas named blob.atlas. And so that's gotta be in your project if you want to be able to find it. So that becomes a reference to all of the textures that are in your atlas. Well now what we want to do is we want to go through and we want to find each of them and we want to load them into a texture data, into our frames array. So for each one of those items that is in our texture we're going to make a loop. And we're going to look for them and first thing we going to do is we going to try and find the name of it by looking. We know what the name is in advance because we specified, we named these files on our own blob00 and 01. And because we know what the structure of these names are we can produce a string that has the same structure. And then we can look into our blob animation texture atlas, for the texture with that name. We named it, we're looking for the names. And then for each one of those textures we find, we add it to our array. This array becomes the source of all our textures that we then are going to use to cycle through our animation. So that's just setting us up, that's the texture. Now each time we make one of these sprites we're going to come down here and we're going to say okay, well before we were making a sprite based on this image. So we're going to comment that out so instead of making it based on the image, instead what we're going to do is, we'll move this down here. We'll pull out the first texture from the collection of textures that we pulled out of our atlas. And we will make an initial sprite based on that texture that we have in that first one. Rather than calling it ball_blue, let's call it blue cloud, cloud_blue. And then we're going to call the same code that we had before to add that sprite to our scene. That's going to remain the same, the properties are going to remain the same. But when we get back from adding all the properties to our scene, we are going to run the action, which causes them to cycle through all the different frames at one time. So, we're going to create an SKAction animateWithTextures. We're going to pass it the frames that we collected up here, up above. We're going to say we want them to last four one hundredths of a second each time. See if we can clean this up. We will not resize them and so you'll see them pulsate as the sizes of each of my images are slightly different. We will not restore it because we're going to be repeating this action forever, that's nested within our action. So we have an action that's being repeated over and over again, and that action is repeat animate textures. Then lastly we have this four key parameter that matches our repeat action forever. I'm sorry, that matches our, did it right, matches our run action command. That's all we're going to change, and so now let's see if I can get the iPad that's attached here. To render so you can see what we're looking at. Here we go. Shrink it down just a little bit. All right, and we're going to run our code on the iPad. Everything built well. Starting our game. And now you can see that each one of those blue dots has been replaced by a little blue cloud that's being animated on a frame by frame basis, using a texture atlas. So when might you use this? Well, if you didn't want little flashing blue clouds to be around, you could use this to do a transition animation as maybe a character moves from going left to going right. You might play through an animation one time. You might use it to sort of have an idle stage for a character that's just sort of like holding their chin or sort of shuffling on their feet, something like that. A lot of different places where you might use it. Just to show you one of the effects, you can see how those are pulsating because the sizes of the frames are changing. If I stop that, I come down here and I ask iOS to resize each one of those images so that they're the same size as that initial texture that I loaded. This time they won't pulsate because they're being resized. So depending on what you want, you could have different effects. And it's important to realize that what's happening here is that those sprites aren't actually rotating. It's images that are being changed as a result. So maybe because of that, this isn't the best example I could have used in the world because you could rotate it manually. But if you did rotate it manually, the shiny light wouldn't continue to come from the top. Because the shiny light spot would rotate as well, unless you rendered the light as well, but that would take more work. In summary, sometimes you need frame by frame animations. You might need them continuously like with these rotating blue clouds. Or you might need them just for a transition, when a character jumps or turns or does some action, when you want to respond to some event and have sort of a transformation happen. And SKAction supports this with an animateWithTextures style of implementation. Using an atlas which is a very effective way of utilizing your graphics hardware to minimize memory transfers of the textures themselves. All right, thank you for your attention. [MUSIC]