[MUSIC PLAYING]
COLTON OGDEN: All right.
Welcome back to GD50.
This is Lecture 8.
Today we're going to be
diving into the world of Unity
for the first time,
which I'm excited about.
Going to be a whirlwind tour, but
I'll try to cover as much as possible.
Transitioning away from 2D and away
from Lua and LOVE 2D into 3D and C#
in the context of Unity.
Today we'll be talking
about Helicopter Game 3D.
So Helicopter Game is a 2D game
that was really famous in the 2000s.
It was a web game.
I was sponsored on a bunch of websites.
Addictinggames.com
still has it on there,
and a few other websites have it.
It was a flash game.
But I remember playing it a lot.
It was the old precursor
to Flappy Bird, which
was mentioned on the Wikipedia page.
There's a reference to it there.
And this is what the
game play looked like.
It was very similar to Flappy
Bird-- a little bit different
in that, instead of trying to
avoid pipes, you're in a cave,
and you're trying to avoid the
ceiling and the ground of the level.
And there were these little obstacles
that would spawn in the middle,
as well.
So you'd have to navigate that.
But it was the same exact mechanic--
the sort of like, click to go up.
And then, when you didn't
click, your helicopter
would just sink down via gravity.
Today we'll be talking about a bunch
of brand new topics, things like Unity,
first and foremost-- the ecosystem
with which we'll be doing
a lot of the things we'll be doing.
C# is the primary
language we'll be using.
So we're going to take a step away
from dynamic languages and move towards
statically-typed languages--
languages like C#, and
Java, and the like.
Blender is a program we'll
look at briefly today,
just because, in the
context of 3D development,
you're going to want to have a tool
that will let you create models.
And so the 3D software that I like
to advocate for the most, especially
for folks that are just starting
out, is Blender, because it's free,
and open source, and it
has much the same feature
set as any commercial software,
like 3D Studio Max, and Cinema 4D,
and the like.
We'll talk about what components
are-- entities and components, how
they relate in this model that Unity
has adopted for all of its programming.
Components are little pieces
of behavior that you can then
combine to form a whole, that will then
drive the behavior of whatever object
in your scene you want,
rather than having
to customize its behavior via a long
chain of inheritance and instantiation.
Colliders and triggers
are important in 3D--
and 2D.
But today we'll be
talking about colliders
and triggers-- things
like the helicopter
colliding with coins, and buildings,
and other planes that are flying.
Each of those has to have a collider.
And certain things have to be
considered triggers in order to trigger
certain behavior with other entities.
Prefabs and spawning-- prefabs
is a huge concept in Unity.
So prefabs are basically
prefabricated objects
that you can customize as you want
to-- lay them out in the editor,
rather than having to
necessarily code all the details.
And then you can instantiate
them in the actual scene,
via code programmatically, in a way
that fits the model you're striving for.
Texture scrolling is something
we'll look at briefly, because it's
the way that we accomplish the infinite
scrolling aesthetic or behavior.
And we'll look at how we can
do that in a different way
than we've done before,
using u-v coordinates,
and specifically looking
at materials, and modifying
certain attributes of those materials.
And lastly, to tie everything
together as we've done before,
we'll look at audio-- things like
audio listeners and audio sources--
what the difference is
between them, and how
to add them easily to our game project.
But first, a demo-- if
there would be anybody
willing to come up and take a look
and play the 3D helicopter game that I
put together, that would be awesome.
Anybody?
Steven?
Awesome.
Thank you so much.
Let me go ahead and actually get it--
so I've pre-built it.
So let me go ahead and.
So the nice thing about Unity is,
it exports to multiple platforms.
And right out of the
gate, you can get just a--
I didn't put an icon for it.
But you can create just a
native application very easily.
And so whenever you're
ready, go ahead and hit Play,
and Up and Down will
move your helicopter.
So this is the 3D helicopter game.
And I don't think we have sound
live, but there should be audio.
Oh, I might have actually-- here we go.
[MUSIC PLAYING]
There we go.
That was my bad.
So there is music playing.
There's sound effects.
So notice that we have a 3D model.
This is what's called a 2.5D game.
So even though everything is in 3D--
the models and so forth--
the actual axes upon which
we're bound are just two.
We're just bound to, I
believe, the x and the y.
Could be the z and the x.
I don't recall offhand.
But we're bound to just
simply two axes of movement.
But all the models, as
we can see by the camera,
are in 3D, including our helicopter.
So we have a few things going on.
We have skyscrapers
that are scrolling by.
We have coins that are also going by
at the same speed as the skyscrapers.
We have a background that
is infinitely scrolling.
We have, of course, our helicopter
which has a rotating set of blades.
And when we collide with a coin,
notice that we get a little--
it might be hard to see in house,
but we have a little particle
effect that plays.
There's airplanes that
are flying up top,
so we're instantiating those,
as well, to fly past us
to provide another layer of obstacle.
And if we collide with an airplane,
notice that we get de-spawned,
and then we trigger another particle
effect to imitate an explosion.
And then, notice we also have
a couple of other elements.
We have a GUI.
We have two GUI elements-- a
coin total at the top right,
and then a game over here in
the middle of the screen, which
only shows up once we have died.
And the explosive behavior-- if you
want to collide with a building,
you'll see that.
It also triggers when you
collide with a building.
So there's two things looking for these
explosions-- the airplanes up top,
and the buildings below.
Those are our two obstacles.
But when they collide with the coins,
we should increment our coin total,
and then display a
different particle effect.
And then this goes on ad infinitum.
You can press Space to restart.
So we have keyboard input
that's based on what
we press, different things happen.
And so that's effectively the
demo that I've put together today.
So thanks, Steven.
I appreciate you coming up to demo it.
So that's the 3D helicopter game.
It's got most of the same mechanics
as the web version from before--
I would say, maybe even more features
just to illustrate a few new concepts.
But that's effectively what
we're going with today.
We're just a pretty simple, Flappy
Bird esque differently-themed game,
based on the same principles.
Fly forever, avoid obstacles.
And in this case, even
get little collectibles.
And so notice that there are
also effectively two states
in our game, which are just the playing
state, and then the game over state.
The two are almost effectively the same.
The only real difference is that one
doesn't have the helicopter present,
and displays a different GUI
element in the middle of the screen.
If you haven't downloaded Unity
already, there's two links here.
So the top link is just
the catchall download link.
And then the second
link is the beta link.
So we're actually using
the beta in this course,
because Unity has started
transitioning away
from a numerical system
for their releases,
and is now going yearly
with their releases.
So the last long-term release
candidate was 2017's version.
But now that we're almost
halfway through 2018,
the newest beta is the 2018 version.
It has a bunch of new features.
So go ahead and check that out.
And everything's been well
tested, and runs very well--
very smoothly on Windows and Mac--
with the new beta.
So what is Unity?
The difference between what we've done
so far and what we're doing today is,
now we're actually using a
full-fledged game engine--
this system.
It's got a built in editor
and all this awesome, cool
functionality that we really
didn't get with Love2D before.
What we were doing before
was using a framework,
and just implementing
everything purely in code.
And as we'll see today, everything
that you want to do that's customizable
effectively is--
or can be-- done via code.
But there are a lot of more
efficient and more user-friendly
ways to accomplish the same
thing, which we'll take a look at.
So Unity has a tremendous
market share right now.
I forget.
I think in 2016 it had like 43% of
all games released were done in Unity.
I don't know what the
current numbers are.
I couldn't find them.
But there are other engines
that are also very well used--
Unreal being among them.
And Unreal actually may
have more market share now,
because of games like
Fortnite, and because it's
been improved a lot over the last couple
of years, and really marketed well.
But Godot, CryEngine-- there
are a lot of game engines
that are similar to
this that provide you
this all-encompassing way of
dealing with your game scene
and with all your game data.
But Unity is a very easy engine
to start getting used to,
and cranking things out,
and being productive with,
without the tremendous
learning curve that some
of the other engines
like Unreal might have.
Unreal does have a more
user-friendly way of doing things.
But if you want to get down into
the nitty gritty with Unreal,
you're coding in semi-arcane C++.
So for folks who aren't used to it and
aren't used to 3D game development,
it can be kind of a
large board to get onto.
The nice thing about
Unity, aside from the fact
that it's fairly easy to get
started with, is that it's free.
And you can use it completely
with all of its features
until you start making over $100,000 in
gross revenue releasing Unity products.
And then there are other tiers.
The next tier above that is
if you start making $200,000,
and you get new features
with these other tiers.
But if you want to just
start up a new company,
and use Unity, and take
something to market--
completely free to do so.
And once you get over $100,000,
that's a good problem to have.
It's not necessarily
too much to ask to start
paying Unity to use it
as a means of getting
onto the market in the first place.
And especially in mobile and VR,
Unity's sort of like the forefront.
It's got even higher percentage.
It's like 60-something or
70% market share on mobile.
And then VR-- from the beginning,
it's marketed itself very strongly
towards the use of VR.
And we'll actually use
VR in the next lecture.
And the way in which we will accomplish
all of the programmatic aspect
of this-- getting things
actually implemented in code--
is via C#, which is very different
than what we've used so far,
which we've used Lua, which is
a dynamic scripting language,
very much like JavaScript.
So C# is very similar to Java, in
which things actually have types.
And so here's a couple of screenshots
of what the Unity editor looks like.
So the nice thing about the
Unity editor, actually--
which we can see right
off the gate here--
is that it's very customizable.
So on the top, that's the default view.
You have a bottom panel that
shows you all your resources,
all your assets, things like
scripts, and shaders, and models,
and textures, and sounds.
You have a nice file browser there
on the left-hand side, which allows
you to easily navigate your project.
You don't have to go looking through
your Windows or Mac computer, using
your finder, or whatnot,
or your File Explorer,
and actually look
through all your files.
You get a nice view there,
so that you stay integrated
within the Unity ecosystem right there.
On the right-hand side, you can see
all the behavior for whatever objects
you might have in your scene.
You get a nice big scene view.
So rather than having to
run your game live, and look
at the behavior that
way, you can actually
see in advance what your
scene looks like, and analyze
your game objects that
way, and their appearances,
and whatever you want to do with them.
And lay them out
perfectly, rather than have
to programmatically figure things out.
And on the left-hand
side there, you can see
a full list of all the game objects.
And then on the bottom
right screen shot,
you can see that the editor
is heavily customizable.
So you can lay things
out however you want
to to fit your style of development.
I often like to have a panel on
top, which shows me my scene view,
but then have a panel right below
that, that shows me the game view.
So if I'm actually running a
game and seeing it happen live,
I can also see it in the scene,
and rotate around in this god mode
that you can get in a lot of games.
And actually analyze
and see things that way,
and analyze their
behavior frame by frame,
even if I want to, in a way
that's not possible with however
I might have coded the camera
in the actual game itself.
So C#.
So has anybody in here
used a static language,
or is familiar with
statically-typed languages
versus dynamically-typed languages?
[INAUDIBLE], Steven.
So what languages have you guys
used, just out of curiosity?
Steven.
STEVEN: Java, C, C++.
COLTON OGDEN: Java, C, C++.
Donny?
DONNY: [INAUDIBLE]
COLTON OGDEN: C and C++.
OK.
So to you guys, this
will be pretty similar.
So C# is very similar to Java.
Almost looks identical at first glance.
There are some features
that are different.
But it was Microsoft's
initiative to compete with Java.
It's a Microsoft language,
first and foremost.
But there are ways to run
C# code on other platforms,
primarily with the use
of what's called Mono.
So Mono is an open source implementation
of what's called the CLR--
the common language runtime--
which is how Microsoft allows several
of its languages, like F#, and C#,
and Visual C++, Visual Basic.
They all compile to this
intermediary format,
like how Java compiles to bytecode.
And you can run any of
those languages' code--
their version of the
bytecode-- with the CLR.
Mono-- what Mono is,
and what Unity relies on
to allow its use across
multiple operating systems,
is a CLR that's not
just Windows specific.
It actually runs on Mac and
on Linux machines, as well.
And you'll actually see evidence of
its existence via the nomenclature used
for Mono behavior.
So within Unity, there's
this thing called a Mono
behavior, which we'll take a look at.
From the beginning, actually, Unity
was developed for Mac platforms
exclusively.
But in 2012 or 2011 they ended up making
it usable across all major desktop
operating systems.
But C#-- suffice to
say, very similar Java.
We'll look at its syntax.
But it's different from Lua in
that, with Lua, you could just say,
oh, x equals 10, or object
equals-- and then create
a table with whatever you want.
C# is a lot less flexible in this sense,
in that you have to actually tell it
in advance what each data type
is that you're trying to make.
So you can't just create
a table or a integer.
You actually have to say, int
my_int, or x equals, and then 10,
and then semi-colon.
So there's also more
syntax to be conscious of.
And so really quickly, I can show
you just what some C# looks like.
We'll take a look at
this again going forward.
But as you can see here, we have public.
So that's another thing about C#.
In Java, if you're
familiar with Java, they're
object-oriented programming languages.
And as such, there are objects
that are public and private,
and you have access specifiers for
different variables and classes
that will tell other variables
and classes whether or not
they can communicate effectively.
So public class just means effectively
anybody can see this class.
Other classes can see this.
But then you have--
see if I have one of these
that has a private variable.
I know there's at least one.
Here we go.
So private, Text, text
here, for example.
So first of all, notice that
these are variable declarations
like we've seen before.
We're saying, this is a
variable that I'm going to use.
In this case, public
GameObject helicopter.
So I'm just defining it.
Or I'm declaring it.
I'm not defining it.
It doesn't equal anything yet.
But I'm saying, this is
going to exist, right?
You can say equals something, and
then define it on the same line.
But in this case, we are just declaring
in advance what different variables
we're going to need later on.
Like for example, here.
We see, in our start method.
And we'll go over what all these
methods are and how they're relevant.
But we can see here, text equals--
and then we're calling some
function called GetComponent.
And then we have some
funky syntax here--
less than, Text, greater than--
and then function call syntax--
two parentheses.
So we can see that
there's a lot more syntax.
But all of the same
principles still hold true.
It's still much the same way
to think about programming.
It's just, there's a little
bit more to stay conscious of.
And we trade off this
dynamism for more performance.
So that's ultimately what it comes down
to-- static versus dynamic languages,
you're trading flexibility
for performance, in this case.
Though C# obviously is
a lot faster than Lua.
We can do a lot more with it.
And actually, Unity isn't
itself programmed in C#.
Unity itself is programmed in C++.
But it allows us to program any
behavior that we want to with C#.
All right.
So that's a look at C# so we can see
also what I was alluding to up here.
We have our private, public,
and we do things with them.
And then, depending on what
we've declared public or private,
these things also
transfer into the editor.
We'll see how all of
that comes together soon.
But suffice to say, that's a
look at C#-- what it looks like.
And we'll use it, and we'll
get comfortable with it.
But it's a little bit different
than what we've done thus far.
Away from programming, we'll a
very brief look at what Blender is.
So I have it installed here.
And this isn't required for the course.
I will provide you with all
the models and all the assets
that you need to get working.
But this is what Blender is.
So Blender almost looks, at first
glance, very similar to Unity.
The big difference is, this
is meant to create new assets.
And technically, Blender does
have a built-in game engine,
but it's not used for
that purpose very much.
But the sole purpose that we
would be using it in this course
would be just to create new 3D models.
So as you can see here, I can click on
these vertices, and move them around.
And I'm not a guru by any stretch of the
imagination when it comes to Blender.
But the helicopter, and
jet, and skyscrapers,
and those kind of simple models,
I made all of those in Blender.
And those are bundled
with the project, if you
want to take a look at
how those are implemented.
And you can download Blender at the--
I forget what the exact
link is, actually.
Let's take a look.
Blender dot org.
And then, if we just go
down here, download Blender,
2.79 looks like the most recent version.
Blender 2.8-- I guess
it's in development.
But there's nothing concrete
about that on the front page.
But yeah.
If you want to model 3D
assets, and you're curious,
and you want a free piece
of really awesome software,
can't recommend Blender enough.
But like I said, I'm going to spend
too much time on it, because it's not
something that will actually
be required in the course
to implement 3D models,
to create 3D models,
since I'll be providing all of that to
you in the project in the GitHub repo.
And so here is a screenshot
of basically what we just saw.
So the fundamental part of Unity.
So first of all, let's take
a look at the Unity editor.
So we can see here much of
what we saw in the screenshots.
But here, I am live
looking at my scene, right?
I have a helicopter.
I have this background back here.
I have a camera--
that's right here.
You can see that it's a camera, because
it's got the little camera icon.
But it's effectively just
an invisible game object.
It's not actually going to be
rendered to the screen ever.
And notice that there are no
skyscrapers, no coins, no jets,
or anything like that.
Those are all instantiated dynamically.
But this is the beginning of our scene.
And it's all laid out in advance.
And we can see here with
this camera preview--
which is kind of hard to see
because it's really small--
but here's a larger view
of what it looks like.
And then we've got a GUI element
here, we've got coins here.
We have our helicopter.
But all of this is a marked
difference from what we've gotten
used to, which is, program
everything, and sort of load it,
and, oh, did I put this
in the right position?
No.
I didn't.
So I got to.
If I wanted to come
over here and just move
the helicopter a little bit which--
like that.
Whoops.
I just triggered it.
If you click on
something, by the way, it
will play any particle systems
that are associated with it.
So you can actually get a
preview for those, as well.
But I can easily just move
it here, to the right,
or to the left, before
the game actually starts.
And if I click on the
camera, we can see it there.
It's a little bit shifted to the left,
as opposed to what it was before.
But if I just press Command-Z couple
of times, take it back to normal.
So game object is an important concept.
So a game object is basically
everything in Unity.
So the camera is a game object.
The helicopter, which is
right here, is a game object.
Everything, by the way, that you
want to see in your scene in Unity
is on this left-hand
hierarchy right here.
So helicopter, the game object.
There's got to be a light
source in a 3D scene in order
for you to actually see things.
So directional light--
that's a game object.
Background skyscraper spawner--
we don't see it anywhere.
But that's also a game object.
It's just an invisible one.
A coin spawner.
There's something called a canvas,
which if we double-click that,
we can see we have this obscenely
large GUI here that, paradoxically,
isn't on top of our scene.
Unity does a very interesting
thing with all of its GUI elements,
in that it basically maps
the canvas to one pixel
being equal to one Unity unit, which
is usually equivalent to a meter.
And it draws this in a
different draw call than it
draws all of the actual 3D stuff--
all the stuff that's down here,
basically-- in World Space.
So when you create a canvas
and you see it's gigantic,
that's just Unity's way of doing GUI.
It's strange.
But apparently they do it
for performance reasons,
because they don't have to calculate
like fractional points of where
the UI is supposed to be in World
Space, which can get really small.
But the canvas is a game object.
Notice that helicopter has children.
It's got blades, a body, and then a
blades collider, which actually could
have been part of the blades object.
Canvas itself has two children--
coin text and game over.
And those are the text on the top
right, and "game over" in the center.
So those are just two
text objects, which
are labels, that we can just populate
with whatever text data we want.
The event system is an object.
That just gets added to your scene
automatically when you add a canvas.
Airplane spawner, explosion
particles, and explosion sound.
So we have all these different objects.
They're all part of our scene,
and they all do different things.
But at the core, they're
just game objects.
That's the core-- like the bottom type.
Yes?
AUDIENCE: So I would imagine
you're not actually using
a helicopter [INAUDIBLE].
COLTON OGDEN: Correct.
AUDIENCE: So should you
actually reset the position
of the background [INAUDIBLE]?
COLTON OGDEN: So the question
was, since we are maintaining
a consistent position with the--
I'm going to try and
scroll in, there we go.
The nice about Unity 2
is, if you right click,
you can use W-A-S-D to
move around the scene,
which is super easy and convenient.
But the helicopter
here stays in one spot.
And the camera always
stays in one spot forever.
So do we move the
background image, like we
do in our Love2D
implementation of Flappy Bird,
where we reset its position?
And the answer is--
I will play it right now in scene
view, and let you decide for yourself.
So let's go to Window.
I'm gonna go to Layouts.
So I like the two by
three, like I said before,
so you can see the scene and the
game running live at the same time.
I'm going to move my camera
in the scene so that I'm
looking at this from back here.
And then I'm going to play the game.
[MUSIC PLAYING]
But so.
Here's where we-- I'm just
going to hold it still.
So what do we think is happening?
Does it look like our thing is moving?
Or is it staying still?
It is staying still.
Any guesses as to how
we're achieving this?
Changing the texture.
We are scrolling its texture.
So when you take a texture
and apply it to a 3D surface,
you map the texture coordinates to
the 3D coordinates of the object
that you want to render.
It's called UV Mapping.
They call it UV, because usually,
when you're dealing with 3D objects,
you have your x, y, z.
And then you want to think of your
texture separately from the 3D objects.
So you use u, v instead of x, y,
since you already have x, y, z
allocated for your 3D object.
Basically, there's an
offset part of the texture--
the material that holds the texture--
there's an offset field that
will reposition the UV mapping
of that texture onto the 3D surface.
And when you offset it, it will
just sort of wrap itself around,
if that makes any sense.
So what we do is we--
and I can actually show you
in the code where this is.
This is going to be mentioned
at the end of the lecture.
But we have the scrolling
background component here.
And there's this thing on each
material called a texture offset,
which basically shifts the UV mapping
of your texture to your 3D object.
And so, by setting that texture
offset to some value offset,
which is very similar to
what we've done before.
Notice that offset is just
scroll speed times time--
Time.time, in this case.
And I don't mean to overwhelm with,
necessarily, all the details here.
But the bigger picture is
that we're taking time--
the amount of time since the
beginning of the game is started--
and we have some scroll speed
that we've pre-determined.
And we can just scroll
the texture offset here.
We're just placing it here at the x.
So this new Vector2, offset 0--
just think of these two as an x and y--
a vector 2, vector 3.
Vectors are just
combinations of numbers.
So 1, 2, 3, 4-- however many you want.
A Vector 2 offset in 0.
So we don't want to
scroll on the y-axis.
We just want to scroll left to right.
So we're going to apply no
texture offset to our y-axis,
but we want to apply a
texture offset to our x-axis.
So that's what their offset there is.
And I included it also here--
notice there's a Bump
Map texture offset.
There's no Bump Map
actually on our texture.
So a Bump Map is effectively--
I can maybe find a good
Google image for it,
if you're not familiar with a Bump Map.
Let me go in here.
I'm going to hope that there's no shady
images on Google Images, but a Bump
Map--
can we see it?
Well, it's kind of hard to tell.
But in a lot of 3D games, you'll
see like bumpiness and shininess
on surfaces.
And that's accomplished the majority
of the time using Bump Mapping.
Because obviously, if you were to model
every single tiny little bump or model
in a surface, it would get extremely
difficult to render large objects.
Because you're looking at
thousands of polygons for a surface
that was actually this
detailed in a game.
So what you do is, you take
what's called a Bump Map,
and the Bump Map gets--
during lighting, it will effectively
skew the surface normals of a 3D mesh.
So effectively, it will pretend as if
your 3D mesh has a bunch of bumps in it
for the lighting.
Only for the lighting.
And so when it gets lit, and it gets
shaded, it looks as if it's bumpy,
but you're still dealing with
a completely flat, completely
simple cubic mesh in this case,
or whatever mesh you want.
And so the long story
short, here, if you
wanted to include a Bump Map on
whatever surface you want to scroll,
or if you want to edit
the Bump Map, this
is here just because you can also
manipulate the Bump Map texture offset.
It's an included field in a material.
So any questions as to
how this works at large?
We still have a lot to cover before
we go into a lot of the specifics.
But conceptually, do we
understand how this sort of works?
OK?
Cool.
So let's go back to the slides.
Right.
So we were talking about game objects.
So all of those things that we
saw before were just game objects.
So let's go back to the default layout,
and then we can look back at our scene.
So this is our scene.
All of those things were
all of our game objects.
Those are ultimately containers.
I talked about this in a prior lecture.
But this is the beginning of an entity
component system, in which case,
these game objects are our entities.
They are the entity class--
container class-- for
what drives behavior.
And the thing that allows us to
actually get interesting behavior out
of this sort of abstraction
is the use of components.
And we'll talk about that.
So components are all of the
things on the right-hand side,
by default of the Unity editor.
So if we're looking at
our camera, for example,
and we take a look at all
these things on the right,
we can see that we have
something called a transform,
we have something called a camera.
A GUI layer deprecated,
so that's by default.
It was imported from a
prior version of Unity,
so you could actually delete this.
A flare layer, which we're not using.
An audio listener-- I believe that
comes with all cameras by default,
though, in case you do want to use it.
An audio listener and an audio source.
So all of these different
pieces are components.
They are what drive the
behavior of this game object.
We can create just a brand
new, empty game object-- oops,
I created it as a child.
We can create a brand new,
empty game object here.
It's just a game object in our scene.
And it's right where our mouse is.
Well, it's right here.
And it does nothing.
It has one component.
And that component is the transform.
Anybody guess what a transform is?
Yeah.
AUDIENCE: Is that position,
rotation, scale, et cetera?
COLTON OGDEN: Yes.
It is the position, rotation,
and scale of a game object.
Something that was before
put into six fields--
or in this case, nine
fields, potentially, or maybe
three fields with children, is now
an object that we can modify at will.
Well, it's a component
that we can modify at will.
So if I do this-- notice,
I'm just scrolling the x.
It's just moving that transform, which
is just the position of that object.
And Unity knows to look at
the transform component,
and render our object based
upon where its transform lies,
rather than us having to manually
set all these things, which we still
can do in the code.
We can just modify them
in the Unity editor
directly via a graphical interface.
It's just an interesting,
helpful layer of abstraction.
So a transform is a component--
a camera, in this case.
It's just a component.
We can attach this to anything we
want to, and it becomes a camera.
And then we can set it to be
either the default camera or not.
The camera has a bunch
of different things.
And I can't claim to know all
of the fields of every object
in Unity, because there's just
a tremendous number of things.
But clear flags,
background, culling mask--
all these things that are relevant
to how the camera does its job--
they are all things that
we have complete access
to here in the Unity editor.
We don't even need to touch code,
really, for a lot of things.
An interesting fun thing
we can take a look at
is if we go to Layouts-- go back to two
by three, and take a look at our game
again.
So we have our camera currently
looking at the screen here.
It's just always in one spot.
And it has a way of
projecting the scene.
It can do one of two things.
It can be perspective projection
or orthographic projection.
Does anybody know what the difference
is between the two, at least visually?
So perspective
projection-- what that does
is it models how real cameras, real
lenses, the human eye, et cetera,
behave in real life.
Things distort a little bit.
And so you see things, depending
on where you're looking at them,
they look wider or skewed, and
not completely geometrical,
like you would if you were just to
draw them at a certain distance.
Things have vanishing points, et cetera.
Orthographic-- things
look a lot different.
So notice instantly, so we
can see here, perspective
doesn't really change a whole
lot visually with our helicopter.
Things do change a little
bit with the background,
because the view angle is
different between the two--
the perspective and the
orthographic camera.
But if we make this a little bit larger.
So I'm going to increase
the size like that.
And I play.
One thing we'll notice--
what's the first thing
that folks are noticing?
You can actually see the difference
between the top and the bottom.
Whoop.
How, in particular, I'll put your
attention towards the buildings.
How do the buildings differ?
AUDIENCE: You can't see the side.
COLTON OGDEN: You can't
see the side anymore.
The lens sort of curves a bit.
And so I'm not entirely familiar
with all the math involved.
But at the end of the day, what it boils
down to is, with a perspective camera,
you can actually gauge
things as distance
relative to each other
a little bit better.
With a orthographic camera,
everything is completely flat,
and no matter how far
away from you it is
on the access that's completely
perpendicular to you,
it's going to look the exact same.
So these buildings are always going to
look the exact same, no matter how far
away they are, no matter
which position they are.
Because everything is just
looked at completely flat.
And the view matrix is
calculated in a different way.
And so, just with a
simple button, you can
change how your game looks completely.
You've probably seen a lot of games.
I believe Crossy Road does everything
with a orthographic camera,
versus a perspective camera.
It has a very distinctive
look, especially
once you skew things a little bit.
But that's just one thing
that you can change just
without having to touch
a single line of code--
how your game looks via just
the camera's implementation.
Let's take things back to how it was.
And there's a lot of things
like the field of view.
So if you want to see
more of the game world.
So things like in Quake
and other shooters,
you can change this view,
usually in your menu settings,
just so you can see more around you.
And it looks a little like
a fisheye lens a little bit,
depending on how you do it.
And that's just more distortion
of the perspective projection.
Yeah.
All of these things, they all have--
I don't know necessarily what
every single one of them does,
just because there's
just a lot involved.
And generally, you don't have
to mess with it too much.
It just ultimately depends on what you
are trying to accomplish in your game.
And you'll end up finding
specific areas of the editor
and specific areas of the
code base and documentation
that you dive deeply into.
But this essentially is what a
component affords you the ability to do.
When you create a component and
you attach it to a game object,
you can easily not only
combine different things
to create this emergent new
behavior and combination
of behaviors for your game objects.
But Unity allows you, via different
ways of programming the components,
to modify them, depending on how
customizable you want them to be,
in the editor itself.
So you don't have to
touch any of this in code.
You can just go into
the editor and quickly
whip things up because of the way that
you've modeled all your components.
And so we see other things
like the audio listener.
An audio listener is something that
will literally listen for audio,
and play it back like a
microphone to the game player.
And then an audio source is
an actual source of audio.
And so it will play that
audio at the location
of whatever that game object is.
So we've combined all these things.
So now we have a camera that
is projecting everything
with perspective projection.
And it's an audio listener, so it's
going to listen for audio in our scene.
And it's also going to play an
audio source and listen to itself.
And that's just the beginning.
We have a whole bunch
of other components
here, which we can take a
look just really quickly.
So the directional light
has a light component.
And so a light, you can
do all kinds of things.
You can make a spotlight,
directional light, point light.
All these look a little bit differently.
You can make it have a specific color.
So maybe if you wanted a really dark
scene, you could have a dark light.
Or you could even emulate dawn
or dusk with an orange light.
That's sort of how you'd
go about doing that.
You can bake your lighting, which
means that you just pre-compute it,
so that you don't have
to render it in real time
when you actually play it on hardware.
A lot of different things,
a lot of different settings.
We don't have time necessarily
to go into all of them.
But looking through
all of these, you can
see all these game objects are just
combinations of these components.
And those combinations of components
are responsible for the behavior
that we get in our game.
That's the ultimate essence of what
Unity is, and how it does what it does.
And to illustrate the difference,
we've talked about this before.
This is an inheritance
chain, where Monster
inherits from Creature, which then goes
to Goblin, Goblin Chief, Elite Goblin
Chief.
In Unity, you could
create a game object,
and then give it a creature component,
a goblin component, a patrol component--
right?
So maybe you want
different things to patrol.
In Unity, it would be
kind of complicated.
But you could create
basically a pathway,
and then have your entity follow
that pathway at a specific time.
And then, depending on
how you've programmed it,
you could specify all these different
characteristics in the editor.
So you could just say
on the editor, OK, I
want you to go patrol from
this range to this range.
And I want you to do it with this
length of time, pause for this long--
right?
And then you can give that
to anything in your scene.
You could make a camera
patrol if you wanted to,
and then have that be demo code
for the beginning of your game.
The flexibility is just insane.
Elite component.
Right?
If you want, maybe, certain enemies
or certain objects, if they're elite,
maybe they shine bright.
And maybe they drop more
experience or something.
A chief component maybe has better
weaponry than a non-chief component.
And then a toxic component, maybe,
is an enemy that, when it dies,
it sprays toxic gas or toxic
liquid all over the place.
But the flexibility is there.
You can ascribe any component to any
object to get any sort of behavior
that you want to.
It's on you, of course, to implement
all these components, right?
You're not going to
get all these for free.
You're going to get a lot for free.
Unity gives you a ton of
components-- really good components.
But you're ultimately going to
need to program your game logic.
And so you'll have to implement
all these things-- elite,
goblin, what it means
to be all these things.
But thankfully, it's
not terribly painful.
The way at which we go about doing
all of this-- and by the way,
are there any questions so far
as to how Unity's model works,
the difference between
composition versus inheritance,
anything we've talked about this far?
All right.
The way at which we actually go
about making our own components,
which is probably what you'll
spend the most of your time doing,
at least in the beginning, when
you're bootstrapping your game,
is programming what's
called a MonoBehaviour.
And so we talked about Mono before.
So Mono is the open source
implementation of the CLR.
And MonoBehaviour, I imagine--
I tried to look this up and
see where it derives from.
I imagine it's because it was originally
a Mac exclusive project, Unity.
And so because everything
was implemented in Mono,
and because this is way it's scripted,
MonoBehaviour became the name.
But a MonoBehaviour is
what a component is.
They are effectively one and the same.
The difference being
that a MonoBehaviour
is how it's illustrated in code.
In C#, if you want to program something
to be a component that you can then
attach to a game object, it needs
to be inherited from MonoBehaviour.
So if we go to coin spawner, here.
And you can see the difference
between what's built in to Unity
and what's your own via--
it'll say script here.
So in this case, I have a
coin spawner object, right?
It's just an empty object, at
least in terms of what it displays.
It's got a transform,
which is irrelevant.
It could be literally
anywhere in our entire scene.
The only difference between
this and the empty game
object that we saw before is
that it has a coin spawner.
And this coin spawner
has this thing here.
All components that you add would
have this script field here,
just to show you that
that's the script that it's
getting it's code behavior from.
But also, we have this field here
called prefabs, which has a size of 1.
And it's actually calculated
based on how many elements
the list that it's responsible for has.
And we have one element,
as it says, here.
And it's got a coin
pre-fab, which is here.
And notice that I clicked on it.
It took me right to it in my assets.
And so prefabs and all of that--
what that means and how to get
that all working--
we'll talk about that.
But a coin spawner script
has to exist in our code base
before we can actually add it
to any game objects, right?
So in my project I do have--
usually, you have assets, a folder
called Assets in your Unity Project.
And then I typically
create a Resources folder.
It's not mandatory that you do so,
but just for organization, I'll
create a Resources.
And then I'll have a bunch of folders
for all sorts of different things
like we've done before.
Where in the Love2D project,
at the parent level,
you have like a Fonts, a Music or
Sounds, and then a source directory.
In this case we have
Fonts, Materials, Models,
all the different assets that
we will need in our game,
but also a Scripts folder.
And all the C# scripts here that we'll
use amongst all of our components--
all of our game objects.
And so you could easily
just go to any of these,
rather than have to go into your
operating system, open up a new window,
and find your file, and
navigate through all the files
that Unity generates for you,
which can be kind of a pain.
You can just double-click on
a coin script, for example.
And it'll open in your default editor.
And so one thing that
I'll just mention here
is, if you go to your
Unity preferences--
on Mac, it's Unity
and then Preferences--
you can go to External Tools.
So by default, starting in 2018,
Unity is transitioning away
from its prior IDE, which was called
MonoDevelop, which was a good IDE.
There's transitioning away
from that, and they're
making it focused on Visual
Studio as the default IDE.
I don't use Visual Studio.
I like VS Code.
So what I did was-- and
what you can do is--
you can choose your
external script editor here,
if you prefer a different
script editor-- like Atom,
or VS Code, or Sublime Text.
And then just browse for
it on your file system,
whether you're on a Windows,
Linux, or Mac machine.
And then you can easily just
choose which file you want.
In this case, I chose VS Code.
And so that effect that
that has is, whenever
I double-click on a
script within Unity, it
will actually open
the IDE or text editor
that I have assigned to
it in Unity's preferences.
And so here is the Coin component
that I have created for this example.
And notice that every component,
first of all, is a class.
And actually, everything effectively
in C#, just as in Java, is a class.
It's a public class.
And notice that I call it Coin, and I
got this colon, and then MonoBehaviour.
So this colon-- anybody know, anybody
take a guess what the colon means?
Tony?
TONY: Extends.
COLTON OGDEN: Extends, yes.
Extends or inherits from MonoBehaviour.
So anytime you have a
component that you want
to create, you want to add it to Unity,
and allow you to see it in the editor,
and allow you to actually
drive behavior of an object,
you need to inherit from MonoBehaviour.
Like it says here on my VS Code, since
I have the extension for OmniSharp,
it will actually tell me,
MonoBehaviour is the base class
from which every Unity script derives.
There's a couple of things here.
So notice that we have a few methods.
So void Start, void Update,
and void OnTriggerEnter.
So anybody take a guess as to what--
ignoring OnTriggerEnter--
does anybody have
a guess as to what Start and Update do?
Yeah.
AUDIENCE: Could it be just like that
and [INAUDIBLE] update [INAUDIBLE]??
COLTON OGDEN: Sorry,
say it one more time.
AUDIENCE: Would it just [INAUDIBLE]
an update or [INAUDIBLE]??
COLTON OGDEN: Exactly.
It would be just like we did
before when we created objects
in our Love2D projects, where we had an
init function assigned to every class,
and an update function
assigned to every class.
And we would call those ourselves.
Every MonoBehaviour can
have a Start method.
In this case, it's empty,
because every time you
create a new script by the Unity editor,
it will automatically-- first of all,
it will automatically create
a brand new file for you.
So let's just say I want
to create a new script.
So if I'm in the Unity editor,
and I go to my assets--
I right-click Create.
And then I want to
create a new C# script.
It'll create it there.
I can say, maybe I want this to be--
I don't know-- Test Component, right?
So this should have the effect
of, when I open it in my VS Code,
this Test Component-- this
was auto generated for us.
We didn't have to write
any of this boilerplate.
But every script that
you create, by default,
is a MonoBehaviour, which it
strictly does not have to be.
You could create a class of your own,
that maybe you call behind the scenes,
or maybe it just represents a
data structure or something.
But by default, anytime you
create a new script in Unity,
it'll save you the hassle of
typing out all this stuff by hand.
And it'll give you an empty Start
method and an empty Update method.
And so, like Tony said, the Start
method gets called as soon as the object
that it's assigned to gets instantiated.
Well, as soon as this component
gets instantiated, rather.
Which often is the case
that it gets instantiated
at the same time as a game object.
Not always.
You can create game
components on the fly.
But this Start method will get called.
Anything that you put in here
will get called right away.
And then this Update method,
Unity will-- every frame,
go through every component
on every live game object--
and will call the code that's
contained within this Update function.
And you don't have to call
this anywhere yourself.
Just by assigning this component
to a game object in your scene,
you get the update, and start,
and all this other functionality
given to you for free.
And MonoBehaviours are
actually much more complex
than just Start and Update.
So if you go to MonoBehaviour
here, we can see that--
by the way, I want to shout
out Unity's documentation.
Unity has amazing documentation--
docs.unity3d.com.
You will go through
pretty much everything
you possibly could ever want with every
object implemented in Unity, in quite
a good detail, with a lot of examples.
But here we can see,
just in the description,
it will tell us, the MonoBehaviour will
get start, update, fixed update, late
update, on GUI-- all of these
functions called for us, assuming
that they're implemented.
And you don't have to implement
them if you don't want to.
If they're not implemented,
they just won't happen.
If there's no start
method, then that means
there's no start logic
for this component.
So it doesn't need to execute.
If there's no update, maybe it just
needs to start at the very beginning,
but never update after that,
don't implement update.
And update will not be called.
All of these are optional.
That's just a small
chunk of MonoBehaviour,
though, because you also have messages.
So messages are functions
that you override.
As you can see, there's
a whole lot of them.
And all of these messages get called,
depending on certain things that
happen in the game scene.
So OnTriggerEnter, for example, if our
object is a trigger, and we enter it,
then the behavior will get
called in that function, which
will allow us to do things like--
if our helicopter enters a building,
we can call that
helicopter's explode method,
which is literally what we do in this
project, thanks to this function.
And all we really need to do is
just a couple of lines of code.
It's very simple.
OnPostRender, OnPreRender--
all these different things
are called at different times.
You can look into all of these, if
you want to, just by clicking on them
and looking at their documentation.
LateUpdate is called after all
update functions have been called.
This can be relevant for
certain physics calculations.
But there's a whole lot of
different things you can do.
You don't necessarily need to
do a lot of things yourself,
if Unity provides you with
the function that gives you
the effect that you're looking for.
And so if you're curious, MonoBehaviour,
and then the docs at large.
This is just all the documentation--
just an insane amount of documentation.
And that's just in the classes.
There's all these other
little side areas, as well.
And so that's sort of
what MonoBehaviour is.
It's a component.
It gets a lot of these
functions called for you.
You don't have to implement them.
But if you do, you get a lot of
functionality for free, basically.
Any questions as to what a MonoBehaviour
is, how it works, and so forth?
Or any of the syntax we've seen thus
far for creating a MonoBehaviour?
All right.
And so, here in our coin, for example,
which we were looking at before,
notice that I'm referencing
something called a transform.
Transform.position.x is less than
negative 25, destroy a game object.
If this is the coin, what do we
think that this is accomplishing?
AUDIENCE: It goes off
the screen [INAUDIBLE]??
COLTON OGDEN: Yep.
So the transform,
recall, was our component
that encapsulates our
rotation, scale, and position.
So we can just say, if
transform.position.x is less
than negative 25, destroy game object.
Because we're spawning
the coins dynamically.
When they get off screen-- just like
we did with the pipes, if you remember.
And I had a screenshot,
actually, in that slide
that showcased what that looked like.
We can see that exact thing live here.
If I go to Layouts, two by three,
and we play the game again,
and then I'll just die at some point.
But if we do this, we're
seeing our scene live.
So we're following this-- yep.
See how the coin-- as soon as
the building, and the plane,
and the coins all get to this point--
this is negative 25 in
Unity units, not in pixels.
Everything in Unity is based on
Unity units, which, by default,
1 is equal to one meter, as opposed to--
we've been thus far using just pixels.
But pixels aren't viable in 3D.
[MUSIC PLAYING]
But that's effectively
what that component does.
It's checking, in our Update
function-- void Update--
if transform.position.x
less than negative 25.
And notice that we don't actually
have to declare transform
anywhere, which is interesting.
That's because MonoBehaviour,
by default, gives you
access to its game objects
transform just by default.
That's just something you get for free.
And then, notice gameObject-- we also
haven't declared gameObject anywhere.
Because by default, we
have access to gameObject.
It's the game object that
this script belongs to.
That this component belongs to.
AUDIENCE: [INAUDIBLE]
COLTON OGDEN: This would be the actual--
so the interesting
thing about the classes
is, you don't have to
explicitly say this.
Because if you had int myNumber equals
10, and you just say, myNumber--
the difference between Lua
and C# and Java is that,
it will already know what
myNumber is, this is myNumber.
It will know its this objects.
AUDIENCE: Yeah.
COLTON OGDEN: You don't have to do that.
Sort of a nice little thing to
save you a little bit of time.
Because you could then just
say, myNumber plus equals 10.
Another nice thing about C#, by the
way, which we didn't get in Lua--
you can do compound
assignment operators.
So you can do plus equals,
minus equals, times equals.
That's one of my little
pet peeves I have with--
oh.
And notice that also, the nice
thing about the fact that I
have OmniSharp-- it'll underline.
And this is just a trait
of most IDEs, honestly.
So you get this with a lot of places.
But it'll tell you myNumber is not
assigned, with the underlining,
and also just by hovering over it.
The named myNumber does not
exist in the current context.
But I can just say, int myNumber.
And then it's gone.
A little bit more that
we have to worry about,
and a little bit less that
we have to worry about.
A little give and take.
But still, I think, overall, C# is
going to be a lot more syntax-heavy.
You do have to worry about things
like braces, and semi-colons,
and putting everything in a boilerplate.
And then, obviously, type declaration,
and return type declaration.
It can be a little bit more than
we've gotten used to so far.
But it's honestly not too bad,
just given that you can use IDEs.
First of all, the fact that you're
statically typing everything,
you can detect a lot
more errors in advance.
If you're trying to do
something with some type
that you're not supposed to
do, like some function accepts
some object of some type, but
you're passing in some other object,
you'll catch that in advance.
And so that's a really nice thing.
But yeah.
It is a give and take.
And also, IDEs will
give you, like I said,
a lot of the functionality-- a
lot of the autocomplete-- that
makes a lot of this more sustainable.
And it's not to say, of course, that
Lua and Love2D don't have their own IDE.
Like ZeroBrane Studio is
popular, from what I understand.
Haven't used it yet.
But particularly when you venture into
Java, and C#, and compiled languages,
static languages-- having those
features does save you a lot more time,
relatively speaking, than when
you're in a dynamic language.
So that's what MonoBehaviours are.
Every component of our game
effectively has-- like the helicopter
has its own script, a Heli Controller.
The coin has its own script-- the
Coin Spawner, the Skyscraper Spawner,
the Skyscraper--
they all have their own scripts
that drive their game behavior.
But they also have scripts and
components that are part of Unity core,
as well.
Including Colliders and Triggers.
So if I'm looking in Unity--
so I'm going to go to--
and this will actually be the last
thing we look at before we take a break.
But if I'm in Unity, and I'm going
to go back to my default layout,
just because it's a
little cramped on a 720p.
Go to my helicopter.
Helicopter's got a
couple of pieces to it.
So let's actually go to
where I can see it here.
So one of the awesome
things I love about Unity
is, it gives you a lot of this editor
magic-- this editor sort of sugar.
It shows you visually where a lot of
the things are in your game world.
So the green rectangles-- anybody
know what those are, or can guess?
AUDIENCE: Hit boxes?
COLTON OGDEN: Yep.
Hit boxes.
Exactly.
These are colliders.
So the blades-- it
doesn't have a collider.
That blades collider
is actually separate.
The box collider here is
this collider right here.
And so a collider is
literally just something
that collides with something else.
And you can set it to
be a trigger or not.
If it's a trigger, then it actually
won't trigger the OnTriggerCallback
function that we briefly saw earlier.
So the things that you
want to activate triggers,
you should make those not triggers.
And then triggers, all you have to do is
just click this little Trigger button.
So what a trigger is is just a
region that you've determined--
or some object that you've
determined-- should cause behavior
when it gets triggered.
So in this case, I've assigned--
actually, I'll just play it.
But the airplane has a trigger, right?
All of these things have colliders,
whether they're triggers or not.
The helicopter-- its
blades and its body--
there are two colliders, two boxes.
The coins all have colliders.
The skyscrapers will have colliders,
and the airplanes have colliders.
The difference is that-- oh, and
by the way, another cool thing.
It's easy to get very
sidetracked, just because there's
so many cool things to talk about.
You can pause the game
while it's running.
So it's paused right now, but it's
in the exact state that I left it.
So there's three coins there.
I got my helicopter there.
I can freely go about the scene.
I can analyze things.
I can actually modify this in real time.
So I can change its
rotation, if I want to.
Probably don't want to do that.
But I could if I want to.
I can change its position, right?
So I can move it left
to right, like that.
And notice that I actually
have just the body selected,
so the blades are kind of separate.
I don't even know what
kind of crazy stuff
would happen if I just messed
with this and just let it run.
I haven't tested it that crazily.
But you are allowed to step through.
Oh, OK.
It looks like they both just go.
Oh, yeah, because they're
parented to the helicopter object.
So they're both going to align.
They're going to move
at the exact same rate,
regardless of how far apart they are.
The individual objects.
But you can just step through your
game's execution frame by frame,
and get a sense of--
if you're trying to pinpoint
a bug, maybe, that's
position-based or
something that's tricky
and you just haven't been able
to find exactly what's going on.
You can look through
your whole scene and all
of the fields of every
object in step time,
just by stepping through--
this button here--
assuming that you're in pause mode.
And then just looking at all the
components here on the right side.
Because those will all still update.
All these fields will
update any time you perform
any changes in the actual scene.
So super helpful for debugging.
I know I've used it a bunch.
And then if I start
again, or if I stop it,
the nice thing is, any
of the changes that you
make while it's running
to your object, they
don't get applied when you
actually go back to the game.
So notice that I messed with the
two pieces, I separated them.
And then I stopped the game.
It ended up going right back to
where it was in the very beginning.
So all this gets just basically
saved like a snapshot.
You can do whatever you want during
your game, and then come back to it,
and it will all get reverted
back to where it was.
Yeah.
TONY: So [INAUDIBLE] if
you hit single player,
and I kept making changes while
I'm not involved [INAUDIBLE]..
COLTON OGDEN: Yes.
So, yeah.
Tony just basically echoed
what I just said, which was,
if you make changes in your
game while it's running,
and you're trying to maybe tweak them
such that it's perfect when you're
actually done, they don't get saved.
So you have to actually make a conscious
effort to remember what you've done,
how you've changed different fields,
to fix any bugs, if they do exist.
But it is something that can be
disheartening or frustrating, if you
finally fix something, and then
you forget what it is you changed.
And then you have to mess
with it a whole bunch.
So remember all the changes
you make, if they're
pertinent to your
actual game's execution
and the debugging of your game.
And then there's also a
console, as well, which is nice.
If you want to output things
like JavaScript style on the web,
you can do console.log.
You can do the same thing with
a debug call here in Unity.
I don't have any of those
calls in the actual game.
But it is something that
we'll look at going forward.
And it is something
that can be very helpful
if you want to measure something
or output something that you can't
necessarily look at in the inspector.
In the case of this game, most of
anything that we want to take a look at
is visible in the inspector.
But if you have an algorithm, maybe
you have a generator that's not visual,
like a level generator.
And you want to make sure that the
data structure representing your level
is generating things properly, you can
output everything maybe via hashmarks
or something in your
console, and actually
see it that way when
you're running the code,
rather than having to run the actual
game and look through it that way.
Some things just are hard
to model in the editor,
and still need console output.
So the console is there to help you.
And so debug.log is the
function, I believe,
that you need to see all that stuff.
Right.
Colliders and triggers.
So we had a little bit
of a tangent there,
but the helicopter is comprised
of these three things.
But the blades collider
should have ultimately
been merged with the blades object here.
But we can think of it as
the blades and the body.
The reason they're separated-- well,
there's two reasons they're separated.
One core reason they're separated
is they're just different sizes.
So the blades are longer than the body.
And so we have, for that
reason, two separate colliders.
So we're looking at the helicopter here.
We can see that the
collider for the blades
extends a little bit
farther than the body.
We don't want to create a box
collider for the entire helicopter,
because a box collider right
that goes out here, for example,
might not be super fair
if we're just coming right
over a building, and our body--
maybe the building's right
here, and we just miss it.
We don't want that to be collided with.
So sometimes you'll need
to combine colliders
to accomplish the collision
detection behavior you're looking at.
The nice thing about box
colliders, which we're using here,
is that they're not very expensive,
because they're just boxes.
It's easy to compute 3D box collision
with other things that are 3D boxes.
And that's actually a
topic in its own is,
taking a complicated model or
object, and then breaking it down,
not in terms of what it looks
like to be collided with,
but how you can simplify the
collision detection of something,
like a character, by just modeling its
arms, its body, its legs, as cylinders
or boxes, rather than
complicated geometry.
You usually don't want to do peer
geometry collision for anything,
because that gets really expensive.
You want to try and aim for simple
shapes to be your colliders.
And Unity gives you a
lot of simple shapes
by default. If you look at, for
example, in our helicopter--
if you wanted to add a
component-- which, by the way,
you can easily do here, just
in the component inspector.
If you're looking at the bottom right,
there's an Add Component button.
So you can add any of the
components that you've written,
and also all the components
that Unity gives you by default.
So if we look at it by
collider, we can see
there's a lot of different colliders
that Unity gives us for free.
Polygon collider, mesh collider,
box collider, capsule collider.
I try and strive for
boxes as much as I can.
Spheres aren't bad.
Spheres are usually fairly
easy to calculate, as well.
But boxes are the easiest.
Capsules are pretty easy, too.
A lot of players will be capsule
colliders, because characters usually
have rounded heads.
So emulating the collision for their
head with a capsule makes more sense.
And we'll look at that, actually,
next week, when we use a first-person
component that we can get for free.
The default collider
for it is a capsule.
But the blades and the body
both have their own collider.
They're not triggers.
But if we look at our prefabs--
which we'll take a look at
what a prefab is shortly--
a skyscraper has a box collider which
is a trigger, as we can see here.
And the coin is a trigger.
And the airplane is a trigger.
So these things all trigger, except
other colliders that aren't triggers.
And if it detects a collision with
a collider that's not a trigger,
it will call the
OnTriggerEnter function,
which we saw is something that
you can get with MonoBehaviour.
Yeah.
AUDIENCE: Could you have two values
if you want to call the special
function two at the same time,
you'd have the regular [INAUDIBLE]..
Is there an easier way to do that?
COLTON OGDEN: Can you give
me a specific example?
AUDIENCE: Well, if I want to
have a pinball game or something,
I'd want to model functioning
when my ball hits something.
But at the same time, I just
don't it to bounce off of stuff.
COLTON OGDEN: Oh, yeah.
AUDIENCE: So you could do that?
COLTON OGDEN: So the question was, can
I implement such that, for example,
in a pinball game, if I have a
ball that collides with something
and causes a trigger to occur, but
also have it bounce off of something.
And you would do that with a rigid body.
So you give it a rigid body.
In this case, I actually gave
a rigid body to the helicopter
because the original goal of mine was
to have it be affected by gravity.
But it turned out that I actually liked
it a little bit better without gravity.
So this rigid body isn't
strictly necessary.
But it has a gravity
component that you can
assign to it that will actually,
then, calculate gravity, and pull it
down wherever-- you have a
global gravity definition that's
in your Unity settings that
will affect it that way.
And so what you would do is, you
would give your ball a rigid body.
And other things that you want
it to bounce off of those,
those also have rigid bodies.
And they can be kinematic
or not, basically,
which we talked about before.
Kinematic can move, but not
be affected by other objects.
And so the object that's a trigger, you
still trigger code, it does something.
So your pinball machine, when
it collides with something,
and it triggers that thing,
it'll still trigger that code.
So whether that's increment
your score, or cause something
to flash, a part of it will
flash, or play a sound,
it'll do that in your OnTriggerEnter.
But your rigid body will
also perform its work,
and bounce off of whatever it--
assuming that you don't destroy it
with that OnTriggerEnter function,
it will bounce off of that
surface, and behave in the way
that you are alluding to.
Does that make sense?
All right.
Cool.
So all these things have triggers.
The IsTrigger flag--
I mean, that's as easy
as we need it to be.
So you just give a box collider.
And the nice thing
about box collider, too,
is if your mesh is a box,
or square, or rectangular,
it will usually just fit it perfectly to
whatever you're trying to assign it to.
So in this case, I remember adding the
box colliders for these skyscrapers.
It just-- because they're
all rectangular, or cubical--
I don't know.
What's the rectangular 3D?
I forget the term.
What is it?
AUDIENCE: Rectangular prism.
COLTON OGDEN: Rectangular prism, yes.
Because they're all rectangular
prisms, the box collector fits them.
It'll scale the right way.
When you have differently
weird shaped objects,
it'll just basically
be as big as it needs
to be to completely encapsulate it.
But like I said before, because the
helicopter has got some weird geometry,
if we were to do that, it would by
default just be this entire box here,
because this is the farthest it
goes out on this particular axis.
So we want to combine meshes
to produce the collision
behavior that we're looking for.
And the trigger enter bit is relevant
because, if your game object is
a trigger, then once we
collide with that object,
we want-- and by default,
when you do OnTriggerEnter,
it will look for the
collider on this object.
It's going to take in a
collider other, right?
And what that is is the
other collider-- the thing
that's colliding with this
object, with this coin.
So the helicopter, because it's
the only other object in our scene
that has a non-trigger collider.
OnTriggerEnter-- this is
going to be a helicopter.
We can just say other.transform.parent,
because our helicopter has children,
which have the actual colliders, and
a parent has the helicopter controller
component.
We're going to GetComponent
the HeliController.
So we're going to go through
our that objects, that other
that collided with us.
We're going to get its transform parent.
We're going to do GetComponent, which
is a function that will just look
through all of its list of components.
We specify which component we
want using this identifier here.
So of class HeliController.
And these angle brackets are
the generic type specifier
syntax, which basically looks for it.
You could pass in any
type here, effectively,
and GetComponent will look
at whatever type is in here,
and get the component of
that type, specifically.
So you do have some sort
of type flexibility in C#,
but you have to go the
extra mile and specify it,
and implement functions that
take generic arguments like this.
Which is similar to Java, and C++, and
other languages that do it that way.
And then once we've gotten that
component of type HeliController,
with this function call,
we execute PickupCoin,
which is a function that's
part of the HeliController.
Any guesses as to what PickupCoin does?
AUDIENCE: [INAUDIBLE]
COLTON OGDEN: Sorry?
AUDIENCE: Increments the coin counter
and tells the coin to disappear.
COLTON OGDEN: Increments the coin
counter, calls the coin to disappear.
Well, it actually doesn't call the coin
to disappear, because we do that here.
AUDIENCE: Oh.
COLTON OGDEN: Destroy game object--
game object is going to be this
coin that's executing this function.
There's one more thing, too.
Do you remember what happens
when we pick up a coin?
Exactly.
The particle effect.
It triggers a particle effect.
We can go to the HeliController
class and take a look at that.
PickupCoin.
Here, coinTotal plus equals 1.
GetComponent AudioSource.
Play.
So it's a little bit weird.
So with audio source, you can
have multiple audio files.
So GetComponents AudioSource
is what we need to actually get
the audio attached to this object.
And at index 0--
because there's only going to
be one audio source anyway.
And then we just call Play, so
that'll play the coin sound.
And then GetComponent,
because there's only
going to be one particle system
associated with this helicopter object.
We're going to get the
particle system object.
And then we're just going to call Play
on that, which will actually trigger
an emission one time of its particles.
That's in a nutshell what
colliders and triggers are.
It's a lot of syntax at once,
because Unity is really big.
But it's pretty simple.
Just make sure that you give the
right shapes to your objects.
Make the right things
triggers that you want
to cause behavior to happen when
non-trigger things touch them.
And then implement OnTriggerEnter
with the behavior-- the game logic--
that you need.
In the case of the skyscraper, for
example, if we look at the skyscraper.
So I have a skyscraper component here.
And then if I OnTriggerEnter
here, it effectively
does the same thing
that the airplane does,
which is just go through the others,
transform parent game object,
HeliController, and then call Explode.
And so Explode-- similar
thing to what PickupCoin does,
and it triggers a particle effect.
But it also destroys the helicopter,
and it tweaks the Game Over text
to turn on at that point.
So any questions as to how triggers
work, or any of the syntax we've
talked about thus far?
I know that it's a lot.
It's kind of a fast tour.
But moving right along.
All right.
Oh, and here's a screenshot I took
just to illustrate the green lines--
the box-- and then the orange is
the actual mesh of the helicopter.
So we're going take a break.
And then when we get back,
we're gonna talk about prefabs
and spawning them, and
dive a little bit deeper
into some of the other
parts of the project.
All right.
Welcome back to GD50 Lecture 8.
This is Helicopter Game 3D.
So before the break, we were talking
about colliders and triggers,
and also just getting our hands used to
using MonoBehaviours, and the editor,
and all sorts of things.
But we haven't really
taken a look at prefabs,
which is a major part of this game.
So the coins, the
skyscrapers, the airplanes--
those are all prefabricated
assets that we have gotten
ready for spawning into our scene.
And we're going to take a look
at how that actually works.
So here's a list of--
in our editor view-- all the
different prefabs that we have.
So we can see airplane,
blades, and body are prefabs.
The coin, all the skyscrapers.
There are three different
kinds of skyscrapers.
And then the helicopter.
The helicopter itself we're
not using as a prefab,
because I've already
created it in the scene,
and it never gets
instantiated dynamically.
But we could easily make
it so, because I have
created a prefab with the helicopter.
So when we're looking
at the scene here, we
notice that we have just the
helicopter, and we have the background.
But there's no skyscrapers, there's
no coins, and there's no airplanes.
Well, we do have our skyscraper spawner,
the coin spawner, and the airplane
spawner.
And the three of those are
just empty game objects,
but they have associated with
them these spawner scripts.
And the spawner scripts,
we've written ourself.
And then, once we've written them,
we just simply add component here,
and then chosen the appropriate spawner.
And so what those do--
if we look in our code actually, and
we go, for example, to the airplane
spawner, we have a Start method.
We have an Update method.
Notice that the Update method
doesn't do anything, paradoxically,
because the airplane spawner
is running over time.
We are spawning airplanes over time.
But the way that we do things
over time asynchronously in Unity
is a little bit different than
anything that we've done so far.
So this Start method here,
we see that we're calling
this function called StartCoroutine.
And that function takes in a
function called SpawnAirplanes.
And so at a high level, a
coroutine is effectively a function
that yields control
every time it's called.
So it'll run, and then, rather than
go through its entire body of code,
and then end or return some value,
and have that just be the end of it,
it'll actually yield, when
you use the keyword Yield.
And depending on what
you've done with that Yield,
it'll pause for some length of time, or
do something for some length of time,
rather than end that function call.
So this SpawnAirplanes function here--
notice that it has a while true.
And so while true is not usually
something that you want in a game,
because that's just going
to lock your game forever.
But in the case of a coroutine,
a coroutine is going to run,
but then it's going
to yield control back
to whatever called it
for some length of time,
or depending on how we've programmed it.
In this case, you can see here--
yield return new WaitForSeconds
Random.Range 3, 10.
Does anybody have an
idea of what that does?
Yeah.
AUDIENCE: The logic [INAUDIBLE]
waits for between 3 and 10 seconds,
and continues.
COLTON OGDEN: It does.
It yields for 3 to 10 seconds,
and then continues its execution.
That's exactly right.
Did you have a question?
AUDIENCE: I was thinking, why do you
have three different skyscrapers set
up?
Couldn't you just have one
skyscraper and change [INAUDIBLE]??
COLTON OGDEN: You could do that.
Yeah.
I guess for the sake of
demonstrating prefabs.
And also, it's a little bit
complex more complicated to get
into dynamic material setting,
and changing materials in code.
But yeah.
You could effectively just create
one skyscraper with one base color,
and then dynamically
change its material.
But also to illustrate having
multiple different prefabs
assigned to an object, that
you can then choose at random
to generate in the game scene.
They might not
necessarily be skyscrapers
that will have the exact same color.
It could be a goblin, or a
orc, or a troll, or something.
And they're all different
prefabs that we've created.
But you can put them in a list,
and then dynamically choose
which one we want at random.
So a few different reasons.
But yeah.
In a situation where everything
is just effectively differentiated
by a single color and
a material change, you
could dynamically swap that as needed.
This code routine that we've
started-- this function that
effectively can pause itself, even
though it's being called while true
is in play.
It yields control with
this Yield keyword.
And what it does is, it allows us to
call something over and over again,
but then pause for some length of time.
Right?
We don't have to maintain a
counter for spawn time in here.
Which we could do.
We could do float spawn
time equals 0, right?
And then float spawn
increment equals like 1,000.
And then while spawn time is
less than spawn increment--
we could say in Update,
if spawn increment.
Or we would do spawn time plus
equals time.delta time first,
to get the length of time that's
passed since the last frame.
And then we would say,
if spawn time is greater
than spawn increment,
instantiate a new airplane.
And then set spawn time back to 0.
And then just rinse and repeat
this over and over again.
But coroutines take out
this need, much like timer
did, for having anything that you
keep track of with a specific timer.
You can do a whole bunch of
different things with coroutines.
One of them, in this
case that we're doing,
is just pausing for some
length of time to do something.
In this case, we want
to wait for some time
in between each
instantiation of an airplane.
So we'll just yield
control back to our game,
because we want to break
out of this while true.
But we don't want to break out of it and
completely break out of this function.
We want this to keep
going over and over again.
So we see here, this
Instantiate function is
where the actual instantiation happens.
And Instantiate takes in a prefab--
so a game object.
So in this case, we have
a prefabs list here.
GameObject public, GameObject
array called prefabs.
So this can take in any number
of prefabs that we want it to.
We're going to return a
range between 0 and length.
And then also, we want it to spawn.
We give it a position
that we want to spawn in.
So Instantiate-- it takes in an
object, it takes in a position,
and it takes in a rotation.
In this case, we want to
give it this position.
So it's a Vector3--
it's an x, y, and a z--
at 26.
So off the right edge
of the screen 7 to 10.
So within a range of
verticality up towards the top.
And then at 11 on the z-axis, which
is aligned with our helicopter
and the skyscrapers.
And then this Quaternion.Euler--
so 3D rotation, the math
behind it is pretty complex.
And I don't know it well at all.
But Quaternion.Euler allows
us to think in degrees,
and actually perform a 3D rotation
on something fairly easily.
So if you want to rotate
something in 3D, Quaternion.Euler.
Negative 90 degrees on the,
I believe it's z, x, y.
In this case, the way that the
default rotation of the airplane is,
we want to set it to
negative 90, negative 90, 0.
You could also set up
your prefab in a way such
that you don't need to pass this in.
You could do Quaternion.Identity
in that case.
But this is just to illustrate how,
if you want to rotate something
in code, how you would do it.
So Quaternion.Euler is the way
that you rotate something in 3D.
So Instantiate-- global
function that you
can call anywhere you want
to, as long as you just
give it a actual object or prefab
that it knows how to instantiate.
And then WaitForSeconds--
another global object,
which is a asynchronous
object that will allow
us to yield for this length of time.
You pass in the length of time here.
It takes it in seconds,
because WaitForSeconds.
And then, as soon as this
length of time has passed,
it's going to come back up here
into this while true instruction,
and then instantiate again.
We don't have to keep track of a time
or anything-- any weird boilerplate.
We just have to call
StartCoroutine here.
And notice that we explicitly have to
call StartCoroutine routine in order
to trigger a coroutine function.
And to do that, it returns
what's called an IEnumerator.
And so a lot of these details,
you don't need to necessarily know
the low-level details of.
I certainly don't know all the
low-level details of everything
that happens in Unity.
But just know if you want
asynchronous behavior,
your function needs to
return an IEnumerator,
which C# knows is a generator
function which will yield control
at predetermined times.
And it will manage it for you.
And to trigger it, you
need to StartCoroutine,
which is a function that
Unity has defined for you.
So any questions as to how this
works at a high level, at least?
AUDIENCE: I'm a little confused
on the syntax for Yield.
Does the Yield return--
COLTON OGDEN: Yes.
Yield takes in something, and you get a
new to instantiate a new WaitForSecond.
It's just the way the syntax
is for yielding an object.
Yield--
AUDIENCE: What is it returning back?
COLTON OGDEN: It's returning
this to the Yield instruction.
And the Yield instruction
is then yielding that.
It is a little bit weird, though.
But you only really have to--
this is a common
pattern that you'll see.
And so you'll just get used to it.
And honestly, this is probably one of
the more syntactically difficult things
about Unity.
So I mean, as soon as
you understand this,
pretty much anything else is
fairly easy at that point.
I would say this is one
of the weirder sides.
Because in Lua, and Love2D, and
those kinds of environments,
it's a little bit easier to do this
sort of thing with as much syntax.
C#, being a statically-typed
environment, to get the same behavior,
you have to go a little bit further.
Do things their way.
But that's getting asynchronous
behavior to work in C#.
And in Unity, typically, in order
to avoid messy state management,
you will use coroutines,
which are IEnumerators, often
with the WaitForSeconds object.
And just make sure to trigger
them with StartCoroutine.
And then call that function
as if it were an object.
Just like that.
And the behavior for the airplane
spawner, the coin spawner,
and so forth, they're
all fairly similar.
So StartCoroutine SpawnCoins.
And then while true.
So coins-- this row just spawns a
random number of coins vertically.
So you can have one, or you
can maybe have a couple.
And then for each of
those, instantiate them
at a random position on the y-axis.
Here, random negative 10 to 10.
In this case, Quaternion.Identity,
because we don't want
to rotate them any differently than they
already are, which I alluded to before.
So Quaternion.Identity just means
no rotation applied to the object.
So whatever its base
rotation is as a prefab.
So it'll be whatever it is
when you see it in the editor,
and when you create a new one, that's
going to be its default rotation.
So basically the equivalent of,
don't rotate this by anything.
And then, same as we saw before,
yields a new WaitForSeconds.
In this case, 1 to 5, so a little bit
more frequently than the airplane,
on average.
More coins.
As the airplane, I believe, was 3
to 10, so every 3 to 10 seconds.
And that's basically that.
And then we StartCoroutine, just like
we did before with the airplane spawner.
And then lastly, the skyscraper spawner.
In this case, we only
have one coin prefab,
we only have one airplane prefab,
but we have three skyscraper prefabs.
And so the actual Random.Range
here comes into play,
because that's how we get the different
color skyscrapers spawning at random.
And like I said before,
this can be extrapolated
to whatever sort of game
environment you want,
where you have multiple
types of objects that
are more complicated
than just a color swap,
and you want to choose them at random.
We're doing all the same
things that we did before.
And also, here, we can see
that they have a random chance
1 in 4, so a 25% chance
of increasing the speed.
So skyscraper spawner actually has--
and this is relevant to the assignment--
skyscraper spawner has a float called
speed here, which is, by default, 10.
And this drives the scroll speed
of the skyscrapers, the coins,
and the airplanes.
And so when we call it static,
do we know what that means?
Yeah?
AUDIENCE: Well, it's the same for
all [INAUDIBLE] objects [INAUDIBLE]..
COLTON OGDEN: Yes.
So no matter how many
skyscraper spawners we create,
they're all going to
share this field speed,
and it's always going to be equal to
the same amount across all instances.
So static means that
it's part of the class.
It belongs to the
SkyscraperSpawner class.
It does not belong to a
SkyscraperSpawner object.
And so we don't ever really want to
change that ourselves in this game.
But the airplane, for example,
notice that in our Update function
here, if the transform.position.x
is less than negative 25,
we should destroy the airplane.
So when it goes off screen,
we should destroy it.
But if not, then we want
to translate this object
on the x-axis by negative
SkyscraperSpawner.speed times 2 times
Time.deltaTime.
So we're translating it
on the x-axis, and we're
using the SkyscraperSpawner.speed
as our core multiplier.
And then if we look at coin--
same thing.
I should ask, what is
one design consideration
if we're looking at this--
all these components?
And let's say we're trying
to get as decoupled as we
can, and well-engineered as we can.
What is a consideration that we
can, noticing that, for example,
this exists in coin, and
this exists in airplane?
AUDIENCE: What's the question again?
COLTON OGDEN: So how could
we better engineer this?
Notice that we have--
and taking into consideration
this component model in Unity--
what could we do with,
for example, this?
AUDIENCE: So that Unity
better [INAUDIBLE]..
COLTON OGDEN: Well, I'm thinking that,
because the airplane and the coin--
well, first of all, it
wouldn't belong in the spawner,
because the spawner's
job is to spawn coins.
But the coins and the airplanes--
they have their behavior, right?
They have their update behavior.
But they're all doing kind of the same
thing, which is scrolling to the left,
and then de-spawning at negative 25.
So a design consideration here would
be, maybe we have a scroll component,
right?
Or a scroll and destroy component.
Or just a scroll component
with an optional destroy flag.
And then we just put this on anything
that we want to automatically scroll
to the left screen and
de-spawn, rather than having
to code this in every single class.
So if you're ever looking
through your code,
and you're seeing, for example, this and
this being the exact same, especially
in Unity, because of how
flexible components are,
try and think about how you can
make it into its own component.
AUDIENCE: So where would you
put the coins [INAUDIBLE]??
COLTON OGDEN: You make it yourself.
So if we went into here, into
our Scripts thing, and just
made a new script.
And then we called it Scrollable.
And then we double-click it,
it'll open up in our editor
that we've chosen in our preferences.
By default, it's going be Visual
Studio with the newer versions.
But now we have a new
scrollable behavior.
And then all we need to do--
we would say, oops--
not that.
If-- once again, I can't type.
Transform.position.x is
less than negative 25,
destroy game object, right?
And so this is the exact same thing as
all that behavior that we saw before.
So now we can take all
of that out of coin--
we can take this out, and we
can take this out here, and then
just add to the airplane
and to the coin prefabs,
we'd just add this
new Scrollable prefab,
and it'll take care of that for us.
Yeah.
AUDIENCE: How would you add that?
COLTON OGDEN: So if we're
going back to Unity--
so the question is, how would you
add the component to the prefab?
So in our prefabs, note that
we have airplane, we have coin,
and we have all the skyscrapers.
So these are all prefabs.
Oh, and I haven't actually
detailed how to create
a prefab, which I apologize for.
So a prefab-- all you need to do
is create an object in your scene.
For example, I did it
with this helicopter.
So I'm going to delete the helicopter,
because this is just the helicopter
prefab.
It's not going to actually delete
the helicopter from our scene.
But if I take this helicopter
here, and then I drag it in here,
notice that now we have a prefab here.
We could take this helicopter out,
and just add a new one right there.
So now I have two helicopters.
That's all a prefab is.
It's just something that
you've made in your scene
that you want to replicate or duplicate
in the future, ideally through code.
And notice it's showing
here in our hierarchy view.
But obviously you don't want that.
But that's how you create a
prefab is, you find something
that you've configured in your
game scene, and then in your code,
you're allowed to then
instantiate that prefab,
assuming that you've made that
prefab a member of whatever class
instantiates it.
So in this case, the airplane spawner.
So notice that we call Instantiate
here, like we saw, before on line 24.
But it's looking at prefabs.
It's a list, and it's looking
at a random range between 0
and the length of the prefabs.
You have to declare a public
GameObject list prefabs here.
And then, once we do that, and we
go to our airplane spawner here,
notice that we have
this prefabs list here.
So we actually get a editor view
of that code, that data structure.
And we can just add
prefabs that we want to.
And if we change the size to 2,
then we can add a second prefab.
Or if we make the size 10, then we
can put 10 different airplanes there.
But we only have one airplane that I
modeled, so I was going to make it 1.
But this is the same thing.
This GameObject list
is that same list, only
that's the view we have
of it in the editor.
And it's just a different
way of looking at the data.
And that's the nice thing about
Unity is that, if you make
any of your fields public, like this.
If I did public int someNumber, right?
And I save that, and I go
back here, my airplane spawner
should get a someNumber right here.
And then I can just set
someNumber to whatever I want.
It doesn't do anything right
now, because someNumber
doesn't affect the script.
But this is a nice way to take the
burden from you out of the code.
You're not experimenting with code.
You're not tweaking some
variable in your script.
SomeNumber 10, run me,
OK-- someNumber 12, run it.
You can just assign it here
in your actual editor view,
and then just tweak it as you want.
So I can just scroll through it.
I can start the game and
I can pause the game.
AUDIENCE: So is it that
you just make it public?
COLTON OGDEN: You have
to make it public.
Exactly.
AUDIENCE: Oh, then that shows in.
COLTON OGDEN: Yep.
And so I can just do this.
And then I should be able to--
I can just change this
now, if I wanted to, to 67.
And so if that actually had some
sort of effect on my game world--
if my game relied on that
number being meaningful--
this would update the scene.
And so you can make whatever--
you can debug this way,
or you can customize your
components more this way.
But it's just a tremendous
amount of flexibility.
And so that's how we're instantiating
this from this list of prefabs.
It's a list of game objects.
We've made it explicit to Unity.
The editor's going to know,
OK, these are game objects.
And so prefabs are game objects.
So we can just put any
of these into this field
here, this element 0 field, or
however many fields we have.
And it will, in the code,
randomly choose one of those,
and then instantiate it.
So any questions as to how
prefabs work, or instantiation,
or anything like that?
OK.
AUDIENCE: Does each prefab
have a unique number or not?
COLTON OGDEN: Does each
prefab have a unique number?
Not a unique number.
They just are all assets
in your folder here.
They have some kind of identifier
to Unity that's hidden from you.
It might be visible
from you if you look.
They might have some sort of generated
ID or something like that, so
that it knows, underneath the scenes.
But it's not something that you
worry about in your actual code.
We've created a list here that's just--
it will expect some number.
It doesn't know how many.
And then, in the editor, you
can actually tell it how many.
Because every list that
you make visible in
the editor will have this size field.
And that's just part of
the editor's abstraction.
The editor has abstractions
for a lot of different objects.
You can create a lot of different
objects in your MonoBehaviours,
and make them public, and Unity
will have a different view for them.
Things like color pickers,
and stuff like that.
I don't know the exact object offhand,
but if you make a public color
picker in your MonoBehaviour
or something like that,
you'll actually get a color picker
here that you can choose a color for,
which is pretty awesome.
And there's a lot of
different customized views.
I think, actually, the directional
light might be an example.
See this color here?
This is somewhere in code.
There's a public color something.
And then in the editor, when
you're actually editing it,
you can choose the color.
And Unity gives you the option
to make it wherever you want.
And notice it's actually
affecting the background there.
One of the really big
strengths of Unity,
and a reason to really make
your components customizable,
is this one-to-one mapping
between your data, your code,
and your editor view of the data.
Take the burden away
from you programming it,
which you're more prone
to make mistakes, too,
and also waste a lot of time.
And then just be able to modify.
How much faster is it
for me to just say,
I want this red color, rather
than color.r equals something,
and then color.g equals something,
color.b equals something.
And then assign it that way.
So that's just a simple
example to illustrate it.
But there's a tremendous
amount of potential involved
in making your components customizable.
And so that's what I did here.
Because I wanted the skyscraper spawner
to spawn not just one skyscraper
but several skyscrapers, I
created this public prefabs list,
that I can then populate
from Unity here.
And say, OK, this object,
this object, and this object.
Put that into the skyscraper
spawner here, in these slots.
And then my code knows to instantiate
it, randomly picking one of those.
Yeah.
AUDIENCE: In the example
earlier, how would you
actually go about making something
scrollable now that you've made that?
Would you just add
component to the coin?
COLTON OGDEN: How would you go about
making something scrollable now that
you've--
AUDIENCE: You declared that
Scrollable class, right?
COLTON OGDEN: Oh, yeah.
So I have a Scrollable script here.
Oh, do you mean the infinite scrolling
background, or the scrollable object?
AUDIENCE: The one where you define it as
being destroyed when it's [INAUDIBLE]..
COLTON OGDEN: Oh, yeah.
So in order to do that-- so we've
made the Scrollable script here.
So you would just go to--
in this case, since we're
instantiating all of the coins, and
skyscrapers, and airplanes as prefabs,
you actually edit the prefab itself.
So I'd go to this coin prefab.
I'd add component here at the bottom.
And I would add Scrollable
there, which is a script.
And you can tell it's yours,
because it says script there.
Just like coin here is a script,
and rotate script is a script.
That's actually an old script
that I didn't use anymore,
because I just made it
part of the coin itself.
But this is another part of what
makes the coin class, by the way,
is this transform.rotate x,
y, and z, either relative
to itself or to the world space.
In this case, it shows the
world space, because I want
it to rotate on the world's y-axis.
But if you rotate an object,
its own x, y, z still exist.
And so you can have something
rotate about its own x, y,
and z, regardless of its
rotation in the world.
And so I want the coin to always rotate.
So 5 degrees on the y-axis here.
So this is another part that you could
take and make it its own script--
just a rotatable script.
Auto rotate script.
And then just make these public fields,
like public x, public y, public z.
And then you could change
those in the editor,
and then actually customize your objects
without having to go into the code
itself.
AUDIENCE: So you don't have to do
any collisions, actually, yourself.
You just click the button and
type in the Collide function.
COLTON OGDEN: Yeah.
You don't have to do any
of the collision yourself,
because Unity comes with
a 3D physics engine.
You have to tell it what to
do when the collisions happen.
But you don't have to actually code
the 3D physics engine yourself, which
is a tremendous amount of work.
One of the big selling
points, definitely,
for doing any 3D things in Unity.
I mean, a lot of engines now
have 3D engines for free.
There was a time when
it was less prevalent.
AUDIENCE: How would you
know what you collided with?
COLTON OGDEN: Because there
is a collider that it gets.
Where is it again?
Is it the skyscraper, for example?
So every skyscraper, when
it collides with something,
this OnTriggerEnter gets
passed in this collider other.
And so that's going to be the
object that you collided with.
You can assign a name to an object, and
then get its name, as well, in code,
if you needed to do that.
In this case, we wanted to know
whether it's the helicopter or not.
So we got the HeliController from it.
But in our game, it's
kind of a special case,
because there's only
one type of object that
has a collider that's a non-trigger,
and that's the helicopter.
So we can assume that this exists
when we do get a collision.
But otherwise, we probably want to
say, get component of HeliController,
and then test it for equal to null.
And if it's equal to null, then
we want to not do something.
If we tried to call
explode on a null object,
that's going to be a
null pointer exception.
And then you're going
to crash your game.
But in this case, we're
guaranteed for that not to happen.
Because, like I said,
the only collider that
can collide with this that's not a
trigger is the helicopter object.
So does that makes sense?
AUDIENCE: Sounds like a physics
problem with an exploding element.
COLTON OGDEN: Oh, yeah.
Yeah.
That's all too real.
In this case, though, all explode is
is, thankfully, just destroy game object
and then start a particle effect.
So any more questions
as to how instantiation,
prefabs, using the Unity editor,
interacting with your model
behaviors, public variables?
Yeah.
AUDIENCE: You get processes, you
first enter the data in that to there,
and then it runs the
code to load the data,
or can you also put
value data in the editor?
COLTON OGDEN: You cannot define--
so the question is, do you first
create the data in the editor,
and then the code, and then
tie them together that way?
In order to get a new component, you
will have to create the class first--
the model behavior that you want--
and give it the public fields that it
needs for the editor to actually read.
So the editor reads your script,
looks through all the public fields,
and then will create the necessary
GUI elements in the editor
to interact with the code.
But this needs to exist.
All this code needs to exist.
Anything that has these public variables
that you want accessible in the editor
needs to exist in code
first, and then you
have the power to use it in the editor.
And then it's customizable
at that point.
Any more questions?
All right.
So that's the prefabs.
So we looked at texture
scrolling before.
And we're going to go kind
of quickly through this.
But all texture showing
was, if we recall,
was I have a scrolling
background class here.
It's got a scroll speed.
So if we wanted to, since it's
public, we can edit it in the editor
and make it faster or slower.
But if we maintain a
reference to our renderer.
Every object has a renderer-- mesh
renderer, typically, for 3D objects.
And the renderer has a
material associated with it.
Everything in Unity has a material.
And material doesn't
necessarily have a texture.
But in this case, our
background does have a texture,
and it's going to be
called MainTex by default.
That's the main texture, if
we want to assign a texture
to see visually on a material.
So material can just be a
color often, but it can also
be a color and also a texture.
So in this case, the
background is a texture.
It does have a texture assigned to it.
And notice that if we
go to the background,
and then here is where
we actually create.
So this is a material here.
It's got a shader.
So we're not going to talk too
much about what shaders are.
We've talked about them briefly.
In Unity, you can go quite
a bit farther with them.
Well, technically speaking, I guess
you could go equally far with Love2D--
2D shaders and 3D shaders, at least
in vertex and fragment shaders.
But for all intents
and purposes, we're not
going to go into detail
on shaders today.
But they're very similar.
In this case, every material
has a shader in Unity,
in order for it to render.
Because anything that renders
needs to be shaded in Unity.
But notice that here we have a texture.
So this is that main texture
thing that we saw before.
And then this is the bump map here.
We don't have a bump map,
because our texture isn't bumpy.
It doesn't have any contour
detail or anything like that.
But you can just select a texture here.
So I could give it that
texture if I wanted to.
Or I have another
couple of textures here.
This texture here.
It doesn't matter which texture you
choose, but you can choose a texture.
And then that material will
then, it will calculate,
based on the mesh, how to
draw that texture best to it.
And you can set every material's
texture offset via its SetTextureOffset
function on the x and the y-axis.
And that'll shift it,
effectively accomplishing
what a scrolling background needs.
It'll draw it, and then it'll basically
wrap around to the other side.
So that's how we get the
infinite scrolling texture.
We just set its texture offset.
We specific call SetTextureOffset
on the main texture,
and then we pass in a Vector 2.
So just two numbers--
offset and 0.
Because we don't want to touch the
y-axis, so it was 0, and then offset
is just some value that
increases over time.
And then Time.time, recall--
time since the beginning
of the game has started.
Time.delta time-- time
since the last frame.
And so we can just do one calculation
in here and update every time,
and then multiply it
times scroll speed to get
the scroll amount that we want here.
And I've set it to 0.1 just
for a semi-slow effect.
But in the editor, if we look at our
scrolling background, which is here.
And then I've made it public, so
I could just easily make this 1.
And I don't know how fast it's
going to be, but 10 times faster.
So probably pretty fast.
Yep.
So it's hauling.
But yeah.
All that is is a shifting how it
maps the texture onto the 3D surface.
And this 3D surface, to
be clear, is just a plane.
So just a plane.
And notice that it doesn't
get rendered from the back.
So anything which is a polygon
has one side that gets shaded
and one side that does not get shaded.
So if you see invisibility on one
side, and not invisibility on one side,
that's not a bug.
That's a feature.
That's the texture
scrolling side of things.
Anybody have any questions
as to how that works?
We won't really need it
for much going forward.
It's not part of the assignment.
But it ties in to what
we've done before.
So I thought it would
be interesting to cover.
Last thing we'll look at is audio.
Audio is pretty easy.
All you need in Unity to do audio is
an audio source and an audio listener.
So a source plays audio.
So James, if you are an audio
source, I'd be an audio listener.
And I'm listening for
audio and playing it back
to the speakers when I hear any sort
of source of audio in the game world.
So you can have infinite audio sources,
but ideally one audio listener.
And it's usually whatever main
camera that you're drawing with.
And then sounds in Unity
can be either 2D or 3D.
In this case, all the sounds that
I've put into this game are 2D.
And that's just this spatial blend here.
Notice that there's a 2D to 3D slide.
And so that'll calculate,
based on where the sound is,
how it sounds in the game space.
And it's based on how far away it
is, and what side of you it is.
And so the main camera has the
audio source for the music.
And so it just starts
the music right away.
Notice that we didn't
have to code any of this.
I just attached an audio
source to the camera.
And then there's a Play On Awake
checkbox, and a Loop checkbox.
So normally we've done like--
at the start of our game code,
set looping to true, and then
play the source.
In this case, we'd have to
do none of those things.
This is just given to
us by Unity by default.
AUDIENCE: You put the
audio on the camera?
COLTON OGDEN: Yep.
AUDIENCE: You could put it on anything.
COLTON OGDEN: You could put
it on anything you want to.
AUDIENCE: The sound is
relative to that object.
COLTON OGDEN: The sound is
relative to that object, yeah.
That's audio.
It's pretty simple.
I mean, it's an art form
when it comes to how
you want to position
things in your game world,
and how you want them
to sound, and whatnot.
And you can get more
complicated with it.
But that's how you would do
basic 2D, in this case, audio.
But you could easily
also do 3D audio just
by making this set to 0 from 0 to 1.
And you can make it
more or less 3D, too.
If it's not all the way to
1, it'll somewhat be 2D.
So you'll hear some of it no matter
what, and some of it will be 3D.
And then setting it to
1, it'll be purely 3D.
So if it gets far enough away,
you won't hear it at all.
The explosion sound, as
well, gets triggered.
And so this happens in the--
I forget exactly offhand
where it gets triggered.
I believe it's in the
HelicopterExplode function?
Oh, yes.
I created an object in the scene that
has an audio source for the explosion
sound.
And because I made this public,
I can just put it on this object.
And so there's a reference to
that audio source at all times.
And so I trigger explosionSound.play
whenever we call this Explode method
on the HeliController.
For the reason that I didn't put it
on this object, because we destroy
this object as soon as
we get into a collision.
And so I didn't want to
put the explosion sound
audio source on this object, because
it would get destroyed in there.
It would not play audio, effectively,
as soon as we destroy it.
So we have to have it
somewhere else on the scene.
I could have also just made the
object invisible, but I didn't.
I destroyed it.
And so, yeah.
That's this explosion sound object
which, if we look at the helicopter,
in the HeliController, which
is all the way down here.
Notice that it has a reference
to an explosion particle
system and an explosion sound.
And we just have to click and drag the
object effectively from here to here
to pair the two of them.
And then the script
that this is referring
to will always have a reference
to those, as long as these
are set to something.
And notice that we also have
coin total we've made public.
So I guess I could experiment with it.
And then speed-- we made this public
so that you can make the helicopter
faster, if you wanted to, or slower.
And so you'll find it often useful
to make a lot of these fields public
just for you to experiment with.
And then there's never
really harm in doing so,
because folks aren't going to be able
to actually see this in the editor
when they download your game.
So make as much public as you
want for debugging purposes,
and just have fun with it.
But that's audio.
Audio sources produce the sound.
Audio listeners listen to the sound.
And actually make it go
through your computer speakers
or whatever your
default audio system is.
And here's just a showcase
of the two on the camera.
And that's audio.
So any questions as to how
the audio works at all?
All right.
A couple of last things
before we close out here.
So the Asset Store is probably one
of the biggest things about Unity
that sells it.
So oftentimes, it's a lot
easier just to get something,
whether it's a library, if you're
programming, or something else,
get something that's
implemented for you,
so that you don't have
to implement it yourself.
In this case, there's an RPG
Systems for Rapid Development
something, Visual Scripting
system, looks similar to Unreal.
There's a ton of things in the Asset
Store-- models, scripts, audio, editor
tool kits.
A lot of cool things.
A lot of it's free, if
you want to experiment.
So a lot of the assets that I got
to mess with in this game here
are free, like the coin and some of
the other stuff that's bundled with it.
There's a lot of really cool
things and really cool systems
to help you for $10 or $20.
You can spend a little
bit of money, and then
get like 25% of your
game done right away.
And then you can actually
get closer to shipping it.
So I think it's hugely valuable
to be looking at the Asset Store
and thinking about how you
can save your time that way,
if you're trying to actually
ship a game and get to market.
So definitely look
through the Asset Store.
See if there's anything that
will make your life easier
when it comes to developing games.
Because I know that I've used it several
times, and I rarely regret doing so.
So Assignment 8 is going
to be pretty simple.
So for the second part,
there's a bug in the game
where, if you die over and over
again, the scroll speed never resets.
So it is keeping faster, and faster,
and faster, and faster forever.
But it's a one line fix.
And I want you guys to find where
to fix it, given that we know,
given what we've seen today.
And there's a hint here
about static variables.
So it will also be detailed
in the spec as well.
But this is an easy part.
This part's fairly easy,
too, because all it really is
is taking the kind of the
same stuff we've looked at--
the coin generator and coins--
and then making gems that spawn in
addition to the coins at a rarer rate.
And these gems should
be worth five coins.
And so when you collide with the
gems, just add 5 to the coin total.
And if you collide with a
coin, add 1 to the coin total.
And that's basically
it for Assignment 8.
So next time, we're going to dive
into first-person games in Unity.
So we'll look at some of the
features that we get for free.
We're going to implement a simple
maze-like game where you can navigate.
And it will be dark and
kind of scary, similar
to a game called Dreadhalls,
which is a mobile VR game.
And we'll actually test out Unity's VR,
and try and get a VR headset in here
so people can check that out.
Cool.
Thanks a lot.
I'll see you guys next time.
