< Return to Video

TANKS! Unity Tutorial - Phase 3 of 8 - Camera Control

  • 0:06 - 0:08
    Phase 3 - Camera.
  • 0:08 - 0:12
    So in this phase, what we're doing is
  • 0:12 - 0:15
    we're going to control, A, where the camera moves,
  • 0:15 - 0:17
    and B, how the camera zooms in
  • 0:17 - 0:20
    order to fit in the two tanks.
  • 0:20 - 0:23
    So you'll notice in this footage as the tanks are driving around,
  • 0:23 - 0:25
    just watch the camera frustum up in the scene view here,
  • 0:25 - 0:28
    notice that that shape is expanding and
  • 0:28 - 0:30
    contracting as the tanks move
  • 0:30 - 0:32
    further apart in order to fit them both
  • 0:32 - 0:34
    in to the view.
  • 0:34 - 0:36
    And that's controlling that size value
  • 0:36 - 0:38
    that I mentioned earlier about zooming,
  • 0:38 - 0:40
    and we're going to talk all about that now.
  • 0:40 - 0:43
    So currently we have a main camera
  • 0:43 - 0:45
    in our game.
  • 0:45 - 0:47
    We need to create what we call a camera rig.
  • 0:47 - 0:49
    It's nothing special, it's just a way to use
  • 0:49 - 0:51
    another separate empty game object
  • 0:51 - 0:53
    to hold our camera.
  • 0:53 - 0:55
    So there' a few different ways to create game
  • 0:55 - 0:57
    objects in Unity, and when I say
  • 0:57 - 0:59
    create game objects I'm usually talking about
  • 0:59 - 1:01
    either empty objects to store things
  • 1:01 - 1:03
    or I'm talking about primitive objects
  • 1:03 - 1:06
    for prototyping or something like that.
  • 1:06 - 1:08
    You've got the GameObject menu at the top,
  • 1:08 - 1:10
    which you can go to Create Empty or you can
  • 1:10 - 1:11
    go to any of these other things.
  • 1:11 - 1:14
    And then you've also got a Create menu on the hierarchy.
  • 1:14 - 1:16
    So from here you can choose basically
  • 1:16 - 1:18
    exactly the same thing, so this menu is
  • 1:18 - 1:20
    the same as this menu up here.
  • 1:21 - 1:23
    It doesn't matter what you use.
  • 1:23 - 1:25
    So I prefer to use the hierarchy
  • 1:25 - 1:27
    and right clicking because
  • 1:27 - 1:29
    that also allows you to do the same things.
  • 1:31 - 1:33
    But we want to create a new
  • 1:33 - 1:35
    empty game object in the root that's going to be
  • 1:35 - 1:37
    our camera rig, so I want you to click on the Create
  • 1:37 - 1:40
    button on the hierarchy and choose Create Empty.
  • 1:42 - 1:44
    We're going to rename this CameraRig.
  • 1:47 - 1:49
    And then we're going to position this
  • 1:50 - 1:54
    making sure that it's first off at 0.
  • 1:54 - 1:56
    So there's a shortcut to that, if you want,
  • 1:56 - 1:58
    so if you're offset at the wrong position
  • 1:58 - 2:00
    you can always reset position by clicking on
  • 2:00 - 2:03
    the gear icon to the right of any component.
  • 2:03 - 2:05
    Choosing Reset Position there will put
  • 2:05 - 2:08
    in zeros for you, just slightly quicker.
  • 2:08 - 2:14
    The rotation of that, we want to set it to (50, 60, 0).
  • 2:14 - 2:16
    So you'll notice that we're using the same rotation
  • 2:16 - 2:18
    as we did for the camera originally,
  • 2:18 - 2:20
    and you'll see why shortly.
  • 2:20 - 2:23
    So very quickly, we reset the position to 0,
  • 2:23 - 2:25
    and the rotation of the camera rig
  • 2:25 - 2:31
    should be (40, 60, 0), (X, Y, X).
  • 2:34 - 2:36
    Okay, then we're going to actually
  • 2:36 - 2:38
    put the rig together so we need to
  • 2:38 - 2:41
    place our camera on to the camera rig
  • 2:41 - 2:43
    as a child object.
  • 2:43 - 2:45
    So all I'm going to do is just grab my
  • 2:45 - 2:48
    Main Camera, drag and then drop it on to
  • 2:48 - 2:50
    the CameraRig like that.
  • 2:51 - 2:53
    One more time, grab the Main Camera,
  • 2:53 - 2:54
    drop it on to the CameraRig,
  • 2:54 - 2:56
    and what you'll see is that Main Camera becomes
  • 2:56 - 2:59
    indented, it's name is slightly over to the right,
  • 2:59 - 3:01
    underneath CameraRig.
  • 3:02 - 3:04
    And what we're going to do is tweak the position
  • 3:04 - 3:05
    and rotation of that main camera,
  • 3:05 - 3:07
    so just have a look over to the right
  • 3:07 - 3:09
    at the transform component.
  • 3:09 - 3:12
    And the position will be just slightly off.
  • 3:12 - 3:15
    So just slightly imprecise so just reset them to
  • 3:15 - 3:18
    (0, 0, -65).
  • 3:19 - 3:22
    And the rotation should already be (0, 0, 0),
  • 3:22 - 3:25
    so I'm just going to put that where it's easier to read.
  • 3:25 - 3:28
    The position of the Main Camera, (0, 0, -65).
  • 3:28 - 3:31
    And the rotation should still be 0 because remember
  • 3:31 - 3:33
    we have made this a child object
  • 3:33 - 3:35
    and it's inherited the same rotation
  • 3:35 - 3:39
    so as a result it's rotation is 0.
  • 3:39 - 3:41
    So just to run through those things again.
  • 3:41 - 3:45
    The CameraRig's rotation should be (40, 60, 0).
  • 3:46 - 3:49
    And the camera itself should be all zeros.
  • 3:50 - 3:52
    Just a quick mention,
  • 3:52 - 3:54
    the position that you see in the inspector
  • 3:54 - 3:57
    is the local position of that game object
  • 3:57 - 3:59
    so because our Main Camera is
  • 3:59 - 4:01
    a child of the CameraRig it's position is
  • 4:01 - 4:03
    local to the CameraRig
  • 4:03 - 4:05
    so it doesn't have any variation in
  • 4:05 - 4:08
    the X and Y coordinates but it is further back.
  • 4:08 - 4:10
    It's 60 units back,
  • 4:10 - 4:12
    but no variation in X and y.
  • 4:12 - 4:15
    Yeah, so note that our CameraRig
  • 4:15 - 4:17
    remember we said reset the position,
  • 4:17 - 4:19
    is on the ground, so I'm just going to set that
  • 4:19 - 4:20
    to global so you can see it.
  • 4:20 - 4:23
    So you see these axis handles in my scene view?
  • 4:23 - 4:24
    That's where that CameraRig is,
  • 4:24 - 4:27
    whereas the camera is all the way up here.
  • 4:28 - 4:32
    -65 back in the local Z axis,
  • 4:32 - 4:34
    so Z being blue there.
  • 4:34 - 4:36
    Now we're going to talk briefly about
  • 4:36 - 4:39
    how this camera works before we dive in to
  • 4:39 - 4:41
    any kind of scripting and functionality.
  • 4:41 - 4:44
    The first thing you need to know about is a frustum,
  • 4:44 - 4:46
    the hilariously named shape of
  • 4:46 - 4:48
    the camera's view.
  • 4:48 - 4:53
    So the frustum, in a standard perspective camera
  • 4:53 - 4:55
    looks like this.
  • 4:55 - 4:56
    So you have these two planes,
  • 4:56 - 4:58
    plane being just a flat rectangle,
  • 4:58 - 5:00
    a near clip plane and a far clip plane,
  • 5:00 - 5:04
    and between those two points is everything that you can see.
  • 5:05 - 5:07
    The difference between what we're doing with our
  • 5:07 - 5:09
    game and what you'd expect with a perspective camera
  • 5:09 - 5:11
    is with a perspective camera,
  • 5:11 - 5:13
    say you've got something up close near
  • 5:13 - 5:16
    the near clip plane.
  • 5:16 - 5:18
    When you then move that further away
  • 5:18 - 5:20
    it looks smaller compared to
  • 5:20 - 5:22
    everything that it's surrounded with.
  • 5:23 - 5:26
    Things, like in the real world, get smaller as they're further away.
  • 5:27 - 5:29
    With an orthographic camera the near
  • 5:29 - 5:31
    and far clip planes are the same size
  • 5:31 - 5:33
    so as a result you don't get
  • 5:33 - 5:37
    any change in scale over distance.
  • 5:38 - 5:40
    So what does this look like?
  • 5:40 - 5:42
    So between those two cameras you can see on the
  • 5:42 - 5:45
    left perspective and on the right orthographic,
  • 5:45 - 5:47
    and you can see that things get smaller,
  • 5:47 - 5:49
    you can see our rocks look smaller than our buildings
  • 5:49 - 5:51
    whereas really they're probably the same height.
  • 5:52 - 5:54
    Whereas in the orthographic view things remain the same.
  • 5:54 - 5:56
    So obviously this is used in a lot of
  • 5:56 - 5:58
    strategy games, if you've ever played things like
  • 5:58 - 6:01
    Command And Conquer, Red Alert, those kind of
  • 6:01 - 6:03
    old school RTS games then
  • 6:03 - 6:05
    that's the kind of view that you were looking at.
  • 6:07 - 6:09
    So the orthographic camera's size
  • 6:09 - 6:11
    is how we zoom, so keep that in mind
  • 6:11 - 6:14
    as we go through this theoretical part.
  • 6:14 - 6:16
    And we zoom by changing that size.
  • 6:16 - 6:18
    So just a quick reminder of what we were
  • 6:18 - 6:20
    looking at earlier.
  • 6:20 - 6:23
    As I change my size value for the Main Camera component
  • 6:24 - 6:26
    it zooms in and out.
  • 6:26 - 6:28
    So during the game we need to be adjusting that
  • 6:28 - 6:31
    value to zoom and then we need to be moving
  • 6:31 - 6:33
    the position of the CameraRig in order to
  • 6:33 - 6:35
    follow stuff around.
  • 6:35 - 6:37
    Slightly counter intuitive to think of it
  • 6:37 - 6:39
    but as you increase the size of the camera
  • 6:39 - 6:41
    the frustum gets bigger so more stuff
  • 6:41 - 6:43
    fits in so it looks smaller.
  • 6:43 - 6:45
    So increasing the size will zoom out.
  • 6:45 - 6:47
    Whereas decreasing the size will zoom in.
  • 6:49 - 6:51
    The other thing to know about is the camera's aspect
  • 6:51 - 6:53
    to if you're familiar with YouTube
  • 6:53 - 6:56
    or video or TV in any way then you'll know
  • 6:56 - 7:00
    what 1080p is, so 1080p just represents a screen size
  • 7:00 - 7:02
    of 1920 by 1080 pixels.
  • 7:02 - 7:04
    We think of this as an aspect ratio
  • 7:04 - 7:06
    of 16 to 9.
  • 7:06 - 7:10
    So 16:9 is our aspect based on
  • 7:10 - 7:13
    those particular sizes, so to find the aspect of that
  • 7:13 - 7:18
    being 16:9 we divide 16 by 9 and get 1.778
  • 7:18 - 7:20
    So the aspect,
  • 7:20 - 7:23
    not the aspect ratio, the aspect of this particular
  • 7:23 - 7:25
    example is 1.778.
  • 7:27 - 7:28
    So what should our camera do?
  • 7:28 - 7:30
    So those two things were just a couple of things to remember
  • 7:30 - 7:32
    for this next part, okay, so what should our camera do?
  • 7:32 - 7:34
    Well we need to follow the tanks.
  • 7:34 - 7:36
    Track wherever they're moving and
  • 7:36 - 7:38
    we need to resize, I.E. zoom
  • 7:38 - 7:40
    to fit the tanks on the screen.
  • 7:42 - 7:44
    So this is the general kind of behaviour that we're getting
  • 7:44 - 7:47
    from the camera as those tanks move apart
  • 7:48 - 7:50
    in this beautiful ballet that we see
  • 7:52 - 7:53
    the camera is zooming out.
  • 7:53 - 7:55
    The other brief thing to mentions is you notice
  • 7:55 - 7:57
    the tanks never quite get to the edge.
  • 7:57 - 8:00
    We have what we think of as a padding.
  • 8:02 - 8:04
    It's a screen edge buffer.
  • 8:04 - 8:06
    An edge buffer for the edge of the screen.
  • 8:07 - 8:09
    That's what it says.
  • 8:09 - 8:11
    And that stops the tanks ever
  • 8:11 - 8:12
    jumping off the screen.
  • 8:12 - 8:14
    So that's the behaviour that we're going for.
  • 8:16 - 8:18
    Okay, so the next thing that we're going to do is to
  • 8:18 - 8:20
    jump in to actually starting the
  • 8:20 - 8:22
    script and then we'll go a bit back to the theory
  • 8:22 - 8:24
    and then we'll carry on a bit at a time.
  • 8:24 - 8:26
    So what I want you to do is
  • 8:26 - 8:28
    look in the Scripts folder
  • 8:29 - 8:32
    and then you'll find a folder called Camera.
  • 8:32 - 8:34
    And there's one called CameraControl.
  • 8:35 - 8:37
    Drag and drop CameraControl on to
  • 8:37 - 8:40
    the CameraRig, not the Camera, the CameraRig.
  • 8:41 - 8:43
    I can't say that enough.
  • 8:44 - 8:46
    CameraRig has the CameraControl script on it.
  • 8:47 - 8:50
    Then we're going to launch that script and have a little look.
  • 8:50 - 8:53
    So double click on the name to open it up in Monodevelop
  • 8:53 - 8:55
    or Visual Studio.
  • 8:57 - 8:59
    So this time we're not going to ask you to
  • 8:59 - 9:01
    write any of the script, this one has already
  • 9:01 - 9:03
    been completed for you but we're going to
  • 9:03 - 9:05
    run through it and explain how it works.
  • 9:05 - 9:07
    We'll start off at the top again with
  • 9:07 - 9:09
    the public variables.
  • 9:09 - 9:11
    So the first one that you can see is
  • 9:11 - 9:15
    the DampTime and we've set that to 0.2.
  • 9:15 - 9:18
    So what the DampTime is is the approximate time
  • 9:18 - 9:21
    that we want to take for the camera to move
  • 9:21 - 9:23
    to the position that it's required to be in.
  • 9:23 - 9:25
    So rather than it moving instantly we're going to
  • 9:25 - 9:27
    damp that movement a little bit
  • 9:27 - 9:29
    and that's how long we want it to take roughly.
  • 9:31 - 9:34
    Then the next one we've got is that ScreenEdgeBuffer
  • 9:34 - 9:36
    that we were talking about, and all that is
  • 9:36 - 9:38
    is a number that we add to the sides to make
  • 9:38 - 9:40
    sure that the cameras aren't at the edge of the screen,
  • 9:40 - 9:41
    they're all the way on the screen.
  • 9:41 - 9:42
    The tanks.
  • 9:42 - 9:44
    Sorry, the tanks.
  • 9:44 - 9:46
    You're welcome.
  • 9:47 - 9:49
    I had to get one in!
  • 9:50 - 9:53
    Okay, so the next one is the Minimum Size.
  • 9:53 - 9:55
    So we don't want the camera to get
  • 9:55 - 9:57
    really, really, really zoomed in, it'll look silly,
  • 9:57 - 10:00
    so we set a minimum size of 6.5.
  • 10:01 - 10:04
    So next we've got a little bit of a complication thing here.
  • 10:04 - 10:06
    We've got HideInInspector commented out.
  • 10:08 - 10:10
    So the reason that that is there is later
  • 10:10 - 10:12
    we're going to come back to this script and
  • 10:12 - 10:14
    remove those comment, so this variable
  • 10:14 - 10:16
    is hidden in the inspector.
  • 10:16 - 10:18
    Currently what we want to do is set
  • 10:18 - 10:20
    our tank to be followed by the camera, so we want
  • 10:20 - 10:22
    it to be one of the targets.
  • 10:22 - 10:24
    However later the game manager is
  • 10:24 - 10:26
    going to set the targets so we don't
  • 10:26 - 10:29
    want to be able to set it in the inspector so we're going to hide it.
  • 10:30 - 10:32
    We still want it to be public because we want other
  • 10:32 - 10:34
    scripts to be able to talk to this script and say
  • 10:34 - 10:36
    'hey, okay I'm going to set those targets for you.
  • 10:36 - 10:38
    We've spawned 2 tanks, I'm the game manager
  • 10:38 - 10:40
    I've put the tanks in and I'm going to
  • 10:40 - 10:41
    tell the camera what to do'.
  • 10:41 - 10:43
    And so we want to keep it public but we'll
  • 10:43 - 10:46
    HideInInspector, so that's what that's going to do.
  • 10:46 - 10:48
    Currently it's commented out so when we test it
  • 10:48 - 10:50
    before we've set up the game manager we can still use it.
  • 10:51 - 10:53
    Okay, so it is an array of
  • 10:53 - 10:55
    transforms, that's what those square
  • 10:55 - 10:57
    parenthesis, square brackets?
  • 10:58 - 10:59
    What do you guys call those?
  • 10:59 - 11:00
    Square brackets.
  • 11:00 - 11:02
    Square brackets, of course, we'll call them that.
  • 11:02 - 11:04
    Why can't we say round brackets?
  • 11:05 - 11:07
    You guys! You're killing me.
  • 11:07 - 11:09
    Alright, so that is an array of transforms,
  • 11:09 - 11:12
    it's all of the tanks,
  • 11:12 - 11:14
    which we've called Targets.
  • 11:15 - 11:17
    Next we've got our private variables,
  • 11:17 - 11:20
    of course we need a reference to the camera so we can
  • 11:20 - 11:22
    access it's size variable and change it.
  • 11:23 - 11:26
    Then these next two variables,
  • 11:26 - 11:30
    you don't need to worry too much about them.
  • 11:30 - 11:32
    basically to damp the zooming and to damp
  • 11:32 - 11:35
    the movement we're using a function which
  • 11:35 - 11:37
    requires a reference to how fast that's happening.
  • 11:38 - 11:40
    And all we're going to do is store those
  • 11:40 - 11:42
    you don't need to worry about them, they will be used
  • 11:42 - 11:44
    by the function, and that's it.
  • 11:45 - 11:48
    The last one we've got is the DesiredPosition.
  • 11:48 - 11:52
    So that is the position that the camera is trying to reach,
  • 11:52 - 11:54
    for us that's going to be the average position
  • 11:54 - 11:56
    of the tanks.
  • 11:56 - 11:58
    We just want it to be in the middle of all the tanks
  • 11:58 - 12:00
    that we have in our game, currently we only have
  • 12:00 - 12:03
    2 tanks, so it's just going to be the centre of those 2.
  • 12:03 - 12:05
    Yeah, and we've got a quick slide just to show that.
  • 12:05 - 12:07
    So we find an average of the tank's position
  • 12:07 - 12:09
    and we're going to set that CameraRig,
  • 12:09 - 12:11
    remember the CameraRig is on the floor
  • 12:11 - 12:13
    and we're going to set it to a point between those by
  • 12:13 - 12:16
    just taking an average of their current two positions.
  • 12:16 - 12:18
    And you'll see that in the script in a little while.
  • 12:19 - 12:21
    We're also going to use that DesiredPosition
  • 12:21 - 12:23
    as the position that we want
  • 12:23 - 12:25
    to zoom based on.
  • 12:25 - 12:27
    So I'll try and explain what I mean by that.
  • 12:28 - 12:31
    If we zoom based on where the
  • 12:31 - 12:33
    camera currently is then
  • 12:33 - 12:35
    it's going to zoom to the wrong size because the
  • 12:35 - 12:37
    tanks aren't there anymore, they're moving around.
  • 12:37 - 12:40
    However if we zoom based on where the tanks are,
  • 12:40 - 12:42
    which is the average position, that DesiredPosition
  • 12:42 - 12:44
    that we want to move to then the camera
  • 12:44 - 12:46
    is going to zoom to the correct size.
  • 12:49 - 12:52
    So next we've got our awake function,
  • 12:52 - 12:54
    which we're going to use to setup the reference
  • 12:54 - 12:56
    that we need, and remember that this is
  • 12:56 - 12:58
    on the CameraRig and we're
  • 12:58 - 13:01
    trying to find a component, the camera component
  • 13:01 - 13:04
    on a child, so we're using GetComponentInChildred.
  • 13:05 - 13:07
    So ordinarily, one quick note about that,
  • 13:07 - 13:09
    if you make use of this it's going to find, just like the
  • 13:09 - 13:11
    audio source I mentioned earlier, it's going to find
  • 13:11 - 13:13
    the first one, we only have
  • 13:13 - 13:15
    one camera and one child object,
  • 13:15 - 13:17
    so it's totally fine to use this in this instance.
  • 13:17 - 13:19
    But be aware that if you're trying to find
  • 13:19 - 13:22
    specific things you might want to use another method.
  • 13:24 - 13:26
    Okay, so the next function that we have is
  • 13:26 - 13:28
    FixedUpdate and we're using FixedUpdate to
  • 13:28 - 13:30
    move the camera because our tanks are moving
  • 13:30 - 13:33
    with FixedUpdate and we want to move along with them.
  • 13:33 - 13:35
    Yeah, so we've got physics objects moving around
  • 13:35 - 13:37
    so we use the same physics function to
  • 13:37 - 13:38
    move the camera as well.
  • 13:38 - 13:40
    The camera doesn't need physics because it's,
  • 13:40 - 13:41
    you know, it's just a camera,
  • 13:41 - 13:43
    it's not going to bump in to anything,
  • 13:43 - 13:45
    but it's keeping things in sync.
  • 13:45 - 13:47
    So that's the important part to remember that.
  • 13:47 - 13:49
    So that FixedUpdate is calling our Move
  • 13:49 - 13:50
    and Zoom functions.
  • 13:50 - 13:52
    For now we're just going to go through moving
  • 13:52 - 13:55
    and then we'll try and address
  • 13:55 - 13:57
    how the zooming is going to work and then we'll
  • 13:57 - 13:59
    come back to the script and go through that then.
  • 14:00 - 14:02
    So the first thing that happens in Move
  • 14:02 - 14:06
    is it calls this function FindAveragePosition.
  • 14:07 - 14:09
    And then once it's found that average position
  • 14:09 - 14:11
    it's going to set the DesiredPosition to that.
  • 14:11 - 14:13
    And then what we're going to do
  • 14:13 - 14:15
    is use the SmoothDamp function
  • 14:16 - 14:18
    to smoothly move the
  • 14:18 - 14:20
    camera between it's current position
  • 14:20 - 14:22
    and the DesiredPosition.
  • 14:22 - 14:25
    So then we've got this ref m_MoveVelocity
  • 14:25 - 14:27
    that was the variable that we talked about
  • 14:27 - 14:28
    that we don't really need to know about.
  • 14:28 - 14:30
    Ref means that it's going to write
  • 14:30 - 14:32
    back to that variable.
  • 14:32 - 14:34
    So it's taking in how fast it's currently moving,
  • 14:34 - 14:36
    it's going to do some more movement and then
  • 14:36 - 14:39
    reset that variable to how fast it's now moving.
  • 14:39 - 14:41
    The last parameter is the DampTime.
  • 14:43 - 14:45
    So that's how long it's going to take, approximately.
  • 14:46 - 14:49
    So let's look at the FindAveragePosition function.
  • 14:51 - 14:53
    So for that what we're going to do is
  • 14:53 - 14:57
    create a vector3 which is blank to start off with.
  • 14:57 - 14:59
    So that's what that new Vector3 thing is
  • 14:59 - 15:01
    doing there, it's just saying 'create a new one',
  • 15:01 - 15:03
    but leave it blank.
  • 15:03 - 15:05
    Them we've got an integer for the number
  • 15:05 - 15:07
    of targets that we're averaging over,
  • 15:07 - 15:10
    and by default we're not averaging over any
  • 15:10 - 15:12
    targets so we'll set that to 0 as well.
  • 15:14 - 15:16
    So next what we're doing is
  • 15:16 - 15:17
    we're using a for loop.
  • 15:17 - 15:20
    So this for loop is creating an integer called i
  • 15:21 - 15:23
    which is known as an iterator.
  • 15:23 - 15:25
  • 15:25 - 15:28
    i is less than that target's length.
  • 15:29 - 15:32
    And for each loop that it does it's going to add 1 to i.
  • 15:33 - 15:35
    So basically remember that the
  • 15:35 - 15:37
    Targets is our list of tanks,
  • 15:37 - 15:39
    so if this game was extended for more than
  • 15:39 - 15:42
    2 players it would have that many
  • 15:42 - 15:43
    in it's list of targets.
  • 15:43 - 15:45
    So if you think of m_Targets as just
  • 15:45 - 15:48
    a list and we just say 'okay, we'll loop through every single
  • 15:48 - 15:52
    tank that we find in that array of targets
  • 15:52 - 15:54
    and then we'll do somethings
  • 15:54 - 15:56
    which are inside that for loop'.
  • 15:56 - 15:58
    So this is a very standard
  • 15:58 - 16:00
    way of using for loops.
  • 16:00 - 16:02
    You have your iterator,
  • 16:02 - 16:04
    starting off at 0, going through an array
  • 16:04 - 16:06
    until it's as large as it's length.
  • 16:07 - 16:09
    Okay, so in that loop the first thing that
  • 16:09 - 16:11
    we want to do is check if the
  • 16:11 - 16:13
    Target's game object is active.
  • 16:14 - 16:16
    So when a tank dies, what we're going to do is deactivate it.
  • 16:18 - 16:20
    So we don't want to be trying to
  • 16:20 - 16:23
    zoom in on a deactivated tank so
  • 16:23 - 16:25
    we're only doing these things if the tank is active.
  • 16:26 - 16:27
    So what this line is saying is
  • 16:28 - 16:31
    if the tank is not active
  • 16:31 - 16:33
    so that's that ! there,
  • 16:34 - 16:36
    then continue, and continue in this case
  • 16:36 - 16:39
    is continue on to the next iteration of the loop.
  • 16:39 - 16:42
    So we'll go back to here and do the next thing.
  • 16:42 - 16:44
    The important part here is that you'll notice
  • 16:44 - 16:47
    that we've got m_Targets[i],
  • 16:47 - 16:50
    so it's basically taking that entry in the list.
  • 16:50 - 16:52
    So i will start off at 0 and then
  • 16:52 - 16:54
    every array that you do in
  • 16:54 - 16:56
    programming will start at 0 as well,
  • 16:57 - 17:00
    and you can iterate one at a time,
  • 17:00 - 17:02
    so the second time it goes through this will be 1,
  • 17:02 - 17:05
    the third time it will be 2, and 3, and so on.
  • 17:05 - 17:08
    So it's basically saying 'this particular entry in the list,
  • 17:08 - 17:11
    is the game object it's attached to active?
  • 17:11 - 17:13
    Or is it not?'
  • 17:13 - 17:15
    We're specifically looking for it not to be
  • 17:15 - 17:17
    and then we continue to look for the next
  • 17:17 - 17:19
    entry in the list.
  • 17:19 - 17:22
    But if it is then we carry on
  • 17:22 - 17:24
    and we carry out these other instructions.
  • 17:24 - 17:26
    Because we need the camera to be populated
  • 17:26 - 17:29
    with how many tanks it can find right now
  • 17:29 - 17:31
    and the actual upshot of this is that the
  • 17:31 - 17:34
    end of the round, when you've got one tank that's
  • 17:34 - 17:36
    been disabled and one left is the camera will
  • 17:36 - 17:38
    zoom in on the tank that won the round.
  • 17:38 - 17:41
    So it's kind of doing both functions for us.
  • 17:41 - 17:43
    Okay so assuming that we're on a
  • 17:43 - 17:45
    tank that is active, what we're going to do is
  • 17:45 - 17:48
    add that tank's position
  • 17:48 - 17:51
    to the average position, so that's that +=.
  • 17:51 - 17:53
    So what that's doing is saying 'take the average position,
  • 17:54 - 17:57
    add the average position to this new position
  • 17:57 - 17:59
    and assign it to the average position again'.
  • 17:59 - 18:01
    That's the +=.
  • 18:02 - 18:04
    And then we need to increment how many tanks
  • 18:04 - 18:06
    that we know there are, so number of targets
  • 18:06 - 18:08
    that we've currently got.
  • 18:09 - 18:11
    Okay so we've added all of the
  • 18:11 - 18:13
    active tanks to this average position,
  • 18:13 - 18:15
    we've counted how many active tanks that there are.
  • 18:16 - 18:18
    Now we're outside of the loop we can say
  • 18:18 - 18:21
    if there are some active targets,
  • 18:21 - 18:23
    if the number of targets is greater than 0,
  • 18:23 - 18:26
    then divide that average position by how many there is.
  • 18:26 - 18:28
    You know, in an ordinary instance with our game
  • 18:28 - 18:30
    there is 2 players, all it's going to do is say
  • 18:30 - 18:33
    'okay, I've found one tank, I've taken it's position,
  • 18:33 - 18:35
    added it to the average and incremented how many
  • 18:35 - 18:37
    tanks are found, we've found two
  • 18:37 - 18:39
    so we've got those two together
  • 18:39 - 18:41
    and we've just divided it by 2 and therefore
  • 18:41 - 18:44
    we've got the position that's between those two points'.
  • 18:44 - 18:46
    And then the last thing that we do before we
  • 18:46 - 18:48
    actually set it is just to say
  • 18:48 - 18:51
    'okay, well we don't want to change the Y position'
  • 18:52 - 18:54
    so we say the Y component of the average
  • 18:54 - 18:57
    set that equal to transform.position.y
  • 18:57 - 18:59
    so remember that this is attached to the rig
  • 18:59 - 19:01
    so it's going to inherit that 0 and keep the
  • 19:01 - 19:03
    position definitely at the ground for
  • 19:03 - 19:05
    where ever that rig is moving.
  • 19:05 - 19:07
    So you should note that that is just a little
  • 19:07 - 19:09
    safety check just to make sure it doesn't go
  • 19:09 - 19:11
    off the ground because the tanks have all got
  • 19:11 - 19:13
    their Y position frozen, if you remember we
  • 19:13 - 19:15
    had the constraints on the rigidbody
  • 19:15 - 19:17
    so they shouldn't be moving up and down.
  • 19:18 - 19:19
    Just in case something goes wrong,
  • 19:19 - 19:21
    somebody puts in a piece of code that moves the tank
  • 19:21 - 19:23
    up and down or something we want to make sure
  • 19:23 - 19:25
    that the camera does not move up and down.
  • 19:26 - 19:27
    So it'll probably never happen,
  • 19:27 - 19:28
    but that's what that's there for.
  • 19:28 - 19:30
    And then finally we're setting the DesiredPosition
  • 19:30 - 19:32
    to that average position.
  • 19:34 - 19:36
    Okay, so let's talk about zooming.
  • 19:36 - 19:38
    Following the tanks is easy, it's just taking
  • 19:38 - 19:40
    the average of two positions
  • 19:40 - 19:42
    and you've got one in the centre.
  • 19:42 - 19:44
    So what about zooming?
  • 19:44 - 19:47
    This is our typical kind of camera view,
  • 19:47 - 19:49
    it's what the camera looks like at the
  • 19:49 - 19:51
    start and what we've designed so far.
  • 19:52 - 19:54
    So what do we know? Well we know that the height
  • 19:54 - 19:56
    from the centre is the size, and we know that
  • 19:56 - 19:58
    the size is what we use to zoom.
  • 19:59 - 20:01
    And we know that the distance from the centre
  • 20:01 - 20:04
    to the right hand edge is that size value
  • 20:04 - 20:06
    multiplied by the aspect, so we gave you an
  • 20:06 - 20:09
    example of aspect earlier, which was that 16:9.
  • 20:10 - 20:13
    But this being our CameraRig
  • 20:13 - 20:15
    we need to make sure that that tank is
  • 20:15 - 20:17
    within the size, so we know that
  • 20:17 - 20:19
    we can see it on the screen if that's true.
  • 20:20 - 20:22
    So this access handle that you can see
  • 20:22 - 20:24
    is our CameraRig pointing down in to the world.
  • 20:25 - 20:29
    That's the CameraRig's local axis.
  • 20:29 - 20:32
    So in an example where our tank is at the top there,
  • 20:33 - 20:36
    we can say that this distance in the Y axis
  • 20:36 - 20:38
    is also the same as the size, so we know
  • 20:38 - 20:40
    distance in Y axis is the same as the size.
  • 20:41 - 20:43
    So we know that if that tank gets further
  • 20:43 - 20:45
    than the amount of our size we
  • 20:45 - 20:47
    probably need to zoom out.
  • 20:47 - 20:49
    And the same goes for if it's going
  • 20:49 - 20:51
    off the side of the screen
  • 20:51 - 20:53
    We know that this distance here is the distance in
  • 20:53 - 20:55
    the X axis for our camera,
  • 20:56 - 20:58
    and that's also the size times the aspect.
  • 20:59 - 21:02
    So those are the two important factors that we know
  • 21:02 - 21:03
    to keep it on screen.
  • 21:03 - 21:05
    So what we want to do is say
  • 21:06 - 21:08
    'well we know where the tanks are,
  • 21:08 - 21:10
    relative to the camera, we can work that out.
  • 21:11 - 21:13
    So we can calculate a size based on it
  • 21:14 - 21:18
    in the Y axis, we can calculate a size based on the X axis,
  • 21:18 - 21:20
    we can go through all the tanks, find out all the sizes it could be,
  • 21:20 - 21:22
    pick the largest one, then the tanks are
  • 21:22 - 21:24
    all definitely going to be on the screen'.
  • 21:25 - 21:26
    So you'll notice in this sum we're saying distance is
  • 21:26 - 21:28
    distance is the same as size times aspect.
  • 21:28 - 21:30
    But we know that on the camera we can just
  • 21:30 - 21:32
    tweak the size to zoom, so we just need to
  • 21:32 - 21:34
    reverse that equation so it's just
  • 21:34 - 21:37
    distance divided by aspect gives us our size.
  • 21:38 - 21:40
    Okay, so let's go back to the script and talk about
  • 21:40 - 21:43
    how this zooming works in code terms.
  • 21:43 - 21:45
    Okay, so you'll notice this looks
  • 21:45 - 21:48
    pretty similar to the Move function.
  • 21:48 - 21:52
    First off we're finding the required size and then we're
  • 21:52 - 21:54
    smoothly damping towards that size.
  • 21:54 - 21:56
    Yeah, so orthographicSize is size,
  • 21:56 - 21:58
    so that's just the API for that
  • 21:58 - 22:00
    value that you saw in the inspector where you saw I was
  • 22:00 - 22:02
    changing size and it was zooming,
  • 22:02 - 22:04
    orthographicSize is that number.
  • 22:04 - 22:06
    So we've got the function that's finding that
  • 22:06 - 22:07
    size and it's returning it,
  • 22:07 - 22:10
    we're storing it in the float called RequiredSize.
  • 22:11 - 22:13
    We're using the MathF.SmoothDamp function
  • 22:14 - 22:17
    to go between the camera's current
  • 22:17 - 22:20
    orthographic size and the required size.
  • 22:20 - 22:22
    And like we did before with moving we need a
  • 22:22 - 22:24
    reference to the ZoomSpeed,
  • 22:24 - 22:27
    like we had with the reference to the MoveSpeed, MoveVelocity,
  • 22:28 - 22:30
    and that's going to happen over the same period
  • 22:30 - 22:32
    of time so we're giving it the same DampTime.
  • 22:33 - 22:35
    So the camera is going to move and
  • 22:35 - 22:36
    zoom over the same period of time.
  • 22:36 - 22:38
    If you don't have the same it's going
  • 22:38 - 22:39
    to look really funky.
  • 22:39 - 22:42
    So now the dreaded FindRequiredSize function.
  • 22:43 - 22:45
    First off, remember we want to
  • 22:45 - 22:48
    find it from the DesiredPosition of the camera
  • 22:48 - 22:50
    not from the current position of the camera.
  • 22:51 - 22:53
    So what we're doing is we're finding the
  • 22:53 - 22:55
    DesiredPosition of the camera in the
  • 22:55 - 22:58
    CameraRig's local space.
  • 22:58 - 23:00
    So do you remember that we had that slide where you
  • 23:00 - 23:03
    had the Y axis and the X axis shown?
  • 23:03 - 23:05
    What we're doing is we're finding the DesiredPosition
  • 23:05 - 23:07
    of the camera in that space,
  • 23:07 - 23:09
    so it might be up a little bit and right a little bit.
  • 23:09 - 23:11
    Something like that.
  • 23:11 - 23:14
    Then what we're doing is we're
  • 23:14 - 23:16
    creating a size variable, which we're
  • 23:16 - 23:18
    starting off at 0.
  • 23:18 - 23:20
    And as we go through all the tanks
  • 23:20 - 23:23
    we're going to find all the sizes that it could be
  • 23:23 - 23:25
    and at the end pick the largest size.
  • 23:25 - 23:27
    So you basically want to say that
  • 23:27 - 23:29
    'we've got 2 tanks and which ever one is furthest away
  • 23:29 - 23:32
    we want to zoom to accommodate that one
  • 23:32 - 23:34
    and therefore we'll capture all of them'.
  • 23:34 - 23:36
    Okay, so like we did before we're
  • 23:36 - 23:38
    looping through all the targets.
  • 23:39 - 23:41
    So going through all the tanks
  • 23:42 - 23:44
    from 0 to just before the length.
  • 23:46 - 23:49
    And again if that target is not active
  • 23:49 - 23:51
    continue on to the next target.
  • 23:51 - 23:54
    So we go back to the loop, keep looking until we find
  • 23:54 - 23:57
    a tank that is active and do something about it.
  • 23:57 - 23:59
    Next what we're doing is finding that target
  • 23:59 - 24:01
    in the local position of the camera rig.
  • 24:01 - 24:04
    So you'll remember in that local space we
  • 24:04 - 24:06
    want to find it up and across,
  • 24:07 - 24:09
    but the world space doesn't look like that,
  • 24:09 - 24:11
    that's just the CameraRig's local space.
  • 24:11 - 24:13
    So what we're doing is we're saying
  • 24:13 - 24:15
    'okay, so the tank that was at the top of the
  • 24:15 - 24:18
    screen in the CameraRig's local space
  • 24:18 - 24:20
    is just going to be some value in Y,
  • 24:20 - 24:22
    if it's on the right of the screen it's going to be some value in X'.
  • 24:23 - 24:26
    So the next bit, we've found the DesiredPosition of the CameraRig
  • 24:26 - 24:28
    in the CameraRig's local space
  • 24:28 - 24:31
    and we found the tank in the CameraRig's local space
  • 24:31 - 24:33
    but remember we want to do this from the
  • 24:33 - 24:36
    DesiredPosition of the camera.
  • 24:36 - 24:38
    But this is quite tricky to get your head around,
  • 24:38 - 24:40
    but imagine those slides that we saw with the tank
  • 24:41 - 24:42
    on screen
  • 24:42 - 24:44
    imagine instead of that being the CameraRig,
  • 24:44 - 24:47
    that's the CameraRig's desired position, that's all that's happening here.
  • 24:47 - 24:50
    So now we've found that vector, from the CameraRig's
  • 24:50 - 24:52
    DesiredPosition to the tank
  • 24:52 - 24:54
    and we're going to calculate the size.
  • 24:54 - 24:58
    So we're saying the size is the maximum of
  • 24:58 - 25:00
    it's current value
  • 25:00 - 25:02
    or this new value that we're calculating.
  • 25:02 - 25:05
    Absolute value of the Y axis of that vector.
  • 25:06 - 25:09
    So the reason again it's the absolute value is that
  • 25:09 - 25:11
    if the tank was at the bottom of the screen you don't want
  • 25:11 - 25:13
    a negative value for size, you still want a positive value,
  • 25:13 - 25:15
    we're only interested in the distance,
  • 25:15 - 25:17
    not whether it's positive or negative.
  • 25:18 - 25:21
    And again for the X axis,
  • 25:21 - 25:23
    we want to choose whether it's the size that'
  • 25:23 - 25:27
    the largest or this Mathf.Abs
  • 25:27 - 25:31
    of the X value of that vector, the X component
  • 25:31 - 25:33
    divided by the aspect, because remember from
  • 25:33 - 25:35
    left to right it's size
  • 25:35 - 25:40
    multiplied by aspect, so to find size it's distance divided by aspect.
  • 25:40 - 25:43
    So one key point to mention here is we've got two
  • 25:43 - 25:46
    things that look like they're doing the same thing to this size variable.
  • 25:46 - 25:49
    They're not, they're basically deciding which is bigger.
  • 25:49 - 25:52
    So we're saying 'is the size currently
  • 25:54 - 25:56
    bigger than this Y distance'
  • 25:56 - 25:58
    and then it'll return whatever that is
  • 25:58 - 26:00
    so then size the second time around
  • 26:00 - 26:03
    is currently set to the biggest value of those two,
  • 26:03 - 26:05
    then we're then comparing whether it's
  • 26:05 - 26:07
    currently bigger than the Y value.
  • 26:07 - 26:09
    So we're just finding that distance away and saying
  • 26:09 - 26:13
    'okay, well X or Y, are they bigger, okay well that one is',
  • 26:13 - 26:16
    and then size is naturally returning that because
  • 26:16 - 26:18
    Max just picks which ever one is bigger
  • 26:18 - 26:20
    and saves it back to that variable.
  • 26:20 - 26:24
    So by this time size is currently the furthest value.
  • 26:24 - 26:27
    Then we just add on the ScreenEdgeBuffer,
  • 26:27 - 26:29
    just to give it a bit of extra distance so that the
  • 26:29 - 26:31
    tanks will definitely fit in to the zoom.
  • 26:32 - 26:34
    And then finally.
  • 26:34 - 26:36
    Finally what we'll want to do is make sure
  • 26:36 - 26:38
    that we're not too zoomed in
  • 26:38 - 26:40
    so we want to apply that minimum size.
  • 26:40 - 26:43
    So we're choosing the maximum
  • 26:43 - 26:45
    of the current size that we calculated
  • 26:45 - 26:47
    or the minimum size.
  • 26:47 - 26:50
    So if size is still 0 because it's so zoomed in
  • 26:50 - 26:54
    then we'll choose 0 or 6.5, we'll choose 6.5.
  • 26:54 - 26:56
    Yeah, so minimum size remember was 6.5,
  • 26:56 - 26:58
    we don't want it to zoom in too much,
  • 26:58 - 27:01
    because you would just not be able to see anything properly.
  • 27:01 - 27:03
    So we find an absolute minimum that it can be
  • 27:03 - 27:05
    and make sure that that's the case.
  • 27:06 - 27:08
    And finally we have a return at the bottom,
  • 27:08 - 27:10
    so this function will actually return something,
  • 27:10 - 27:12
    so it's returning that value, so where ever we see
  • 27:12 - 27:17
    the FindRequiredSize used, so that's here in the Zoom function,
  • 27:17 - 27:20
    then it's getting that value returned out of it.
  • 27:21 - 27:24
    And the last part of this wonderful script is
  • 27:25 - 27:27
    SetStartPositionAndSize.
  • 27:27 - 27:31
    Okay, so a quick thing to note is this is a public function.
  • 27:31 - 27:33
    So it can be called from outside of the script.
  • 27:33 - 27:36
    What we're going to use this function for is
  • 27:36 - 27:38
    when we've got a game manager we're resetting
  • 27:38 - 27:41
    the scene at every round
  • 27:41 - 27:43
    but we don't want the camera to smoothly move to that
  • 27:43 - 27:45
    new position, we just want it to
  • 27:45 - 27:47
    find the right size, find the right position and set straight to those.
  • 27:48 - 27:50
    So that's what we're doing here, we're finding the average
  • 27:50 - 27:53
    position, setting the Transform.Position straight to that.
  • 27:53 - 27:56
    And then with the Camera.OthrographicSize
  • 27:56 - 27:59
    finding the RequiredSize setting and straight to no SmoothDamp.
  • 28:00 - 28:01
    Okay, if you understood all that
  • 28:02 - 28:04
    you're awesome.
  • 28:04 - 28:06
    So we appreciate that this is a difficult and
  • 28:06 - 28:08
    confusing concept, like we said before
  • 28:08 - 28:11
    there's a commented version of this script
  • 28:11 - 28:13
    in the Completed folder, so do have a look at that afterwards.
  • 28:14 - 28:17
    And so let's go back to our slides.
  • 28:17 - 28:19
    So the CameraRig is what we need
  • 28:19 - 28:21
    to actually assign these targets to, so currently
  • 28:21 - 28:23
    we've got one target, one tank.
  • 28:23 - 28:24
    Okay?
  • 28:24 - 28:27
    So what we're going to do is go back to Unity.
  • 28:27 - 28:29
    What you'll have noticed is that we've got a
  • 28:29 - 28:31
    Targets array because of the
  • 28:31 - 28:33
    square brackets that we had in the script.
  • 28:33 - 28:36
    So that gives us an expandable arrow,
  • 28:36 - 28:38
    so if I expand that I can see Size 0.
  • 28:38 - 28:40
    So that array currently doesn't have any
  • 28:40 - 28:42
    items that we can put in to it.
  • 28:43 - 28:46
    What we could do is we could give it a size of 1 and assign it,
  • 28:46 - 28:48
    but a quick way to assign things
  • 28:48 - 28:50
    is to drag on the thing you want,
  • 28:50 - 28:52
    so I'm going to drag Tank, and you see when I hover
  • 28:52 - 28:54
    over the word Targets it gives me a little
  • 28:54 - 28:57
    green + icon, I can let go
  • 28:57 - 29:00
    and it will populate that with a 1 and assign the tank
  • 29:00 - 29:03
    to the first element in that list.
  • 29:04 - 29:06
    Okay, so one more time.
  • 29:07 - 29:08
    Here's selecting the CameraRig,
  • 29:08 - 29:10
    You can see Targets is here, it doesn't need to be
  • 29:10 - 29:12
    expanded, it doesn't matter if you do or not.
  • 29:12 - 29:14
    But we're going to just drag the tank,
  • 29:14 - 29:16
    which is our target for the camera to look at.
  • 29:17 - 29:20
    Drop it on to the word Targets, let go, and you should see
  • 29:20 - 29:24
    you've got a size of 1 and Tank is listed in there.
  • 29:24 - 29:26
    Just to remind you, in the brackets there,
  • 29:26 - 29:28
    in the parenthesis next to Tank I should say,
  • 29:28 - 29:31
    we have Transform, that's the type that it's looking for.
  • 29:31 - 29:35
    So with the tank, the position is stored in the transform component
  • 29:35 - 29:37
    so we just look up that position
  • 29:37 - 29:40
    via that and so that tank is the reference it's got.
  • 29:40 - 29:42
    Later when we have a game manager
  • 29:42 - 29:44
    we will hide this Targets variable
  • 29:44 - 29:46
    in the inspector, we'll uncomment that line
  • 29:46 - 29:48
    that says HideInInspector and that will
  • 29:48 - 29:50
    disappear from the inspector totally.
  • 29:50 - 29:52
    The game manager will then populate that list for us.
  • 29:54 - 29:56
    Cool. Save your scene.
  • 29:58 - 30:01
    Okay, so we should now be able to play our scene.
  • 30:02 - 30:04
    And drive around, it should look like this.
  • 30:04 - 30:06
    We can now explore our wonderful world.
  • 30:07 - 30:09
    of the desert.
Title:
TANKS! Unity Tutorial - Phase 3 of 8 - Camera Control
Description:

more » « less
Video Language:
English, British
Duration:
30:11

English subtitles

Revisions