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.
