< Return to Video

The Unity Tutorial For Complete Beginners

  • 0:00 - 0:06
    Hi, my name is Mark. For years I've wanted to 
    make my very own video games, using software
  • 0:06 - 0:13
    like Unity. Unity is the powerful game engine 
    behind titles like Cuphead, Neon White, Tunic,
  • 0:13 - 0:19
    Outer Wilds, Hearthstone, Firewatch, 
    and even the Pokemon Diamond remake.
  • 0:19 - 0:26
    But I've always found that lengthy, multi-part, 
    meandering tutorials just send me to sleep. I
  • 0:26 - 0:31
    can't learn by watching someone else - I have to 
    get hands-on and figure things out for myself.
  • 0:31 - 0:38
    And so last year I developed a solution that 
    actually works. It's a three-step technique
  • 0:38 - 0:45
    where you: one just learn the absolute basics of 
    Unity. Then, two, cement those lessons with simple
  • 0:45 - 0:51
    exercises. And then, three, figure out the rest as 
    you go along. And it totally worked! In the space
  • 0:51 - 0:57
    of about a year, I went from ripping off iPhone 
    games to working on my very own puzzle platformer
  • 0:57 - 1:03
    about magnets. And I released an interactive 
    video essay that's had over 100,000 plays.
  • 1:03 - 1:09
    But wait, I hear you say! How do you do 
    step one? How do you learn the basics,
  • 1:09 - 1:12
    when the software is so complicated to figure out?
  • 1:12 - 1:15
    Well for me it was about writing down 
    a list of things I would need to know,
  • 1:15 - 1:20
    regardless of what game I was going to make. 
    Things like how to make a character appear and
  • 1:20 - 1:24
    move them around the screen. How to make 
    stuff spawn in and then delete it again
  • 1:24 - 1:29
    later. How to have collisions and game 
    over and animations and sound effects.
  • 1:29 - 1:34
    Then I learned all that by hunting through 
    lengthy tutorials, reading the Unity docs,
  • 1:34 - 1:37
    Googling esoteric words, and doing a lot of trial
  • 1:37 - 1:42
    and error. And so the whole point of 
    this video is to save you that hassle.
  • 1:42 - 1:46
    This video is the tutorial I wish 
    I had when I was learning Unity.
  • 1:46 - 1:52
    So in the next 40 minutes we're going to use the 
    engine to make Flappy Bird. Not because we want
  • 1:52 - 1:57
    to make Flappy Bird, but because in order to 
    remake this addictive iPhone game, we'll need
  • 1:57 - 2:02
    to learn basically everything I just listed, 
    from spawning objects to getting game overs.
  • 2:02 - 2:08
    This tutorial will cover every step of the way 
    from downloading Unity, to understanding the UI,
  • 2:08 - 2:14
    to writing your very first line of programming 
    code, to building a game that you can share with
  • 2:14 - 2:19
    your friends. And then, when the tutorial is over, 
    I'll share some concrete next steps that you can
  • 2:19 - 2:26
    take in order to continue learning the rest by 
    yourself. Sound good? Then let's get started.
  • 2:27 - 2:34
    Okay, let's start by getting Unity from the 
    website. Download and install the Unity Hub.
  • 2:35 - 2:40
    And then you'll need to make a free account 
    to actually use it. Once that's done,
  • 2:40 - 2:46
    you'll be asked to install the Unity Editor 
    - I'm using version 2021.3 for this tutorial,
  • 2:46 - 2:49
    if you're watching a million years 
    in the future and wondering why
  • 2:49 - 2:52
    things are different. Let's pretend 
    I have fast internet - Neeooowwwwmm.
  • 2:52 - 3:00
    We're not quite done yet. Under installs, hit the 
    cog icon on the Unity Editor and pick modules.
  • 3:00 - 3:05
    You'll see that Microsoft Visual Studio has 
    been ticked - this is the software we'll use
  • 3:05 - 3:11
    to write programming code. So hit continue. 
    And install Visual Studio. On this screen,
  • 3:11 - 3:15
    scroll down and tick game development 
    with Unity, and untick Unity Hub,
  • 3:15 - 3:20
    because we already have it. Neeooowwwwmm. 
    We don't need to make an account to use Visual Studio,
  • 3:20 - 3:24
    so skip that. And don't bother loading 
    it, we'll open it later.
  • 3:24 - 3:31
    Okay, that's all done now. So in Unity Hub, pick 
    new project. Choose all templates. And use 2D,
  • 3:31 - 3:36
    Core. This is an empty project, with a 
    few configurations to make it suitable
  • 3:36 - 3:41
    for 2D games. Give your project a name, 
    hit create, and let's get game makin'.
  • 3:43 - 3:49
    In step one, we're going to become familiar 
    with the default Unity user interface. And
  • 3:49 - 3:52
    as we explore the different panels, 
    we'll make the bird appear on screen.
  • 3:52 - 3:59
    Right. So this is the default screen layout 
    for Unity, and it's split into four panels.
  • 4:00 - 4:05
    First of all, down here, is the Project panel. 
    This will contain everything that is in our game
  • 4:05 - 4:13
    - like sprites, sound effects, scripts, tiles, 
    fonts, and so on. Some of this stuff will be made
  • 4:13 - 4:18
    in Unity as we go along. But we can also just drag 
    and drop files from elsewhere on our computer.
  • 4:18 - 4:23
    Like, I've made some sprites for the bird 
    and the pipe in Photoshop and I'm going to
  • 4:23 - 4:28
    import them into my project like so. I'd 
    recommend you make your own - that's always more
  • 4:28 - 4:32
    fun - but if you have zero artistic ability 
    then check the description for these assets.
  • 4:32 - 4:39
    The next panel is the hierarchy. This contains all 
    of the stuff that's in the current scene - which,
  • 4:39 - 4:43
    in most games, will be a level. We're 
    going to start by making the bird,
  • 4:43 - 4:50
    so right click and choose Create Empty. This 
    has made an empty GameObject... so what's that?
  • 4:50 - 4:57
    Well, a GameObject is essentially an invisible 
    container. It has a position in space, a rotation,
  • 4:57 - 5:03
    and a scale. Then, you can fill that container 
    with components - to add extra features. For
  • 5:03 - 5:08
    example, if we add a Sprite Renderer component, 
    we can slap the bird image onto the GameObject.
  • 5:08 - 5:13
    Absolutely everything in our level will be 
    a GameObject with components - the bird,
  • 5:13 - 5:16
    the pipes, even the user interface and the camera.
  • 5:16 - 5:23
    All of this magic happens in the third panel, the 
    Inspector - which is for messing with GameObjects.
  • 5:23 - 5:28
    So, once we've selected our new, empty GameObject 
    we can put a name in the top field - let's call it
  • 5:28 - 5:35
    Bird. And we can see and change the GameObject's 
    position, rotation, and scale, under Transform.
  • 5:35 - 5:42
    We can now press Add Component, pick Rendering, 
    and pick Sprite Renderer. To make this work,
  • 5:42 - 5:46
    we need to fill in the sprite field - 
    so just drag the bird image from the
  • 5:46 - 5:50
    project panel into the field 
    and viola, we have graphics!
  • 5:50 - 5:53
    That will, of course, show up 
    in the fourth and final panel,
  • 5:53 - 5:57
    the scene view. Here we can see 
    what's in our current scene, and,
  • 5:57 - 6:02
    if you want, you can use these tools to 
    move stuff around, scale it, and so on.
  • 6:02 - 6:07
    This section has an extra tab for game view, 
    which shows us what the game will look like from
  • 6:07 - 6:13
    the main camera when it's running. Also, from this 
    dropdown, we can set a resolution or aspect ratio
  • 6:13 - 6:19
    to get a better idea of what it will look like 
    when played - so I'm going to choose 1920 by 1080.
  • 6:19 - 6:24
    Oof, the bird takes up way too much space. 
    We could scale it down, but let's actually
  • 6:24 - 6:30
    just zoom out the camera. Like I said before, the 
    camera itself is a GameObject in the hierarchy.
  • 6:30 - 6:36
    And it has a camera component with stats we can 
    mess with. By changing the size, we can zoom out.
  • 6:36 - 6:39
    I'm also going to change the 
    background colour. Lovely.
  • 6:39 - 6:44
    We can now press the play button up 
    here to start... the world's most
  • 6:44 - 6:48
    boring game. Okay, let's make it a bit more exciting.
  • 6:49 - 6:55
    A quick recap. Unity has four panels by 
    default. Project holds all the stuff in our
  • 6:55 - 7:01
    game. Hierarchy lists all of the GameObjects 
    in the current level. Inspector lets us see
  • 7:01 - 7:05
    and change those GameObjects. And we 
    can see the level in the scene view.
  • 7:05 - 7:11
    And a GameObject is an invisible container that we 
    can fill with components, like a sprite renderer.
  • 7:12 - 7:16
    In step two we're going to use more 
    components to make the bird into a
  • 7:16 - 7:19
    physics object that is affected by 
    gravity. And then we're going to
  • 7:19 - 7:23
    write some programming code to make the 
    bird fly up when we press the space bar.
  • 7:23 - 7:30
    So let's add another component to our bird: 
    a Rigidbody 2D. This turns our bird into a
  • 7:30 - 7:37
    physics object, with gravity. So when we hit play, 
    the bird drops, and falls off the screen. Cool.
  • 7:37 - 7:42
    We'll also want this bird to be able to interact 
    with other objects, so let's add a collider.
  • 7:42 - 7:44
    A circle collider 2D.
  • 7:44 - 7:50
    Back in scene view we can see the collider as 
    a green outline. It's a bit off-center for me,
  • 7:50 - 7:55
    so I'll use the offset to move it. And, a 
    little game design trick - if we make the
  • 7:55 - 8:01
    collider a bit smaller than the image, it will 
    let the player get through pipes even if they
  • 8:01 - 8:05
    juuust touched the edge. It gives the game a 
    bit of leniency and makes it feel more fair.
  • 8:05 - 8:11
    The final thing to add right now: a script. 
    This essentially lets us make our own custom
  • 8:11 - 8:17
    component - but we'll have to write it ourself 
    using programming code. Choose New Script from
  • 8:17 - 8:22
    the components list. And call it BirdScript. 
    Once it's loaded, double click the script
  • 8:22 - 8:27
    field to open it up. This will open the file 
    in Visual Studio, which we installed earlier.
  • 8:27 - 8:31
    So, welcome to programming! It's not too scary,
  • 8:31 - 8:35
    promise. We'll take it slow. We're writing 
    in C sharp, that's the programming language.
  • 8:35 - 8:41
    And the only thing to worry about right now 
    is these two chunks here: start and update.
  • 8:41 - 8:47
    Start is for any code that will run as 
    soon as this script is enabled. And it
  • 8:47 - 8:53
    runs precisely once. Update runs constantly 
    while the script is enabled. And it will fire
  • 8:53 - 8:57
    off every line of code, every single 
    frame. Over and over and over again.
  • 8:58 - 9:03
    So the main thing we're going to be doing 
    with code right now is - well, if we go back
  • 9:03 - 9:08
    to Unity - see these numbers and text fields in 
    the components? And how we can change them in
  • 9:08 - 9:13
    the Unity editor? We're just going to write code 
    to change these stats while the game is running.
  • 9:13 - 9:18
    Just as a dumb example, and we'll 
    delete this in a second. In start,
  • 9:18 - 9:26
    we can type gameObject - that refers to this bit 
    up here. And then a dot. You'll see a list appear,
  • 9:26 - 9:31
    and many of the items refer to stuff back 
    in the Inspector, like isStatic,
  • 9:31 - 9:39
    tag, layer, and name. So let's pick name. 
    Then write an equals sign. And in quotes,
  • 9:39 - 9:45
    give our bird a name. Finally, we must always 
    use a semi-colon to mark the end of a command.
  • 9:45 - 9:50
    And we must always save the script
    before we go back to Unity.
  • 9:50 - 9:54
    Now, when we run the game... the name of 
    the GameObject has been changed. Nice.
  • 9:55 - 9:59
    Okay, delete that code. That was just 
    for sillies - but it shows us how we
  • 9:59 - 10:03
    can use code to talk to the game. We can 
    write a command by choosing someone to
  • 10:03 - 10:08
    talk to - in this game, the GameObject 
    - and then a topic of conversation - its
  • 10:08 - 10:14
    name - and then a command - change it to 
    Bob Birdington. We'll be doing this a lot.
  • 10:15 - 10:20
    So what we actually want to do is... in 
    the Rigidbody 2D's component, under info,
  • 10:20 - 10:23
    we'll see a greyed-out field 
    for velocity. And we want to
  • 10:23 - 10:27
    write some code to add upward velocity 
    to the bird to make it fly into the air.
  • 10:27 - 10:33
    The problem is... initially, a script can 
    only talk to the GameObject's top bit and
  • 10:33 - 10:37
    the transform. Right now, this script is 
    completely unaware of the other components.
  • 10:37 - 10:42
    So we need to sort that out first. We need 
    to make a special slot on this script for
  • 10:42 - 10:48
    a Rigidbody2D - so we can then talk to it and 
    send it commands. This is called a reference.
  • 10:48 - 10:52
    We're going to create the reference 
    up here, between the class name and
  • 10:52 - 10:58
    the start function. We're going to 
    write public Rigidbody2D myRigidbody.
  • 11:01 - 11:06
    So we now have a slot to store a Rigidbody2D. 
    And we have a name that we can refer to - to make sure
  • 11:06 - 11:12
    we're talking about this specific Rigidbody2D. And 
    because we made it public, it means we can access
  • 11:12 - 11:18
    this slot from outside the script. So, if we save. 
    And go back to Unity, we'll see that the script
  • 11:18 - 11:25
    component now has a field for a Rigidbody2D. We 
    can drag the component into that slot, and viola.
  • 11:25 - 11:29
    We have established a line of communication 
    between the script and the Rigidbody.
  • 11:29 - 11:36
    Okay, back in Visual Studio. In update, 
    we can type myRigidbody. Then dot. And
  • 11:36 - 11:40
    now look at all the things we can talk 
    about. Angular drag, gravity scale,
  • 11:40 - 11:46
    mass - these are all properties on the 
    component. The one we want is velocity.
  • 11:46 - 11:51
    We want to set this to a new number, and so, just 
    like before with the name, we'll write an equals.
  • 11:51 - 11:57
    Now what we're actually writing here is a vector, 
    which is two numbers, to represent a position in
  • 11:57 - 12:02
    2D space. And in this case, it's used to represent 
    a direction for the bird to travel. We want the
  • 12:02 - 12:09
    bird to go straight up, so zero, comma one would 
    be a good one. I'm just going to use Vector2.up,
  • 12:09 - 12:14
    which a built-in shorthand for zero comma one. 
    And to give it a bit more power, I'm going
  • 12:14 - 12:20
    to multiply that vector by a number. Say, 10, 
    which should send the bird flying up in the sky.
  • 12:20 - 12:25
    Now, like I said before, any code in 
    update will run, over and over again,
  • 12:25 - 12:32
    every frame. So if we save the script and 
    hit play in Unity... off goes our bird. Bye!!
  • 12:32 - 12:36
    That's not what we want. We want this to only 
    happen when the player hits the space bar. So
  • 12:36 - 12:41
    it's time to use the most fundamental bit 
    of programming code: the if statement.
  • 12:41 - 12:43
    An if statement is like a gate.
  • 12:43 - 12:48
    You can surround some code with a fence, 
    and every frame that code will be completely
  • 12:48 - 12:52
    ignored. Unless, the game meets some 
    specific conditions that are written
  • 12:52 - 12:57
    on the gate - in which case the gate is 
    open, and the code is read and executed.
  • 12:57 - 13:01
    So we want to say "if the player hits 
    the space bar, then add upward velocity".
  • 13:01 - 13:06
    To do this... we can write if, and then in 
    brackets we can write the condition. This time
  • 13:06 - 13:12
    we're not talking to a component, we're talking to 
    Unity itself - specifically its input system. So
  • 13:12 - 13:20
    we'll write Input. Then we can pick GetKeyDown, 
    and in brackets, KeyCode.Space. This asks Unity
  • 13:20 - 13:25
    if the space bar has been pressed on this frame. 
    And then we'll finish with equals, equals true.
  • 13:25 - 13:31
    A quick note on equals signs - we use one 
    to make the thing on the left be the same
  • 13:31 - 13:35
    as the thing on the right. And we 
    use two if we're just checking if
  • 13:35 - 13:39
    the thing on the left is the same 
    as the thing on the right. Cool?
  • 13:39 - 13:44
    Anyway. So this code says... if the space bar 
    has just been pressed, then... and then we'll
  • 13:44 - 13:49
    use curly brackets - these are the fence in our 
    little analogy - and put the flap code in here.
  • 13:50 - 13:54
    So, now in update - every frame the game 
    will go to the gate and be asked "hey,
  • 13:54 - 13:59
    has the spacebar just been pressed?" If yes, the 
    code will fire and the bird will flap. If not,
  • 13:59 - 14:03
    it will skip the code in the curly 
    brackets and try again next frame.
  • 14:03 - 14:08
    So - save the script and go back to 
    Unity. We can now hit play and tada:
  • 14:08 - 14:11
    the bird goes up when we press space. We have now
  • 14:11 - 14:17
    created a character and made it react 
    to input. This is a video game. Hooray!
  • 14:17 - 14:23
    However, it feels like trash. The flap isn't 
    right, and it doesn't feel like the original
  • 14:23 - 14:32
    iPhone game. So we could change this number. 
    Save. Open Unity. Run the game. Not quite right. Stop. Change
  • 14:32 - 14:37
    the number. Save. But that's slow and 
    dumb. Let's do something smarter.
  • 14:37 - 14:42
    First, we're going to make a variable. Let's 
    go back to the top of the script and under
  • 14:42 - 14:47
    our reference to the Rigidbody, let's make 
    a public float called flapstrength. A float
  • 14:47 - 14:52
    is a floating point number - basically a 
    number that can have a decimal place. And
  • 14:52 - 14:58
    then back in our update code, we'll multiply 
    the vector2.up by flapstrength, instead of 10.
  • 14:58 - 15:02
    Now, back in Unity, you'll see that 
    the script component has a new field:
  • 15:02 - 15:07
    flapStrength. And we can change that 
    whenever we want to make the game feel
  • 15:07 - 15:11
    different. We can even change it during the 
    game, but note that anything you change while
  • 15:11 - 15:15
    the game is running won't save when you 
    press stop. This means you can play with
  • 15:15 - 15:19
    values to your heart's content without 
    worrying about screwing up your game.
  • 15:19 - 15:23
    So, if we mess with the flapStrength, 
    and also the gravity scale on
  • 15:23 - 15:27
    the Rigidbody, we'll hopefully get 
    to something that feels good. Ah,
  • 15:27 - 15:30
    changing numbers back and forth: 
    honey, that's game design!
  • 15:30 - 15:31
    Recap time.
  • 15:31 - 15:36
    We can use code to change the properties 
    of a component, while the game is running.
  • 15:36 - 15:41
    A script cannot talk to the other components 
    on the gameobject, by default. You have to
  • 15:41 - 15:45
    make a line of communication by storing 
    a reference to that specific component.
  • 15:45 - 15:50
    We create the reference in code, and then 
    fill it in Unity by dragging and dropping.
  • 15:50 - 15:56
    Code in start runs once, when the script comes 
    into existence. Code in update runs continuously,
  • 15:56 - 16:02
    every single frame. But, we can use if statements 
    to skip some code, unless a condition is met.
  • 16:02 - 16:05
    And we can use public variables to change certain
  • 16:05 - 16:08
    values in Unity's inspector - 
    even while the game is running.
  • 16:09 - 16:14
    Okay, so the secret to Flappy Bird 
    is that while it looks like a bird
  • 16:14 - 16:18
    is flapping along through a world of 
    pipes - it's actually not. The bird
  • 16:18 - 16:24
    stays completely still and the pipes move 
    across the screen. So in step three we're
  • 16:24 - 16:29
    going to make pipes spawn into the world, move 
    across the screen, and then delete themselves.
  • 16:29 - 16:32
    We'll start by making the object 
    we want to spawn. This will be
  • 16:32 - 16:35
    two pipes which move across the 
    screen, from the left to right.
  • 16:35 - 16:40
    Let's make another GameObject called 
    pipe. Put it exactly on the bird for now,
  • 16:40 - 16:45
    to get the sizing right. And then we'll 
    make another object within this one,
  • 16:45 - 16:51
    called top pipe. This is a child of the 
    first GameObject's parent. This way we
  • 16:51 - 16:55
    can nest multiple GameObjects, and move all 
    of them at once just by moving the parent.
  • 16:56 - 17:00
    So let's repeat what we did for the bird. 
    Add a sprite renderer for the pipe image.
  • 17:01 - 17:07
    And add a collider - a Box Collider 2D, this time. 
    We don't need a RigidBody because it's not going
  • 17:07 - 17:13
    to be affected by physics. We can then move it up 
    above the bird - but keep the X position as zero.
  • 17:13 - 17:19
    Finally, we can duplicate this whole top 
    pipe object. Call it bottom pipe. And flip
  • 17:19 - 17:24
    it upside down by changing the Y scale to 
    minus one. Then move it down below the bird.
  • 17:24 - 17:31
    As you can see, if we mess with the pipe 
    parent GameObject, both pipes move, scale,
  • 17:31 - 17:35
    and rotate along with it, with the 
    parent as the pivot point. So let's
  • 17:35 - 17:39
    add a script to this parent's object 
    to make it move across the screen.
  • 17:41 - 17:46
    We'll start by creating a variable for 
    moveSpeed. If we give it a number here,
  • 17:46 - 17:51
    it will fill this as the default value in 
    Unity. But we can always change it there, later.
  • 17:51 - 17:56
    Then we'll write code to move the object, in 
    update. Now it would be lovely if we could just
  • 17:56 - 18:03
    type transform.position.x, and change this number 
    directly - but, no, boo, you have to change the
  • 18:03 - 18:09
    entire Vector in one go. Oh, and this time we're 
    gonna have to use Vector3, instead of Vector2,
  • 18:09 - 18:15
    because the transform has three numbers. Even 
    though we're making our game in 2D, Unity is still
  • 18:15 - 18:20
    fundamentally a 3D engine and so it's keeping 
    track of the object's depth with the Z value.
  • 18:21 - 18:26
    So, here's what we'll do. We'll take the 
    current transform.position. And then equals.
  • 18:26 - 18:31
    We want to add to its current position, 
    so write transform.position again. And
  • 18:31 - 18:37
    then plus. And finally, in brackets, 
    we'll do Vector3.left * moveSpeed.
  • 18:39 - 18:44
    Back in Unity, press play and 
    vroooof. That's way too fast. Now,
  • 18:44 - 18:48
    you might think that you could just change 
    this moveSpeed variable down to a really
  • 18:48 - 18:53
    small number like 0.001. And that will work 
    - but that's not actually the problem here.
  • 18:53 - 18:59
    You see, code in update just runs as often as it 
    can. In fact, if we check the stats in Game view,
  • 18:59 - 19:03
    we'll see the game is running at 
    over 1,000 frames per second. Heh,
  • 19:03 - 19:08
    sorry PlayStation 5. 120 fps? Pfft, 
    that's got nothing on Flappy Bird.
  • 19:08 - 19:12
    And the real problem is that the game may run 
    at different speeds on different computers,
  • 19:12 - 19:16
    and we don't want the pipe to move 
    faster or slower depending on your rig.
  • 19:16 - 19:23
    Real games have actually made this mistake - in 
    Dark Souls 2, weapon durability was once tied
  • 19:23 - 19:31
    to frame rate, so your swords would break twice 
    as fast at 60 FPS, compared to 30 FPS. That was a whoopsie.
  • 19:31 - 19:36
    Luckily, it's a pretty easy fix. We 
    just multiply it by Time.deltaTime.
  • 19:36 - 19:41
    This ensures the multiplication happens the 
    same, no matter the frame rate. We didn't
  • 19:41 - 19:45
    need it for the velocity code because 
    physics runs on its own little clock,
  • 19:45 - 19:49
    but otherwise we will need it. if you want to 
    know more - about this, or anything really,
  • 19:49 - 19:54
    the Unity docs are a good place to 
    check. You'll find info and sample code.
  • 19:54 - 19:59
    Okay, now with that fix in place, our pipe 
    moves smoothly across the screen. Lovely.
  • 19:59 - 20:05
    Next, we want to create a system that will 
    continually spawn new pipes. To start,
  • 20:05 - 20:11
    take the parent GameObject from the hierarchy 
    and drag it into your project. This creates a
  • 20:11 - 20:17
    prefabricated GameObject. Or prefab. This is like 
    a blueprint for a GameObject and we can create new
  • 20:17 - 20:22
    versions of this entire GameObject- with all 
    its children, components, and properties. Oh,
  • 20:22 - 20:26
    and before we move on, we can delete the 
    original in our hierarchy now. Bye bye.
  • 20:26 - 20:29
    Let's make a new GameObject called Pipe Spawner.
  • 20:31 - 20:36
    We'll put it just to the right of the camera. And 
    we'll make a script for it. The purpose of this
  • 20:36 - 20:42
    script is to spawn new versions of the pipe prefab 
    every few seconds. And because the pipe already
  • 20:42 - 20:47
    has code to move left, the pipe will automatically 
    move across the screen as soon as it spawns in.
  • 20:47 - 20:51
    We're going to write some code to 
    spawn that prefab we just made. So
  • 20:51 - 20:54
    we'll start by making a reference 
    to the prefab.
  • 20:54 - 20:59
    Up here, we'll type Public GameObject pipe.
  • 20:59 - 21:04
    Then in Unity, we'll use the same drag and 
    drop method to fill the slot, but this time,
  • 21:04 - 21:08
    instead of a component, we'll drag 
    the prefab from the project panel.
  • 21:08 - 21:12
    Now,
    Unity has a nice built-in method for spawning
  • 21:12 - 21:18
    new GameObjects. We'll type Instantiate, and then 
    open the brackets. In here, the command is asking
  • 21:18 - 21:23
    for some extra details. we can actually flip 
    through these to find different, I dunno, recipes?
  • 21:23 - 21:28
    I guess? Number 4 looks good - it will create 
    an object at a specified position and rotation.
  • 21:28 - 21:33
    So, for the GameObject, we can 
    type pipe. For position
  • 21:33 - 21:38
    we can just type transform.position to 
    get the position of the object holding
  • 21:38 - 21:42
    this script. That will make it spawn on 
    top of the spawner. And for rotation,
  • 21:42 - 21:47
    let's just use transform.rotation so, 
    again, it's the same as the spawner.
  • 21:48 - 21:53
    Let's run it and oh my god, that's not 
    what we want. Spawning works great,
  • 21:53 - 21:56
    but they're coming out every single 
    frame - and we want them to come
  • 21:56 - 22:00
    out on a nice interval that we can 
    control. So, back to Visual Studio.
  • 22:00 - 22:05
    What we're going to do now is to write some 
    code to make a timer. this will count up for
  • 22:05 - 22:10
    a specified number of seconds, run some code, 
    and then start the count again. To do this,
  • 22:10 - 22:15
    we'll need to make a couple variables. A 
    spawnRate is how many seconds it should be
  • 22:15 - 22:20
    between spawns. And then a timer is the 
    number that counts up. We can make this
  • 22:20 - 22:23
    one private as we won't be changing 
    it in the editor or anywhere else.
  • 22:23 - 22:29
    In update, we'll do another if statement. This 
    time, if the timer is less than the spawnRate,
  • 22:29 - 22:35
    then we want to make the timer count up by one. 
    So we'll take the timer as it currently is,
  • 22:35 - 22:40
    and add Time.deltaTime to it. This creates 
    a number that counts up every frame,
  • 22:40 - 22:43
    and works the same no matter what 
    your computer's frame rate is.
  • 22:43 - 22:48
    We can actually shorten this by changing it to +=, 
    but, don't feel like you need to make your code as
  • 22:48 - 22:53
    short as humanly possible just to avoid 
    getting sniffy YouTube comments. If
  • 22:53 - 22:58
    timer = timer + is easier to read and 
    grasp, then that's absolutely fine. You
  • 22:58 - 23:02
    can always swap to the other version in 
    the future when you feel more confident.
  • 23:02 - 23:05
    Now, before I said an if statement is like a gate.
  • 23:05 - 23:10
    And we can add another gate to the 
    side of it, with else. This means,
  • 23:10 - 23:15
    if the condition isn't met, then skip the 
    code - and do the code in else, instead.
  • 23:15 - 23:23
    So we'll put the spawn code in here, and also 
    reset the timer to zero. So now, every frame, it
  • 23:23 - 23:28
    asks if the timer is less than the spawn rate. If 
    it is, then count the timer up. If it's not - i.e.
  • 23:28 - 23:33
    the timer has actually met or exceeded the spawn 
    rate, then spawn a pipe and start the timer again.
  • 23:33 - 23:39
    Put this in Unity and - pretty good. I'm happy 
    with that. The only problem is... we have to
  • 23:39 - 23:44
    wait ages for the first pipe to spawn. It would 
    be good if this came out immediately, right?
  • 23:44 - 23:50
    Now, we could copy and paste the spawn code 
    into start, so it happens once in start.
  • 23:50 - 23:55
    And then happens over and over in update. But 
    that's a bad idea. You should generally try to
  • 23:55 - 24:01
    avoid having the same, or even similar code 
    in multiple places. What happens if we want
  • 24:01 - 24:06
    to change how the spawn works? We'll have 
    to find and change it everywhere. No good.
  • 24:06 - 24:10
    Instead, we can put the spawn code in 
    a new function, and then just run that
  • 24:10 - 24:15
    function. So here, below update - but 
    above the final curly bracket - we'll
  • 24:15 - 24:21
    make a function called void spawnPipe(). And then 
    cut and paste the Instantiate code into there.
  • 24:21 - 24:28
    Now we can just write spawnPipe, with empty 
    brackets, in both update and start. This will run
  • 24:28 - 24:32
    all the code in that function when these lines 
    are executed. And with that done, it will make
  • 24:32 - 24:38
    a pipe as soon as the game begins, and will make 
    new pipes every time the timer maxes out. Perfect.
  • 24:39 - 24:45
    However - this is a pretty boring game, right? The 
    pipes always come out in the middle. we want them
  • 24:45 - 24:49
    to come out at random heights. So, remember 
    that when we wrote the instantiate code,
  • 24:49 - 24:53
    we had to pick a position for the object 
    to appear? We'll change that value.
  • 24:53 - 24:58
    Right now the pipes always spawn on the same 
    position as the spawner. We want the X value
  • 24:58 - 25:04
    to be the same... but for Y, we want to pick a 
    random point somewhere above or below the spawner.
  • 25:04 - 25:09
    So let's create a public variable 
    for a heightOffset, maybe 10.
  • 25:09 - 25:14
    And then we'll make a float called lowestPoint. 
    Because we're making this variable inside the
  • 25:14 - 25:20
    function, rather than at the top of the script, it means 
    it can only be used within the function. But,
  • 25:20 - 25:22
    also, it means we can set 
    it by doing a calculation.
  • 25:22 - 25:30
    so we'll do equals transform.position.y - 
    heightOffset. And then we'll make another
  • 25:30 - 25:37
    one for highestPoint, but this time it's plus 
    heightOffset. That gets us these two numbers.
  • 25:38 - 25:41
    Then we'll replace the transform.position 
    in our Instantiate code.
  • 25:41 - 25:47
    We're gonna write new Vector3, we have to write that 
    whenever we're specifying our own numbers for a
  • 25:47 - 25:54
    vector. and then in brackets we'll specify the X, 
    Y, and Z values as three different floats. For X,
  • 25:54 - 25:59
    we want this to be the same as the spawner, 
    so we'll do transform.position.x. But for Y,
  • 25:59 - 26:05
    we can do Random.Range. And in the brackets for 
    that, we can supply a minimum and maximum point
  • 26:05 - 26:12
    to pick from. That's lowestPoint and highestPoint. 
    Then a 0 for Z. And close the brackets.
  • 26:14 - 26:20
    Back in Unity.... nice! The pipes will 
    spawn anywhere between these two numbers.
  • 26:20 - 26:25
    Oh, one last thing. Every time these 
    pipes spawn they'll appear and move
  • 26:25 - 26:30
    left.... forever. Which isn't great practice - 
    they're off screen and doing absolutely nothing,
  • 26:30 - 26:35
    and yet they're still in memory and running code 
    every frame. And if too many spawn they'll start
  • 26:35 - 26:40
    to spill out the side of your monitor and 
    make a right mess of your desk. So let's fix that.
  • 26:40 - 26:45
    Now we could make a timer, and delete the 
    pipe after a few seconds. But instead,
  • 26:45 - 26:51
    we'll check the X position of the pipe, and delete 
    it if it goes past a certain point. We'll borrow
  • 26:51 - 26:58
    the bird to find out the X coordinate of the 
    left of the screen. Looks about minus 45. In
  • 26:58 - 27:06
    the pipe move script, we'll add a float for a 
    deadzone. -45. And then a simple if statement - if
  • 27:06 - 27:13
    transform.position.x is less than deadZone, then 
    destroy the GameObject that holds this script.
  • 27:16 - 27:19
    Run it in Unity and, bam, they're dead.
  • 27:19 - 27:24
    Let's do one more thing, just as a teachable 
    moment. Just before the destroy line,
  • 27:24 - 27:33
    let's write Debug.Log, and in brackets, Pipe Deleted.
    Then, back in Unity, you'll see one other panel
  • 27:33 - 27:39
    I skipped during the UI demo - it's a tab next 
    to project, called console. Then when we run the
  • 27:39 - 27:45
    game... every time a pipe is deleted, our 
    message is sent to the console. This is a
  • 27:45 - 27:50
    wonderfully useful way to debug our code, because 
    we can find out exactly what the code is up to.
  • 27:52 - 27:53
    Recap time!
  • 27:53 - 27:56
    GameObjects can be turned into prefabs,
  • 27:56 - 27:59
    by dragging them from the hierarchy, 
    and dropping them into the project.
  • 27:59 - 28:04
    You can then drag these into scenes - I use 
    prefabs to create levels in my puzzle game,
  • 28:04 - 28:09
    for example. Or you can make a spawner 
    to instantiate new ones during the game.
  • 28:09 - 28:13
    Timers are a great way to make 
    code happen on a certain interval,
  • 28:13 - 28:17
    but always use Time.deltaTime to keep things 
    consistent across different computers.
  • 28:17 - 28:22
    If statements can have an else gate, 
    to make code fire if the condition
  • 28:22 - 28:27
    is not met. You can also have else 
    if, to make more complicated gates.
  • 28:27 - 28:31
    And you should try to delete GameObjects if 
    they're no longer needed, to free up memory.
  • 28:32 - 28:36
    Okay, our next step is to keep 
    track of the player's score,
  • 28:36 - 28:39
    and show it to the player 
    on the user interface. Then,
  • 28:39 - 28:43
    we want the score to go up by one, every 
    time the bird goes through the pipes.
  • 28:43 - 28:47
    So, remember that a GameObject doesn't 
    have to be a physical thing in your game
  • 28:47 - 28:53
    world like a character or an enemy - it 
    can be a completely invisible manager
  • 28:53 - 28:58
    that's just keeping track of critical data 
    like health, or time, or score. And then,
  • 28:58 - 29:01
    we can make that information visible 
    to the player, using a user interface.
  • 29:01 - 29:07
    So let's start by making the UI. Like 
    everything else, it's a GameObject in
  • 29:07 - 29:12
    the hierarchy. This time go down to 
    UI and pick text - which may be under
  • 29:12 - 29:17
    legacy. We'll need to zoom really far out 
    on the scene view to actually see the UI.
  • 29:17 - 29:22
    To make sure the UI looks the same on every 
    device, we'll pick this new canvas GameObject
  • 29:22 - 29:28
    and set the canvas scaler component's UI scale 
    to scale with screen size, and choose a sensible
  • 29:28 - 29:34
    reference resolution - I'm gonna use 1080p again. 
    We can then move our text around. You'll notice
  • 29:34 - 29:40
    that UI has a rect transform, rather than a normal 
    transform. The most important thing to note is
  • 29:40 - 29:45
    that you don't really want to mess with scale of 
    elements - instead, change the width and height.
  • 29:47 - 29:49
    I'll then increase the font size and set the default
  • 29:49 - 29:53
    text to 0. And then check it 
    all looks nice on the game view.
  • 29:53 - 29:57
    Okay, now we want to make a script 
    that will store the player's score,
  • 29:57 - 30:00
    and change the number on the UI to that score.
  • 30:00 - 30:03
    We'll make a GameObject called Logic Manager.
  • 30:04 - 30:09
    And we'll give it a script. This script is 
    going to keep track of high level information
  • 30:09 - 30:14
    like the player's score. And it will have 
    various meta-level functions that we can run.
  • 30:14 - 30:18
    So we'll delete start and update, we don't 
    need them in this script. We can always add
  • 30:18 - 30:23
    them back later if we change our mind. We want to 
    store a number for the player's score. This time,
  • 30:23 - 30:28
    we don't want a float because we only ever 
    want round numbers. So let's do an int,
  • 30:28 - 30:30
    instead. That's an integer. No decimal places.
  • 30:30 - 30:35
    And because we want to update the UI 
    text we just made we will, as always,
  • 30:35 - 30:41
    have to make a reference. Except... 
    text doesn't seem to be a thing?
  • 30:41 - 30:46
    Ah, well. By default, a script only loads 
    in the stuff you need for basic Unity
  • 30:46 - 30:52
    functionality - but if we go up to the top 
    and type using UnityEngine.UI;, we can now
  • 30:52 - 30:59
    access more functionality - in this case, UI 
    stuff. Now we can make a reference to text.
  • 30:59 - 31:05
    We'll need to drag the text component into this 
    field back in Unity. Because we're referencing a component
  • 31:05 - 31:10
    on another GameObject - the text on the UI 
    - the best way to do this is to just drag
  • 31:10 - 31:16
    the whole GameObject into our slot. This will 
    automatically find the text component for us. Handy.
  • 31:16 - 31:20
    So now we want to make a function. And 
    we'll call it addScore. And because
  • 31:20 - 31:25
    we're going to run this function from 
    other scripts, we'll set it to public void.
  • 31:26 - 31:31
    This function needs to do two things. Add 
    one to the player's score. Easy enough,
  • 31:31 - 31:39
    we know how to do that now. And change the text 
    on the UI to be this number. Oh, the text box is
  • 31:39 - 31:46
    looking for a string - a sequences of characters 
    - and our score is an integer. They look identical
  • 31:46 - 31:52
    to us humans, but robots are fussy. Easily fixed, 
    mind you, by adding .toString() to the game score.
  • 31:53 - 31:57
    To make sure this works, let's give 
    ourselves the power to run this function
  • 31:57 - 32:03
    from Unity itself. All we need to do is write 
    ContextMenu, and a name, above the function.
  • 32:05 - 32:10
    Now, in Unity, while the game is running, hit the 
    little dots on this script and pick the function.
  • 32:11 - 32:14
    Nice! This sort of thing comes 
    in real handy for testing.
  • 32:15 - 32:19
    Okay, so now that we know the function 
    runs, we specifically want to run it
  • 32:19 - 32:23
    when the bird goes between the pipes. 
    And the way to do this is collisions.
  • 32:23 - 32:28
    Now if two objects have colliders, they will 
    bash into each other - in fact, in our game,
  • 32:28 - 32:33
    the bird will already crash into the pipes because 
    we've added colliders to both. However - you
  • 32:33 - 32:38
    can also have invisible colliders, called 
    triggers. They don't create an actual collision,
  • 32:38 - 32:42
    but they do let you know that two objects have 
    touched - and you can run code at that moment.
  • 32:42 - 32:45
    So we're going to put a 
    trigger in between the pipes,
  • 32:45 - 32:51
    so we know that the bird has passed through them.
    And then at that moment, we'll run addScore.
  • 32:51 - 32:56
    Let's open up the prefab for the pipes. We'll 
    make another GameObject called middle - and
  • 32:56 - 33:01
    it needs a box collider. Let's make it 
    this sort of shape. And this time we'll
  • 33:01 - 33:06
    tick the box isTrigger. Finally, let's add 
    a script to this new middle GameObject.
  • 33:06 - 33:14
    Beneath Update, type ontrig, and the autocorrect 
    will help us type out OnTriggerEnter2D. Just
  • 33:14 - 33:19
    press tab to autofill. Anything in this 
    function will run whenever an object first
  • 33:19 - 33:26
    hits the trigger. There's also OnTriggerExit and 
    OnTriggerStay, for future reference. And its in here,
  • 33:26 - 33:30
    that we want to run the addscore function we 
    wrote earlier... except. ah. once again,
  • 33:30 - 33:34
    this script doesn't know about any other scripts 
    in the game, until we make a reference to it.
  • 33:34 - 33:41
    So we can write public LogicScript logic. 
    But back in Unity, you'll quickly realise
  • 33:41 - 33:46
    that you can't drag the script into this 
    slot. You can't drag it from the project
  • 33:46 - 33:51
    panel - we can only talk to an instance of a 
    script that lives on a GameObject. But we also
  • 33:51 - 33:57
    can't drag from the scene into the prefab. That's 
    because the pipe doesn't exist in the scene yet,
  • 33:57 - 34:01
    it will only exist when the game is running, 
    and the spawner starts making pipes.
  • 34:01 - 34:06
    So, instead, we'll need to fill 
    this reference using code. and
  • 34:06 - 34:08
    this needs to happen when the pipe first spawns.
  • 34:08 - 34:13
    To do this, we'll need to help the 
    code find the logic script. To do this,
  • 34:13 - 34:17
    take the Game Logic object, and 
    look at the top of the inspector:
  • 34:17 - 34:24
    you'll see tags. From the drop down, 
    choose add tag. Make a new tag called, say,
  • 34:24 - 34:30
    Logic. And make sure you go back to the GameObject 
    and actually set this new tag. You will forget to
  • 34:30 - 34:35
    do this approximately eight thousand times in 
    your Unity career, so look forward to that.
  • 34:35 - 34:37
    Now, back in the PipeMiddleScript,
  • 34:37 - 34:47
    under start we can write logic = 
    GameObject.FindGameObjectWithTag("Logic").
  • 34:47 - 34:51
    this will look for the first GameObject 
    in the hierarchy with the tag,
  • 34:51 - 34:54
    Logic. In our case, there will 
    only ever be one in the scene,
  • 34:54 - 34:58
    so we know it will always find the 
    right one - but do be mindful of that.
  • 34:58 - 35:02
    And then we can add .GetComponent<LogicScript>();
  • 35:03 - 35:09
    So, as soon as a new pipe spawns, it will look 
    through the hierarchy to find a GameObject with
  • 35:09 - 35:14
    the tag Logic. Then, it will look through 
    that object's components to find a script
  • 35:14 - 35:19
    of the class LogicScript. And if it finds 
    one, it will put that in our reference slot.
  • 35:19 - 35:23
    It has done the exact same thing as 
    dragging and dropping the component
  • 35:23 - 35:28
    in the Unity editor - except it has done 
    it instantly, during run time. Excellent.
  • 35:29 - 35:34
    So now, the pipe's middle script can 
    find and talk to the logic script.
  • 35:35 - 35:41
    And if we write logic.addScore, this 
    will run that code. Back in Unity,
  • 35:41 - 35:47
    hit play and if we did everything right, the score 
    will go up by one when we pass between the pipes.
  • 35:47 - 35:53
    Oh, and just for future proofing and whatnot, 
    let's make sure that it was actually the bird
  • 35:53 - 35:58
    that went through. We'll do this by putting the 
    bird on a layer, and checking if the colliding
  • 35:58 - 36:04
    object was on that layer. Go to the bird's GameObject 
    and this time, instead of the tag, we'll change
  • 36:04 - 36:11
    the bird's layer. Make a new one, remember to 
    actually assign it, and make a note of the number.
  • 36:11 - 36:15
    Now, on the pipe's middle script,
    we can add an if statement around addScore,
  • 36:15 - 36:20
    and check if the collision that just happened 
    was with a GameObject on the bird's layer.
  • 36:23 - 36:27
    One more bit of future proofing, while we're on 
    the subject. Go back to the Logic Script.
  • 36:27 - 36:33
    And, let's take the AddScore function, and in these empty brackets we'll write int
  • 36:33 - 36:39
    scoreToAdd. And then instead of 
    adding one, we'll add scoreToAdd.
  • 36:39 - 36:45
    Then in the pipe middle script, we can write 
    a 1 in the brackets after addScore. Right
  • 36:45 - 36:50
    now this does exactly the same thing as we 
    had before. But, as you can surely guess,
  • 36:50 - 36:55
    you could later add some other goal 
    in the game that adds, say, 5 to your score.
  • 36:55 - 36:59
    This allows us to make a function 
    more versatile, as it can be used
  • 36:59 - 37:03
    in different ways, from different places. 
    Part of being a good programmer, I think,
  • 37:03 - 37:07
    is making stuff less rigid, and keeping it open for 
    future ideas.
  • 37:07 - 37:13
    This makes it easier and faster 
    to iterate on your designs.
  • 37:13 - 37:14
    Right! Recap!
  • 37:14 - 37:18
    UI is just another GameObject, 
    but if we want to reference any
  • 37:18 - 37:23
    of these components we'll need to add 
    using UnityEngine.UI to the top of the script.
  • 37:23 - 37:26
    GameObjects can be completely invisible things,
  • 37:26 - 37:30
    merely there to keep track of rules, 
    logic, score, and so on.
  • 37:30 - 37:34
    If we want to a reference a component 
    when one of the GameObjects is not in the scene,
  • 37:34 - 37:37
    we'll need to find that component during run time.
  • 37:37 - 37:42
    One way to do this is to use tags, 
    findGameObject, and GetComponent.
  • 37:42 - 37:47
    A public function can be run from another 
    script, as long as you have a reference
  • 37:47 - 37:51
    to that script. And we can even pass 
    in variables when that function runs.
  • 37:51 - 37:57
    And Collisions and triggers can be used to make 
    stuff happen when two objects touch.
  • 37:57 - 37:59
    Speaking of collisions, let's 
    move on to the next step...
  • 38:01 - 38:07
    The final step is to add a fail state. When 
    the bird hits the pipes, the game is over.
  • 38:07 - 38:11
    We'll do this by making a game over screen, 
    and have it appear when the bird crashes
  • 38:11 - 38:16
    into a pipe. The game over screen will have 
    a button, which we can use to reset the game.
  • 38:17 - 38:21
    First, let's make that game over 
    screen. On the canvas GameObject,
  • 38:21 - 38:28
    add a new empty one called game over screen. 
    Then, in that parent, add a text for game over.
  • 38:31 - 38:37
    And also a a button - that's also 
    under legacy. Resize it. And change
  • 38:37 - 38:42
    the text on the button - the text can be 
    found as a child on the button itself.
  • 38:43 - 38:48
    So back on the button GameObject, 
    on the button component, you'll see
  • 38:48 - 38:54
    this bit that says On Click. This is 
    an event, and it allows us to call a
  • 38:54 - 38:59
    public function on a GameObject. So let's 
    make a function for restarting the level.
  • 39:00 - 39:02
    We can put this code in the logic script,
  • 39:02 - 39:07
    underneath our addScore function. You 
    could make a seperate script if you want,
  • 39:07 - 39:12
    but I think this is fine. Let's make 
    another public function called restartGame,
  • 39:12 - 39:18
    and in here we'll write code to restart the 
    scene. Just like before with the UI, if we're
  • 39:18 - 39:23
    managing scenes then we'll need to add a line the 
    top - this time, using UnityEngine.SceneManagment.
  • 39:24 - 39:30
    Now in our function, we'll call up the 
    SceneManager and then, dot, LoadScene. This
  • 39:30 - 39:35
    is looking for the name of a scene. Literally the 
    filename. But because we want the current scene we
  • 39:35 - 39:43
    can simply type SceneManager dot GetActiveScene, 
    brackets, dot name. Close off all the brackets.
  • 39:45 - 39:48
    Now back in Unity, add an event to this button.
  • 39:49 - 39:53
    Then drag in the logic GameObject. 
    and find the restartGame function.
  • 39:57 - 40:03
    Give it a test and... nice. Every time we 
    press the button, the game begins anew.
  • 40:03 - 40:08
    Now obviously we don't want this to be on the screen 
    all the time - just when we fail. So,
  • 40:08 - 40:12
    we can just take the whole game over screen 
    GameObject and disable it with this checkmark.
  • 40:13 - 40:16
    Then we'll make it show up when 
    the bird hits into the pipes.
  • 40:16 - 40:23
    Let's write the function first. Again in the 
    logic script, let's make a public function for gameOver.
  • 40:23 - 40:28
    We'll need to make a reference to the game over screen GameObject.
  • 40:28 - 40:30
    And fill it in Unity.
  • 40:31 - 40:39
    And then we can simply type 
    gameoverscreen.SetActive true in this function.
  • 40:39 - 40:42
    So we want this function to trigger 
    when the bird crashes into a pipe.
  • 40:42 - 40:48
    Back on the bird script, let's reuse that 
    code from before to access the logic script
  • 40:48 - 40:53
    from the bird script. Yes, we could drag 
    and drop the reference in Unity, but hey,
  • 40:53 - 40:58
    we've written this code now. And then we're going to do 
    a similar thing to the trigger code, but this time
  • 40:58 - 41:03
    we'll use OnCollisionEnter2D, because the pipes 
    are solid objects, and not set to be triggers.
  • 41:03 - 41:10
    And when that collision occurs, trigger 
    the game over script with logic.gameOver.
  • 41:10 - 41:16
    Back in Unity... it kind of works, but we can 
    still play in the game over screen. Not ideal.
  • 41:16 - 41:21
    So, I've talked about a few key 
    variable types, already. Floats
  • 41:21 - 41:28
    and ints are numbers. And string is usually 
    for text. The other important one is a bool,
  • 41:28 - 41:34
    short for boolean. This is a really simple 
    type that is either true, or false. On,
  • 41:34 - 41:38
    or off. Yes, or no. It's a great way to 
    simply check or change something's state.
  • 41:39 - 41:44
    So let's have a bool called birdisalive, 
    and make sure it starts as true.
  • 41:44 - 41:49
    Then when the collision happens, 
    we'll set birdisalive to false.
  • 41:49 - 41:54
    And finally, we'll add an extra condition to 
    our very first if statement. We're going to
  • 41:54 - 42:01
    say if the space bar has just been pressed and... 
    written with two ampersands... and birdisalive is
  • 42:01 - 42:06
    equal to true. Actually, we don't need to 
    add this equals equals true thing. It does the exact
  • 42:06 - 42:11
    same thing without it. But, again, it's up to you 
    - maybe it's easier to read this with the full code written out.
  • 42:11 - 42:17
    Anyway, now, the bird won't flap if it's 
    dead, which seems quite logical to me.
  • 42:17 - 42:24
    The final thing to do is to build the game. Which is really easy.
    Pick file, build settings, and build. Pick a folder on
  • 42:24 - 42:32
    your hard drive. And let Unity do its work. Then you 
    can open this file to play your game! Amazing.
  • 42:32 - 42:35
    In a very short period of time, we 
    have made a pretty functional game.
  • 42:35 - 42:40
    And what’s more, we’ve learned loads 
    of fundamental lessons about Unity.
  • 42:40 - 42:44
    We have made a character that moves 
    in response to our input. We have
  • 42:44 - 42:49
    spawned in new objects on a timer. We 
    have created a UI that shows a score,
  • 42:49 - 42:54
    and made that score tick up when conditions are 
    met. And we've got the ability to get a game over,
  • 42:54 - 42:56
    and start again.
  • 42:56 - 43:00
    Now, I should note that there are different - and 
    perhaps better ways to do pretty much everything
  • 43:00 - 43:05
    in this tutorial. For example - I used Unity's 
    old way of checking for inputs, and the company
  • 43:05 - 43:10
    has since developed a much, much better Input 
    System. But it's a lot more complicated to
  • 43:10 - 43:16
    use - so this simple method is great for now, and 
    you can look into the new input system later down
  • 43:16 - 43:21
    the line, when you feel more confident. That's how 
    it went for me. There's also TextMeshPro, which
  • 43:21 - 43:28
    has replaced the old legacy UI system - so you'll 
    want to graduate to that, at some point, as well.
  • 43:28 - 43:32
    Anyway, these are lessons that will be useful,
    for making all sorts of games.
  • 43:32 - 43:37
    But... the game isn't quite finished yet. 
    There's still a few more things to figure out. Though,
  • 43:37 - 43:41
    I don't want to tell you how to do everything. 
    So i'm gonna give you some suggestions for how
  • 43:41 - 43:44
    to finish up the game, but I want you 
    to try and figure it out for yourself.
  • 43:44 - 43:48
    So first of all, we need to have a game 
    over if the bird goes off the screen.
  • 43:48 - 43:52
    That shouldn't be too hard. There's 
    also a bug where the score can go up,
  • 43:52 - 43:55
    even after a game over. Try to solve that one too.
  • 43:55 - 44:00
    We also want sound effects. I want you to add 
    an Audio Source component to the logic manager.
  • 44:00 - 44:06
    fill it with a sound effect file. Reference it on the 
    script. And have it play when the score goes up.
  • 44:06 - 44:11
    Then, i want you to play around with the particle 
    system to make clouds appear in the game.
  • 44:11 - 44:16
    Next, open the animation window, and 
    add some flapping wings to the bird.
  • 44:16 - 44:19
    Then i want you to add another 
    scene to make a title screen,
  • 44:19 - 44:23
    so the game doesn't immediately 
    launch into the action. Here's a clue:
  • 44:23 - 44:26
    you'll need to add this new scene 
    to the build settings window.
  • 44:26 - 44:31
    And finally, if you want a real 
    challenge - use PlayerPrefs
  • 44:31 - 44:35
    to save the player's high score to the hard 
    drive, and draw that on the UI as well.
  • 44:35 - 44:41
    For each one of these, you will probably want to 
    Google the relevant terms, read the Unity docs,
  • 44:41 - 44:45
    watch some quick tutorial videos, or 
    ask for help in the comments down below.
  • 44:45 - 44:49
    Next, you could expand on 
    Flappy Bird. Get creative
  • 44:49 - 44:53
    and add in ideas or designs that weren't 
    there in the original iPhone game.
  • 44:53 - 44:58
    For example, with a little messing around I gave 
    the bird the ability to shoot out a missile,
  • 44:58 - 45:03
    and then I added targets to the pipes. You've 
    now got to hit the target with a missile to open
  • 45:03 - 45:08
    a gap you can flap through. It's pretty cool, 
    and adds a lot more depth to the simple game.
  • 45:08 - 45:12
    In fact, I'd love to see how you 
    might expand on the original game. If
  • 45:12 - 45:15
    you make something interesting, record 
    a bit of footage, pop it on YouTube,
  • 45:15 - 45:19
    and drop a link in the comments. I might 
    feature some of them in the future.
  • 45:19 - 45:21
    And then, finally, I'd recommend that you take
  • 45:21 - 45:26
    another simple game and try to 
    remake it in Unity, like we just did right now.
  • 45:26 - 45:31
    This is a great technique because you don't have 
    to worry about art or design...
  • 45:31 - 45:35
    just code. And the problem-solving puzzles you'll face are
    a perfect example of
  • 45:35 - 45:39
    what real game development will be like.
  • 45:39 - 45:46
    Good candidates for this include Pong, Space 
    Invaders, Breakout, Pop the Lock, Angry Birds,
  • 45:46 - 45:52
    various WarioWare mini games, and that dinosaur game 
    that plays in Chrome if your internet's broken.
  • 45:52 - 45:55
    So, in this video I wanted to teach you the
  • 45:55 - 45:59
    fundamental concepts behind Unity 
    - but, the rest is up to you.
  • 45:59 - 46:04
    Luckily, I reckon this sort of hands-on, 
    self-directed, learn from your mistakes style of
  • 46:04 - 46:10
    learning is the most fun and effective way 
    to make stuff stick. But we’ll see!
  • 46:10 - 46:14
    Let me know how you got on in the 
    comments down below. And if you
  • 46:14 - 46:17
    want to watch my game development 
    story - which is still ongoing,
  • 46:17 - 46:22
    promise - then click here, 
    for episode one of Developing.
  • 46:22 - 46:25
    Thanks very much to my Patrons - they're 
    the reason you don't get mid-roll
  • 46:25 - 46:31
    ads in a looong video like this one. You 
    can help support GMTK at Patreon.com.
Title:
The Unity Tutorial For Complete Beginners
Description:

more » « less
Video Language:
English
Duration:
46:39

English subtitles

Revisions