COLTON OGDEN: All right.
Welcome, everybody, to CS50 on Twitch.
My name is Colton Ogden and today we're going to be taking a look at--
to depart from prior streams we're going to transfer or transition from 2D
and using Love and Lua to 3D and using Unity and C# today.
So a little bit of a transition from a dynamic
to a sort of statically typed languages and object
oriented programming languages, but should be a good time.
Some people in the chat already here.
So I see [? Bavik ?] is here.
So hello [? Bavik. ?] Good to see you again.
[INAUDIBLE] good to see you.
ForSunlight, good to see you.
We've got a bunch of people here.
[INAUDIBLE], nice to see you.
Thanks for joining us today.
Ann100, thanks for coming in again from Peru.
Good to see you, as well.
Yeah, we've got a lot of people in here already.
A lot of people are interested in Unity.
So if you're unfamiliar--
I'm going to transition to my desktop here--
I have a couple of things going on here.
I've got Unity in the background, but if you don't have Unity already,
you're going to want to go to Unity3D.com and then if you click
on this button that says--
I'll make it a little bit bigger so we can see a little bit better
here and zoom in--
it probably looks something similar to this if you're looking at this video
maybe in the future, should still be somewhat similar.
But on the front page is a Get Unity button
that takes you to a page where you can choose which version of Unity you want.
There's different versions.
There's a plus, a pro, and a personal.
Plus and Pro would be for if you're working for a company,
or not even necessarily a company-- well,
I guess probably it would be in a company situation,
but a small or a large company.
Or if you're just a hobbyist or making below a certain threshold of income,
you can go to the personal option.
Try Personal and then it will ask you to accept the terms and conditions
and then download the installer for your operating system,
or what's called Unity Hub, which is a fairly new thing that they've
done which allows you to actually maintain multiple different versions.
[? Bavik ?] says, "wow, yeah, I wish we could
get a certificate similar to professional development."
42Force, "hello Colton."
Hello 42Force, good to see you.
And Reema7 says, "Unity star."
Reema7, I don't believe I've seen you yet, so thank you for joining us today.
Got a fair number of people here already.
So yeah, it should be a fairly painless process, no matter what operating
system you're running.
But definitely go here.
Go to the front page.
Click the blue button.
Follow the instructions.
Download Unity Hub or the installer for your operating system.
I chose Unity Hub, just cause I think that's where
they're sort of trending towards.
They've made a lot of changes in the last year or so with Unity,
and that is one of them.
Once you have that up and running, which should be relatively
painless, although it might take a long time because Unity is rather large
and also comes with a bunch of different packages
for building games for different platforms, like for Android, for WebGL,
for Xbox, PS4, all sorts of different platforms.
Unity is amazing in that respect.
So it may take you a little bit of time.
But it's very much well worth it.
So once you do have Unity Hub installed, it
should look something like similar to this when you first open it up.
It'll ask you to log in, so you will need a Unity account, as well.
So I believe the Unity sign up link is fairly painless.
Looks like id.unity.com will allow you to actually create a Unity ID.
You will need to specify a username and a password and email or password
and then you will need to log in on your machine in order to use it.
But it is a free account and relatively easy to setup,
just like Unity personal is free and rather painless to set up.
42Force says, "from Manila in the Philippines.
Had to stay up and catch you again."
Thanks so much for staying up.
We're trying to make the streams a little bit earlier,
especially on the Friday streams where we do
the longer ones, the game dev ones.
So hence why we're starting at 1:00 today.
Often we start at 3:00.
So thanks for staying up.
I'm not sure what time it is in the Philippines.
Philippines time.
Right now it is 2:00 AM in the Philippines?
OK, wow.
Well, thank you very much for staying up that late to tune in today.
And feel free to go to sleep.
We will post the video later on YouTube.
And if you're watching on YouTube, you can tune in live at twitch.tv/CS50TV,
which will probably be in the YouTube description.
So once you have Unity Hub all set up, you have a Unity ID,
you've downloaded Unity Hub for your operating system
and it's taken you probably a half hour or so because it's a large download,
it'll look something like this when you go to create a new project.
So there's different tabs up here, all the projects that you have.
It has some tutorials baked in so that you can actually
walk through some preset projects, and then a bunch of different versions.
If you decide to-- maybe you have different Unity projects that have
different compatibilities--
you can go to the installs thing here.
You can also go to a new project, open a project, settings,
look at your account, blah, blah, blah.
The important thing is the new project because that's
what we're going to do today.
We're going to build a project from scratch.
We're going to look at pong in 3D today.
And actually, let me make sure my mixer is set appropriately.
It is not.
So I should-- now I should sound a little bit better.
I forgot to turn off my mixer.
So now I should sound a little crisper and not as weighty, I guess.
There shouldn't be as much background noise.
Let me know if that sounds any better.
It looks like now my volume might need to be turned up a little bit, actually.
So I'm going to do that, as well.
And then if all is good, we should be set to go.
42Force says, "thanks for checking."
I was genuinely curious.
I wasn't aware that it was that far east or west,
depending on how you look at it.
KeithSCH says, "hello from the UK."
Hello, Keith.
Thanks so much for joining us today.
Ann says, "it's lunchtime here."
It's about lunchtime here, as well.
OK, awesome.
This is worth to watch live, very engaging lectures as always.
Thank you so much.
I appreciate it.
That's why I love twitch so much.
We can have a sort of back and forth.
And maybe today we'll cooperate on sort of implementing this project.
So what are we doing today?
Well, we're going to make a version of pong.
So if you're familiar with what pong is, we teach it in my games course.
It looks something similar to this.
The image is not quite working the way that I wanted it to.
It looks like they changed their Google Images UI today, which is hilarious.
But it looks something similar--
and you can't see because of the chat, as well--
but it looks something similar to this where
you have a paddle on the left, paddle on the right,
or vice versa, because I'm currently flipped.
And the goal is to sort of make the ball bounce past your opponent's paddle
and strike some area beyond where it exists.
And that will trigger a point for you on your side of the screen
where you can see there's a score written there, four and two.
And it'll be something very similar to what we did today,
except we're going to do this in 3D instead of 2D
because Unity is, first and foremost, a 3D engine,
although it is a 2D engine, as well.
2D was not something it originally came with many years ago.
But as of the last few years, it's had quite a good solid set of 2D features.
But it's fun to explore it in 3D.
So that's what we're going to do today.
We're going to make a 3D version and we're
going to implement it from scratch.
I do have some notes that I took when I implemented it just
in case I do hit a stumbling block.
But we should be fine.
It's a fairly easy project to undertake, even as a completely beginner at Unity.
Although we will be doing some coding today.
So the nice thing about Unity is it does allow
you to not have to code as much as, say, Lua
and Love 2D, which is what we were doing the other day,
because that is a purely code-based framework.
It has no built-in graphical tools.
Unity is much more of all encompassing editor.
And we'll take a look at the editor tools and see what that looks like.
OK, I missed a few comments here.
Ann says, "yes, it sounds better."
Awesome, thank you so much.
[INAUDIBLE] says, "sounds better, yes."
ForSunlight, "our green tech teacher taught
how to make a real pong game in class, and I'm learning the virtual form."
A real pong game, that sounds like it would be much more difficult.
Do you mean, like, in hardware or, like, a physical-- like, how to make a--
like, actual paddles and a table?
Nobody ask long questions today.
There's nobody to read them.
I will do my best to read every question that comes through,
even the long ones, even the long ones today, just for you guys.
Agree.
"Played pong is an arcade game back in the '60s," says Keith.
Yeah, no, it's been around for a long time.
But it's such a great game to use as a teaching tool
because it has all the basics and it's still somewhat fun.
It's a nice, like, entry level piece of software to write, a game to write.
And we use it in my games course as the first game that we teach.
I'm going to come over here to the other laptop
and just plug my games course shamelessly.
CS50.edx.org/games.
We teach how to use Lua and Love 2D as well as Unity in that course.
And it's online on EdX for free.
The first game that we do in Lua and Love 2D is pong.
But today we're going to be doing it in Unity in 3D,
so it's going to be even better.
"Can't be sure, [INAUDIBLE]"" says Bavik [INAUDIBLE]..
OK, so I'm in my Unity Hub thing here.
I'm going to get rid of chrome here just because it's a little bit distracting.
I'm in 1080p today, as well, just because the 720p in Unity,
it can be a little bit cramped.
So we've expanded the size of today's background a little bit.
There's no CS50 dot--
or twitch.tv/CS50TV in the bottom left today.
I might find a transparent overlay I can plug over it.
But if you're watching on YouTube, twitch.tv/CS50TV again.
And that'll be the last time that I plug it.
So I'm going to specify a project name, 3D pong.
Just going to save it in my home directory,
which is the default location that Unity will store all of your projects.
You can specify whatever folder you want.
If you keep all of them in your home directory,
it's probably going to be a little bit crowded,
but I'm not too worried about it right now,
just because I'm not using this as a full production machine,
more just like teaching tool.
But if you have, let's say, maybe slash Unity projects in your home directory
or whatnot, that's a great place to put projects.
We're doing 3D template not 2D template.
You can choose between 3D, 2D, 3D with extras,
high definition RP, all these things.
Most of those are all brand new to the Unity beta series.
And if you download Unity today, or at least soon,
compared to where this video is released,
it'll probably be a beta version of Unity.
Unity is in this sort of continuous beta process.
And they've started naming their versions.
Previously it was Unity 5.
Now they started naming it after the year and they suffix
the year with B some number, which is the current beta.
But the betas are all very stable, basically the same thing
as a release, an RC or Release Candidate type of software.
We're not going to use analytics because that's just too much.
And once we do that, we click the nice blue button,
we should get Unity starting up and doing all of its stuff.
And our project will be up and running shortly.
ForSunlight says, "physical one but not metals."
OK, interesting.
That's pretty cool.
I am not so great with physical stuff, using tools and hardware
and things like that.
I'm much more comfortable with software, but if push comes to shove,
we can always figure it out, right?
But yeah, as you can see, Unity takes a little bit of time
to initialize your project.
It has a lot of stuff it needs to import and compile to get running.
But this only needs to happen one time as it initializes your project.
And then thereafter, it'll be faster.
I'm impressed everyday what they make as projects.
I am nominating the teacher for STEM so everyone can use her projects.
Yeah, sounds super cool.
Super awesome.
You should plug the-- if you have pictures or anything of that project,
definitely plug it.
So it says my Unity version is a little bit behind.
I'm on beta 5.
I think currently it's on beta 9, 2018.
But it doesn't matter because we're not using any features that
are specific to the betas.
If I'm being perfectly honest, I don't even
know what the beta 9 features are versus beta 5,
just because I haven't paid super close attention.
But this is Unity.
Let me expand this a little bit.
So the chat is blocking stuff that's not super important yet,
although I may end up shrinking or disabling chat
at some point because we probably will need all the real estate we
can get on the screen, or at least I might turn it off intermittently.
Unfortunately, it clears every time I do that so I can't actually
bring it back in full.
But we might end up not needing it for a lot of the chat, anyway.
So I'll keep reading out the questions.
But this is the Unity editor.
So it's by default made my hierarchy view a little large.
Don't need it to be that big.
But we can see here we have a few different things.
So this is quite a bit different than using anything or implementing anything
in Love 2D or Lua, because those are all just programming environments.
They're frameworks that you trigger with function calls, effectively.
This is a whole built-in-- or it's a whole sort of all in one editor, right?
We have what's called a scene view up here.
So if I right click and I rotate my mouse,
I can look around the scene, which is currently empty, or at least
mostly empty.
I have a couple of objects.
I have a camera, which you can see on the left,
and I have a light source, which you can see on the right.
Below my scene view, I have a game view.
So that's where I can actually see a rendered frame of what my game will
look like when I actually run it, which is nice so that I don't actually
have to keep running my game.
If I just want to see that something visually is changing
or that my camera is aligned correctly, it renders continuously.
Not 60 frames per second, necessarily, but if you update your scene
it will reflect in the game view.
And you can see it's named game here, although it might be a little bit hard
to see because it's a really tiny interface.
And then the Scene tab up here.
And then there's also the Asset Store tab, which we probably
won't look at today, but in the future we can definitely take a look at that.
Reamof7 says.
"I'm so excited.
Did that roll the ball tutorial and was so lost."
Yeah, well, if you have any questions as we're going through today's code,
definitely let me know.
Today's code will be similar to that.
It's been a while since I've looked up the Unity roll a ball code,
but most of that actually should be fairly similar to the things we
talk about today, things like rigid bodies and using basic game objects.
Yeah, should be more or less similar.
So we have our scene.
We have our game view.
We have what's called our hierarchy.
So this is what shows everything in our scene.
So like I said earlier, we have a main camera and a directional light.
Can I make this any bigger, by chance?
Let me just see.
It's a little small, but I'm not sure if that's something we can easily change.
Zoom, maybe?
Can we do that?
Oh, that just zooms the--
I think that just zoomed the game view.
But this is the hierarchy here.
And you should be able to-- if you're watching this in 1080,
you'll be able to see it just fine because I'm actually
shooting it in 1080.
But this is the hierarchy which shows all of our objects.
So like I said, this is the camera on the left.
This is the light source on the right.
And the camera is obviously what is going to be rendering our scene.
It's like we have an actual world that we're using now.
And you can think of it as a physical camera.
And you can actually change it.
So if I were to go over to this camera, I can actually click on it
and edit its transform.
So notice that I clicked this button up here at the very top left,
this little arrow thing right up here.
And what that allows me to do is it triggers these three
arrows, these three colored arrows, which
tells me I can move this object along any of these arrows.
So these are all different axes.
So now we're not in 2D where we have just x and a y.
We're actually in 3D.
So we have x and y and then we also have z,
which you can sort of think of as going towards you--
towards or away from you in space, right?
And you can arrange your world such that x accomplishes that function, as well.
But the trend typically is to have x and y be sort of the frame like this,
and then z to be the vector that points between you and the game world, right?
So it's that extra third dimension.
And so if I drag one of these arrows, you
can see that I'm actually moving the camera up and down.
And I can do that.
I can move it left and right, as well.
And it's not actually going to change anything in the scene,
or at least visibly, because we don't have any objects in the scene.
We don't have a point of reference.
But I could easily go over to my object hierarchy,
for example, right click, go to 3D object cube.
Notice that now I actually do have a 3D object.
And I could actually move this around with its transform,
just like I was doing with the camera.
And you can see that the game view is actually rendering this in real time
every time I change the object it's changing what's rendered to the screen.
And so if I move the camera, just like I was moving the object,
now it has the same effect where things are changing based
upon where the camera's position is.
And the camera can also rotate, as well.
So maybe I don't necessarily want to just move it.
I want to actually change what angle it's looking at.
I can do that with this command up here.
Notice that up at the very top left I have that button that I click to move.
Next to that on the right of that is an actual rotation tool
which allows you to not only translate on a given axis
but rotate on a given axis, as well.
So super flexible, allows you to position everything the way
that you want.
Want to get everything sort of back there.
All right, let me just take a look at the chat,
make sure I didn't miss anything.
"Hello from Bangladesh," says [INAUDIBLE]..
Good to have you, [INAUDIBLE].
I'm not sure if you've been here before.
I don't recognize the name, but I'm glad to have you today with us.
Thanks so much for joining.
So, pong in 3D.
So we've covered-- so the scene view.
We've covered the game view.
We've covered the object hierarchy.
We can add objects.
We can move them.
We can rotate them.
That's sort of the foundation of what we do, right?
Any scene that we have is going to have models
that are in our view that get rendered that can maybe rotate around,
that can move around, interact with each other.
And obviously we're going to want to do some programming of certain things
in order for them to have more complex functionality,
for example we want to be able to move our paddles in real time, for example.
We want the ball to bounce off of surfaces.
So we're going to need to tell it how--
we're going to need to give it the right components or tools in order
for which to detect sort of collisions between other objects
and those sorts of things.
But we'll dig into that a little bit.
I'm going to finish off our tour here of the object-- or the editor view
real quick by just seeing this tab over here.
And I disabled the chat so that it's not sort of covering up
what I'm trying to demonstrate.
We can bring it back if we don't need it as much in a little bit.
But this is sort of a file system view of your project
so that you don't have to do the tedious sort of file management
that you would often have to do in something like Lua or Love 2D.
Let's say I want to add a graphics--
or I want to add a sound file to my project.
I'm going to need to generate the sound file, put it somewhere,
which I still would have to do with Unity.
But at that point, I still have to manage it in the file system.
If I want to move it around or do anything with it outside of Lua or Love
2D, I'm going to have to manually go into Finder or File Explorer,
if I'm on Windows, or whatever the default sort of window manager
is in Linux or other operating systems.
But in Unity, you actually get a file system view within the editor itself.
And you can move files around and this becomes very helpful
as we start digging into using resources amongst our game objects.
For example, if we want to assign a sound to a paddle
or to a character moving around the scene,
we can just click and drag the sound file
in our actual hierarchy-- or our file system
or project view here directly onto our game object.
We don't have to do anything in code.
You don't have to link those things in code rather than in our file system.
It's super nice, super handy, super integrated.
And then the last big thing that you see by default is on the right here,
this thing called the inspector.
And if I click on my main camera, for example,
you can see the inspector populates with what are called components.
And these components are responsible for all behavior in Unity.
So for example, everything has a transform component
by default, which is what gives it a position, a rotation, and a scale.
So whenever we actually manipulate, for example, this transform on the y-axis,
it's actually changing values if you see in the position field
there on the right.
And if I were to move it along the x-axis, you get the same thing.
It's now manipulating the exposition.
And those are all sort of text fields that you can manipulate or edit
yourself.
So if I were to say this is going to be position two,
notice that it instantly moved to 2 on the x-axis, 2 Unity units, which
by default is approximately 1 meter.
So you have the not only fine-grained control
via using the actual sliders, the arrows themselves, in the scene view,
but also manipulating them as by entering them manually in these fields.
And you can also manipulate them programmatically through scripts.
The camera, as an example, also has a camera component
which allows it to render to either itself
or to something else, which is super nice.
For example, you can render it to a texture
and have something like a TV in your scene
that's actually getting the input of another camera in your scene.
But by default, whatever your main camera is
is just going to render to your default graphics
device, which is your graphics card, which
will be broadcasting to your monitor.
And you can do various things.
You can have the camera have a skybox as it's background.
So notice that in the game view down here,
we have sort of this sky view behind our cube.
But if I wanted it, for example, just to be a solid color,
I can just click solid color there and maybe make it white or make it black
or make it blue, any of those, and it changes as well.
If I, for example, wanted a more simple aesthetic--
and we actually will do that.
We will do that later.
We'll have a background color of maybe some gray-ish
and then the rest of our scene will sort of
be black and white, similar to the actual pong, but obviously in 3D.
But these are components.
These are going to be what's responsible for all of the behavior in our game.
Now, today's stream is probably going to be about three hours long
as we implement pong.
I would say if we do go over, it possibly might go to four hours,
depending on if we go into any sort of side tangents
or if we want to do a particular deep dive on some subjects,
depending on the complexity, of course, of the topic.
But I'm going to estimate three hours, potentially four hours.
But it will be a from scratch, fairly encompassing tutorial.
So I think that is the-- that's more or less sort
of the basic gist of the default editor settings and the default panels
and sections.
We'll see more as we continue implementing a lot of this game.
But I think the next step will be to actually think about,
what are the pieces of our game and how to implement them there.
So I'm thinking pong, it needs paddles.
It needs a ball.
So what I probably want to do is have maybe a couple of rectangular,
cube-like, I guess, rectangular prisms to be our paddles, and then a ball.
We can use a sphere to be our ball.
And Unity thankfully makes this fairly easy to just add by default.
So this cube I wanted to delete here.
And I'm going to set my camera back to its default position.
Udon Master says, "would it be a 3D pong but works only on the 2D axis?"
Yes.
So today we're going to implement a 3D--
it's going to be a 2.5 D version of Pong, where everything is in 3D,
and we can see it in 3D, and we can see perspective.
We can see how--
we can rotate our scene around and see it working that way.
But we're only going to be able to move left and right, just
like the original pong game lets us move.
And it's going to therefore still be constrained effectively
to a two-dimensional axis.
The paddles themselves are more a one-dimensional axis.
The ball itself will be moving in 2D.
And so therefore that's more what gives it the 2D feel.
But yes, good question.
OK, so I'm going to go ahead and start adding some placeholders for what
I want in my scene.
They're not placeholders as much as they are just
kind of shells for what we'll be implementing later.
But let's say I want a cube.
I'm going to-- let's say this is going to be paddle one.
And notice that I gave it a name here in the scene or the object hierarchy, just
to let me know what that object's purpose in life is.
So it's paddle one.
I'm going to go up here to where I have the Hand tool, the Move tool,
the Rotation which you looked at earlier.
There's also something called the Scaling tool.
I'm going to click on that.
I'm going to shrink this down a little bit on the y-axis.
Notice it's just sort of flattening the paddle.
I'm going to do this, as well.
So I get kind of a--
kind of a paddle view here.
Now, if you right click and you use WASD,
you can actually move around your scene like in a game.
You can actually move the camera in three dimensions, more
like you're flying around, which is kind of nice, rather than necessarily
having to click and rotate around.
I like using WASD so I can move backwards, forwards, et cetera.
This paddle is more or less good.
I'm going to just flatten it a little bit more.
And then do I want to extend it?
Maybe I'll extend it a little bit on this direction.
I'm going to come out here.
I'm going to go back to moving it.
So the nice thing is you can actually use
QWERT to change how you're manipulating the transform, whether you're just
moving the hand around the scene, whether you're
moving the actual thing itself, whether you're rotating it,
whether you're scaling it.
So I'm going to hit w to actually move it.
I'm going to move it over here.
And I'm going to sort of set my scene up the way that I think I might want it.
So I have that paddle there.
I'm going to move it a little bit over here.
I'm going to make sure my paddle is selected.
I'm going to Command-D to duplicate it.
I'm going to call it paddle two.
And it's going to be in the exact same location as the paddle
that I just made, but I'm going to kind of just
move my view over here a little bit.
I'm going to just drag it right over like that.
I'm not using any, necessarily, hard-coded placements for these.
But I could if I wanted to.
I could say the Z on this one, maybe it should be negative 5.
And then the Z on the other one should be, let's say, 5, right?
So they're about-- what would that be?
That would be about 10 units apart.
So they're exactly 10 units apart at this point.
But we're just eyeballing it.
We don't necessarily care too much.
I have two paddles now.
They're kind of in opposite views of each other.
It's a little bit hard to see, so I'm just going to do that.
Now, the nice thing that you can do is if you have your camera selected
and I go over to--
I believe it is game object.
And then you do Align With View, you can actually
do that and now the camera is rendering exactly how we're looking at the scene.
So this is super handy if you want to look around and find
just the perfect angle but you don't want
to manually move your camera around.
You make sure your camera is selected, go to Game Object,
go to Align With View.
Super handy.
I'm going to go back here just a little bit.
I'm going to add another thing to my scene.
I'm going to create a 3D object.
I'm going to make a plane here.
So it's about the fifth or so option.
And so now this is going to be sort of my ground object.
Let's make sure that it's--
so it's going to be something like that, right?
Probably going to need to scale it out just a little bit.
So I'm going to hit r to scale on the z just a little bit.
It's a little bit hard to see, unfortunately.
So why don't we do something with color?
So right now we have a few different game object types.
But they're all white.
It's hard to kind of see which one is which.
And the way that Unity does colors and makes things look differently--
beyond colors, also just different ways to light things and make things
look like they have different textures associated with them--
is through materials.
So in my assets, I have a sub folder in assets called scenes.
I'm actually going to go to my assets.
I'm going to right click it.
Create a new folder.
And I'm going to call this materials.
And so what this will do is now I have a couple of folders within assets.
In materials, I'm going to make sure that's selected.
I'm going to right-click that.
I'm going to go to Create a New Material.
And notice that the icon is sort of like this sphere.
So it just, at a glance, tells me, oh, this is going to be a material.
This isn't a script.
This isn't an image.
This isn't an audio file.
This is a material, which means that you can assign this
to an object in your scene and give it some sort of color
or some sort of texture.
I'm going to call this--
we'll call this the board mat.
And then I'm going to go over to this little color picker
thing on the right where the inspector is,
next to where it says albedo, which is just sort of like the light reflection
parameter of your material.
And notice that it pulls up this little color widget which is super handy.
I'm going to make that a sort of dark gray color.
And nothing has changed in my scene because I haven't actually
assigned my material to anything yet.
So I'm going to click on that material.
And this is something nice about Unity.
You can just click and drag from your scene into--
from your inspector onto the scene.
And now the material, it highlights in advance
to tell you how it's going to change.
And then it actually changes.
Now, the problem is that I believe the paddles are underneath the--
yeah, they're underneath the plane.
So I'm going to make sure that the paddles go above the plane.
So I'm going to--
I'm just going to lower the plane down.
So I'm going to hit W again, lowered this just a little bit.
And now notice that we can see our paddles against the background,
as opposed to everything just being white.
Now, I don't quite like how big the board is.
I want the palace to kind of touch just up against the--
just up against the edges.
So I'm just going to do that.
This might be a little bit too close for comfort for the game, but we'll see.
We'll fine tune it as we need to.
And yeah, that's our play field all set up.
Now, the directional light is casting a shadow, which is kind of cool.
So a directional light-- and we haven't talked about lighting yet--
is a light source that just means illuminate
the entire scene like sunlight.
So no matter where you put it, it's not going
to change how it actually behaves.
So if I were to just move this anywhere, like
if I move up or down, on its local x-axis, on its local y-axis,
notice that it doesn't actually change the shadows at all.
So if we're looking at the shadows there and I move this,
the shadows don't change whatsoever because it
doesn't matter what position your directional light is.
It's a global light source.
So it's going to behave the exact same on every object
no matter where it's located.
I'm probably just going to leave it as is because I kind of like the--
I kind of like how the shadows sort of add a little extra layer
just as-- you demonstrate to us even more that we're in 3D.
I'm going to--
I think I'm going to make the background darker, though.
So I'm going to set the background not to skybox but to solid color and not
to blue because it's a little hard in the eyes,
but to kind of this darker color, this darker gray.
And so now when we render our game on the bottom left,
we're actually seeing a fairly easy to view shot of all of our objects.
We have our paddles nice and cleanly set against our board, which is nice
and cleanly set against our background.
So everything is working pretty nicely.
If anybody has any questions thus far on Unity,
definitely toss them in the chat.
I'll be looking at it.
But yeah, that's getting all the placeholders in there for now.
The next step I think would probably be to have maybe our paddles moving
back and forth.
I guess before we can do that, we can also just add the ball to our scene,
right?
I'm also going to rename the plane to board.
It doesn't matter too much.
But I'm going to create a 3D object.
I'm going to create a sphere.
It's quite a bit too large.
It's a very large pong ball.
I'm going to set this roughly in the middle
here, so right about there, right about here-ish.
I'm going to shrink it down quite a bit because it is rather large.
And I'm going to go over to my scale.
I'm just going to set all these to 0.2 manually
so I don't have to do it myself.
Is that too small, maybe?
We can do-- maybe we'll do 0.3, how's that?
We'll do 0.3 on every axis so that we get a uniform scale because if we-- we
can scale different numbers on different axes
and that will have the effect of elongating the ball.
So if, for example, if my y is still 1--
[COUGHS]
Excuse me.
Not y, 0.3.
If we set the z, for example, to 3, we can
see that we get this very elongated ball that looks like a very distorted oval.
So you can scale differently among different axes.
But to get a uniform shrink on your object,
you want to scale the same amount on every axis.
So I'm setting 0.3, 0.3, 0.3 on a scale, on my ball.
And that's roughly a good size, I think.
Let me just get out of the transform view
so we can see what our scene looks like.
And if I were to run my game, which I can do, absolutely do--
you click the Play button at the very top.
And now it's actually rendering the game in real time,
like properly, as opposed to just changing the game view
when we make changes to the scene.
But nothing is changing.
Nothing is happening.
This is our game, right here.
But this is actually running like an actual game.
It's running 60 frames per second or however close it can get to that.
But it's completely non-interactive because we haven't programmed
any interactions within our objects.
They don't have any sort of physics so they're not falling.
They're not doing anything.
So what I want to do is start thinking about how to implement
some interaction amongst the--
amongst the paddles, or how to actually let them
move left or right in the scene.
[? MachaBean ?] says, "best of luck."
Thanks, [? MachaBean. ?] Much appreciated.
Yeah, we're off to a good start.
"The light reflection is so cool," says Astley.
Yes, agree, definitely.
And there's a million different things you
can do with textures to make all kinds of different cool effects,
things called shaders which will change how light interacts with your objects
to give them different sort of artificial details
or different abstract colorizations.
It's a lot of cool stuff you can do with shaders.
Reema7 says, "now the good stuff is happening."
Yeah, we're getting there.
We're getting there.
Slowly but surely.
All right, so now we can start taking a look
at how to add new behaviors to our scene using what are called components,
which we talked about earlier.
We looked at some components that were on the camera.
If we look at our paddle, paddle one, for example,
we can see that it has components, as well.
It has this thing called a mesh filter, which allows it to actually contain
all of the vertices for our mesh.
It has a mesh renderer, which has the code necessary to take those vertices
and actually render it to the screen.
It has a thing called a box collider, which
comes by default on every 3D object that you
add to the scene, which allows it to collide
with other objects for collision detection.
And it has a material, which all objects by default
get the Unity default material, which is this white sort of semi-shiny
looking material.
But we want to say if I press left or right on the keyboard I
want my paddle to move left or right, which we
can do through the power of scripting.
And so this is where we get into C# and the actual programming side of Unity
and implementing our own what are called mono behaviors.
You can think of mono behaviors and components
as sort of being the same thing.
And they just named mono behaviors because C# on Mac needs what's called
the mono framework, which allows it to actually run C# dot net applications,
which traditionally are Windows-only.
And Unity actually started off as a Mac-only game engine,
but over the course of time became very much a multi operating system game
engine.
So how do we implement our own component from scratch?
So I'm going to go to my assets folder.
I'm going to create a new folder here, call it
scripts just to keep everything fairly organized.
So this is a good way to stay organized.
But you could do things however you want,
as long as you sort of impose your own sort of consistent scheme
for keeping your files in the right way.
In my scripts folder, I'm going to right click.
I'm going to create a C# script.
Notice that that came up on the menu there.
And then I'm going to call this paddle.
And so the paddle script is going to be anything
that encapsulates the behavior of paddles and how they should operate.
So if I double click on paddle, the script that I just created,
notice that it opens up my default text editor, which in my case
is VSCode, Visual Studio Code.
I believe by default now it is Visual Studio proper, so actual Visual Studio,
which is a larger and more feature-rich IDE for actually debugging and running
your applications.
My editor-- I thought I disabled this, but it has these--
I have what's called Omnisharp, which is an extension that will allow it
to actually give you a lot of real time sort of analysis of your program
if you're running a C# application.
And it analyzes the solution file and does real-time debugging and reference
checking.
I'm going to disable the reference code lens because it's kind of obnoxious.
Notice that that took away all those reference words that were here before.
I'm going to zoom in a little bit so you can see a little bit better.
Make sure this is all over there.
Turn the chat back on because now we'll actually have the ability
to see it on our text editor.
And then close this bottom thing here.
So if we're looking at this, this is the default structure for a Unity script,
a C# script in Unity.
And this is C# syntax.
It's very similar to Java, if you're familiar with Java
and you've ever programmed in it.
But basically, we have these-- it's based around the idea of a class.
So everything in C#, everything in Java, is a class,
which is just a representation of some object type that should exist and it
allows us to build beyond things like ints and floats and strings,
things that you see in other programming languages to represent basic number
and data types.
We can actually implement the idea of an object called
a paddle and all of the data and functions that
should be ascribed to it.
So the ability to, for example, move, or whatever data
it needs to keep track of how to move.
Zodiac says hi.
Hi, Zodiac.
Good to see you again.
So noticed that this is what's called a public class.
So it's available anywhere in our application because it's public.
If it were private, it would not be available.
We are using all of these things by default up
here, using system.collections, using system.collections.generic, using
Unity Engine.
These are things that you get imported for you for free that basically tell
your script, I'm going to use data inside
of these namespaces called system.collections,
system.collections.generic, and so on and so forth,
that have some code already written for me
so that I can include those into my own script.
"So you'll create another class for the ball?" says Astley?
Yes.
We will create another class for the ball, and a few other ones, as needed.
And we'll actually create a separate one for the-- if we have time,
we'll do some AI for the paddle and create
a separate script for the paddle.
[? Bavik ?] says, "yes, exactly."
You can create a class for pretty much anything you want to,
and you can create classes that aren't even necessarily mono behaviors.
So what a mono behavior is, is that's something specific to Unity.
And that basically means that this script can become a component.
You'll be able to actually see it in the inspector
and be able to manipulate it with the fields
that we were looking at earlier, for example, the transform, how
we were able to change the position, rotation,
and scale of that transform ourselves.
We can actually change that here.
But we can also, when we've made it a public class and we've created these
public variables-- for example, if I said public int score, like that--
basically we're saying this integer called score is going to be publicly
available, meaning that because we're using a mono behavior,
because this is a Unity component-- mono behavior, Unity component--
we'll have access to this score variable within our editor itself.
So real quick, we'll take a look at that.
So if I go back to my game here, it will compile any changes
that you make to a script.
It will compile for you as soon as you get back into the game.
I'm going to go to my paddle one.
I'm going to go down here to this-- where the inspector is,
and thankfully the chat is just above it.
But if I click this add component thing here,
notice that it brings up a little search dialog.
I can actually click--
I can look for paddle, which it added it to my sort of list
that I could choose from.
Click paddle.
And then you won't be able to see it because the chat is there.
But if I disable the chat, you can see that I actually
have access to score here, and I can set that to whatever I want.
For example, if I set that to 10, now the score is 10.
We're not doing anything with the score.
It's just a piece of data.
But that allows us to have access to a lot of things
that, instead of needing to change them in code, maybe
we want to just make them accessible in the editor
and change them ourselves there.
So back to VS Code, that's what you get for making
any of these pieces of data public.
Different from public class, this is specifically
related to making anything within your component public, right?
And notice that unlike Lua, which allowed us to just say score equals 0,
image equals image, we actually have to specify the type of the data.
We can't just say score and have C# figure out what score is.
We have to say it's an int.
It's an integer, meaning that it has to be
a whole number, negative or positive, and that will be our score, as opposed
to an image, as opposed to a floating point
value, which has a decimal point, as opposed to infinite data types that you
can make of your own type.
So beyond the variables that you can actually put into your component,
you can also see that it comes with a couple of default functions, default
methods, in this case start and update.
And so what start does is this is a block of code.
It's empty by default because Unity doesn't know how you want to use it.
But basically it says at the very beginning of the game
when this object is what's called instantiated-- meaning created
from nothing, in object terms, object-oriented terms.
When we create this object, it's going to call the start method
and run it just one time, at the very beginning of its lifecycle.
And then we have this function called update.
And what update does--
and again, it's empty because Unity doesn't
know how we want to use the object.
It's meant for us to write it ourselves.
We want to, in this function, specify everything
that this component should do every single frame of execution, which
typically is one sixtieth of a second, if we're
running our game on a computer that's capable of running it without lagging,
in which case the frames might be--
it might run it at a--
maybe every two frames, every three frames update would then get called.
MetalEagle says, "transform is a CSS style to rotate things on a web page.
I find it neat that the wording is similar."
Yeah, no, absolutely.
And it all sort of comes from geometry and linear algebra,
the idea of a transform, applying to something in Euclidean space.
And our cart--
I sort of get the terms mixed up.
A Cartesian coordinate system, Euclidean space, all that sort of thing.
[? Bavik Knight ?] says, "strongly-typed language."
Yes, C# is a strongly-typed language, in which we have to specify,
rather than letting it figure out what the data is, what it means,
how we should treat it.
It needs to be explicitly told.
And this allows it to perform more optimization as related to that data.
And it actually compiles it down to an intermediary format
for what's called the common language run time, the CLR, which
is sort of similar to the JVM, which is the Java Virtual Machine, which
is a layer closer to machine code but still a little bit above machine code.
All right, so that's the anatomy of a basic component.
Now, what we want to do is I want to be able to say if I press left or right,
I should move my paddle, you know, left or right, right?
So if I say if input.getAccess--
or rather, I'll just say get key left, which
means if I'm using this thing called input, capital I, which is something
that Unity gives you.
And it has a function called getKey.
This is sort of like love.keyPressed, if you're familiar with the other streams
that we did on Lua.
But basically, I can say if I'm getting the key left,
I want to do this thing called transform.translate.
And let's say I want to move--
make sure that I'm on the right axis.
So I'm on the x-axis.
I want to move it left, right?
And we could see up at the top right, it gives us
a indication of where negative and positive are, positive and negative
are.
So in this case, positive on the x is to the right and negative on the x
is going to be to the left.
So I want to move my--
I want to move my paddle to the left some amount when I hit left,
a literal left key on the keyboard.
Notice that I took that as a string very similar
in spirit to how we did things with love.keyPress.
And I took a key which had a string type.
So it takes a vector.
So let's say new vector 3.
And then let's say negative 3, 0, 0.
So what this will do is it will perform a translation,
just like we did with ourselves in the Unity editor
by clicking on its three dimensional transform object in the scene view,
this will do the same thing but allow us to do it in code.
And I can say else if input dot getKeyRight transform dot translate.
And notice that C# is a little bit different than other programming
languages in that functions and methods are typically capitalized.
This is a stylistic thing that C# does, which is very different from most other
languages.
But this is something that you will see a lot when diving into C#.
And it's also a very idiomatic in C# to make sure that your curly brackets are
on the next line as opposed to how we typically do things in, like, say,
JavaScript or even Java.
You have your curly bracket on the same line as your method.
Now, you can change these rules as you see fit.
But it is common practice in the world of C# to do things this way.
So we will try to stick with that trend, just for consistency.
But if you're working by yourself, you can kind of
adhere to whatever your own--
whatever your own preferences are.
[INAUDIBLE] says, "translate is another CSS style for a web page."
Yes, I am somewhat familiar with both of those.
I don't dig into CSS a lot, but you'll see that nominclature
around quite a bit when dealing with anything
related to sort of moving objects around the screen.
CSS and most game frameworks, they all rely on the same terminology.
I'm going to go into my other else if block here.
And then notice that when I called transform.translate,
there are a few things going on here.
So first off, this lowercase transform is lowercase because it is a field.
It is a private--
well, it is a public piece of information associated with every game
object and every component has access to it,
which just means whatever the transform is of this current game object.
So if we assign this paddle script to one of our paddles, either one,
we'll have access when we call this update
function on whatever that specific game object's transform is.
So you will get transform sort of for free, which is nice.
You don't have to--
notice that we didn't declare anywhere in our script,
but we have access to it, just because that's a feature of mono behaviors.
They are given a reference to that transform for free.
We looked at what translate was and then the translate function itself
takes as an argument a new vector 3.
So the new keyword basically says, let's instantiate this new object,
a brand new object of a specific type-- in this case, it's a vector 3--
and a vector 3 is essentially just three values stored together as one.
And typically x, y, and z.
And because we wanted to move our object left or right
and that mapped to the x-axis in our scene, the parameter that we populated
in our vector 3 was negative 3.
If we press left, which went to the x-axis, and then positive 3.
If we pressed right, also on the x-axis.
JewishRambo says, "why vector 3?"
Just covered that.
A vector 3 is just a x, y, z pair, and that's
what the transform.translate function accepts as its argument.
And that's a function that is written in Unity.
It's something that Unity has defined in advance and that's what it expects.
And that's another thing about strongly typed languages
is they expect very specific arguments as opposed
to languages like Lua or Python, which allow you to basically give it
whatever you want.
You have to make sure that you give it the right data type
or it will give you an error.
In Unity, it will say there was a compilation error.
[INAUDIBLE] says "3D vector?"
Yep, a 3D vector, z, y, z.
[INAUDIBLE] says, "makes sense."
And so if I were to go back to my application, back to Unity,
and I have a paddle just on this first--
or a paddle component just on this first script.
And the second paddle does not have the script.
So if I were to run this and my code is correct, if I hit left or right,
notice that it just goes insanely fast.
It's working.
So if I hit left, it goes left.
If I hit right, it goes right.
But it's going way too fast.
And that's because it's going 3 Unity meters per frame,
which is not the desired behavior.
We want it to move effectively 3 meters per second, or negative 3 meters
per second, which is a bit more of a rational scale
at which to move our paddles.
And this is something that's a result of--
this is something that we can fix using what's
called delta time, which is something that we have actually
looked at in Love 2D which is the amount of time that
has elapsed since the last frame.
And so Unity thankfully gives us access to this very easily.
We can just do something as simple as our negative 3 in our x
parameter of our vector 3 here we can say times time dot delta time,
times time dot delata time.
And so we're scaling now that 3, the negative 3 and the 3, by however many--
however much time in seconds has elapsed since the last frame,
which should be about 0.0016 or 0.016, something similar to that.
Just like we did before, If you watch the prior streams on Lua
and Love [? TD, ?] update takes a parameter called
delta time, which we multiply by anything that we
want to move over the course of time.
Translations typically should abide by this,
or you will be moving in meters, not in meters
per second, which is the ideal amount that you should be moving your objects.
So if I go back to Unity and I run this again,
it's going to compile it for a second, but as soon as we're ready to go,
notice that now the paddle is actually moving at a much more reasonable rate.
And if I press left or right, only the paddle that had the paddle component
is updating.
The other paddle doesn't have any components of our own
on it, so it's just staying there completely still.
So super easy to get some basic paddle movement.
Now, the paddle is not constrained at all,
aside from being constrained on the x-axis,
because that's the only thing it's looking at.
So we need to decide how do we actually block
the paddle from moving beyond the left and right edge of the screen, right?
And so we could do this with--
we could do this in a couple of ways.
But typically what you'll do is you'll use a physics engine
to compute collisions between objects.
And the way that we're going to do that is with what's called a rigid body.
And if you-- by the way, if anybody has any questions on the code
that we went through or how I got it to work, how we use time.deltaTime,
again, time is this thing that Unity gives you for free.
It's part of this using Unity engine up here.
Same thing with input.
Input and time are both static objects that you
have access to different fields on that get updated for you.
They both are basically--
Unity feeds them information as it's running.
And you can access that information at any given time
just by referencing capital time or capital input
and then whatever the function is that you need.
So let's put a few more objects in our scene.
I'm going to go back here.
I'm going to create a few different things.
So I'm going to create some 3D objects.
I'm going to create a cube.
I'm going to move this cube over to the left boundary of my game.
I'll just make sure that it's more or less in the right spot.
Needs to be like that.
And then I'm just on the edge, just like that.
And this is going to be basically just the--
Andre says, "hi Colton.
Just curious, why using get key rather than get axis?"
In this case, get axis would work fine, too.
There is something that we could do which
is kind of handy, in that we could actually
expose the different keys for our paddles so that I could say--
if I were to say, for example, public string horizontal, vertical,
and then I were to say input.getKey horizontal--
or rather, sorry, they're both horizontal.
If I were to just say left right and then I were to say this is left
and this is right--
so we made this.
We made these two variables here called public string left and right.
And we could probably do this with get access as well.
Get access is ultimately a more flexible solution
if you're going to publish your game on multiple different platforms.
Get axis basically relies on you specifying in your Unity settings what
each axis maps to, for example horizontal being
a set of different buttons, and the--
for example, if you're on a console, get axis will map to your control stick.
You can also say that it's also A and D, if you want to move left and right.
And it's also left and right.
You can specify all these things.
But in this case, I'm going to say--
I'm going to make the left and right a little bit more flexible
so that I can map them to different objects and have exposure in the editor
and a little bit more fine grained control.
So now I can say public string left right, just like that.
And there's probably a way to do this in get axis, as well.
But I'm going to go over to my paddle now,
paddle one, and if I write in here left and right.
Now if I run this, it should have the exact same behavior
as before where I can move left and right.
But if I go over to my other paddle, paddle two, which doesn't have a paddle
component, I add a paddle component, and then I
say left should be a and right should be d on that one.
And then I hit--
save my scene-- and then I hit play.
I can go left or right on that one and then A and D on the other one.
I've essentially modularized-- or not modularized, but I've--
what's the word I'm looking for?
Factored out the button presses between my paddles
such that I can flexibly sort of set them however I want to.
And you could ultimately do something like get axis left and right, as well.
And that would have the same effect, and would probably
be a little bit more flexible.
But no real super fantastic reason, I guess, in the end.
But just because that is kind of an easier way to also think about it.
Get axis is a little bit more of a higher level abstraction on input
that requires you to specify some things yourself in the settings
and requires you to kind of dig around a little bit.
We can maybe take a look at that in a future stream.
Oh, yes, and a good point, says Andre, about get axis for the sort of touch
and go behavior.
You can set it so where get axis--
basically, get axis gives you a value between 0 and 1,
which allows you to scale--
or I guess negative 1 and 1, I believe--
which allows you to scale the value such that if you're using a control
stick, for example, which we're not here--
and that's another reason why we're not doing it because I'm just
using a keyboard as input.
But you can actually scale, then depending
on how much they're pressing on the control stick, you can--
or the mouse-- you can make the movement more or less.
Because you're just going to do a multiplication of that
get axis result on top of the--
you're going to multiply your get axis value against the speed at which you
want to move, where ours was negative 3 and 3 on the x-axis.
But yes, excellent point, Andre.
If we were doing something for a console game or for a--
like, a shooter, for example, or some other input source,
I would say get axis is definitely the way to go.
We're just doing the keyboard for today.
WhipStreak says, "I was late.
Sorry.
But I'm here now."
WhipStreak, did you say your name was Nate?
I think you said that last time you were here, right?
I apologize if I'm getting that mixed up with somebody else.
Trying to remember the folks that come here regularly.
But thanks for joining in.
Glad to see you.
[? Asley ?] says, "when you put in left or right,
you didn't specify the arrow keys.
So how did it know how to use them?"
I got the a and d--
So if we're in our paddle one--
so notice that here I said left and right here where I wrote them--
I wrote literally left and right, which map to strings.
So remember that instead of having everything hardcoded here-- because
previously I just basically said the literal string left,
which means that no matter which paddle has this component, left will move it.
I wanted to make it more flexible.
So I declared these public strings up at the very top here,
left and right, which because we declared them as public,
they get exposed in Unity in our component here.
So it's a little bit hard to see because of the chat.
I'm going to move the chat up a little bit,
just so we can maybe see a little bit easier, just like that.
So the left and right, in this case, I wrote them in myself
as the values of those variables instead of hard coding them.
I was able to do that differently on paddle 2 because instead
of saying left and right, I wrote A and D.
So I just basically did the same thing I did
with paddle one hardcoded by writing left and right here for paddle one.
And then I changed it for paddle two to demonstrate why
it's nice to have that in a variable.
So now I can have two paddles, but I can make
them both move independently because previously, since left and right were
hard coded, if I pressed left and right, they would both move
in conjunction with one another.
But the keyboard presses are, in fact, simulated over time.
Yeah, because they're going to be called--
get key is going to be called every frame if that's
what you're referring to, Andre.
Jewish Rambo, can you put in a good word for me to get into Harvard.
Unfortunately, I have no say over that.
I apologize.
If I did, I definitely would.
I am but a humble technologist with no hands into the actual hiring--
not hiring, but what is it?
Blanking on the word.
The process by which to get in as a student.
"Got it.
Thank you," says Astley.
Absolutely.
So now we have movement of our paddles.
And the AI will sort of be a different version of this, but kind of similar.
Admissions-- that's the one.
Sorry, yeah.
I wish I could.
I unfortunately-- literally zero involvement
in the admissions process and zero influence.
I wish I could.
But we've made our input work.
So now the next step is what I was doing was
I was sort of creating these boundaries for our game, for our for our walls.
So I want to create the left and the right walls of our pong game
because if you play the game, in pong, when the ball bounces
off of the walls that aren't where the paddles are-- so normally
it's oriented such that the paddels are on the left and right
and the walls are the top and the bottom.
So if it hits those walls, and actually, that's how it looks like in the screen
there.
If it hits the left the top and the bottom--
or the left and the right, depending on how you're looking at it,
where the paddles aren't--
then it should just bounce and go back into the game space.
But if it were to go past either of the paddles like a goal,
then it should trigger adding one to the other person's score, right?
So I'm going to make the walls right now.
So what I'm going to do is I'm going to go into R to scale my cube.
I'm going to scale it all the way such that it's taking up the entire wall
there.
Good enough.
And then I'm going to call this wall wall left.
I'm going to then go over to the mesh renderer component.
I'm going to disable the chat so you can see.
But the mesh renderer component is over here on the right side.
If I click on this checkbox right here, it'll actually disable that component.
And so this is a nice way if you want certain components to turn on or off,
given certain programmatic behavior, you can do that here manually,
or you can do it via code.
So you can say dot enabled equals true or false,
and that will disable that component.
I want the wall to work, but just like in pong,
I don't want to actually see the wall.
So I'm just going to disable the mesh renderer.
It's still there.
And it still has this box collider which is very important.
That's actually what we're going to need.
But it's not being rendered.
So I'm going to duplicate that.
I'm going to come over here.
I'm going to move it over to the right just like that.
I'm going to title it wall right.
And notice that now I have two walls that
are the right sizes of our game space.
They're invisible, so we won't see them.
But when we actually do some more work on our game,
we can have the ball bounce off of those walls as we need to.
And we do that because it has this thing called a box collider.
So we're effectively only using the cube for its box collider, essentially.
I'm going to save my scene.
Make sure you save your scene.
So by default, you remember that I do have a scene here.
And it gives you a sample scene as your default scene.
And a scene is just a collection of game objects,
just like this, put together in your object hierarchy
with all of their components set in a particular way.
And this allows you to preset, for example, a game view or a menu view
or something else and to be able to change amongst them super easily
or to have various levels that you may have preset--
level one, level two, level three, Waterworld, Fireworld,
whatever you want.
So you can just simply arrange all of them as scenes
and then just load them in and out as you need to.
We're not going to do any scene changing today,
although we can certainly look into it in the future for something
more complicated.
We're going to be able to do all that we want to do in just one scene here.
So I'm going to do one more thing.
I'm going to create another 3D object.
Actually, I can just do it with these.
So I'm going to duplicate the wall left.
I'm going to move it over here.
I'm going to rotate it along the y, just like that.
Make sure that it is set to negative 90, just like that.
I'm going to then move it over here just past the edge of the screen, just
like that.
I'm going to call this player two goal.
I'm going to duplicate that, call that player one goal, move that over here,
make sure that I'm in the right spot.
Looks like it's perfect.
And then now we have our goals set up such
that we have our left and our right walls and then we have our goals.
If it collides with the left and the right walls, the ball should bounce.
And we should also-- our paddle should also not
be able to move past it, which we can set.
And when it hits one of the goals, the goals
aren't actually going to behave like colliders.
They're going to behave like what are called triggers.
So if I were to go to my player one goal and player two goal,
notice they have both of them selected.
I hit Command click.
You can do this with Control click.
And I click on this is trigger thing down here in the box collider.
Now those goals are going to function as what are called triggers.
And we'll take a look at what that means in a little bit.
Effectively what it means is we can say when something collides with this,
do something, as opposed to let it behave like a wall
where it will just interact with things physically.
A trigger is something that can be very flexible.
It can be a zone where maybe you trigger the next level loading.
Or it could be this goal area where when the ball hits it,
it triggers the ball going back to the center of the screen and one person's
score incrementing.
A trigger is very flexible, and not the same thing, necessarily, as a collider
functioning in the context of physics.
Andre says, "what I meant was get axis simulates a key press so
that on holding down the key right arrow,
the values go from 0 to 1 over the course of something
like 1/10 of a second rather than the instantaneous value of one of get key."
Is that the case?
So if you hold down--
oh, I see.
Such that it will have a sort of like smooth behavior,
if that's that you're talking about?
That's cool, actually.
That could be handy if we wanted to do a more fluid movement of the paddle.
We could maybe take a look at that in a little bit, mess
around with a little bit, because that would
be a-- that's a nice little touch.
Pong itself doesn't-- their actual vanilla pong doesn't have, I think,
this notion of smooth scrolling.
I think it's very discrete in that it just moved when you
rotated the paddle or manipulated the--
when you pressed whatever-- whatever interface--
because there are a million different versions of Pong
for constants and stuff.
I don't think it was smooth scrolling by default.
But that would be a nice touch to have for a 3D version.
Astley says, "Unity makes everything so much easier, as far as I can see,
that it kind of feels like cheating."
Yeah, I think that's sort of the goal, right?
You don't want making a game to be to be a process that works against you.
You kind of want to eliminate as much friction as possible.
So having a very nice interface, being able to see things live update,
having a bunch of built-in components that have
all this awesome functionality is very nice.
I'm a big fan.
And I'm not a Unity expert.
I know my way around it to a certain degree.
But it's a very fun and rewarding process.
So I'm looking forward to some more streams of it in the future.
JPGuy says, "Colton and the chat, what's up?"
Good to see you, JP.
We're just doing some Unity programming here.
We've set up our scene.
We've done a little bit of coding, as you can see, and some C#.
We have the paddles moving.
So if I were to move the paddles left and right here,
so I have my bottom paddle.
So notice that bottom is the game view and up top is the scene view.
And the nice thing about the scene view is the game is running right now.
But I can actually move my scene over here if I wanted to and still play.
In that case, I got--
the focus was still on the scene view, so it was still moving around.
But the paddle I can still see is moving in the scene view.
And I have free God mode view of the scene camera, which is super nice.
And often you'll see this referenced in games and engines
as a debug camera, which will allow you to actually, in real time,
navigate the scene with complete flexibility, which
is great for debugging things that you would normally not
be able to see super easily with a first person controller or a third person
controller.
We showed this, actually, in my games course when we did--
what was it?
A 3D maze where we wanted to generate the 3D maze
and actually see that it was generating correctly.
But the character was a first person character.
And if you're using the first person character in your game
and testing it that way, you're not going
to know that the maze was generated a specific way because you kind of need
to see what the maze looks like from super up top, right?
So that's what the scene view lets us do very flexibly.
JP says, "oh, awesome.
I didn't know Unity did that."
Well, yeah, definitely.
Tune in for the rest of this.
This is going to be a fun ride.
So I'm going to stop rendering the game engine, or the game view, rather,
and think about how I want to get the ball moving.
So the ball, if I click on it, ball is currently called sphere.
I'm going to rename it to ball just so that it's more semantically meaningful.
The ball comes with a sphere collider, which is super nice.
The different objects come with all sort of different colliders.
And the collider is shaped differently and calculates physics
and calculates collisions a little bit differently.
The thing that we need to start doing to actually allow our objects to interact
physically is introduce rigid bodies.
So I'm going to add a new component to the sphere called a rigid body.
And what a rigid body is is something that
tells the physics engine to perform frame-by-frame calculations
of the rigid body.
And you can see that it gives you options to select things
like mass and drag, angular drag, all different sorts of things,
whether affects effects it or not.
Which, gravity should not affect our ball,
so I'm going to click the checkbox off on that.
And gravity by default in Unity is along the y-axis.
So it's up in our game world.
So like it is in real life.
But you can change that, if you want to, in your Unity project settings.
If you want gravity to apply on the z or the x-axis,
you're more than welcome to do so.
It's fairly non-standard, but it works.
Right now I'm also going to add a rigid body to my paddle.
So a rigid body also not affected by gravity.
Want to check that off.
And I'm going to add another rigid body to my other paddle.
So now our three main objects that are interacting with each other
have these rigid bodies, which the physics engine
will be able to look at frame by frame and do calculations on,
which is super handy.
So again, click off the checkbox on the use gravity.
JP [INAUDIBLE] says, "will you extend this
to have a true 3D pong in all three directions limited
within a box sort of boundary?"
That'd be cool.
Maybe.
We could make it maybe mess around with it in the future.
I don't know about today, because I think
we're going to take up the full stream just implementing the basic 2D version.
But I could see that being viable.
In this case, if we--
cause gravity would be disabled.
We could make a top boundary and a-- but we're
going to do some constraints on different axes.
So if we disabled certain constraints and then enabled extra button presses,
we could certainly do that--
up, left, down, and right and WASD could then move the different paddles.
It wouldn't be terribly complex, but I don't
think we'll have time today to fully dig into that.
But maybe in the future just to mess around.
Voice keeps cracking.
Get some water.
That's an awesome idea, though.
I'd be happy to explore it.
The JPGuy says, "the 2D version looks complicated enough
to casually create in a stream."
Yeah.
I mean, it's not terribly complicated, but I
want to explain as much as I can so that people following along,
if they've never, ever used Unity, actually can understand everything
that I'm doing.
And so that's going to take up a little bit more of the time, I think.
Because if we were building this with people
that knew all this stuff already, we could probably
whip this up pretty fast.
But this assumes, like, day 0 Unity exposure.
And I think that's important.
I think that we should definitely take our time.
ForSunlight says, "like me."
Yes, awesome.
Hopefully everything has been clear so far.
Definitely toss questions in the chat if there's anything that's not clear
and I'm more than happy to elaborate on it.
All right.
So where were we?
"Thank you for day 0," says ForSunlight.
You're welcome.
Absolutely.
And you'll forgive me for having the chat disabled on the screen right
now just because the Unity editor is pretty busy
and needs a lot of screen real estate to be
able to see everything that's going on.
When we get back to coding, we can turn it back on.
42Force says, "yes, me too."
Yes, awesome.
I'm glad there's so many folks here joining in that have never used Unity.
And I hope that today's examples will prove interesting and/or
inspiring enough to keep going.
Twitch Hello World says, "for something as simple
as the left and right movement of the paddle, is there something in the GUI
that does it, out of curiosity?"
No, not in the sense of us being able to move them on key press,
to the best of my knowledge.
I think even with state-- with using the Unity animator state machines I
don't think that that's super--
I mean, it's not obvious to me that that's something that we get for free.
I'd have to dig into it a little bit to see.
But I don't think that's something you'd want to necessarily implement,
even if that were the case, because I think at that point
you're getting into sort of somewhat unorthodox use cases
for using for using Unity.
Generally, when you look at examples in the Unity documentation-- which,
by the way, now is an excellent time to plug that.
So Unity manual.
So if you just type in Unity manual in Chrome or whatever browser,
it'll come up to this user manual.
And there's a ton of topics where it goes into all this stuff--
working in Unity, navigation, graphics, physics, all this sort of stuff
go into a lot of different detail.
Scripting, multiplayer networking.
There's a ton of stuff.
And I believe if we looked up Unity input, for example,
Unity scripting API input, you'll get a lot of very detailed information
on how it works.
And you can see here's an example of somebody using a basic class to get
whether they've pressed fire one.
And get button down is, I believe it's just a single press rather
than a continuous press.
So this says fire one, which in this case is,
I believe, the same thing as get axis, where
you have a prior named variable in your settings,
your project settings, which then says fire
one maps to x on the Xbox or space on the PC,
whatever, a little bit more flexible.
Then it just gives you some input there through some debug information.
And debug.log, that's another cool thing to look that.
That allows you to, in real time, display errors or any information
to the console, which if you type control or Command shift C,
you get access to this console here where you can do some live debugging
and display variables, just like you would
do a print statement, for example, in C, printf statement in C,
or print statement in Lua.
Same idea.
"Have you developed in the Unreal Engine before?" says JP Guy.
"If so, which do you prefer between Unity and Unreal?"
I've looked at Unreal a little bit.
So Unreal is a bit more--
it's a bit harder to get into in the proper programming sense
because it's C++ and it's got a lot of sort of arcane stuff, a lot of--
it's pretty complex, a lot of static classes
and variables and things of that nature, that are--
it's an eyeful, I guess, an eyesore when you first get into it.
The great thing about Unreal, though, is that it
allows you to use visual scripting with what are called blueprints,
so just as a quick little aside here.
You can actually code visually using these things here,
which are sort of node-based.
It's like a node-based programming language, kind of similar to Scratch,
I guess, if you're familiar with CS50.
And we teach scratch for the first week or two.
It allows you to, instead of coding, you can chain building blocks together.
And that'll sort of act as your programming language,
which is a lot easier than the C++ aspect of it.
JP The Guy says, "ew, that looks awful."
It's actually not bad.
If you compare it to the C++, you can get a sample of some of the use Unreal
C++ what it looks like.
And not all of it's terrible.
But there's a good number of it, a good amount of it,
that can be a bit overwhelming.
So this is a little bit hard to see.
Can I see that super easily?
In this case, it's not terribly bad.
But there's a lot of things that unreal does very specific to itself, which--
like this U class thing which goes above a class definition.
And it can get pretty hairy if you're not super familiar with it.
I much prefer the blueprints, the Unreal blueprints.
But if you know this the code base-- the thing about Unreal is its performance
is really, really good.
Like, it's got great cutting edge graphics compared to--
Unity's got good graphics, too.
But the nice thing about Unity is it actually will run well on a Mac.
Like, I'm giving you a tutorial on a Mac.
And giving a tutorial with Unreal on a Mac
would be, like, almost impossible, because it almost doesn't run on a Mac.
And it looks terrible even when it does.
So that's another thing.
Unity is such a nice, like, performant game
engine for getting into game development and even publishing game development,
whereas Unreal is kind of like, if you want the best of the best graphics
and you're into hardcore shader programming and all that stuff,
there's a lot of cool stuff you can do in it.
But Unity is much easier to get into.
And Unity itself has a really cool visual scripting
language if you're interested in that.
It's called Bolt. And it looks like this, so a little bit cuter looking.
It's in the asset store.
It's not free.
It's 70 dollars, which is the unfortunate part.
But it looks like this.
And it looks kind of nice, right?
Like, you can kind of see we have a game object with a function called
get name, which is going into whether the string contains
some value, whether it contains enemy, in this case.
And then if it does, we have a branch, which
is the same thing as an if statement.
And then if it's true, we're going to go to Add a Force of some value--
push force, it looks like, normalized-- which
I'm not entirely sure what that is off the top of my head.
But you can lay out your whole logic in this very nice, clean building blocks
manner.
And this I have a feeling that one day they're
going to make this a built-in feature of Unity.
They've done this with a lot of really good libraries and good tools
that Unity's come with.
But I don't know.
And this is for people that aren't familiar with programming
and want to do something more visual.
You have that option.
And this is sort of how programming in Unreal Engine is.
So you can sort of compare the two kind of on that basis.
But yeah, Unreal Engine is really cool in its own ways.
Unity is cool in its own ways.
I think you should try them both out and see which one you like better.
But certainly if you want to try Unreal, make
sure you do it on a decently-performing machine, probably a PC,
unless you're using a Mac Pro or something with a really good graphics
card.
Otherwise you won't be able to read it super well, unfortunately.
At least in my experience that has been the case.
And that was a long aside.
I apologize for that.
[INAUDIBLE] says, "you always need to code up something anyway
because Unity can't guess exactly how you would want to move your objects."
Correct, yeah.
Yeah, it's hard to sort of put that general of a--
hard to make something that general work for every use case.
Right.
Yes, [INAUDIBLE].
I figured if there were, it would give up some granularity, though.
I was just curious if there was a simple default to use in the GUI.
To the best of my knowledge, there is not.
Again, I'm not an expert, so there might be some way to do it
in an odd sort of unorthodox use case.
I want to say probably not, but I'm sure there's
a lot of things about this engine that I don't know.
Rema says, "it looks like the Neverwinter Night's Quest editor."
I'm not terribly sure.
Quest Editor.
Yeah, maybe there's a part of the-- oh, like this, maybe?
This thing?
Kind of?
I'm not terribly familiar, unfortunately,
with the Never Winternight's Quest editor,
but I think I see where you're coming from.
Andre says, "incidentally, in Unity as of 2017,
print is an alias for debug.log."
Oh, that's cool.
I didn't know that.
TIL.
Thanks for that bit of information.
OK, so we got sidetracked a little bit.
I apologize.
It's my fault. Let's take a look at--
it's so old you don't have to look it up.
Now, I've played Neverwinter Nights, but I never ever actually tried
to make my own content with it.
So it's cool that they gave you the I've heard
good things about how robust the tooling is on it, but anyway.
The ball.
We wanted to move the ball some direction.
As a default it will be random, probably.
And then we'll want it to bounce off of the walls
and then ultimately off of the paddles.
So if I run it, let's see if anything happens.
I don't think anything will happen.
I can move the paddles just like I was doing before.
Gravity is not affecting them.
But they do have rigid bodies on them now.
So they should be able to process collisions.
So if I were to go to the ball--
I'm going to go to scripts and I want to actually create a new C# script called
ball.
Let's open that up in my editor.
And it'll be here available-- if you're using VSCode,
it should pop up in the left-hand side where
your project view is, your scripts are.
I'm going to keep that disabled.
The ball is-- basically what we want to do is we want to say,
OK, when the ball starts, I want to shoot it off in some random direction.
And if we look at our game, we see that we probably
want to send it in a random 2D direction where x and z are randomized
and y does not get any kind of randomization, right?
So first off I'm just going to test this now.
I'm going to say on start I want to--
and what is it?
Oh, we need the rigid body.
We need a reference to the rigid body.
So this is another thing, too.
I want-- basically, I want to say if I'm a ball,
I want to make sure that I also have a rigid body, because there's not ever
going to be a case where my ball doesn't have a rigid body,
my paddles don't have rigid bodies.
So you can do this thing called require component.
And this is called an attribute.
This is a C# feature which gives it some metadata,
which with fancy runtime analysis of the object it will be able to determine,
OK, this class requires that not only is it going to have a ball component,
but I also need to have a rigid body component associated with this game
object.
So the ball essentially requires and it will--
it will, if you don't provide it, it will load in a rigid body.
So I can then say, rigid body rb, which is just a--
it wants to auto populate my--
dammit.
Wants to auto populate my variable declaration there,
which I guess maybe the more robust would be the better way to do it.
But I want to say--
I want to get a reference to my rigid body.
I'm going to turn the chat on, too, just in case anybody has messages,
since we're in the text editor view here.
I want to get a reference to my rigid body.
So it won't know what the rigid body is until the object is instantiated
and can actually grab that rigid body.
So I'm going to say rb equals get component rigid body.
And the angle brackets syntax here might be a little weird
if you haven't seen it before because the angle bracket is basically what's
called a-- it's a generic specifier.
And what it will allow you to do is you can call this get component function
on any data type that you want.
And if I were to specify some other type of mono behavior here,
it would give me that component, not the rigid body.
You can specify whatever component type, the class type,
you want within these angle brackets.
And then it takes-- it's a function, so after
that it still needs to call the function with these parentheses.
And one other thing I forgot to mention, typeof is just a way in C# for you
to get the actual type data for a given class name.
So in that case, I want the type data for what a rigid body is.
So if I say rb is get component rigid body,
it's going to look at the current game object.
And it's going to call get component off of whatever this object is
of the type rigid body.
And it's going to grab that and store that in my rigid body rb variable here.
And notice I did not declare it public.
I don't want it to be public.
This is going to be a private variable that no other script should
be able to get a reference to because I don't want other scripts to mess
with it at all.
This is just going to be a rigid body that I tweak within my code.
And the exact function call--
I'm not 100% sure, but thankfully I have [? IntelliSense. ?]
So if I were to hit rb dot, notice that it
populates all of my potential functions that I could call.
So I believe it is--
which one is it?
I want to basically shoot it in a given direction.
I want to apply an impulse to it.
I can cheat.
I want to see if it has the--
OK, it's here.
It's add force.
So if you add a force to something, it will just
apply some energy towards that object.
And it can be gradual or it can be an impulse.
An impulse is what we want because we want
to shoot in a direction at a specific time or at a specific constant speed.
So it takes a-- it takes the actual direction,
because we want it to be in a given direction, as a vector.
And remember that we wanted that direction to be along the x and the z
and not along the y because if we have some value shooting in the y direction,
it's going to go up or down.
And we want it to stay aligned perfectly within this two-dimensional plane
in our 3D world.
If we were implementing a 3D version of pong
in the true sense where the ball is able to go up, down
as well as left and right, in this case we
would maybe want to set an impulse along the y-axis.
But we're not going to do that.
Instead, I'm going to say 404.
I'm going to hardcode it.
And then I'm going to specify a force mode.
So there's different force modes.
So force mode dot, for example, acceleration,
which means that it will accelerate the object.
It will start off slow and move faster.
But I want it to have that value instantly.
I want it to instantly start moving at 4 units in the x direction and 4 units
in the z direction, which should have the result of it moving up
and to the right when we run our game.
So I'm going to--
actually, this is not going to go in the update function
because that will just consistently add a value to it every frame.
And it'll start going really fast.
I want that to just be in the start function right where it begins.
I don't want it to happen every frame because it would just
add this over and over again.
This would become 8, 8 on the 2nd frame, 12, 12 on the 3rd frame,
16, 16, and so we're moving really, really fast.
"Like a Java list integer, a list," says [INAUDIBLE]..
Yep, same exact thing.
Generics just like in Java.
JP Guy says, "IntelliSense is life."
Yes, it's hard not to--
it's hard to go back once you've gotten used to it in VSCode.
It's a really nice feature, something that you just get and it just works.
And it's super nice.
OK, so we've got our component, our rigid body.
We've got a reference to it and we've added an impulse force to it at 4, 4.
And we can randomize that later, which we will do.
We can make it random on the negative and random on the positive direction
and we can make sure that it's not too small of an amount on either axis.
Otherwise, it'll just be going back and forth in a sort of straight line.
Or it just won't go at all.
So we can do that later.
But right now, we're just going to test it with some hardcoded values.
I'm going to save that.
I'm going to go back to Unity.
And then I'm going to run this.
And I'm going to make sure that my ball has
the ball component, which it does not.
So I'm going to make sure--
make sure when you create a component and you finish fleshing it out
and you want to test it that you've actually put it onto an object
because if you don't put it on an object,
there is going to be no objects calling these start and update
functions every frame, right?
So I'm going to do that.
I'm going to hit play.
And then what happens?
The ball, just as we wished, has moved out.
You can see its transform is sort of freaking out
and it's rotating all over the place.
But it did.
It indeed moved in the correct direction.
And not only that, but because we specified
these-- we created these walls left and right
and they have these things called box colliders on them, the box colliders
will actually affect rigid bodies just by default. So the ball
was able to move into a rigid body or into a box collide.
The rigid body-- sorry, the ball, which had a rigid body on it,
was able to move into the wall which had a box collider on it.
The box collider wasn't a rigid body because we
don't want those to move around and be affected by physics transformations.
But the ball, because it interacted with the box collider, it bounced.
Now, it didn't bounce correctly.
If you notice, it actually bounced in a really weird direction.
It kind of went in a straight line, which is not what we're looking for.
So notice that instead of bouncing out and then kind of bouncing
back out in kind of like the opposite vector, in the opposite direction,
it just kind of went into a flat line, very much defined the laws of physics.
So we have to fix that.
And we can do that using what's called a physics material to give
our object some proper bounciness.
42Force says, "wow, [INAUDIBLE]."
Astley says "plus."
Yes.
Very, very exciting.
OK.
And also, it should interact with our paddles because we are--
because those have box colliders on them, as well.
JP Guy says, "checkmate, Newton."
Yes, exactly.
We're diving deep into the world of physics here.
And I am not a physics expert.
I just happen to know what the right things to manipulate
are to get the, in this case, the physics working.
So everything in your game that can interact
using rigid bodies with other things, other rigid bodies or other colliders,
will behave according to certain properties of that object,
certain physical properties.
Now, this is most pertinent in terms of today--
bounciness.
Bounciness is the factor that we want to manipulate because it didn't bounce off
of the wall.
And in fact, it hit the wall and then it just
proceeded to move in a straight line along the z-axis for some odd reason
because it doesn't have a bounce factor to it.
"The laws are to be broken," says The Rb Ball 2018.
Yeah, exactly.
Newton's third law of motion just didn't work there.
Yeah, no, it didn't, because there is not
enough bounciness between our ball and the walls.
So the ball needs--
it needs to be, like, completely bouncy, basically.
And we can do that by creating a physics material
and basically changing how our object works,
basically turning it from a metal ball to a rubber ball, kind of.
You can think of it that way.
So in my materials folder, I'm going to create
a physics material, which is down here, below where you see timeline.
I'm going to disable chat, just so we can see what's going on.
And it has this different little icon here where it shows a--
aptly shows a ball bouncing off of some surface.
Now, I'm going to call that bouncy mat.
I'm going to go over to the right where I have my inspector.
And I have a few different parameters I can tweak here.
I have dynamic friction.
I want that to be zero, static friction, want that to be zero--
basically how it loses momentum when it rubs up against stuff--
and then bounciness, how much it basically takes
its current angle of movement and reverses it
when it interacts with something else.
I'm going to set that to 1.
So these exist on a spectrum between 0 and 1 for all of those.
For the friction combine, I'm going to set that
to the minimum, which means it's basically
going to not calculate friction.
And for the bounce combine, I'm going to set that to maximum.
And the low level details of how this works I can't explain.
It's super tremendous detail.
I'm sure with enough deep diving into the physics system of Unity,
we could maybe explore and look at it.
But essentially, you can think of the friction
combine to be how is it averaged out, the friction between two objects
and how the force is changed between the object that's moving,
the object that has the material, and the bounce combine.
Basically, how does it average the bounciness of both objects,
and then calculate the bounce that should result.
In this case, we want it to be the maximum of 0 and 1.
In this case, because our object has 1, it'll
always be 1, effectively, which will always be full bounce.
Going to be a slippery material plus the wall.
Yeah, exactly.
But it's not going to slide against the wall because we are using it as a--
excuse me, as a just bouncing platform.
Now, another area that you would want to potentially use
a physics material for that kind of purpose
would be a ice world, for example, if you've
played games like Banjo-Kazooie or million different games I've done this.
And you're walking on ice, for example, you'll
slide around because the ice has a different physical material-- physics
material-- than, say, grass, in such that the ice has
no friction, or at least much less friction,
than the grass, which maybe has half or full friction.
So you can get a bunch of different kinds of use cases
out of manipulating your physics materials as a result of that.
Now, the bouncy material, I just want that to be applied to the ball.
So I'm going to click that, drag it over to the ball.
The ball now has a bouncy material reference
in its actual sphere collider.
So the collider actually maintains a reference to the physics material.
So it's right here.
And so now one other thing that we need to do
is if we want this to work off of the paddles
because the paddles are themselves rigid bodies and you when it calculates
bounce operations off of rigid bodies it takes their mass into consideration.
And if you set the mass to just be one on the paddles,
it actually won't bounce back off of the paddle.
It will flatten and start moving along the x-axis, which is not ideal at all.
That's completely nonsensical sort of physics behavior, in this case.
So what I'm going to do is in mass with both of the paddles selected
I'm just going to set them to 1,000.
And note that this doesn't actually influence
how we move the paddle because we're just translating it on its transform.
We're not applying an impulse to it.
If we were applying impulses to our paddles,
then the impulse would have zero effect on an object of 1,000 mass.
I'm not entirely sure what the mass unit is in Unity.
If anybody knows, definitely toss in the chat.
But suffice to say, 1,000 is 1,000 times more than one.
So it'll likely have 1,000 times less effective of an effect
if we were to use a--
use add force on a rigid body associated with an element of 1,000 mass units.
So not something that we should have to worry about with our walls
because they don't have rigid bodies associated with them.
But we should have to worry about that with our paddles.
Now, let's actually see if this is working.
Weren't able to move fast enough to get there in time.
So I'm going to actually bump the speed on the paddles up a little bit.
So we didn't make that a variable.
So what I'm going to do is I'm going to go back to my paddle class
and I'm going to say public float speed.
And I'm going to say--
I'm going to set that by default to 3.
You can initialize that here where your variables are, if you want to.
But it's going to, by default, be three.
And if I go back to my paddles now, because I made it a public float,
every paddle now has a speed parameter that I can adjust.
So if I click on--
if I go to speed and I click 5 and I go to the other paddle and I hit 5,
now I should be able to move fast enough to at least catch the ball.
Still not quite fast enough.
Oh, you know what it is?
Because I'm still referencing this value with the 3.
So what I need to do is say negative speed
and then speed here, not the negative 3 and 3 that we hardcoded before.
And now if I run the game and let it compile its scripts and I play,
we do, indeed, move faster.
And it does bounce the ball appropriately.
Except now, notice that we are getting some weird behavior with our paddles.
So that's completely to be expected.
It makes for a very alternative version of pong.
I don't think it'd be very easy to play.
But there are a couple of things that we did not take into consideration
before we started testing.
But we can see that at least the bounciness is working appropriately.
[? Bavik Night says ?] "1,000, is it in grams?"
I believe the idea is mass in kilograms, seeing
as gravitational acceleration by default is 9.81 units per second.
Yes, I believe that--
I believe that is correct, yeah.
Now that I'm thinking about it, that makes perfect sense.
And every square is one meter.
So mass would be in kilograms and force is in Newton's in a relative way.
So 1,000 would require a great deal of force.
Yes, yes, absolutely.
Now, our physics system freaked out a little bit, though, as you saw.
But that's completely to be expected because we are not
constraining the collisions that take place between our ball and the paddle.
Or we're not constraining, basically, them the axes
upon which our paddle can move.
So if I were to move this, the reason that it bounced so crazily
is because I'm trying to collide it against this left wall
and this right wall.
And I'm moving this massive 1,000 kilogram object just at will
because I programmed it--
I programmed to move the transform.
But that applies force in my game.
It's still applying a physics operation.
It takes in the transform, its speed, into consideration, and the rigid body.
And so we're colliding with the walls in that case, right?
These two walls that are invisible.
So what we want to do is constrain where the paddle can move
and how it can rotate.
We don't want our paddles to ever rotate.
And we only want them to move along the x-axis, right?
Thankfully, Unity makes this super easy.
If I go to paddle one and paddle two and I click on their constraints
little field there in the--
you should be able to see that.
I'm going to move a little bit over.
If you see the--
there's a constraints drop down on the rigid body, right?
And I can click x, y, and z for freeze position and freeze rotation.
And this is nice because this will allow us to say,
don't ever rotate on a given axis and don't ever
move along a given axis, right?
And so I probably don't want to freeze position on the x-axis
because that means I won't be able to move my paddles.
But I can certainly freeze the position on the y-axis and on the z-axis.
And I can freeze their rotation on every single axis
because they're not going to ever rotate, right?
The result of that is if I run the game again
and I try to collide, no matter what I do--
it looks like it still went through the--
did I make the--
might not have made that thing big-- oh, no, it's
the collision detection, right.
Another thing we have to do is make sure that we do interpolated collision
detection using continuous dynamic.
And I can't tell you the low-level details of how exactly these work.
But interpolated collision detection basically
allows us to ensure that if a certain number of frames go by or whatever,
where maybe we run our game at 30 frames per second or 20 frames per second
instead of 60 frames per second, it will calculate the collision
detection that it should have done for the intermediate frames.
It will interpolate that for us.
And continuous dynamic, I'm not entirely 100% sure how it differs in terms of--
I haven't looked at the manual.
But I do know that that is the more appropriate collision detection
for things like we're doing here.
And it just-- it's a little bit more fine grained.
But beyond that, the low level details, I'd
have to do some reading on the physics engine a little bit.
"Further reading," says JP Guy, "on the grip slip behavior of a bouncing ball.
A bit of overkill for a Unity game but interesting nonetheless."
Yeah, I'll take a look at that.
I had to consult--
what did I consult?
I ended up having to consult a couple of videos on this.
Unity has their own tutorial on making continuous bouncing ball.
But I didn't watch that one.
But now we shouldn't be able to move past our boundaries anymore.
Or maybe we do.
OK.
Hold on.
Let me figure out why it's doing that.
Did I start-- is it too thin?
Hold on.
I'm not sure why.
So I didn't do it when we were at speed 3 before.
I'm curious, curious as to why it's doing that.
So I'm going to go to--
so I didn't test the game at speed 5 when I was messing around
with implementing it.
I didn't test it at speed 5.
So I'm just going to bring the speed back down to 3 to see if that fixes it.
Paddle one, paddle two.
They're both three.
Let's try that again.
Let's see if it'll go through though the wall.
OK, so it doesn't go through the wall anymore, which is interesting.
I wonder if we make the wall a little bit larger if that has any effect.
Let me try that.
If I go in here and I go to Edit Collider and I scale them along the--
oops.
I don't want to do that.
Let's go over here.
Let's scale this just a little bit.
It shouldn't have this issue, so I'm not entirely sure.
Let's try that again.
I want to go back to 5, because I did 5 as a speed.
Let me do that.
Play.
No, it still wants to go through.
That's fascinating.
It is interpolated.
The good news is our paddles aren't flying
all over the place, which was part of the problem that we had before.
Interpolate is for-- sorry.
Let's see.
[INAUDIBLE] says, "interpolate is actually
for the motion of the rigid body to avoid
mismatch between physics update, which is always at 60 frames per second,
and graphics updates, which may vary.
It's supposed to fix visual glitches like jittering,
but doesn't always work too well."
Ah, OK, good.
Thank you for that.
Math08, "are you using floats?"
Floats for what, exactly?
That's a unit it uses by default. I know interpolation exterpolation
only from math four in college.
Yeah.
My math background is a little bit on the primitive side.
Continuous dynamic, did we not have continuous dynamic?
Try the third option for the collision--
paddle one, paddle two.
Yeah, they are on continuous dynamic.
So I'm not sure what that is.
I'm not sure why it's behaving like that.
They're both-- yeah, they're both continuous dynamic.
That's very weird.
I did not have this problem at all in testing.
Wow.
Thankfully the ball doesn't move through it, but man, that's bugging me.
Sorry.
I'm getting a little bit distracted by actually playing the game now,
which is a good thing.
That means we're making progress.
I thought mathematics was still required in Comp Sci, or am I wrong?
You're not wrong, necessarily.
I think it depends on what you want to do.
So one of my goals is to learn linear algebra to a very competent degree
because linear algebra is very widely used in 3D game development and 3D game
programming.
You don't need to necessarily know it for Unity, to use Unity,
but it doesn't hurt.
And being able to understand a lot of the underlying stuff, I think,
gives you an edge, which is why I want to learn it.
I'm not super comfortable with it.
Things like vectors, for example, are like a basic--
and matrices-- are a basic aspect of linear algebra.
And 3D graphics is ultimately just manipulating
vertices and matrices in certain ways.
So it's cool to know it.
But learning, like, to do a lot of programming,
you don't necessarily need to know beyond algebra and geometry.
"Thing is, because the interaction between translate and impulse,"
says Math08.
So we're not actually applying an impulse with our paddle.
So the impulse is with our ball.
The ball is the only one getting an impulse.
It is an issue with the translate, probably.
So I'm going to-- just because I know it works at speed 3--
I'm going to set the speed to 3 for now.
I should have tested it with higher values in advance
to see exactly what the issue is.
Continuous dynamic was supposed to fix it.
I can try with continuous to maybe see if that works, as well.
Does discreet work, maybe?
Discrete.
Let me try that, see if that works, actually.
Let's move-- I didn't change the setting, did I?
Whoops.
It still moves through the wall.
I'll do a quick Google, maybe see if that has a result.
Rigid body translate moves through collider.
I guess we could do add force.
I think that would work, actually, if we just changed it from to--
changed it from translate to add force, we could do that.
So if I just said paddle requires a component type of rigid body
and then I went to--
instead of doing a transform.translate, if I did--
first we need to get a reference to it.
So we're going to need rigid body, rb, equals get--
or we can't do an equals yet.
But I can say rb equals get component rigid body,
just like we did before with the ball.
And then I can say, if input get key left, we'll do rb dot add force
and then force mode dot impulse, right?
So that'll be the same thing.
rb dot add force.
Force mode dot impulse.
Because, yeah, to the point of what the person was saying in the thread there,
transform.translate is technically just teleportation.
So I could see why it would screw with the physics system a little bit.
I guess if you're at a small enough movement speed,
it doesn't matter too much.
But since we're doing this and we want to adjust the speed,
we probably want to take a look at that.
So if we go back to paddle one, paddle two, let's
set those both to speed 5 again.
And let's make sure my code works.
So let's see if I can move left or right, which it can't.
OK.
Interesting.
Oh, because the impulse is scaling off of delta time.
So we need to make this negative speed and regular speed
not scaling it by delta time because now we're going to get the--
we're going to get that scaling by delta time
because we're applying that impulse, right, or moving it
based on units per second or meters per second
just because we're using the physics system.
There's a lot of comments.
Sorry.
Let me zoom back up there.
W Wood, can you make bump stops that are separate to the walls the ball hits?
Can you elaborate on that?
Do you mean, like, obstacles in the game world?
Udon Master says, "vectors are life and hell too."
Yeah, they're definitely useful.
I could see--
I know they get pretty complicated the more you get deeper
into linear algebra.
[? Bavik ?] [? Knight, ?] "MIT OCW for the win for math."
Yeah, no, they have excellent courses.
I was watching a financial economics class at MIT ED which was really good.
JP Guy says, "I have a good PDF about linear algebra and game engines.
I'll email it to you."
Yeah, definitely do.
Definitely do.
Twitch Hello World lists your info on a good linear algebra class.
If you do a twitch session on that, it'd be so terrific, as well as
on robotics and arduino, hopefully.
Robotics would be really cool, actually.
I'll see if I know anybody that knows robotics.
Linear algebra would be interesting.
I certainly wouldn't be able to give, I think, a great lecture on it.
It would probably be me streaming learning it
and I don't know if that would be fun for people to watch.
So I might just--
I might maybe find somebody that knows linear algebra
and have them do a session on it.
But it'd probably have to be in the context of games
to make it still fairly CS applicable.
Oh Bavik, you absolute madman, mentioning MIT doing a Harvard stream.
Now, we're-- MIT and Harvard are good friends.
Come on.
[? Bavik ?] [? Knight ?] says, "they both are the best.
And CS50 starts from MIT's Scratch interface so it wouldn't hurt much."
Exactly, we are best buddies with MIT.
We use Scratch.
[INAUDIBLE] says, "you can also use move.
I think translate will override the collision."
The move function.
Transform dot-- is it transform.move?
Unity transform move?
Can you-- you mind specifying which function you mean, [INAUDIBLE]??
JP Guy says, "fair point."
Andre says, "yeah, rigid body--" oh, rigid body dot move.
OK.
Rigid body dot move.
We could do that.
Rigid body dot move.
Move position.
And so that will--
oh, you know what?
Yes.
Yeah, yeah, yeah, you're right.
You're right.
Because we're adding an impulse.
If we do it every frame, that would be disastrous.
We don't want to do that.
We want to do rigid body dot move.
Good call on that.
You guys are much--
move position, specifically-- you guys are much more talented at this
than I am.
Move position a new vector 3.
It does not take a second position.
Now, does move position actually take--
oh, it's a new position.
So we have to take its current position, then, and figure that out.
Or can it take a--
because if we're specifying a position for it to move to,
then that's not the same thing as--
that's not the same thing as moving it along an axis, right?
Yeah, it moves it to a position.
So that means we would need a reference to whatever position is in.
Oh, sorry.
Missing some other-- missing some other comments here.
Something like rb dot move position transform.position
plus transform.write times speed times time dot delta time.
Yeah.
Yeah, that could work.
Let's do that.
So copying what [INAUDIBLE] graciously provided to us in the chat.
If we do rb dot move position and then transform.position--
whoops.
Not driven rec transform transfer.
Sometimes Intellisense works against you.
transform.position plus-- in this case, we want to move left,
so transform.left times speed times time dot delta time.
OK.
Wait.
Why does that-- transform does not contain a definition for left and no
accessible--
transform dot-- is it vector3.left?
Probably that, right?
And then go down here.
And then this would be vector3.right.
People are asking for that linear algebra PDF.
OK, so "linear algebra session would be really fun," says Astley.
[? Push ?] Hello World says, "yes, that would be awesome.
The math [INAUDIBLE] could apply linear algebra to AI and/or games.
And if you ask questions, as in the AI session, it is terrific."
Got to move the rb, not the element itself, right?
It should move the whole game object, correct?
The rigid body maintains a reference to the whole object
and will move the whole object.
Oh, yep.
Times negative speed.
Yes.
Correct.
Shout out to [INAUDIBLE] for helping us out in the chat
here with the clutch last minute changes to the code base.
Very talented Unity engineer.
Let's see if that works.
I'm not 100% sure if it will, but we'll find out.
OK, so hold up.
So it moved them, but it didn't detect collision.
Transform dot-- oh, this needs to be minus, right?
Does it?
No, because we're going to add--
this would be a negative value, right?
So left wasn't working, but right was working.
But more importantly, it wasn't actually detecting collision,
which is the more concerning part.
Yeah, so the math-- my math is not quite working out.
Oh, vector three dot--
right.
It has to be vector3.right always because it's going to be 1.
And then-- that makes sense.
That should work, right?
Fun times live coding on stream.
Here we go.
Oh, there we go.
That works.
Cool.
So it still passes, through.
It's detecting that there is something there,
but it will still move it past it, unfortunately.
So it's not-- we haven't fixed the problem.
Oh, because we're not using interpolation, right?
We changed it to discrete, I think.
So we go back here to interpolate, to continuous dynamic,
and then we try to run it.
Fingers crossed.
This should work, right?
Nope, still doesn't work.
That's funny.
It still detects that there's something there
and it wants to push back against it.
But it's still not quite working.
OK.
I might just revert back to the speed 3, just for the sake of demonstration.
And we could figure out another time.
"Math primer for graphics and game development by [INAUDIBLE],","
says JP Guy.
I trust you guys get this book legally, being decent human beings and all.
[INAUDIBLE] says, "no there's another anyway.
Thanks.
JP Guy-- "use vector3.left you don't need to negate the speed."
Yes, that's correct.
JP Guy, you get it.
Try setting [INAUDIBLE] to use dynamic.
Maybe add force, but not every update.
That would be a little harder, add force,
because then how do we determine when we want to--
I guess we would say we have to have a flag that basically says start impulse,
right?
And then if it intersects with the walls,
set the impulse to zero or whatever.
[INAUDIBLE] says, "put the move position inside
of fixed update instead of update.
I'm really puzzled, LOL."
Yeah, that could be it, actually.
Let's try that.
Void.
So fixed update will run for your physics every--
it will basically calculate this every frame rate independently, essentially,
which allows you to get around a lot of weird physics bugs.
So let's try that.
Ooh, that looks good.
All right. it was fixed update.
So good.
Good job.
Shoutouts to [INAUDIBLE] for that, for the clutch suggestion there.
So yeah, update works every frame and will
get called every frame that you run, depending on your frame rate.
But if your frame rate fluctuates, update is going to run differently.
It's going to run in different iterations.
And so it's going to--
basically, delta time is going to change.
It's going to be a larger value, which is sort of why we're
clipping into our walls left and right.
If you run it fixed update, it will ensure
that that gets run at a consistent amount,
given the amount of frames that have passed.
It will basically-- if you run it a fewer number of frames,
it will run it-- it will basically do the catch-up needed
to keep you on track.
And so that's how you can get around a lot of weird physics bugs.
So shoutouts to [INAUDIBLE].
Thank you for tossing that in there and helping us debug today.
[INAUDIBLE] says, "yes, JP Guy."
42Force, [INAUDIBLE].
Awesome.
All right.
So we have our paddles moving around, which is great.
We got that part all set up.
Apologies that it took so long to figure out.
Now, the ball will bounce appropriately.
It will bounce off of the paddles and it will bounce off the walls.
But what we need to do--
and maybe I should put an annotation or something in there
for the YouTube video when we finally release it
so people can skip all that debugging, but what we want to do now
is basically detect whether or not someone
has scored against another person.
So we can have text labels on the left and the right side
which say just what our score, is right?
So we can do that pretty easily, or at least
we can mock it up pretty easily if I say go down to the UI, go to text.
And then I'm just going to call this player one score.
I'm going to create another text in my canvas here and call it player--
whoops-- call it player two score.
Now, what I did was I went to add a new object.
I'm going to disable the chat just for a second.
I went to add a new object UI text.
And when I did that, I got a canvas element.
And so the canvas is basically your UI manager for anything
that you use Unity's 2D UI stuff for.
It all goes inside of a canvas.
And it also added an events system to my scene,
which is used for touch events and other things
that we won't actually use today for interactive GUIs.
Today, all we're really interested in are some text labels.
So here I have a--
I added two text labels.
So one's going go on the left.
One is going to go in the right.
One is called player one score and one is called player two score.
I'm going to expand this a little bit.
Unity's UI system is a little bit strange.
You'll notice that in the bottom I see the text label
itself like it's supposed to be rendered onto the screen in 2D, right?
But in the actual scene, I've got some weird funkiness
going on where I've got this massive label here in 3D space
and I've got this big old rectangle.
And this is Unity's way of actually rendering the UI over your game.
It'll actually create the gigantic canvas that maps one to one, I believe,
with Unity units and allows it to more efficiently render
variable-sized GUIs, as opposed to having it sort of be here in 3D space
the same size as your game.
And what happens is Unity has a separate camera that'll actually
render the UI on top of whatever it is that you're
rendering with your main camera.
So if I double click on the player two score,
I can see it really massively in 3D.
And our scene is just down there way in the bottom.
And if I-- actually, if I grow this, the canvas should grow quite a bit.
So the larger your game view is, the larger your canvas.
You can see it shrinks accordingly.
So in real time, it's resizing the canvas.
I want to get a 2D view of what my canvas looks like.
So I can go up here to the very top left-- a little bit hard to see,
potentially.
But there's a button that says 2D.
And that allows you to switch between 2D and 3D views.
So I do that, I click 2D, now I'm in the 2D view of Unity.
And I can look around my canvas, just like I
would want to lay it out on the screen, as opposed
to it being some sort of weird 3D giant structure, right?
So if I move this over here-- whoops, grab the--
keep grabbing the light.
Notice that there's this fifth button here
on the very top left, which is the rect tool, which allows you
to actually manipulate GUI elements.
So I can move these around however I want to.
This is the player one score.
So what I want to do is I want to put this at the top left-ish.
And I want to put my player two score kind of at the top right-ish.
Just like kind of like that.
Going to eyeball it.
And I want to make them white because it's a little bit
hard to see currently.
So I'm going to go over here.
I'm going to make sure my player one score is selected.
On the right hand side, I have a color picker for the color of the text.
I'm just going to do that for both of those.
I'm going to change the size because the font size is a little bit small.
You can see it in the game view down below.
That's a preview of what I'll look like when it's rendered.
But it's a bit small.
I'm going to set the size to 32 and the size of 32.
Notice that the text disappeared.
That's because the rect is a little bit too small for the text.
But if I grow it out, it'll appear again.
I'm going to do that again right here.
And I'm going to set this to be left-aligned
and I'm going to set the right one to be right-aligned.
Notice that there's these little buttons here which
allow you to choose the formatting options for your text.
So it's a very flexible way to arrange your interfaces.
No longer do we have to necessarily do, like,
printf statements where we specify a padding
amount for rendering a given string.
We can just do it visually here, which is nice.
Now, what I want to do is I want to make sure that this label here on the left
is always relative to the left and doesn't have a fixed location.
So I can click on this little box here at the top right,
and it will give me a dropdown at different anchor points.
So I'm going to select this one right here, which is top left anchor point.
Notice that I got a little left--
a little icon that showed up up there on the very top
left, just to demonstrate that.
And I'm going to have my player two score selected
and I'm going to make that a top right anchor point.
Notice that an anchor point showed up there.
So no matter how I resize my game, those labels will stay relative.
The distance that they are now, they'll stay
relative to the top right and top left corners
of the game, which is super handy.
Should be able to demonstrate that.
You can see, as I re-scale my game, the game view, the labels,
they stay really close to the top left and top right corners of the game.
So super easy, super basic.
What I'm going to do is I'm going to set these both to be 0, just like that.
Just like that.
And so now I have what looks like sort of the basic idea of pong,
where I have the scores there.
But all it is is just a couple of strings with the literal character
zero, so not terribly useful yet.
What we want to do is programmatically determine whether we have basically
scored against our opponent and then update those scores to reflect that.
So what we can do--
I'm going to create a new class.
I'm going to create a new script.
I'm going to go to my assets, scripts.
I'm going to create a new one called score.
And if I open up score, we'll see that it's just
a default component as anything else.
I'll enable to chat again.
If people want to say some stuff, it'll be visible.
This score is going to basically just keep track of the--
it's basically just going to be text that gets updated.
Now do we actually need to have a separate score?
We do end up needing a score at some point.
But we keep track of the score in our actual paddles themselves.
So notice that I declared score up here.
And it should be set to zero by default. So the score
is going to be on each paddle.
Each paddle will keep a reference to the score.
And then it will update the text on each of those different text labels
that we just created.
So it will update if we end up scoring against an individual person.
And so what I want to do, also, is I want
to have a goal class, because what we're going to do,
in order to check to see whether we have scored against somebody,
is we're going to basically determine if our ball collides with a goal, right?
So if I go to scripts, create a new C# script called Goal,
and then open that up, you'll recall earlier that if we take a look
at our player two goal and player one goal,
we have box colliders on both of those, but we made sure to select the is
trigger checkbox here, which allows us to say this is not going to collide
with other rigid bodies in the physical sense that we normally do when we have
a box collider and a box collider with forces and they hit each other.
Instead, this box collider is going to disable its collision.
It's going to act as a trigger, which means
that it's going to be listening for collisions from other objects.
And what we can do is in our goal class we can say void on trigger
enter collider other.
And this is another function that Unity calls for us.
Whenever we have a trigger that collides with something else,
we can say I'm going to get some collider called other.
And I can get the information off of it.
And I can do something with it when I end up actually getting that collision,
right?
So the goal is going to--
now how did I do this before?
So there's going to be the scores, right?
The paddles are going to--
or rather, the-- paddles are going to maintain a reference
to their own score, which we're going to calculate every time we do get a goal.
We're going to say, if the score of paddle one is greater than 10,
game over.
Or if the score of greater than or equal to 10--
or if the score of paddle two is greater than or equal to 10,
then we also want to trigger a game over.
And we want to make sure that we specify which of these two players
was the winner, so player one or player two.
And then we also want to reset the ball if we get a collision,
if we hit the goal.
And we also want to make sure that we have some sort of count down--
3, 2, 1, probably-- in order to give the player chance
to think about their next move, to basically say, oh, it's about to start.
I'm going to get ready.
And then rather than that this is the ball, always just starting instantly,
which can be kind of bad design, right?
OK.
So on trigger enter.
So if we do get it such that the goal detects-- either of the goals
detects that a ball was the winner, we want the other paddle's score
to increment, right?
Got to boost that APM during the countdown screen.
Yeah, yeah, exactly.
So the-- when we get into on trigger enter, when
our ball collides with a goal, we want the opposite paddle's score
to increase.
So we know that we're going to need a reference to a paddle.
We can call this probably enemy paddle, right?
And then we can say on trigger--
minimally, we can say enemy paddle dot score plus plus, right?
The enemy's paddle is going to increase.
It's going to go from 0 to 1, 1 to 2, 1 to 3, 1 to 4, blah, blah, blah.
And then we're going to want to reset the ball
and include some sort of logic that puts it in the middle
and it does the countdown.
Additionally, what we want to do is we want
to reflect this change in score in our UI
because our UI is separate from the paddles currently, right?
So what we can do is in our score--
so this is where it's important to have the actual paddle referencing
and manipulate our text--
we can say in our score, which these are our text
variables which have their 0, 1, 2, 3 that we just added to the UI.
We can say, we also want to get a reference to a paddle.
This is going to be our paddle.
And every frame I basically want to say text--
rather, this is going to require a component of type text, type of text,
right?
And for this, you actually need to use Unity Engine.UI.
So we do that, and then in our update we can say text.
First we need to--
couple things we need to do.
We need to create a text variable called text.
This will be our text component, which has the reference to our actual text
information.
In start, we want to get a reference to it.
Using get component which we've done before.
So this will get initialized on Start.
And then every update, we just want to keep it in line with our UI.
So what we can do is we can say text.text equals
and then paddle.score.toString.
And so what this will do, because our text.text--
so our text component itself has this field called text.
And within that-- that text itself is going to store a string variable.
It's going to have some text data that it displays in its widget, right?
We can't assign that just the raw score, because the score is going to be int.
So we need to cast it.
We need to-- well, not cast it.
Well, we need to convert it to a string using the .toString method,
which is available on any integer in C#.
And what that allows us to do is now every frame
we're just going to say, hey, what's our current score?
Update it.
What's our current score?
Update it.
What's our current score?
Update it.
There's fancier ways to do this such that it doesn't
have to ping every update using getters and setters which
we could take a look at.
But we're not going to do that.
It's a little bit fancier.
Maybe in a future video we'll take a look at that.
But for right now, every frame we're just going to say, what's our score?
What's our score?
And just update it every time, right?
So go back to Unity.
Go to our player one score.
What I want to do is I want to add a component here.
I'm going to add a score component.
And then the score component for the player one
is going to get a reference to the player one paddle.
So I'm going to drag the paddle over.
Notice that I just drag the object over here.
Because I said it's a public paddle, anything that has a paddle component
I can just put onto that field, right?
So I just click and drag, super nice and easy way
to create a relationship between two components, two scripts, two game
objects that have different scripts.
Player two score, same thing.
I'm going to add a score component.
I'm going to go to player two--
paddle two, rather.
Drag a reference over to it, just like that.
And then now every frame are going to update
and check to see what the score is on the paddle and then update the UI.
To string works for only integers in C or for any objects, like in Java?
It works on, I think, all objects.
And by default it will get some default toString function.
But you can overwrite it yourself, depending
on the object type that you have, which would give you some more flexibility.
JP Guy says, "couldn't you just trigger an event
when the ball exits the playing field, AKA flies past one of the paddles?"
Yeah.
And that's what we're going to be doing with--
that's what on trigger enter is.
It triggers an event to--
with our box collider, which fires the on trigger enter function, which
we could--
so if we go over to goal, on trigger enter,
we could get a reference to the text, which means our goal then
needs to have a reference to the text.
And if we do things that way, it'll just get
a little bit-- we'll have kind of, like, references
to a lot of objects between a lot of objects,
which would be somewhat more performant, and you
would want that for certain use cases.
But this case is a very light use of the update function.
So we won't implement it that way.
And we can also just use getters and setters to do it that way, too.
But we will need to establish more relationships between our objects
if we wanted to do it that way.
And it just a little bit more code and a little bit
messier for something that's not super taxing.
So it's not worth it, in this case.
But yeah, you definitely could, for any object, yeah.
If you write your own class and you want to string to behave differently,
you have to do that yourself.
OK.
So our UI widgets now have a reference to where they're pulling the data from.
And it gets updated every frame.
So what we want to do is make sure that our score actually
increments, which it does.
So we need to make sure our goals have the goal component.
Did I actually do that?
I did not.
So for each goal, I'm just going to add a goal component.
And then individually, I'm going to set their enemy paddle.
So remember, if player two goal is interacted with-- so in this case,
this goal up here--
I want player one's score to increase.
So player two goal's should have a reference to paddle one.
Inversely, player one goal should have a reference to paddle two cause
when their triggers get collided with, the other paddle's score should
increase, right?
So I'm going to hit play.
This should work, I think.
It went right to 10 for some reason.
Not sure why it did that.
Let's figure that out.
So why did that get-- oh, because I hardcoded 10
in paddle one's score earlier.
So I'm going to set that to 0.
If you write in the component, a value here,
it will override the default component, even when you start the game.
So in that case, earlier I had written 10
in there just for demonstration purposes.
But now we can see, though, that our UI is actually
reflecting the score, which is nice.
So I'm going to do that.
And we did see that it incremented.
So I'm going to let that score against player two.
So you'll notice that player one, his score increased,
his or her score increased.
However, the ball did not return back to the middle of the screen, which
is a very important thing that we need to do because pong isn't terribly
useful if we just get one point scored.
And then the ball just goes forever off into 3D space, right?
So on trigger enter needs to now actually have a reference to the ball.
So this is where coupling sort of makes sense.
I'm going to need our ball to know how to set itself back
into the middle of the game.
And then once it's in the middle of the game space, again, ideally eventually
it'll have a countdown so that it doesn't just
immediately go back and then move in a direction, which
can kind of get a little disorienting for somebody playing the game.
I want it to count down and then move in a direction, in a random direction,
ideally.
Right now it's still in a hardcoded direction.
So if I go to the ball class, the ball class should have a reference to--
sorry.
It should have a function that allows it to reset in the center.
So we can do that.
I can say-- let's just say I want a function called return
to center, right?
And that means basically, transform the position equals new vector3, 0, 0,
0, right?
Or I think it's 0.2 and then 0.4, something like that, right?
Slightly above the plane.
And make sure that you appended f at the end of a decimal point number,
a floating point number, because floating point numbers by default in C#
are doubles.
But this function takes floats and the compiler
will distinguish between the two of them.
Let me see here.
So the ball is currently set at 0.06--
set that to 0--
0.06, 0, and 0.05.
OK.
0.06, 0, and 0.05.
So a little bit above the--
is that where I want it?
Probably want it at 0--
want it at 0 like maybe--
probably 0, 0, 0, just right in the center.
I'm going to do that.
That's easier.
But yeah, if you're not familiar, if you see
an error trying to pass in a floating point number to a function that takes
floats, make sure you put the F at the end of the decimal point
or at the end of the number, because that tells it specifically
cast this to a float, not a double.
Back into initial position as in the starting position for the ball.
Yep, exactly.
So return to center will do just that.
And then what I want to do is every time a goal gets a--
either of the goals is collided with, I want the ball--
or one ball-- to go to the center.
And maybe I don't necessarily want a ball reference on each goal script
such that I have to manually click and drag the ball over.
I could do that.
That'd be fine.
But let's say I just wanted to--
let's say I just wanted to call the ball--
just wanted to find it wherever it is in the scene
and then call some function on it, right?
So I can say game object dot find.
And then I give it a name.
So it'll be ball.
And then dot get component ball dot.
And then I can say what was the function?
It was called return, right?
Game object dot find ball dot get component of ball dot--
ball does have return to center, right?
Yep, it does.
Oh, because it's not public.
Has to be a public method if you want to call it from another function.
Dot return to center.
Should be available now.
Now I can call it just like that.
So what I've done is I've said I've called
the global game the static GameObject.find function, which
will look for a string, will look for a game object based off
of a string called ball, in which case I have named my game object ball.
This is the string it's looking for.
It's looking for a game object called ball.
Remember, these are all game objects.
And then they're comprised of components.
So it's not looking for a ball component.
It's looking for an object in the hierarchy called ball.
And then on that object, I want to call get component of type ball
as a function and then the new return to center
function that I just defined in the ball mono behavior class.
So now if I run this and I get a score, boom, it goes back to the middle.
So works perfectly fine.
Bavik says, "is default not public?"
Default is private.
That is correct.
Not public by default. So it's working.
And I don't think we have a--
we don't have any logic in place for getting to 10 at all.
No?
So this will just go on indefinitely until--
I guess until we reach the limit of the integer in C#,
which should be about 2 billion.
And then it'll loop back around probably to negative 2 billion,
which isn't what we want.
What we want it to do is when we get to 10,
we want to say basically toggle some state
this says now it's game over, right?
So let's do that.
I could probably do that on the ball, right?
I could say-- do I want to do that on the ball?
I have all of the notes.
But I want to see if I can do it--
we can do it from scratch here.
We can figure it out.
So the ball is an object, sort of like a global--
like a global state object that we could use that gets
a reference to both paddles.
And then can do the comparison that says if the score is greater than 10
on paddle one, increment-- or, you know, then
game over, the paddle is greater than two, game over.
The first thing that I think I want to do
is I want to create a new UI element called text.
And I want this to be my count down text.
And then I want a winner text, as well.
So what this is going to do is I'm going to have text that renders
when we're in a countdown state.
And then I want to have text that renders
when the winner has been determined after one or the other player
gets to 10 points.
So the winner text I'm just going to make empty.
I will make it 32 pixels.
And I will make it white, just so it's easy to see.
Same thing for the count down text.
Make it white.
I'm going to center both of them, 32.
You're not going to be visible immediately, but that's OK.
I'm going to do this.
Delete the text.
Grow it out.
And then center it.
And so winner text and countdown text are just set to empty strings.
But we can populate those ourselves.
Does Unity work with floats or with doubles by default?
Floats with default. Floats by default, rather.
OK.
So when I trigger a return to center, what
I want to do is trigger the countdown, as well, right?
I want the countdown to occur immediately before the ball--
as soon as the ball goes to the center.
And then I want there to be a 3, 2, 1.
And then the ball starts moving.
And I want the ball to stay completely still while it's in that state.
So probably should include it in this return to center function.
Almost sounds like return to sender.
Is the ball retaining the momentum if it crossed the goal with?
Yes.
And that is another aspect of what we want to do.
We want to make sure that that is random each time.
So we can set its velocity that way.
And then that will have the effect of giving it a different velocity
every time it goes back to the center, which we could do that here, as well.
So let's say I want to-- and also this will be taken out and put into here,
the add force function that we called before.
Except we're not going to add force anymore.
We're just going to set velocity.
So I'm going to say rb dot velocity equals new vector 3.
And then I'm going to say 404 for now.
But what I'm going to do is we're going to randomize this.
So I want to make sure that this x and this z get a random value
every time we run the return to center function.
So what I can do is I can say--
do I want it to be an int?
Yeah.
I'll just make it an int.
So I'll say int velocity on the x is equal to random dot range.
So this is where we're going to use what's called the ternary operator.
So basically what I want it to do is I want
to be a value that's either between negative 7 and negative 4, or rather
negative 7 or negative 4, or 4 and 7.
I want it to be between those ranges.
I don't want it to be smaller values like 3, 2, 1, or 0, or negative 1,
or negative 2, or negative 3.
We could do that to a certain degree.
But it will cause our ball in certain situations
to move in a straight line, which could get to be kind of subpar,
especially because if it's in a straight line
it'll just keep moving in the same--
no, we won't be able to-- because we won't
have any influence over the direction currently.
And we won't be implementing directional influence in this tutorial.
But we could certainly think of ways to do that using,
perhaps, nested colliders or rather multiple colliders that have
effects on velocity when they collide.
But today we're just going to do simple bouncing off the walls
and colliders with rigid bodies.
And I want to make sure that the negative values and positive values
that I give to my x and z for the velocity fall
within a specific subset of numbers, right?
So basically what I can say is, I want to do one of two things.
I want to either give myself a number between negative 7 and a negative 4,
or a value between 4 and 7.
So I'm going to say random dot range of 3--
or rather, 1 to 3 is equal to 1.
Question mark.
And what this is basically saying is if--
because random dot range with integers is exclusive for the larger term,
this is basically going to give me a number between 1 and 2,
which is a 50% chance.
So it's like negative 7, 7 minus 3, 3.
Kind of.
Only, it's going to be--
I guess in vectors--
can we do that with a simple vector calculation?
Can we say negative 7 7--
it'd be a little bit--
I think a little bit more complicated with the vector math in that case.
But kind of, in that case.
We're basically saying negative 7--
basically it's going to be between negative 7 and negative 4, or 3 and 7,
4 and 7.
Want to create a velocity where the vector sum is between 4 and 7.
The vector sum is between 4 and 7?
I'm not sure.
If you can elaborate on that.
I'm not sure what you mean by that.
In that case, you could just use Pythagoras.
Maybe?
If you can elaborate, perhaps.
Again, I'm not an expert mathematician by any stretch.
7 less than or equal to x, [INAUDIBLE] or equal to 3
where 3 is less than or equal to x is less than or equal to 7.
Almost.
The first one, negative 7 less than or equal to x, less than
or equal to negative 4 for that one.
So I'll show you here.
I'll say random dot range 1 to 3.
If it's equal to 1, which is a 50% chance,
then we're going to say it's equal to random dot range of negative 4
or negative 7, or using the colon, if that's not
the case that that first condition was true,
then I'm going to set it to a random dot range between 4 and 7.
Right?
Copy that for the z.
And so it's a ternary statement that basically does a comparison between 1
and 2, flipping a coin.
It's either going to be negative 4 to negative 7 or 4 to 7.
And there might be a more elegant way to write that out mathematically.
Definitely toss them in chat if that's the case.
But this is a simple, easy way of sort of visualizing how it
works using a coin flip, effectively.
And what we can do is I can say velocity is equal to vel x and vel y, right?
Sorry, vel z, not vel y.
And transform dot position is equal to a new vector 3 0, 0, 0?
Yes.
We want that to be the case.
We want to reset our position to the middle, just like we did before.
And so now if I call this in our code, we
should see a random value every time when we run our game here.
Let's try it out.
Whoops.
So in that case--
whoa.
That was weird.
I was not expecting that.
We had some weird behavior there.
I'm not sure why-- oh, because we forgot to constrain our ball.
So another thing we want to do is we want
to constrain our ball such that it doesn't move along the y position.
So we want to freeze y position.
And then we freeze this rotation, as well,
because we don't want it to rotate.
We just want it to move.
You can also use random dot value for the coin flip,
gives a float between 0 and 1, so you can check for a greater than 0.5.
"Yeah, that's correct," says [INAUDIBLE]..
OK.
Try that.
There we go.
That's better.
I'm going to let it do that.
Return to the center.
Boom.
So it is randomizing it.
That's nice.
It's changing the velocity.
And it's more or less the same kind of--
the same kind of a 45 degree angle-ish code.
And that's just because we're kind of constraining
our range of values between 4 and 7, just
for the sake of ease of the tutorial.
If we wanted to get fancier with it, our paddles
would manipulate the velocity, the angle at which the ball bounces off
of it, such that we would get more acute and more obtuse angles.
But yeah, Astley says, "so the question is, like,
if and the colon is like else if?"
Yeah, it's more like if else, not else if, necessarily.
So basically we check this condition.
So this is a Boolean--
this whole thing here is a Boolean expression.
Random dot range 1 to 3 is equal to 1 because it's exclusive of this 3.
So it's going to return 1 to 2.
It'll return 1 to this number minus 1.
So this will be either 1 or 2.
And we're basically saying, if it's equal to 1--
so a 50% chance, maybe random--
then we want to do this bit of code.
Else, we want to do this bit of code.
So basically, rather, it will evaluate this expression,
which means it will get assigned into this because we're using
this equals here at the very beginning.
So we're equaling the whole calculation of this expression.
It's a ternary operator and a ternary expression.
So it's if else, yeah.
If else, not else if, though.
The colon case will happen no matter what.
There's no condition for that if the first expression evaluates to false.
Yeah.
Just a nice convenient way to write if else.
We could have written this whole thing out in an if else statement, as well.
But it's just a little bit easier to read and sort of visually see
what's going on that way.
OK.
So we've done that.
We've got our ball spawning in a random direction, which is fantastic.
That's what we wanted to do.
We froze our position so that it doesn't bounce in a weird direction, which
is what it did earlier.
That was an elegant way for real numbers in Python
would be like random dot random minus 1 times 7 minus Python
dot random minus 1 times 3.
Yeah.
It can be a little bit nasty, sometimes, dealing
with specific ranges of random numbers.
Generally, you don't want it to be in sort of split--
it's kind of like a piecewise function in this case, I guess you'd call it,
where it's split kind of amongst two different realms, two different domains
or ranges.
But yeah, usually it's not that painful.
It's usually just a random dot range some number, two numbers.
But anyway, so now we have the collisions.
We have the ball returning.
We have randomization.
So what we want to do is we wanted to test whether somebody has won.
And if they have won, we want to say it in the y.
So we can probably do that with the ball.
So what I'm thinking I'll do is I'll let the ball script have
a reference to the two paddles, right?
So public paddle, paddle one, paddle two.
So the ball is going to maintain a reference between both--
to both paddles, and can compare their score.
So if we say if score or if paddle one dot
score is greater than or equal to 10, then I
should probably do some sort of win condition.
If paddle two dot score is greater than or equal to 10, do some win condition.
And then otherwise, it's just going to go down after that.
It's going to run the rest of this code.
So what I can do is I can say maybe I want a reference to that text
from before.
So what I can do--
do I want to do that?
I guess I could.
Yeah.
So what I'll do is I'll actually have a reference to the text.
So I'll say public text when text.
Right?
And this is where we have a bunch of components talking to each other.
And so often you'll want to kind of figure
out the most elegant way to have all your stuff talk to each other.
This is not terrible.
But continuing to do this forever and ever will be not super sustainable.
So you want to be careful.
But remember, we have to include the Unity engine, not UI,
if we want to use a text.
So I'm going to say public text, win text,
notice that if we go down to my ball script I have a win text reference.
I'm going to just--
this win text right there.
I'm going to also drag in a reference to paddle one and paddle two
since we wrote those as public variables.
So now our ball is kind of like our-- almost
like having our whole game on itself, or at least
the important variables that determine whether or not we win,
because it has the function that returns to the center anyway.
So it's kind of nice to have the logic in there.
So every time we call return to center we
can basically do a calculation on the score.
And if we want, if someone won, we can just change the text
and then that's it.
Otherwise, we can start the countdown and go into the next--
go into the next step, right?
So what I want to do is I'm going to say if paddle one dot
score is greater than or equal to 10, win text dot text dot enabled--
or sorry, win text dot enabled is true, and win text
dot text is equal to player one wins.
Cannot use single quotes.
That's a bad habit from using languages like Lua.
But that's that, right?
Win text dot enabled is equal to true.
Win text dot text is equal to player 2 wins.
And that's that.
And again, recall we have the text set to disabled.
So in our UI, if I go over to winner text, for example, winner text is--
actually, it's not disabled.
So I'm going to click that to make sure it is disabled.
Same thing with countdown text.
I don't want those rendering while they don't
need to be, even though they will probably not have a value by default,
I should still keep them hidden until they need to be alive.
And that's what this enabled is true thing does.
So remember, this win text is a reference to this text component here.
So if I say win text dot enabled is equal to true or false,
it's the same thing as checking that box and saying you can or cannot display
it.
And remember, if we click or unclick any of these components, they--
like the mesh render, for example, for our paddle--
it turns it on or off and displays it or doesn't display it.
Depending on what kind of component that is, it can maybe do a calculation.
It can maybe display something.
So if you just want your component to be off when you start
and then turn on programmatically, that's
how you do it-- dot enabled equals true or false on the component itself.
[? Bavik ?] [? Knight ?] says, "yeah, the random function that you elaborated
on was more mathy."
Yes.
A little bit more mathy.
So we have our win condition set here.
And if it's not the case that somebody-- or that one of the two paddles has won,
then what we want to do is probably do this bit of code with the velocity.
Set the position to the middle.
And then probably what I want to do is--
this is where I want to eventually do the countdown.
Another thing that I want to do is as soon as somebody does win,
I want the game to stop, right?
I want it to say that they won and it's done, right?
So what I can do is I can say time dot time scale is equal to 0.
And what this will do is it basically does the equivalent of stopping time.
The timescale is how things move, like if you--
between 0 and 1.
So if it's 1--
or I guess you could--
I think you can go even higher than 1 to speed up time.
But it'll effectively slow down time if it's a number that's less than 1.
So you can have slow motion, or if it's 0, pause the motion.
So if you have a pause screen, for example,
you can just set the timescale to 0.
And what this will do is effectively stop our game
as soon as somebody has gotten a score of greater than 10, right?
And we could restart our game, too.
We can have somebody checking for input, one of the components checking
for input, and says if get key or get axis space or pause or whatever,
and time dot timescale is 0, and then restart the game.
And head back to put the ball back in the center.
And so on and so forth.
So if I run this, I'm going to let somebody get to 10 points.
3, hopefully fairly quickly.
Boom.
So player two.
And I guess I didn't make my box large enough.
But it should say player two wins if I go to my player two--
my winner text-- and just make it a little bit larger, like that.
See, it's just a little too small.
But player two wins.
And notice that the game stopped.
The ball is frozen in the place where it was before.
And it demonstrates that we are, in fact, calculating
the logic of when somebody gets 10 points, and reflected that in our UI,
and in our game stake, sort of.
We sort of have an ad hoc game state with if statements.
But we could do this with the state machine,
if we wanted to, in a more complicated setup.
Today we're not going to mess with state machines at all.
I'm going to make that a little bit larger because changes
that you make to the UI aren't actually reflected when you come back
into the UI from the game.
So anytime you change something in Unity while the game is running,
it will go back to how it was before the game was running.
So you can mess with values in your game while it's
running to get the perfect setup for everything.
But just make sure to go to make note of what you've set them to
and set them in the editor after the game
has stopped running because all your changes are volatile and will disappear
as soon as you go back into the editor.
So something to be mindful of.
So that's why I went back and I resized the box again.
The countdown text I can keep as is.
It's a fine size.
But now when the player wins, one of the players
wins, we should actually see the full text in the middle of the screen.
Now we want the ball to give us a 3, 2, 1.
That's kind of one of the last things we want to take a look at, probably.
And so the way that we can do that is--
so the game is--
it takes place over--
the 3, 2, 1 takes place over time, right?
A second is going to pass between the 3 and the 2, between the 2 and the 1,
between the 1 and the actual ball starting off in a specific direction.
And so what we want to do is set the--
we want to set the--
we do this over the course of time asynchronously
in what's called a co-routine.
A co-routine is just a function that takes place sort of not technically
in its own thread, but you can almost think of it
as taking place in its own thread separately
from the main flow of your game.
And this is how you can get a lot of asynchronous behavior to work in Unity.
And you have to write co-routines in a very specific way in order
for them to work.
So what we can do is I can say, public i enumerator countdown.
And co-routines do need a count-- or a i enumerator return
type, which is how Unity does its co-routines.
And i enumerator is just a collection of things that can be iterated over
and Unity co-routines will be--
Unity co-routines will be--
are essentially collections of code elements
that it iterates over, as opposed to a collection of, say, items
in a list or a hash map or whatnot.
Remember that the change to the rect box you make in the game mode
will not stay.
Yes, yes.
[INAUDIBLE] to my point before, anything that you change in the game mode
will not be reflected in the editor when you go back.
By the way, Unity recommends also slowing down
time dot fixed delta time by the same rate
if you're playing around with slowing things down.
Yeah, that's a good point.
That's a good point.
I don't think it should cause any issues here,
just because we're stopping the game altogether when we end.
But yes, I think if we were doing physics calculations
and we were slowing things down by a fractional amount, especially,
we would want to do that.
We would want to slow our fixed time and our update time.
Good point.
OK, so in the case that we do want to count down everything,
I'm going to say--
let's say in our co-routine when it's finished, that's when we--
that's when we finally want to actually set our velocity, right?
So I can do that.
I can do that here.
I'm just going to set those variables in there, just like that.
So our countdown is actually going to do the resetting of the velocity
as soon it's finished.
Legend Snake 28's got the pog champ.
In the countdown function, this is where we're
going to do the asynchronous behavior.
And we're going to see how exactly that works using something called the yield
return.
And so yield return is basically a way of saying pause
the execution here in this function and on the next frame
go back to the next sort of iteration of the loop, which
is what it will usually be.
You'll usually do co-routines in some sort of a loop, right?
In our countdown, is it is indeed in the form of a loop.
So what it is going to be a--
we're going to set an int to num equals 3.
And we're going to do a 3, 2, 1 countdown, 3, 2, 1 and then countdown.
So what I can say is 4--
actually, I don't even need to do this.
I don't need to initialize this.
I can just say for int i is equal to 3, i is greater than 0, i minus minus.
So a countdown loop as opposed to a count
up loop, which is what you usually see.
I'm going to say--
I want to have a reference to some text again.
So win text and countdown text.
I want to say--
first of all, I want to say countdown text dot enabled is equal to true.
And then I want to say countdown text dot text is equal to i dot to string.
So it's going to be 3, 2, 1.
It's going to set the actual string value of that--
it's going to basically convert that number to a string.
Set that into the text of the countdown, which remember is the UI element
itself.
And then I'm going to do something called yield return new wait
four seconds one.
And what the yield return new wait for second to one does is it--
it's called a yield instruction.
And Unity has a scheduler where it looks at all co-routines that you've created
and basically keeps track of how long each one is supposed to execute or wait
until the next element in its collection is fetched from the i enumerator.
So basically it's just a collection of code segments.
In this case, the enumerator is going to be the blocks of these.
It's going to be kind of an abstract way of looking at code as items in a sense.
And it's basically going to do this.
Wait a second.
It's going to then come back to this on the--
after this wait for a second has finished.
So it's going to wait for a second after it's set the string to that variable.
Then as soon as that second is finished, it's going to come back to this loop.
It's going to decrement it to two.
Do it again.
Wait for another second.
Decrement it to one.
Wait for another second.
And then at zero it's going to have finished.
And then at the very bottom, we can yield return null, at which point
we also want to--
well, rather, what we can do is say we want no velocity.
I want to set the velocity to that variable, to the x,
z that we declared up top.
And so basically, this will have the effect
of setting our velocity of our ball to 0 when it starts.
So when the countdown begins, it's zero velocity.
It's not moving anywhere.
Position's in the middle, 0, 0, 0, I'm not moving anywhere.
And then after all of this is done, these yields--
remember, the second pass is in between each iteration of this loop.
It's going to then set the velocity correctly.
And then you'll return null.
At the very end of this function, that's when the co-routine is finished
executing, and then it will just--
it'll just be done at that point.
So I can say start co-routine count down.
So this is in the case that nobody has gotten up to 10 points.
I want to call this function called start co-routine.
This is a function that puts this co-routine
into the Unity scheduler, which they don't publicly
have the source code available for it.
But you can imagine it as just a list of count
of co-routines that are constantly being iterated through every frame
and looking at their wait for seconds amount
and seeing if the amount of time between the last frame and this frame
is passed.
And they can go on.
But you do need, in order to execute a co-routine,
you can't just say countdown like this.
It's not going to work.
You have to say start co-routine countdown.
And that will let Unity start managing it for you
and actually doing the necessary logic that you need to get it to work.
And so what that should do-- oh, one last thing, after that loop is
finished, we need to say countdown text dot enabled is equal to false.
And that is all we need, because then on the next iteration of countdown,
it'll start at three again.
So let's see if that works.
Let's see if I didn't screw it up.
I do need to set a reference on the ball to the countdown
text, which I can do like that.
And then if I hit start--
3, 2, 1, and then the ball doesn't go.
Interesting.
Let's see where we screwed that up.
Oh, because I copied it.
I didn't actually say vel x and vel z.
You're going to want to do that.
Let's try that one more time.
vel x and vel z.
Let's go.
3, 2, 1.
And then it goes.
Beautiful.
So in that case, I screwed up the actually getting the ball.
There we go.
That's better.
But yeah, so pretty all-encompassing.
It works pretty well.
"Yeah, minor bugs," says JP Guy.
Yeah.
Hate those.
Those are the worst.
That minor bug was a source of, like, a five minute hurdle on one
of the last streams with naming one of the maps the wrong way.
That was beautiful.
But yeah, that pretty much is it, actually.
I mean, the game now will go to game over.
And once it's hit game over, it will stop altogether, right?
Let me verify that that's true.
It should-- yep, because it will do this.
Time scale is going to be equal to 0.
And then if it's not the case that that's true,
that's when it goes to start co-routine for countdown.
But that was I think pretty much everything I wanted to talk about.
I'll stick around for a few more questions,
but that's the gist of 3D pong.
We have a fully working, fully two player version of pong.
So one person's left and right.
Let's see if I can play against myself.
No.
And then when somebody loses, it just says player X wins.
So I think that's what we're--
where we will cut the stream.
It is at the three hour mark now.
If anybody has other ideas for games they
want to maybe implement in Unity or not in Unity,
we can certainly take a look at that.
And I'm always open to more ideas.
I think it's super fun.
I would love to do more Unity in the future,
but I also do want to dive into some more 2D stuff.
So on next-- which day is it?
I forget.
I think it's next Wednesday I'm doing tic-tac-toe in Lua and Love.
So if you want to join us again for a little bit more basic game programming,
it'll just be Love 2D tic-tac-toe.
Udon Master says, "Space Invaders on go dot."
So I'm not too familiar with go dot.
We can maybe do Space Invaders in Lua or Unity.
I'm not sure if I can maybe find somebody that knows go dot.
JP Guy says, "good job again."
Thanks for streaming.
Thanks so much for coming in and joining us again, JP.
You're here very consistently.
Reema7 says, "new Twitch category."
I don't think we're the first people to do this, but yeah, it's--
I think this is a great use case of twitch,
being able to do all this live and interact
and just sort of build things together like it ended today in the chat,
helping out with the physics issue.
That was awesome.
As much as that might have been frustrating to look at,
I think that that was a great example of how this can be a nice collaboration
tool, more than it even is educational.
Although, this is intended to be an educational stream,
but we could certainly do like a more live collaboration type thing,
a lot of ideas.
So we'll see where it goes.
I thought you referred to this as a 2.5D game?
Is this referring, for example, to the creation of the paddles in 3D
and the way the shadows are cast, and does the user always
see the same fixed point of view?
So Twitch hello world, 2.5 D just means that it's rendered in 3D engine,
but we're constrained to some 2D axis.
So in this case, all of the behavior that we do--
the ball and the paddles moving--
that's all in 2D.
But it's rendered in 3D.
So things are casting shadows.
We have 3D meshes interacting with each other and 3D collision.
That's all occurring.
It's just more the way that the mechanics are constrained.
[INAUDIBLE] says "thank you, Colton, for the stream."
Thank you for coming and being a part of it.
Much appreciated.
It's my pleasure.
[? Bavik ?] says "thank you, this was a good one."
Thanks, Bavik.
Appreciate it.
Thank you for tuning in.
And what software do you use to stream, OBS?
Yes.
Stream Labs OBS.
So there's OBS proper and then stream labs OBS.
Stream Labs lets us do the Twitch chat integration and other fancy stuff,
so that's pretty nice.
But yeah, Stream Labs OBS.
Yeah, thanks, Colton, says Astley.
Thank you, my pleasure.
Reema7, "thanks for the stream.
Keep it up."
My pleasure, thank you.
Andre, "it's also awesomely educational.
The amount of time [INAUDIBLE] and I tripped over those kinds of bugs
is probably more than I'd like to admit."
Yeah, I mean, I'm going to trip over many bugs going forward.
And today was, you know, we had a few-- a couple of small ones.
To be fair, I didn't test the speed going higher
than three, which I should have done.
That was my mistake.
But we fixed it.
We collaboratively sort of powered through it.
It was fun.
Sorry, I can't read the name on that one.
[INAUDIBLE] says, "browser crashed, so I missed the last few minutes.
Thank you, Colton."
That's not good.
Which browser are you using where it crashed?
I'm sorry to hear that.
W Wood, enjoying all these streams.
Thanks.
I'm getting sound issues in each one.
But it might be just me.
Can you elaborate on the sound issues?
I'd like to know what they are so we can fix it for sure if it's on our end.
JP Guy, "what was your Twitch username again, Colton?"
I don't personally have a-- well, I do have a Twitch username,
but I don't stream personally to it.
But the Twitch for today--
oh, you know this one, I guess.
It's obvious.
But if you wanted my personal one, it's this one.
I don't stream yet.
Maybe in the future game stuff, maybe.
I don't know.
This takes up enough time to where I don't
feel like I'd want to necessarily go home and scream again after this.
I mean, maybe.
Playing games on steam is easy.
It doesn't require a whole lot of mental effort.
I guess it requires you to stay on, but that's a different issue.
PM seems easier than sending an email.
Oh, yeah, I guess.
I don't ever go on twitch for messages, though.
Like, I'm not signed on, so you have a better chance of emailing me.
So cogden@cs50.harvard.edu.
Email would be safer, I think.
"Chrome had too many tabs open, I think," says [INAUDIBLE]..
Yeah, Chrome is a memory hog.
But I mean, even I have, like, 20 open sometimes and I don't crash.
So I'm curious how many tabs you have open if yours is crashing.
Probably can't even see what they are.
Cuts out briefly periodically and kind of
sounds as if trying to switch between lab mic and camera mic.
That could be the bit rate of the broadcast, W Wood.
So if your stream quality is--
if it's dynamically changing the stream quality,
then that's typically what it sounds like.
You get sort of like--
it sounds like you're switching between a camera and a lab,
but what you're actually doing is you're just getting a decreased bit rate
and it just has the effect of sounding lamer.
Email was coltonoscopy, right?
Yeah, coltonoscopy@gmail.com, cogden@cs50.harvard.edu
is my work email.
I check my work email more often than I check my personal email during the day,
probably.
"Might just be me," says W Wood.
Yeah, if anybody else is getting that same issue, definitely let me know.
We can take a look at it.
CS50 mail, yeah, that would be preferred.
Twitch Hello World, "if you were to create scenery for this
and you have the art for it in 2D art files,
would you suggest building assets similar to how
you did the paddles, then bringing the art in simply to use as textures
on these or bringing the art files in as they are
and just adding effects here and there to make
it look consistent with the shadows cast by the ball and the paddles?"
Ultimately, that's artistic discretion, I think, because you're describing 2D.
So if you were to make 2D art textures for this, like grass for the ground,
for example, there is a million different ways you make that look.
If you're talking about models, 3D models included in the game,
those will cast light naturally because they're using the same lighting
calculations as the paddles.
So that's what you might want to do if you're
thinking of actual physical scenery that you want realistic lighting on.
I would probably think about doing that.
But for 2D, you use what are called sprites, generally.
And it's going to be a little bit different in that case.
My Chrome froze initially quite a few times.
The desktop app on Windows just crashes.
Is there a chance that in the future we could
see something like phasor framework with socket io for web games,
says Udon Master.
Potentially.
I used phasor a little bit.
They just recently changed to phasor 3 and they've done a lot of stuff.
And the documentation was, last I checked,
a little bit messy and kind of incomplete.
So I'll take a look at it and determine if that's
something we could take a look at and then maybe do some game development on.
Good suggestion.
Thank you for it.
Throat is getting a little bit sore, not terribly.
These are hard to do.
I feel like doing enough of these, eventually my voice will just give out.
But we're in there.
I'll stick around for just a couple more questions if anybody has them.
Again, if you're watching this on YouTube after the fact and you
aren't following our Twitch channel, it's twitch.tv/cs50tv.
We stream often.
I would say 4 times a week, usually, at least as of now.
And the plan is to continue doing so.
I usually do one or two streams a week, three hours on game development.
And we have guests talk about things like React.
We have GitHub.
We have CICD.
On Monday we have--
let me just make sure that my schedule is correct on this.
I'm not 100% at the moment.
I believe on Monday it's Kareem, Kareem the dream.
How do I get out of this?
Let's go back to this.
Go to Facebook.
Let me just make sure that my schedule is correctly,
because I don't have my calendar up on this computer.
So I go to events.
If you're not following our CS50 Facebook,
definitely follow our CS50 Facebook.
We have all of our events listed there.
So on Monday, we have Kareem is his name, Kareem the dream.
He's going to be talking about CI/CD, so deploying apps,
testing apps, including that in your GitHub workflow, if you're interested.
So super useful stream if you're interested in dev ops at all
and want a sense of how to deploy apps.
Probably do a demonstration of deploying something to GitHub pages or Heroku.
Not 100% sure what he has in store.
On Tuesday, CS50s Dan Coffey is going to talk about Draw 50.
So Draw 50 is the app that David uses in Sanders.
So let's go to our--
let's go to CS50 2018 lecture zero.
Plug a little CS50 here.
And then let's go to where David's drawing on the screen.
Is he drawing anywhere visually?
So he has this-- he has this big screen in lecture where--
what's a representative lecture?
Maybe lecture one?
I don't remember which lecture he actually drew on it.
I would love to get a little screenshot.
Well, anyway, he uses it as a giant digital blackboard
because we're using an app that Dan Coffey wrote in JavaScript
that allows using Paper JS and Hammer JS, allows him to write and erase
just like it was a giant blackboard.
So it's pretty cool.
And so Dan's going to talk about how that works on Tuesday.
On Wednesday, it's going to be yours truly again.
We'll do tic-tac-toe.
We'll do it in probably Unity--
or not Unity, in Love 2D and Love again.
A little bit more of a low--
not low-level, but a basic entry-level game style.
And on Friday, Linux command tutorial with Nick Wong
who did a video this week on--
I'm blanking.
What did we talk about?
Machine learning.
We built a binary classifier in tensor flow.
So all kinds of topics.
I do games generally, but I co-host with everybody
else who does all kinds of other stuff.
Sounds like I could do three models and simply lay the face from the 2D
art over it as a texture to start.
Thanks.
Yeah.
You would have to do something like that.
But it doesn't map cleanly.
You have to do what's called UV unwrapping
and you have to do that generally in a 3D software package like Blender
where you actually unwrap all of the faces of your mesh onto a 2D plane
and then put your texture onto that and sort of map them together.
But yeah, you could do a texture onto a simple surface and--
onto a simple surface that doesn't have a lot of faces,
and just do like a flat--
sort of a box or a plane unwrapping.
But that's not-- that's generally not what you do for models.
With models you do want to use UV unwrapping.
Bavik says, "probably with strings."
I think what we're going to do is we're going to use--
we're going to use graphics, so we'll use it like a pixelated x and a circle
for tic-tac-toe, and probably stay away from strings,
I think, just to keep it a little bit more interesting.
But you could do it--
absolutely could do it in strings at the command line, for example.
One of the first things I got taught in a C++ class many years ago was we did
a C++ command line script of tic-tac-toe.
So you absolutely could do it with strings.
But we'll be using images.
Yeah.
"Complex models have to be mapped," says Reema.
Yes, correct.
Ray declares there is no string in C in that lecture.
Char arrays are drawn as contiguous memory blocks.
Oh, that's what you're referring to.
Yes.
You're right.
Yeah.
I don't remember exactly what timecode it is, what lecture it is.
I M GSH, I'm not sure to pronounce that.
Imgsh says, "Unity related with Java?"
No, not at all.
But C# is very similar to Java.
And that is where the relationship sort of comes into play, I guess.
Or at least people think there is a relationship.
But yeah, Unity is completely scripted in C# in Java and C# are very,
very similar, at least on the surface.
They looked very similar.
Twitch Hello World says thanks.
No problem.
If anybody has any last questions, I think I'll answer them,
and then in a couple of minutes here we'll sign off for the day
and then call it a week.
And then next week, we'll start strong with some CI/CD with Kareem Zidane.
Be sure to tune in for that and for all lectures next week.
And keep providing us with ideas because the more ideas we have,
the more awesome stuff we can make.
I can come up with ideas, but sometimes it's nice to have a little bit of fuel
to work off of, you know.
"Thanks, this was so interesting," says Twitch Hello World.
Absolutely, yeah.
No, I love Unity.
I would love to dive a little bit deeper into it.
We did a very basic thing today, but there
is so much with [? cinna ?] machine and something
that I really like is called pro builder and using character controllers
and actually making worlds and making interesting gameplay mechanics,
making--
you can make a shooter, probably a kid-friendly shooter for a stream.
But yeah, we can do a lot of cool stuff.
Andre, thanks Colton.
This was really cool.
Thanks, Andre.
Thanks for tuning in.
Thanks for your assistance today while we coded.
I know there were a couple of small little hiccups we ran into.
And [INAUDIBLE],, thank you again very much for your assistance today.
Awesome.
As usual, have a great weekend, everybody.
Yes.
Yes, definitely have a great weekend everybody.
[INAUDIBLE] 12, "thanks for taking the time to do this."
My pleasure.
No, it's a lot of fun.
We could potentially do longer streams in the future.
I was thinking of doing, like, maybe an 8 hour stream.
I know that sounds kind of ridiculous, but a lot of Twitch streamers
do, like, 8 hour streams.
That would be pretty cool.
We could do a Python stream from scratch,
like somebody who has never programmed before,
like, walk them through Python from ground zero to like nothing.
That would be cool.
Like a long-- and they could chop it up into separate YouTube videos,
maybe, something like that.
Agree, good to see what you guys are doing with my models.
GG well played.
Have a nice weekend.
GG well played, Reema said.
Browser's acting up.
Freezing.
Have a good day.
See you guys next time.
See you, Bavik.
Sorry that your browser is acting up.
Damn, eight hours.
"That's hardcore," says JP Guy.
Yeah.
There's a lot to cover on just getting somebody started with Python or C.
You know, we don't go into a lot of depth--
we do go into fair depth in the lectures,
but we only have an hour and a half to cram a tremendous amount of material.
And imagine what we could do in eight hours, right?
Robotics, Matlab would be a good idea.
Yeah.
I'm nowhere near qualified to talk about any of that,
but I could maybe look around and see if somebody is into robotics.
It would be a little trickier with robotics,
just because then we have to have a camera that's filming a robot,
you know?
That could get more tricky.
Especially when you need, like, zoom shots and stuff like that.
Currently our camera is mounted onto a TV that I'm looking at as a monitor.
So it would be difficult, but not impossible.
Matlab, for sure.
But I have never used Matlab, so I would be the last person
to give a seminar on Matlab.
"Have a great weekend, everybody," says Astley.
Says [INAUDIBLE],, "I'd love to go into depth in machine learning.
Machine learning is super interesting."
Me, too.
I would love to go more in-depth into machine learning
from a more basic approach because, I mean,
even I was getting lost with the Nick's seminar.
And I mean, that's just natural, I think,
because machine learning is such a vast topic.
But machine learning from bare basics to something functional
would be super cool.
But yeah, again, I'm not qualified to do that.
I'm barely qualified to give game lectures.
I'm just kidding.
This was fun.
Whenever we hit those little tiny roadblocks on the code,
it's a nice opportunity to operate under pressure.
Just grab [INAUDIBLE] if you want to check out the basics of Matlab.
The syntax is identical.
OK.
Might check it out.
I've never had occasion to try it, but, yeah, basic.
I understood, like, 5% of what Nick said.
No, I mean, machine learning is serious, right?
And it's hard core.
But if you know machine learning, like, you're set, right?
I wouldn't mind learning knowing more about it, and AI.
AI, too, would be super cool to be super familiar with, right?
Right, well, it's 4:19.
I'm going to wrap up the stream here, I think.
So thanks everybody who tuned in today to our basic introduction
to Unity and 3D implementing pong going from 2D to 3D.
It was a tremendous amount of fun.
And I love Unity a lot.
I'd love to dive deeply into it.
I might have said this before on stream, but some
of the things that I've always wanted to do
is make an N64 era platformer, like Banjo-Kazooie or something like that.
So doing something like that in Unity would
be super cool to do on stream over, like, a multipart series.
JP Guy says, "machine learning and big data are probably
the most relevant fields right now."
Yeah, definitely.
That's what I hear.
It's a shame that games doesn't quite have that level of prestige,
but you know, we get by.
Games are fun, right?
I'd be interested in a streaming overview of algorithms and data
structures, architecture, and analytics respectively.
I hope to take those courses, though a bird's eye overview is interesting.
Yeah, me too.
I mean, I have a lot of that.
I wouldn't mind reviewing myself.
So getting people in here to actually walk us through algorithms and stuff,
that would be pretty cool.
We'd probably want to do it in code, just to kind of see it work.
And if we can see it visually, too, that would be interesting, as well.
Yeah, this is CS50 on Twitch.
If you're not following us on Twitch, twitch.tv/cs50tv if you're watching
on YouTube after the fact.
Colton, you must have made some games by yourself.
Can we see them or play them?
They're on the games course, the cs50.edx.org/games.
I've probably started a million side projects that I've never finished.
But the CS50.edx.org/games, which I'll plug again--
CS50.edx.org/games-- they're more or less complete in that they are very
similar to, like, the classic games.
They're pretty robust, games like Mario and Zelda and Pokemon and Angry Birds.
Those give you a representation of some cool stuff.
I love how unsupervised AI and intelligent agents follow up
to the Machine Learning Stream.
Nick would be the guy to ask.
So I'll reach out to him.
Again, he's doing a stream next week on Friday on Linux commands.
So if you're eager to jump into the CLI and get
a little bit more comfortable with piping and ls and cd and rm--
rm dash rf slash--
don't don't actually write that into the command prompt.
But if you want a tutorial on all that stuff,
he's going to give us one on Friday, next Friday.
All right, everybody.
Thank you so much, again, for tuning in.
This was CS50 on twitch.
This was Unity 3D.
I will see you all next time on Monday with Kareem the Dream, some CI/CD.
Have a good night.