The Unity Tutorial For Complete Beginners

00:46:39
https://www.youtube.com/watch?v=XtQMytORBmM

摘要

TLDRIn this tutorial video, the creator shares a practical three-step method for learning Unity, aimed at aspiring game developers who struggle with traditional long-winded tutorials. The method involves mastering foundational aspects of Unity, reinforcing knowledge through hands-on exercises, and building games incrementally. The video walks viewers through creating a version of the popular game "Flappy Bird," covering topics such as UI setup, scripting, game physics, and collision detection. By the end, the viewer should have a fundamental understanding of Unity and an operational Flappy Bird game. The creator encourages active learning by inviting viewers to expand on the project and venture into recreating other simple games using Unity.

心得

  • 🎮 Learn Unity by creating Flappy Bird - a hands-on approach!
  • 🚀 Understanding GameObjects and components is crucial.
  • 🖱️ Unity's UI tools make game interface integration easy.
  • 📜 Scripting in C# allows for dynamic game interaction.
  • 🏗️ Use prefabs for efficient object management in Unity.
  • ⚙️ Manipulating game physics enhances gameplay experience.
  • 🔄 Timers and if statements control game events effectively.
  • 💥 Use collisions and triggers for interactive gameplay.
  • 🧠 Develop problem-solving skills by recreating simple games.
  • 📈 Continuously iterating on designs is key for improvement.

时间轴

  • 00:00:00 - 00:05:00

    Mark expresses his long-standing desire to create video games using Unity. After experiencing ineffective tutorials, he devised a three-step method to learn Unity basics, practice through exercises, and learn progressively by making a game. This method led him to successful projects, including a video essay with 100k plays.

  • 00:05:00 - 00:10:00

    Mark sets up a plan to learn Unity's basics by identifying crucial actions needed for game creation. He learned through tutorials, Unity docs, and trial and error. This video aims to save others time by providing a comprehensive tutorial to recreate Flappy Bird, covering from basics to sharing the game with friends.

  • 00:10:00 - 00:15:00

    The tutorial begins with downloading Unity, setting up Visual Studio, and creating a new 2D Core project. Mark explains the Unity interface, intended for creating a bird sprite from imported assets. He outlines the project's four main panels: Project, Hierarchy, Inspector, and Scene View, and their functions.

  • 00:15:00 - 00:20:00

    Explaining GameObjects and components, Mark shows how to create a bird object with a Sprite Renderer component, enabling it to display the bird image. He demonstrates adjusting object properties and camera views, culminating in a basic setup where the bird image appears on the scene view for further development.

  • 00:20:00 - 00:25:00

    Mark introduces the Rigidbody2D component to apply gravity to the bird, causing it to fall. He guides through creating script files in Visual Studio to manipulate GameObject properties using C#. By coding spacebar input, users can launch the bird upward using velocity changes, blending technical programming with game design.

  • 00:25:00 - 00:30:00

    Mark elaborates on code structure, introducing if statements and public variables to adjust the bird's movement dynamics. He emphasizes efficient code practices and real-time parameter adjustments in Unity. The session sets up the bird movement mechanics foundationally, simulating the basics of Flappy Bird's gameplay dynamics.

  • 00:30:00 - 00:35:00

    The video progresses to making pipes as obstacles, implementing GameObjects to spawn moving pipes across the screen. Utilizing prefabs, Mark crafts a system to instantiate pipes on a timer, ensuring proper game flow. He addresses technical challenges involving frame rate consistency, demonstrating strategic code planning.

  • 00:35:00 - 00:40:00

    Mark shifts to score tracking and UI, introducing invisible GameObjects for managing gameplay data. By creating and manipulating UI components, he implements score increments when the bird passes through pipes. The explanation extends to designing collision checkers and writing scripts for interactive triggers, enhancing gameplay complexity.

  • 00:40:00 - 00:46:39

    The final phase integrates game-over conditions using collision detections, with UI panels to restart the game. Mark explores booleans and other variable types for game state management. The tutorial concludes by building the game, suggesting further personal exploration and expansion of the game concepts, and encourages community engagement.

显示更多

思维导图

Mind Map

常见问题

  • What is Unity used for?

    Unity is used as a game engine for developing video games across multiple platforms.

  • What is the three-step technique mentioned?

    The three-step technique involves learning Unity basics, practicing with simple exercises, and figuring out the rest incrementally.

  • Why did the creator decide to make this tutorial?

    The creator aimed to provide a simple, effective Unity learning method that they wish they had when starting, avoiding lengthy, meandering tutorials.

  • What does the creator recommend doing with this tutorial?

    Following the tutorial helps one remake Flappy Bird while learning Unity basics, with suggested next steps for further self-guided learning.

  • What are GameObjects in Unity?

    GameObjects in Unity are invisible containers that can hold components to add features, serving as elements like characters, pipes, and UI in games.

  • What is the main purpose of the Logic Manager in the tutorial?

    The Logic Manager tracks game status elements, such as scoring, and manages visible UI updates during gameplay.

  • Why use Time.deltaTime in game development?

    Time.deltaTime ensures that game actions occur at consistent speeds across different computer hardware, regardless of frame rate.

  • What is the purpose of triggers in this Unity tutorial?

    Triggers are used to detect when the bird passes through pipes in the game, which helps in scoring.

  • How can one restart the game in this tutorial?

    A button on the game over screen is coded to restart the scene, essentially restarting the game.

  • What future steps does the creator suggest after the tutorial?

    Suggestions include adding game features (e.g., sound effects, animations), and trying out building additional simple games independently.

查看更多视频摘要

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