COLTON OGDEN: All right.
We just took a look at setting up our environment
so that we could run lua and love.
Now we're going to actually dive into the code base for the Pong Track
with pong0 the day0 update.
And you'll get access to source code that
has all of these individual sections listed out
with this exact same numbering scheme so you can follow along
with the final product of each lesson.
So the day0 updates goal is to get a screen
up looking something very similar to this.
And actually you'll notice that it's almost identical to what
we did before, the only difference really being that the window size is
now 16:9 aspect ratio as opposed to a square, which is Love's default.
And also the text is centered in the middle of the screen
instead of at the very top left, because we're actually
going to be using a different function, as we'll find out here pretty soon.
Now, before we get into all this stuff, we should take a step back and really
start looking at what makes a game.
As you're learning how to program, and you're taking a computer science
class, an intro class, you're probably under sort of the understanding
that an infinite loop is usually a bad thing.
And it usually is in most contexts.
It's often the result of a bug, an erroneous while loop or the like,
that doesn't have an end condition.
Or a spinning beach ball, if you might be
using a graphical application on Mac or Windows
or the like that might have a bug in it.
With games, infinite loops really are what
a game is at sort of the most distilled sort of basic form.
You have, as you see here, this illustration shows input,
updating, and rendering.
So as you know, a game really is just something
that goes on over and over again.
You're a character in a world or maybe you're solving puzzles or the like,
but they always seem to go on forever.
And they change depending on how you interact with them.
This is really the key difference between an infinite loop
that's a bug versus an infinite loop that's been used properly.
Now, the main key steps here really are processing input.
So we need to take in keyboard input or mouse input or the like
so that we can move things on the screen,
we can select options and menus, et cetera.
We need to update the game afterwards, which is usually
a byproduct of processing input, and also calculating things like AI
and velocity of things that we've set previously.
This might happen multiple times, as is shown by the clock icon there,
depending on how much time has passed since the last frame.
And lastly, once things have updated, we want to render them to the screen.
We want to actually show how something's xy position might have changed
and maybe its color, maybe a bunch of things.
And then as you see, at the very bottom of that is another arrow that
leads back to processing the input.
And this happens over and over again, oftentimes 60 times a second
on most modern machines and consoles.
So some important functions we should look at before we dive into the code
are some of the most foundational functions using love.
They are love.load, love.update, and love.draw.
And now, love.load is really just a bootstrap function.
It just has whatever you want to put into it to start your game,
whether you want to maybe create some variables, initialize the window,
as we'll see here pretty soon.
Love.update is the update portion of our game loop.
It actually lets you change things depending
on this variable, this argument, called dt, which is short for delta time.
We'll take a closer look at delta time in a couple
of sort of iterations down the track.
Love.draw is where you should just place anything
that draws something to the screen.
And behind the scenes, love will actually call love.draw
after it calls love.update.
Now, a couple of functions that are a little bit less foundational
but are important to this iteration are love.graphics.printf,
which is similar to print but is, like C's printf, customizable in as much
as you can choose a few different ways to style your text--
centering it right, aligning it, and so on.
And love.window.setMode is how we can get
past just having a square window to having something a little bit more
along the lines of modern screens, a 16:9 aspect ratio.
So that's it for the explanation.
I'm going to transition out of the slide deck,
and we're going to actually implement pong0.
So what I'm going to do is back in my Home directory,
I'm going to create a new directory inside of Pong.
I'm going to call this pong0.
And then I'm going to just drag this over
to vscode right here so that it opens up as a folder in vscode.
And this is important for me because of that plug-in
we talked about in the last lecture.
I'm going to create a new file.
I'm going to call this main.lua.
Now, remember, love expects a main.lua file.
This is very important.
This is where it sort of bootstraps the whole entire game application.
You can have other source code files, other lua files, other resources.
But main.lua is sort of the main in C, where the interpreter, the compiler,
just knows to go there to start your application.
Now, we saw love.load before, and I'm just
going to define a function using the function keyword.
I'm going to call it love.load with curly braces, much as you've seen in C,
and then the thing about lua that's different from C
is that you do need this end keyword here
to tell lua that this is the end of the function definition.
Now, I'm going to do the same thing with love.draw,
which we saw in the last example.
In love.load, we're going to take a look back
at title love.window.setMode, which is where we can actually
decide how big do we want our window, our games screen,
to be when we launch the application?
Now, we haven't specified any variables or any numbers
for how big we want it to be.
But I'm going to define a couple of constants here.
WINDOW_WIDTH equals 1,280 and WINDOW_HEIGHT is equal to 720.
Now, these aren't technically constants in the sense
that the interpreter will prevent me from assigning to them later,
like we can do in C with const, but the fact
that they are all capitalized with underscores
tells the programmer that they are constants.
They should be treated as constants.
So in an honor system sort of way, we're going
to be treating these as constants.
They should not be adjusted.
So what I'm going to do here is I'm just going to pass those into,
and I'm going to just for size expand this out to full screen.
I'm going to pass those two variables into the love.window.setMode function.
And I'm going to make sure I spell height correctly.
And then lastly-- and we alluded to this in the last lecture--
I'm going to pass in what's called a table to this function.
Now, a table is very similar to a Python dictionary,
where it takes in key value pairs.
In lua, the table is really the only data structure.
So whether you want to use it as an array
or as a table or any other interesting combination thereof,
you only have tables to choose from.
In this case, we're just going to use it just like a regular key value pair
dictionary or hash table.
I'm going to specify that full screen should be equal to false,
vsync should be equal to true.
And resizable is going to be equal to false.
And it's pretty self-explanatory.
We don't want this to be full screen.
I just want to show the window.
Vsync just means sync it to my monitor's refresh rate
so I don't see any screen tearing.
And resizable just means I can't scale the window after the fact
and distort the aspect ratio.
Now, let's go ahead and save this and run this just
to make sure it's working.
And indeed, we can see that instead of a square--
it's a little harder to see maybe in front of the terminal
here so I'm just going to hide that.
But this is the window that we have now, just a black window.
Nothing's being drawn to the screen, but it is indeed a 16:9 aspect ratio.
I'm going to quit that.
I'm going to go back to my text editor.
And I'm going to go into love.draw where love
knows that this is where you should place any of the drawing functionality.
So what I'm going to do is I'm going to say love.graphics.printf Hello
Pong, the string like that.
And printf takes in sort of arguments a little bit
differently than you might expect.
So it does take an x and a y.
Interestingly, I'm going to specify that x should be 0,
y is going to be the window height divided by 2--
so it's actually going to be right in the middle vertically of the screen--
minus 6 because the font size is actually 12 pixels.
So by going in the middle of the screen but in decreasing the--
sort of offsetting that by negative 6, we
end up actually getting the font right in the middle of the screen.
All things in love are drawn relative to their top left.
So it's going to be drawn sort of shifted up 6 pixels.
And because it's 12 pixels, that puts it firmly in the center.
Now, the next argument is going to be sort of the width upon which
we want to align this string.
We want it to be centered.
So the last argument's going to be the string literally centered.
But we need to tell it how much do we want to center it within.
We want to start it sort of at the left side,
and I want to center it within, well, the WINDOW_WIDTH,
because that's how big the window is.
And we want it to be exactly right in the middle of the window.
So I'm going to say a WINDOW_WIDTH there for these sort
of column size of our centering.
And then lastly, I'm going to specify the string center just like that.
And then I'm going to run the application.
And we do it in [INAUDIBLE] Hello Pong written
right in the middle of the screen, almost illegible because it's so tiny.
It's 12 pixels.
But it works just as we expected it to.
And it's very simple.
And now it actually is a little bit more modern in the sense that it'll fit.
We could full screen this, and it would fit most modern desktop screens.
So that was a very simple sort of day0 update, pong0.
Pong1, we're actually going to take care of the fact
that our text is really tiny right now.
We're going to zoom in.
We're actually going to sort of stretch our raster, our smaller texture raster,
to fit a 1280x720p window to give us a bit more of a retro sort of NES Super
Nintendo era look.
And we'll take care of that with the low-res update in pong1.