3.6 Programmatically Adding Blocks
This lesson will focus on a better way to add the blocks to the scene: math. This method is much more flexible and will allow you to extend this game to contain more and more levels as you go.
1.Introduction3 lessons, 07:37
2.Introducing SpriteKit7 lessons, 54:48
3.Building a Game11 lessons, 1:30:25
4.Conclusion1 lesson, 01:49
3.6 Programmatically Adding Blocks
In this lesson we are going to try to be a little bit smarter in how we place the blocks in our level on how we actually want to lay them out and have them bounce around. So I've kind of rewound here a little bit. I got rid of the reference to grabbing the block programmatically, the way we were doing it before. And I also removed the block that I manually placed out on to the visual designer so that we could start to add these things in via code, so you can see what that looks like. Now you can do this with SK sprite nodes or SK label nodes or whatever, you don't have to use this designer so don't feel like you have to do it. You can absolutely do all of this in code, but I kind of wanted to see you a nice little split, both ways, so you can kind of determine what works best and what's more comfortable for you. So let's come back into our GameScene.swift file, and what we wanna do is introduce a method of being able to add in some nodes programmatically, and actually get them to show up on the screen. Well, it's actually quite simple, and you're gonna do almost the exact same thing that we did up here for this ball, except for the fact that there's no ball out there already with this child name of whatever you want it to be. So I'm gonna create a block. So we're gonna say, let block equal to SKSpriteNode, and we're gonna look at some of the overloads here. And we have one that has a color and a size, so that seems like a good place to start. So we're gonna set this to have a UIColor of, we're gonna get that ugly green color back, and then we wanna give it a size. So we'll use CGSizeMake and I believe when we were doing it visually we said that it was 150 wide and 40 tall. So now we have this block and let's just see what it would take to actually get it on the screen. So we're going to say that block.position is going to be equal to CGPointMake, and then we can just kind of give this arbitrary values. I mean, you can really get into some interesting math, and if you look around on different sites and things like that you're gonna find very interesting ways to calculate how to put these based on screen sizes. But just to kind of give you a, a starting point, what you can do is base some of these things off these screen dimensions, and that's always a, a nice little trick to be able to do. So what you can do is you can call a method called CGRectGetHeight or GetWidth. So I can say CGRectGetWidth and I can pass into it the rectangle of what it is I'm trying to get the width of, and I'm simply gonna pass into it the frame that's coming from my current SKScene here in my GameScene. So that's going to give me the width of my current frame. And then we'll divide that by 2, cuz that's gonna give us kind of a center, a center point, and then we want to maybe subtract from that the block.size, say, .width divided by 3, or some sort of strange characteristic on how to actually calculate that. And then we'll do something similar here. CGRectGetHeight for the y value of where we're gonna stick this. And let's just say that we're going to continue to use the frame as a point of reference and we're going to multiply that by, so we want it to be about three quarters of the way up the screen, so we're gonna say times .075. So we'll go ahead and save that, and then finally, we're just gonna call a helper method here called AddChild, which is, belongs to our SKScene, and we wanna pass into it, block. Now we'll go ahead and save that, and we'll run our application, and this should start up, and we should see a green block. And we do, and then we can then move around and see what we can do with that block, and eventually once our ball goes ahead and hits that, and actually what you're gonna see here is that it's not going to is it's actually going to travel right through it, and that is simply because we haven't set those physics properties on this block. So let's go ahead and do that now. We could start by saying that our block has a physicsBody equal to an SKPhysicsBody, and we're gonna use the rectangleOfSize overload, so we're gonna say of our block.frame.size, and that's going to give it that physics, that rectangular body like we did within our designer, and then we can start doing all the normal things that we've done up here before. So we can start by saying blaock.physicsBody.allowsRotation is equal to false and we'll kind of do something similar where we grab this here copy. You'll want to start to go through some of these again where friction is gonna be equal to zero. And our restitution is gonna be equal to 1 and our damping values, our damping values are gonna be equal to 0. And of course we also can't forget that we're also gonna have to set the fact that we don't want this to be dynamic. Once again this is going to be a static objects, we want to set that equal to false. So we can go ahead and save that. And then obviously after we do this, we wanna be able to set up its bit mask again like we did before, so we're just gonna say that its categoryBitMask is equal to our BlockCategory. And just so it doesn't take quite so long to hit it, I'm going to maybe cheat a little bit and change this calculation to go in the other direction, so we'll save that. And if we were to run our application again, if we've done everything right, what we should see is that once the, the ball actually hits the block we should see the same the characteristics that we saw before. We should see it disappear like that, and our score has increased to 100. So now we're really starting to get down the path of where we're trying to get to. Now that's very nice, but how do you do that for multiple blocks? Well let's say I wanna add, let's say I wanna create a level where I had say maybe say four blocks all lined up together with no padding, no spacing in between them, and they were just out there. So you had a total of having the option of scoring 400 points, maybe? But then ultimately that was gonna be the end of the level. So how would we do something like that? Well, it's quite simple. We would just take this block of code that we've just written, this guy right here, and we would wrap it in a loop. So we're going to create a, a for loop here, and we're gonna say for i in, and we're gonna say within the range of 0 to, we'll say 3, that's going to be inclusive. Then what we wanna do is we want to run all this code here four times and put place or position these blocks accordingly, and then add them to the scene. So now, obviously if we were to run this block of code, we're just gonna get things blo, stock, stacked up on each other. And we're not going to be able to see it, there's going to be four blocks but it's gonna look like one, so in order to modify that or make it look at least somewhat interesting we're gonna have to take into consideration this i or some sort of outside variable to space things out a little bit. So, we're gonna start by creating a little bit of an offset off the left-hand side, so we'll say maybe 250 and then we'll add to that and we'll say we're going to take the CGFloat value of that i and we want to multiply it by the block.size.width value and we're going to add to that say 20. Something along those lines. So now what we should get from this is a layout of these blocks at least a little different than we have. So let's go ahead and run this and see what we get. So there we go, we get four blocks laid out there, but what you're gonna notice is now we can, we can hit two of them at a time, we can hum up and hit them from the top, and see now we've actually finished hitting all four of those. Our score has incremented, and we haven't had to touch anything on the design, or at least from the block perspective we've been able to add, very quickly and programmatically, four blocks to the screen and still maintain the same characteristics of how it works. Now that's a very nice feature. Now, you could go out and continue to create these kind of crazy mathematical equations to figure out where to lay things out based on how many blocks and the size and the width and all that kind of stuff. And that's fine. You can definitely do that. Or there's nothing that says you can't create some sort of properties or configurations or settings files somewhere that's going to say for level one, lay them out in these different configurations at these points and these block sizes and paddle sizes and ball sizes and all those sorts of things. So you definitely have some very interesting ways of calculating these things and placing and, and setting up these levels for your users. But as you can see it's quite simple to implement and get things out of the screen working just as you would wish. Now, the next problem that we're gonna tackle is, it's very nice to be able to knock those things out, but how do you know when the game is over? And what we haven't talked about yet, like the ball just hit on the bottom, how do you know when the game ends and you lose? So we now we have to take into consideration those two scenarios, when do you win? When do you lose and how do we handle that scenario? And that's exactly what we're gonna start talking about in the next lesson.