Placeholder Image

字幕列表 影片播放

  • COLTON OGDEN: All right, hello world.

  • This is-- oop, you're a little cut off there.

  • This CS50 on Twitch.

  • My name is Colton Ogden.

  • I'm joined briefly by--

  • DAVID MALAN: David Malan.

  • Nice to see everyone again.

  • COLTON OGDEN: Today we're doing--

  • well, first of all I should say happy Thanksgiving, happy late Thanksgiving.

  • Hope you enjoyed your holiday if you were celebrating Thanksgiving here

  • in the US or abroad.

  • We had a bit of a weekend here but we're back.

  • We're streaming today.

  • I just came back.

  • I'm a little tired.

  • I don't know about you.

  • Did you enjoy your Thanksgiving?

  • DAVID MALAN: I'm very rested, ready to start the day.

  • COLTON OGDEN: Ready to start the-- you have the hackathon this week.

  • DAVID MALAN: Indeed.

  • COLTON OGDEN: CS50 Hackathon.

  • DAVID MALAN: CS50's all night hackathon, 7:00 PM

  • to 7:00 AM later this week on campus.

  • COLTON OGDEN: Yeah.

  • So that'll be a good time, an all nighter with IHOP

  • and a bunch of other stuff.

  • Today on Twitch what we're going to do is

  • a from scratch implementation of Space Invaders.

  • Did you play Space Invaders when you were--

  • DAVID MALAN: I did.

  • When I a kid this was the state of the art.

  • Space Invaders probably came out a few years before I really got into games,

  • but this was high tech.

  • COLTON OGDEN: Yeah, this was-- oh, and thanks Jumpjump123 and Lifedevourer22

  • and DZsniper.

  • I saw that you guys followed before the stream began, so thank you very much.

  • But yeah, so we're going to do a from scratch using Love and Lua,

  • just kind of like how we did Snake and how we did Memory Game,

  • and what was the-- we did one last one that I can't remember.

  • Having a brain fart.

  • But yeah, so I'm going to jump to my laptop.

  • DAVID MALAN: I'm going to jump out, but I'm

  • going to hop into chat later and stay in touch.

  • COLTON OGDEN: Cool, cool.

  • Thanks a lot.

  • DAVID MALAN: Good too see everyone.

  • COLTON OGDEN: All right.

  • Oh, and this is funny.

  • You'll like this, by the way, before you leave.

  • I made the mistake, and everyone else from Twitch can enjoy this.

  • I'm wearing a green shirt.

  • So I am wearing an invisible shirt today.

  • DAVID MALAN: Oh, this is great.

  • So we could actually see things through you.

  • COLTON OGDEN: Yeah, exactly.

  • A little bit less screen coverage of me, more of the screen.

  • DAVID MALAN: Such a professional.

  • OK, on that note.

  • COLTON OGDEN: But yeah, that was a funny thing

  • I realized when I was coming in here to set the green screen up.

  • Let me just say hello to everybody before we actually begin.

  • I know we had quite a few people in the chat prior to everything starting up.

  • So, [INAUDIBLE],, Bavich_knight, Forcelnight, Fatma, Brenda,

  • Realcuriousqe, thank everybody who--

  • all the regulars I see are here.

  • Nishthegamer, hello!

  • Bavich_knight, hello!

  • Rajeshcanonrk, I think I have seen that name before.

  • Correct me if I'm wrong.

  • Good to see you.

  • Cloudxyzc definitely has been here before, hello.

  • Nuwanda3333 is [INAUDIBLE] and Goal1.

  • So thanks everybody who is already here.

  • So yeah, Space Invaders!

  • This is going to be fun.

  • So, Space Invaders we actually taught in the games course that I teach, GD50.

  • It was a project that we implemented.

  • We ended up scrapping the project idea from the course

  • for the second iteration of it just because it was a bit too much work.

  • But it's a great game because it's similar in some ways

  • to Breakout which we teach just prior to that,

  • because it's kind of this vertical oriented game

  • where you play as a spaceship that shoots up

  • towards the top of the screen.

  • And Breakout is a game where you're a paddle that moves left to right

  • and you bounce a ball back up to the top of the screen.

  • So I sort of feel like the two games were sort of related in a sense.

  • I think certainly the folks that implemented Space Invaders probably

  • played Breakout and were inspired.

  • And Breakout I do believe was implemented by Steve Wozniak

  • although I'm not 100% sure on that.

  • So let's do a quick old Wikipedia and just verify whether that's true.

  • Breakout the game which is here--

  • so it's by Atari.

  • I know that he implemented the Apple II version.

  • I'm not 100% sure if he--

  • oh yes, Steve.

  • So he did design breakout for Atari.

  • And then he implemented it for the Apple II.

  • And from what it says here, it was a big influence on the actual architecture

  • of the Apple II.

  • So gaming has a huge influence in the history of personal computers as well.

  • Inolove19 watching from the Philippines, thank you very much for tuning in.

  • I would like to read your comments [INAUDIBLE]..

  • I'll try to comment as much as I can.

  • What did I miss?

  • I opened and David was already leaving, says Aslee.

  • Yeah, you missed-- unfortunately he made a brief appearance and you missed it.

  • But surely we'll get him on stream again, maybe next week even.

  • Jebcochasin says, what are--

  • I apologize if I'm mispronouncing that name.

  • It could be Yobcochasin or Yobcochosin.

  • What are we going to do today?

  • We're going to implement Space Invaders from scratch.

  • So if you're unfamiliar, in prior streams

  • we've used a framework called Love2d and a language called Lua.

  • So you can download the framework Love by going to Love2d.org.

  • So I'm just going to go straight to that main page.

  • And for whatever operating system you're using you can download it,

  • if you're Windows, Mac, Linux, or otherwise.

  • And you can download prior versions, newer or older versions.

  • It's a super nice, super easy to use framework

  • that gives you a lot of abilities to do drawing and input and sound

  • and all kinds of other stuff.

  • So we'll be using that.

  • I'm sort of going to be assuming that you've maybe watched the prior streams.

  • But we'll still take it fairly slow so that folks

  • that are tuning in for the first time can follow along

  • without too much difficulty.

  • But definitely if you haven't downloaded the framework yet, download it here.

  • It's going to download an executable that you will then

  • use to run game code.

  • And if you go to the wiki page which is at the top right,

  • you go to this getting started page.

  • This getting started page will tell you, depending

  • on what operating system you're running, how to actually run your game.

  • So if you're on a Windows machine for example,

  • usually the easy way would be clicking and dragging your game folder

  • onto the executable or the shortcut.

  • But there are other ways to do it.

  • If you're on a Linux or a Mac machine, you

  • can alias the location of the actual executable file and then call that.

  • I have it set up so that in my terminal, for example--

  • I'm going to clear this--

  • I can just type love dot like that.

  • And that will actually call the love executable

  • and run it with dot, which is the current directory that I'm in.

  • So if I'm in a directory that has a main dot Lua, this will work.

  • It won't work right now because I'm not in a folder that actually has that.

  • So by default, if you just type love or type the path

  • to where it is on your machine and you have it actually there,

  • you should get a box that looks something like this with a balloon--

  • if you're running 11.1, with a balloon and a scrolling background.

  • So that's Love.

  • That's sort of the basics of how to actually find

  • it and get started with it.

  • Thanks for this game.

  • It's one of my favorite games, says Goal1.

  • Yeah, it's an awesome game.

  • I love the Breakout pset of old, says Bavich_knight.

  • Yeah, it was a great pset.

  • And I remember, I contributed a little bit to that pset as well.

  • That was right when I started working for CS50 roughly.

  • We had a laser part of that pset if you remember that,

  • and that was the part that I contributed.

  • Hi everyone's, says Lintzpotaguara.

  • Hey, Lintz, thanks for joining us.

  • Taking CS50, this is my first time watching your stream,

  • says Jacobchaussen.

  • Yes, thank you very much for joining.

  • So typically what we do is, we have a bunch of people come in,

  • people that work with CS50, myself included.

  • And we usually implement something from scratch from the ground up

  • or we'll take a look at something and we'll

  • cover a broad overview of that subject.

  • For example, Nick Wong has come on to talk about Linux commands

  • and machine learning.

  • And we've had Veronica talk about Python.

  • David's come on to talk about regular expressions and going from C to Python.

  • So we cover a bunch of stuff.

  • I focus on game development so if you like games, yeah, game programming,

  • tune in to my streams.

  • And I also co-host with everybody else that

  • comes in to sort of give a little bit of a conversational feel to the stream.

  • And I notice the camera shot is a little bit lower, too,

  • today so you can actually see the top of my laptop.

  • You can see I have an Inn and Out sticker representing

  • my home state of California.

  • Virtual office hours, says Fatima.

  • Yes, very much so.

  • Hanscost, hi everyone from Italy.

  • Thank you so much for joining us all the way from Italy-- super awesome.

  • Every time somebody in the chat says that they're from some place

  • abroad, someplace that's not in the United States,

  • it's just such a cool feeling to know that everybody around the world

  • is tuning in-- especially considering how late it probably

  • is over there right now.

  • Although maybe in Italy it's not so bad.

  • I think in the Philippines, or was it somewhere else,

  • it was like 2:00 AM or 3:00 AM typically for a lot of these streams.

  • Curase is from Italy as well.

  • Jakobchaussen just signed up, yeah.

  • Thank you so much.

  • First stream ever on Twitch, wow.

  • We got some new people in today.

  • This is exciting.

  • All right, so Brea--

  • not Breakout.

  • Breakout is the game that we were comparing Space Invaders to.

  • We want to actually take a look at Space Invaders.

  • Thank you very much, Fearblaise, for following.

  • So, Space Invaders was I think one of the first big arcade

  • games that came out.

  • And this was around the era where arcade games were kind of like the games

  • to go play.

  • There weren't really very many home consoles.

  • Although in 1978 you did have the Atari 2600 which was a very big home console.

  • But just prior to this for several years there

  • were very much not any console games.

  • It was all arcade games.

  • So if you wanted to play Pong for example, or other games--

  • typically Atari was the big contender in this era,

  • although other companies came out.

  • Whoever made PacMan, I forget offhand, that was a huge one.

  • PacMan was Namco.

  • And that was in--

  • oh, that was in 1980 actually.

  • I apologize.

  • So that was actually afterwards.

  • But this era, the early '70s until the '80s

  • and going into the '90s even a bit, was dominated by arcade machines.

  • But as the '90s came about, arcades went the wayside and now arcades are very

  • rare and almost like novelty--

  • not novelty.

  • They're the opposite of novelty--

  • antiquated.

  • And therefore they have this particular unique value to them.

  • But this era was very arcade dominated.

  • So Space Invaders, if we can get a screenshot.

  • It looks something like this.

  • It's a little bit hard to see.

  • But essentially, as I sort of described earlier,

  • you have this ship at the bottom which is this guy right here.

  • And these things right here are defenses,

  • barriers you can hide behind, bunkers or barricades.

  • And your goal I guess is, you're defending Earth from an alien invasion.

  • And that's what all these aliens up here are.

  • So there's five rows of, it looks about--

  • what is that?

  • Like 10, 11, 12--

  • 1, 2, 3, 4, 5, 6, 7, 8, 9, 10--

  • 11 aliens per row.

  • So 55 aliens, give or take.

  • And they sort of go around the screen left to right in this formation.

  • And they gradually progressed towards the player.

  • And your goal is to shoot them.

  • And if you take any damage from them, as by colliding with them

  • or by getting hit by one of their laser beams, you obviously lose a life.

  • And you get some points every time you destroy an alien.

  • And so they just come in waves.

  • You clear the waves.

  • It's this loop of defending Earth in this abstract form

  • from an alien invasion.

  • Hello from Morocco, says Elias.

  • c4reni-- Estonia!

  • That's the first time I've seen Estonia, I think, in the chat.

  • So c4reni, thank you very much.

  • Georgia, not the state.

  • Hey, guess what?

  • I customized the prompt after that stream with Nick.

  • I welcome all the new people tuning in says Bavich_knight.

  • Oh, awesome.

  • Yeah, yeah, that stream was super cool.

  • Definitely watch that if you haven't already.

  • And tomorrow Nick is coming in to talk about setting up a web server with AWS.

  • So if you enjoyed that stream with me and Nick,

  • definitely tune in tomorrow for that.

  • That's going to be super cool.

  • Fearblaise, hello from Estonia.

  • Hello, Colton, is there a vacant job in the CS50 team, says Gaston?

  • Unfortunately there is not per what we've talked

  • about before in the stream, Gaston.

  • So currently there is not.

  • If there is one, there will probably be a notification

  • on the CS50.harvard.edu website.

  • Jacobchaussen, thank you so much for following, tuning in and following

  • today.

  • Game history lesson, yes, a little bit, although my dates sometimes

  • are a little bit skewed because I don't study it too reliably.

  • But certainly that rough--

  • I get a rough sense of it, you know, a rough history.

  • Bavich_knight, Unix prompt customization,

  • I was patiently waiting for that in Linux basic stream.

  • I do remember that.

  • I do remember that, sorry.

  • That stream was heavily dominated by awesome tangents.

  • But yeah, there were a lot of cool paths we went on.

  • But sometimes it took us a while to get to some of the things

  • that we wanted to talk about.

  • Redhat236, this is really cool for me.

  • Thanks, Redhat, I appreciate it.

  • And Isotv, finally CS50 time again.

  • Yes, the holiday break was long.

  • The winter break is going to be kind of long as well.

  • But we have a couple weeks of streams set up

  • for all of you, so definitely tune in for that.

  • So, Space Invaders.

  • So, we know what Space Invaders is.

  • So now our goal is to figure out how we want to implement it.

  • I'm way too zoomed in right now.

  • So, the way that we did this in the games course-- and this

  • is completely from scratch.

  • I'm not using any source code to reference or anything.

  • We're just going to completely implement this from scratch.

  • So if you have ideas as we're implementing this,

  • definitely chime in with them.

  • We can collaboratively do this.

  • But I'm not using any sort of backup code.

  • We're doing it completely from scratch.

  • But I have a sense of the things that we'll

  • need to do, the pieces that we'll need to integrate in order to make it work.

  • The first thing that we need to take into consideration

  • is the fact that this game is designed to be a vertical game.

  • So the games that we have looked at so far are horizontal.

  • And we've been implementing them with a 16 by 9 aspect ratio more or less.

  • So today what we're going to do is we're going to actually implement

  • our first vertically oriented game.

  • And games now are not typically vertically oriented

  • because that would be--

  • it's not conducive to modern screens.

  • The typical modern screen is a 16 by 9 raster,

  • meaning that the width to the height ratio of the pixels is approximately 16

  • by 9, 16 to nine.

  • So your typical 1920 by 1080 or 1280 by 720p,

  • or many 4k resolutions or the like, are typically 16 by 9.

  • And you can get ultra wide monitors, which I believe is 21 by 9.

  • And those are the really long width monitors,

  • the opposite of what we're going to be implementing today.

  • But the game that we want to do today, since the nature of the game

  • is vertical, just like Breakout is for example,

  • we're probably going to want to do a resolution that's

  • more catered to this sort of gameplay.

  • And let's see if they actually have the resolution, which they do.

  • So we can see here on Wikipedia if we go over here,

  • the specs are that the display was a Fujitsu MB14241, which

  • was the video display controller that they actually

  • had in the arcade machine, the physical hardware.

  • And it output at a 224 by 256 raster.

  • And what this means is, it's going width by height.

  • So normally nowadays resolutions are wider than they are taller.

  • But this was actually taller than it was wider,

  • which is why the second number there is larger--

  • 224 by 256.

  • And so that's what we're going to do.

  • We're going to actually use the resolution native

  • to this game, the base resolution, and we're

  • going to implement that for our game now.

  • But we're going to put it in a window that's much larger than that

  • so that it does--

  • because if it were on our screen, 224 by 256 pixels, it would be pretty tiny.

  • It'd be hard to see what's going on.

  • So we're going to do what we did in the last stream

  • for tic-tac-toe, where we actually create

  • a virtual raster using that library that I showed before, the push library.

  • We're going to say that that raster is to 224 by 256 pixels.

  • And then we're going to put it into a window that's

  • about four times larger than that-- actually probably

  • three times larger than that so it fits on the screen.

  • And what it's going to do is, the window is

  • going to be something like approximately 700 by 800 pixels.

  • And then it's going to stretch that to 224 by 256 raster.

  • And basically it's going to have the effect

  • of growing all the sprites and everything in the game

  • by three times its size.

  • And that's how we can achieve the sort of retro look

  • while also getting it to fit on the screen

  • and be playable and not super tiny.

  • OK, let's see.

  • Apparently Tetris was made in 1984, so after Space Invaders and PacMan,

  • says Estley.

  • Yes, yes, roughly around the beginning of the NES era.

  • And I believe it was super popular for the Gameboy

  • because they actually bundled Tetris and the Gameboy together.

  • And so that's why Tetris is one of the best selling games of all time,

  • is because they take into consideration that bundling and the Gameboy

  • was just ridiculously high selling console, handheld console.

  • And so that's sort of the history of Tetris and why it also blew up.

  • It was a perfect game, also, for mobile, just given the fact of how addicting it

  • was and how simple was and how on the go it was, right?

  • Only game I played was Tetris.

  • I could not handle being eaten and getting chased, so that's Forsunlight.

  • Assuming that's a reference to PacMan.

  • Yes, and PacMan is a game I would like to very much implement on stream

  • as well another day in the future.

  • So we'll take a look at that.

  • I'm going to set up a project.

  • So I'm going to go into my Streams folder.

  • I'm going to create; a new folder.

  • So whatever operating system you're on, this process will look very similar.

  • I'm going to call this Space-invaders.

  • I'm going to open that up in VS Code, as by just on Mac clicking and dragging it

  • over to VS code which I have on my doc.

  • And what that will do, because I clicked and dragged the folder over,

  • it'll actually open it up in my editor as a project, not just

  • an individual text file.

  • And if you're unfamiliar with VS Code, this is Visual Studio Code.

  • It's a pseudo IDE, so it's a text editor but it

  • has some IDE features like debugging and a really good plugin system.

  • And it's very heavily developed.

  • It's sort of the contender with Adam.

  • And Adam is also a very good text editor.

  • Sublime is also another very good text editor.

  • Those are sort of the three big ones.

  • So if you're looking for a text editor, VS Code and Adam are free.

  • Sublime Text is sort of free in that it'll bug you with a prompt over

  • and over again if you haven't bought it to register

  • but you don't technically have to do so.

  • I prefer vS code, so that's what I'm going to be using today.

  • It wants to install a helper tool, so I'm going to deny that.

  • And also a great thing about VS Code which I'll demonstrate

  • is that it gives me the ability with a certain plugin to just hit Command L,

  • and that'll load the game into--

  • command L for Love, I guess.

  • It has a integration with Love such that it will load my project in Love

  • without me having to go, say, to the terminal and type Love dot every time,

  • or go to my desktop and click and drag the folder over

  • to the executable, which is what you would have to do in Windows if you

  • don't have a similar setup set up.

  • So, I'm going to create a new file on my project called main.lua.

  • Folks that have been to the stream already know this process.

  • But new folks, this is the entry point for a Love 2D game.

  • I'm going to title it with a comment block.

  • I'm going to give it an author.

  • I'm not the actual author of the original game Space Invaders

  • but I'm the author of this clone.

  • So this is a comment block in Lua.

  • So just dash dash square bracket square bracket, just like the slash star in C

  • or in JavaScript.

  • And then I'm going to just create a few functions.

  • I'm going to command b to get rid of my sidebar there.

  • So these functions are functions that are part of the Love framework.

  • They are called by the Love framework.

  • Every frame, or in the case of Love.load, just once

  • at the beginning of your application.

  • And these are functions that almost every single Love project will have.

  • You don't technically need a Love.load load definition in your game.

  • For a lot of games--

  • well, some games-- you don't necessarily need

  • love.update, for example the tic-tac-toe game we implemented last week.

  • You can do it with Love.update, or you can do it

  • with Love.keypressed which is another function that we will probably need.

  • So Love.keypressed takes a key.

  • And so these are kind of like the base functions

  • that are part of the Love 2D framework.

  • These are functions that Love 2D will just sort of call.

  • It'll look for these functions by name.

  • So it'll see whether I've implemented a Love.load function, whether I've

  • implemented a Love.update function.

  • And if I've implemented them it'll call them

  • in a function called Love.run, which is actually hidden

  • but you can override it yourself.

  • And Love.run basically is just a function

  • that gets executed as the main game loop of a Love 2D the application.

  • Ba ba ba ba, Bavich_knight says, Vim.

  • Vim is another text editor that you can definitely

  • use if you're comfier with the command line.

  • It's got a bit more of a learning curve than Adam or Visual Studio Code.

  • But if you're comfy with it you can do a lot of really cool things with it.

  • People upload what are called their Vim RCs

  • to GitHub which allow you to customize how it behaves, sort of the shortcuts

  • and the appearance of it.

  • I'm not a Vim user but David, for example, is a Vim user.

  • So if you're into that aesthetic and into a more command

  • line oriented approach to development, definitely check Vim.

  • Vim is a great text editor.

  • So we have the main functions for our game.

  • The first thing that we talked about was the actual setting

  • up the resolution for our game.

  • So that's what I want to do.

  • I want to create a virtual width and a virtual height.

  • And actually, because we're going to be doing things a little bit more--

  • this is going to be a little bit larger of a game.

  • And I should preface this whole thing by saying

  • this might take more than one stream because this game is

  • somewhat complicated.

  • Because of that, because it's going to be fairly complicated,

  • I'm going to be a little bit smarter about how I organize my code today.

  • So rather than starting to declare all of these constants,

  • that's why they're capitalized.

  • They're going to be values that don't change.

  • Rather than declare all of these constants at the top of the main .lua

  • file, which is sort of bad practice if you just clump all your code together

  • in the main .lua file, I want to create a separate file called constants.lua.

  • And this will be where I can, as this name implies,

  • put all of my constants, all of my variables that will not change.

  • And there isn't technically a constant semantic in Lua

  • because Lua doesn't enforce constant variable assignment.

  • But by sort of saying, oh, these variables are capitalized

  • and these underscores, as is the common notation in most programming languages,

  • we can, as programmers, sort of mentally declare and associate

  • these variable names with the idea of those variables being immutable,

  • meaning they shouldn't be changed.

  • And that's sort of what you should do as a programmer

  • when you're using a dynamic language and you

  • want to use these constructs that are more common in other programming

  • languages.

  • You want to use proper variable naming, right?

  • So virtual width and virtual height-- so the virtual width and virtual height

  • are going to be the height and width of the arcade machine

  • as it was developed originally, right?

  • So the width of the arcade machine was 224 and the height was 256.

  • So I'm going to say the virtual width should be to 224

  • and the virtual height should be 256.

  • As you can see, that means the width will

  • be smaller than the height, which means we'll have a more vertical looking

  • window when we actually load the game, when we actually render the game.

  • I'm going to take these declarations.

  • I'm going to remove them from main.lua and I'm

  • going to put them in my constants.lua.

  • And these variables, because I haven't specified

  • what's called local scoping on them by writing that, this means that they'll

  • be accessible within any source file, any main file, or any Lua file,

  • that requires that source file.

  • So for example, if I say require constants,

  • this will load all of the global variables from the constants.lua file

  • into my main .lua file.

  • So it essentially has the same effect as me copying these and putting them

  • into here, effectively.

  • SmartScreen is prohibiting the execution of the editor installer.

  • Also there is only a Vista plus version, says Gaston119.

  • Are you referring to VS Code?

  • And then Bavich_knight says, more modularized.

  • Yes, more modularized.

  • Modularization is a very good virtue in programming generally.

  • Making sort of building blocks of your code and building blocks

  • of your project in terms of source code files,

  • tends to make things easier to debug, makes it easier for other people

  • to work on separate pieces at a time.

  • So you want to typically do that.

  • For small projects like we've done with tic-tac-toe and with even

  • Snake and the memory card game, those are small enough such

  • that you don't have to worry so much about these ideas.

  • But it's good practice.

  • Anything that's larger than 100 or 200 lines of code,

  • generally you want to think about breaking that up

  • into separate modules, a module being a piece of code in a text file.

  • But it can also mean a class or a function.

  • It just means building blocks that you can assemble and use interchangeably.

  • OK, so we've done that.

  • So we've put our constants into a constants.lua file.

  • Another thing that I want to do is, I want to actually make

  • a window within a window height.

  • So we have a raster.

  • We have a-- basically, you can think of drawing to a texture

  • almost, that we're going to expand to fit some window

  • size, an actual window on our desktop.

  • Because our window, we don't want to actually render

  • a native 224 by 256 window onto our desktop because that'll be super small.

  • We won't be able to play it.

  • I want to declare a separate window width and a separate window height.

  • And I don't really want to think too hard about this.

  • So what I'm going to do is, I'm just going to say virtual width times three.

  • I'm going to say virtual height times times.

  • And what this will do, is the window height and the virtual width

  • and virtual height will always be three-- well, they won't always be,

  • but they will at the start of our application

  • be three times the size difference.

  • So this will allow us to zoom in while retaining the aspect

  • ratio that we have established.

  • Another thing we have to do is, I want to use that library,

  • that virtual raster library we used last for tic-tac-toe,

  • which was a couple weeks back actually, called Push.

  • And so if you're unfamiliar, the Push library,

  • you can find it easily on GitHub.

  • So Push library Love 2d, it's GitHub.com/ulydev/push.

  • I happen to already have it on my machine

  • but you'll see an image that looks like this demonstrating

  • how they're rotating that high text.

  • And it's staying pixilated.

  • It's not interpolating.

  • It's actually being rendered at this 50 by 50 pixel resolution

  • while being zoomed in so that we can actually

  • see it like it's a retro zoomed in look on our machine, right?

  • I'm going to use the version that I already have on my machine,

  • so it's in my lib folder.

  • I'm actually going to copy this lib folder from the tic-tac-toe project.

  • So I have a lib folder with a push.lua in it.

  • If you download this library you'll get a push.lua.

  • That's the file that you want from that library.

  • I'm going to copy that lib folder over into my Space Invaders folder

  • right now.

  • So now in my Space Invaders project, if I go back to here for example,

  • I see I have a lib folder with push.lua.

  • In my main I can say, at the very top, push equals require push--

  • sorry, lib/push.

  • And remember, when you're requiring something in lua you don't need to say

  • .lua.

  • It'll infer that you're referring to .lua.

  • So you can just say, lib/push or constants, just the string constants,

  • and that will have the same effect as if you were saying require constants.lua.

  • All right, now what I can do in my Love.load function-- remember,

  • this function happens one time at the very beginning

  • of the applications running.

  • I can say push colon setup screen.

  • So, colon just means on the push object, which we're initializing here,

  • so requires returning essentially a table.

  • But push, a table that has a function in it called setup screen.

  • And I'm going to say, push colon setup screen virtual width,

  • I'm going to command b to get rid of that virtual width, virtual height,

  • window width, window height.

  • And remember, these variables were in constants.lua.

  • But because I required it, they're actually visible within my main.lua.

  • I'm going to say full screen is equal to false, Vsync is equal to true,

  • and resizeable is equal to true.

  • So Vsync just means it'll sync to your monitor

  • so you won't get screen tearing if there's any scrolling.

  • It's not really something that we'll have to worry about here.

  • Full screen just means we don't want it to be full screen because that'll

  • be a little bit weird looking.

  • And then resizeable just means that if I want

  • to resize it during the games running, I actually can

  • and it'll resize accordingly.

  • And if I go into my update function--

  • sorry, not my update function, in my draw function I can say,

  • push start push finish.

  • And whatever happens between start and finish on the push library

  • will get rendered at this fake resolution.

  • If we decided to draw something without it being within the push start

  • and push finish, it just draw to the native window,

  • the window that we've declared was three times

  • the size of virtual width and virtual height.

  • So anything that we want to draw at this retro look, this 224 by 256 resolution,

  • almost like we're drawing to a virtual arcade machine

  • that we're then rendering to a proper window,

  • we want to do it within the push start and push finish function calls.

  • And we can test this by saying love.graphics.print hello--

  • actually, we'll just say Space Invaders.

  • I think we've done hello world already before.

  • And if everything goes according to plan and if I run this,

  • I have a syntax error on line 13 which is-- oh,

  • I accidentally put a period there instead of a comma.

  • Don't do that.

  • If I run it, now we see indeed our game window is vertically oriented

  • and taking up the majority of my screen actually.

  • Hopefully it's not--

  • I think it actually is just ending at the bottom of the screen.

  • So it be OK.

  • That should be just the right size.

  • I can't tell if it's super visible on the stream itself

  • but the text for Space Invaders is actually blurry.

  • It also doesn't have a window title and I can't quit with escape.

  • So those are a few things that I probably want to add to it.

  • If you notice, if you're running anything with this push library

  • and you notice that the text is blurry or anything that you draw is blurry,

  • that's because you have filtering enabled on all of your textures.

  • So love.graphics.setdefaultfilter nearest and nearest will fix that.

  • So that'll set the filter of anything that you

  • render to the screen, or anything that you load and then render to the screen

  • after this function call, to nearest neighbor

  • filtering meaning that it will be pixilated.

  • Jebcocheson, if you are using VS Code make sure that you have the--

  • let's see, where is it?

  • This is the extensions.

  • The Love 2D support by Pixelbite Studios will allow you to command-L or Alt-L

  • if you're on a Windows machine.

  • But you have to have the Love binary in a specific place.

  • Wherever you do have it, if you click on the cog menu

  • here you can actually-- oh, the cog menu doesn't work there.

  • If you go to the settings, which is--

  • I don't think you can access the settings from here.

  • It doesn't look you can.

  • So you actually have to go to your preferences, settings,

  • and then go to your extensions down here.

  • It's a little bit because I'm running at seve--

  • my computer is at 720p so everything is a little bit zoomed in.

  • But eventually you'll see Love 2D.

  • Oops.

  • And the Settings menu is also super jammed full of stuff.

  • Let me see, where is it?

  • CSS-- oh, right here, Love 2D config.

  • You'll see that there is a--

  • ba ba ba ba-- a default location that it will expect it in.

  • If you just have it in your applications folder on a Mac

  • it should work normally.

  • If you're on a Windows, it sort of expects that Love exists

  • at C:/programfiles/love/love.exe.

  • So that'll be where, I think by default if you just

  • get the installer for Windows, it'll install it there.

  • And on a Mac, just make sure that it's in your applications folder.

  • So applications and then Love.app whatever it's named by default.

  • And then it'll know that it's there and it'll work.

  • But yeah, that's how you get it to work in Visual Studio-- in VS code, sorry.

  • If you're on a PC, you can do the same thing in VS Code.

  • But if you want it to run at the command line

  • it's a little bit complicated with Power Shell.

  • You can click and drag your folder over to the shortcut on your desktop

  • but it's a little clumsy.

  • So I'd probably recommend getting this configured,

  • downloading Love, installing it through the installer,

  • and then using the alt L shortcut with the Pixelbite extension.

  • So definitely take a look at that.

  • Now let me zoom back in a little bit just so that everything is

  • a little bit clearer on the stream.

  • Actually, is this still clear, still relatively clear?

  • Because it'd be a little bit easier to fit code onto the screen, I think.

  • So let me know if that's still pretty visible.

  • That bottom left gear stuff on VS Code is Settings.

  • Right-- oh, right here, yep.

  • The code right here--

  • or, the settings right here.

  • But yeah, that's how you do it on Windows and Mac.

  • Awesome, Jacobchaussen, if I'm pronouncing that right.

  • I apologize if I'm not.

  • Glad you got it working.

  • Seafloorrenny says, it's OK.

  • OK, but basically now I can hit Command L. And now it's more pixilated.

  • On my preview of the stream it looks the same

  • as it did when I ran it without filtering, maybe a little bit crisper.

  • I'm looking at a somewhat small preview of it.

  • But you should have seen a difference with the default filter function

  • call, so definitely set that if you haven't already.

  • A couple of other things that we can do, Love.window.settitle to Space Invaders.

  • And then, in love.keypressed I'm going to say,

  • if key is equal to escape then love.event.quit.

  • So love.window.settitle as its name says just

  • sets the titles, so the title bar of your application so when you run it

  • it doesn't say untitled, which just looks a little bit sloppy.

  • And then this live.keypressed function will fire every time

  • you press any key on your keyboard.

  • So you can define the behavior that you want Love to sort of determine

  • when you press a key.

  • You can check which key it is but he's using an If statement.

  • So if the key is equal to the string escape--

  • all keys are given a string value, so for example any of the letters,

  • the individual letters or numbers on your key,

  • would register as that particular key.

  • Space, enter, return, tab, alt, option-- all these keys

  • have a string value that you can call.

  • I'm going to say if key is equal to escape, then love.event.quit.

  • And that will have the effect of, when I run the game I can press escape.

  • Also notice that the top of the window has the Space Invaders.

  • Asley says, still looks pretty blurry only to me.

  • Perhaps a different font would be less blurry.

  • Yeah, so what you're seeing is the aliasing in the default font.

  • So it is blurry and in a sense.

  • It's not filtered blurry, so it doesn't have the actual fined tuned--

  • or that, not fine tuned, but it doesn't have a higher resolution blurriness

  • to it.

  • What you're seeing is the individual pixels are just different colors.

  • But you are seeing individual pixels now at a zoomed in level.

  • And yes, that's because this font does have different color pixels to give

  • a smoother appearance, or more rounded appearance,

  • when you're actually viewing it at a native resolution on your monitor.

  • So it's not conducive to zooming in but it

  • is more appealing to look at when you're viewing it at a smaller level.

  • So yes, we do want a different font.

  • And we can do that, as we did last week, by going to dafont.com.

  • So we go to dafont.com and I go to pixel fonts.

  • You can browse a lot of these in pixel/bitmapfonts section right here.

  • You can browse all kinds of cool different fonts

  • that are all pretty retro looking, and all their different licenses

  • are here on the right.

  • So you can see some of them are 100% free, for example.

  • Some of them are free for personal use.

  • You can't use it in a commercial project but you

  • can use it for your own projects and not worry about getting into trouble.

  • Some of them are public domain.

  • Some of them are--

  • all of these are actually pretty generous.

  • Some of them are not free and you have to actually pay for a license.

  • This one here looks like a retro sort of Western font

  • which is actually pretty cool.

  • So if were to make like a pixilated Red Dead Redemption or something,

  • that would look nice.

  • I'm going to choose a font that makes it look kind of like NES font, I think.

  • Something like Press Start To P is pretty good-- press start to play.

  • Let's see, what's a good font?

  • So, Space Invaders has sort of this--

  • well, I guess that era, the Atari arcade era, had a sort of vectorized look.

  • So the fonts were all kind of angular looking.

  • So something like this would actually be pretty-- or not this, not

  • Visitor but-- well, I guess Visitor.

  • Visitor would be pretty appropriate.

  • It's 10 pixels.

  • I kind of want an eight pixel font.

  • 04B03 is actually a pretty good font.

  • I kind of like that one.

  • That's one I think I actually used a lot in the games course,

  • because it had a nice look and it's eight pixels.

  • Pixel Aerial 11-- so on the last one, I thought I saw on an NES looking one.

  • I think I might want to use that one.

  • So, which one was it?

  • Was it this one?

  • No, this is pixel mix, free for personal use.

  • It was Minecraftia, very appropriate, eight pixels.

  • Retro Computer, Press Start to Play--

  • we'll do this one.

  • So the Press Start to Play one, I think that one's good.

  • So I'm going to grab that one.

  • Oh, it looks like I already downloaded it.

  • So OK, that's good.

  • I might have actually used it last time in the last stream for the tic-tac-toe,

  • actually.

  • Fonts, 8-bit-- oh, 8-bit and Press Start to Play.

  • Yeah, I think I did use it last time.

  • So, in my Space Invaders folder I'm going to create a Fonts folder.

  • I'm going to then paste that font in there, the Pressstart.ttf.

  • You'll get a ttf file from dafont.com typically when you download a font.

  • And so that's just the file that you need to have to use that font.

  • And then if I go into my project, I can say--

  • after I do the filter, set the filter, because if you do it before the filter

  • your font will be blurry, I can say gfonts--

  • or, I'll just say gfont equals love.graphics.newfont and then

  • fonts/pressstart.ttf.

  • And then I can say, love.graphics.setfont to gfont.

  • So the lowercase g is another semantic sort

  • of token I'm adding to the symbol of the variable

  • to basically tell me that that's a global variable.

  • I should know that whenever I see gfont, it's accessible anywhere

  • in my application.

  • And this is to help me from clobbering different variables

  • and using global variables unintentionally,

  • or using local variables as global variables unintentionally.

  • So whenever you use a variable that should

  • be accessible throughout the whole application,

  • try in a dynamic language like Lua, typically try

  • to use something to differentiate it, to make it clear that it's global.

  • So that lowercase g is intended for that purpose.

  • Whoa, this stream just reset for some reason-- or the chat reset.

  • I accidentally went backwards.

  • And because I went backwards, I got rid of the chat in the monitor

  • that I'm using to the side.

  • So I'm going to use my other monitor.

  • Ba, ba, ba--

  • Space Invader, the editor fonts are fine.

  • Out of interest, how much do you prepare in advance for these streams

  • and how much of this syntax do you know by heart, says Isotv.

  • So, for a lot of these games streams-- so, it depends on the stream.

  • So, for the Unity one I did a lot of prep in advance

  • to make sure that I understood what I was doing

  • and all the different corner cases that I could run into.

  • And it turns out I still ran into a few.

  • Thankfully Andre and Irene are typical regulars in the chat

  • and they kindly helped me out with a couple of things

  • I stumbled upon unexpectedly.

  • But for a lot of the Love and Love 2D stuff,

  • I actually don't do much prep in advance because I've done a lot of this stuff

  • before.

  • So Space Invaders, for example, I programmed before

  • in the spring for the games course that I

  • taught at the Harvard Extension School.

  • And for tic-tac-toe and for memory game and for Snake,

  • they're simple enough games that don't really require

  • a whole lot of thinking in advance.

  • Now, there were some situations where I did stumble

  • upon an algorithm or a piece of the algorithm

  • that I had to think about a little bit on stream.

  • But I think that also there is a double edged sword in prepping and not

  • prepping.

  • So, by not prepping you do run into those cases

  • where I don't have the code in front of me

  • so I don't necessarily know what I'm going to run into

  • and I don't necessarily know in advance the algorithm

  • and I don't have something as a crutch to fall back on.

  • But if I have a strict script to follow, then I

  • have no real opportunity to go off on a tangent

  • or to explore a different way of doing things

  • or to take suggestions for the chat or to change fundamentally

  • how the game is working because if I do that, then the game has

  • strayed potentially away from the original goal of the stream.

  • And that won't work super well live and be a super conversational system.

  • So the intention for these streams is to be much more conversational and casual.

  • And so for a lot of these, there is nothing really prepped in advance

  • per se, aside from some research and for the Unity stuff I typically

  • tend to do a bit more prep.

  • Now, for certain streams, like David does a lot of prep in advance

  • and we have more of an outline that we follow a little bit more rigorously.

  • And for some of the other streams we've done it's been that way.

  • But mine are a bit looser.

  • So, thank you for the question.

  • Yeah, because I'm getting the same error on line seven saying

  • there's unexpected syntax near the parentheses.

  • I only wrote commas.

  • Unexpected symbol near traceback in the function require.

  • Function [INAUDIBLE] function XP call main net seven.

  • Post your code on pastebin, I'll take a look, says Twohourstrike.

  • Line seven, push setup screen--

  • so make sure that setup screen is getting a capital S for the second S.

  • Virtual [INAUDIBLE],, virtual width, window width, window height of--

  • you do have a redundant comma there in your function calls.

  • So at the end of window height you do have an extra comma.

  • So that's what Twohourstrike said.

  • Search Space Invaders on dafont, says Karalse.

  • Sure, let's do that.

  • I actually didn't think to do that.

  • So, with Space Invaders--

  • oh, that's cool.

  • They have a font that's actually made out of aliens.

  • So that's interesting.

  • That'd be an interesting way of actually making a Space Invaders game,

  • would be only with fonts.

  • It doesn't look like it would be necessarily possible because it doesn't

  • like they give you the spaceship.

  • I guess you could construe the third alien as a spaceship, in a sense.

  • But yeah, that's a cool font.

  • Thanks for tossing that in.

  • You'd use that font instead of sprites, Karalse.

  • Yeah, in a sense we could.

  • But the problem with that is that then we

  • have to worry about drawing these sprites, the text objects,

  • in sort of weird--

  • first of all, we'd have to call love.graphics.print.

  • And we would have to know which character maps to which sprite.

  • So we'd have to say--

  • it's probably something like 0, 1, 2, 3, 4, 5, 6, 7, 8, 9.

  • So we'd have to say, love.grapics.print, the string 0, 1, 2, 3, 4, 5, 6, 7, 8

  • or 9.

  • And then we have to give it an x or y-coordinate

  • in much the same way that we would have to do with a actual graphic object.

  • But no, it could work.

  • And we could get coloring through it.

  • But I don't think this is an approach that you would typically

  • see outside of a console game.

  • So if you were, say, implementing this at the CLI like this,

  • then it would kind of make sense--

  • or I guess a--

  • well, I guess maybe it wouldn't work necessarily for a typical shell.

  • But you could emulate a shell in Love 2D as by something like a roguelike game.

  • And rogue like will do this a lot, where for example--

  • let's go, if we go to Images, roguelike.

  • So the typical roguelike is an ASCII game.

  • Your typical classic roguelike looks something

  • like this, where all of the game is actually rendered using text,

  • using ASCII text.

  • And nowadays, roguelikes can be implemented using Unicode text as well,

  • and that's a much more flexible option because then you're

  • not limited to just--

  • how many characters is in ASCII?

  • Is it 127?

  • I don't remember offhand It's either 127 or 256, one of those two.

  • Or actually, it might be less.

  • It might be 7-bit.

  • I don't remember offhand.

  • But you can only render a very limited set of characters in ASCII

  • compared to what you could do with a Unicode text file, for example.

  • But yeah, you could do something like this, run this and make a virtual shell

  • and then have those guys move around.

  • It's just a little bit strange.

  • I don't know if I would typically-- you could technically do it,

  • but it's kind of a roundabout way of getting that behavior.

  • It's much better to actually use sprites, I think.

  • I would imagine that would be a much better way to do it.

  • What is an EOF error?

  • Says, EOF is expected near end.

  • It means that it's finding the End Of File without an end statement, I think.

  • You are not ending your function or an if statement with the end keyword.

  • So notice that for every if statement, like we only have one if statement now.

  • But notice that I have an end keyword that ends this if block.

  • So every if block needs to have an end at the end of it,

  • to sort of be the start in the end syntax.

  • And whatever was within that is the body of code that gets executed

  • if this if condition is true, right?

  • And every function similarly has an end keyword to tell Lua,

  • this is the start of the function and then

  • the end means that it is the end of the function.

  • If you don't have a matching start and end--

  • 128 ASCII says.

  • OK, so it's a sort of limited unsigned--

  • what would that be?

  • Yeah, 7-bit-- 7-bit unsigned.

  • If you don't have an end key for every function, then that's a syntax error

  • and you'll get an EOF issue like you tossed in the chat there.

  • You could use that font as sprites.

  • Those are seminars, prepped and planned, says Fatima.

  • Yes, yeah, those are seminars.

  • And to a degree these are kind of similar to seminars

  • in spirit, just a little bit looser and a little bit more conversational.

  • Raw, live coding, yes.

  • I think it means you have redundant ends somewhere.

  • Perhaps-- oh, and that's true too.

  • You can get an extra end and get an error similar to that.

  • I don't remember the syntax differences between the two issues.

  • But yeah, one of those two is likely the situation.

  • Mkloppenburg-- oh, and Andre, perhaps the font could be used in text.

  • For example, instead of kills you could have an alien character or something.

  • Yeah, that'd be cool.

  • That'd be cool.

  • Mkloppenburg, be late to the show and of course I

  • won't be able to watch everything.

  • Will watch it later on.

  • Keep up the good stuff, Colton.

  • Thanks, Mkloppenburg, for tuning in as always.

  • Hope you tune in on YouTube afterwards.

  • So kind of like curly braces, says Isotv.

  • Yes, exactly like curly braces.

  • Lua does not have curly braces, which is nice

  • because I'm not a fan of curly braces.

  • I'm also not a fan of the end keyword.

  • I'm actually much more of a fan of the way Python does it,

  • with enforced blocks, indentation blocks.

  • I think that's a much cleaner way to do it.

  • But Lua is still nice enough of a language where it's not a huge deal.

  • But typing these end keywords can be a little bit too much.

  • And also the function word, I just think Python

  • does things a lot better in a lot of ways, so

  • function being deaf and not having ends.

  • You do need colons in Python, which is something, an extra bit of syntax.

  • But it's a very small thing so it's not a huge deal.

  • And then end would be like a semicolon?

  • Yeah, kind of.

  • The end is a little bit more like a closing curly bracket,

  • you could think of.

  • OK, so we've been at it for a little while.

  • And now that I reload the game we see that we

  • do have Space Invaders being rendered.

  • It's a bit large.

  • It shouldn't be that large.

  • And that's because by default Love assumes that we want our font

  • to be, I believe, 16 pixels.

  • So if I just specify eight pixels when I actually

  • create the font in the love.graphics.newfont function call,

  • it will make it much smaller.

  • So now it is indeed an eight pixel size font.

  • Is that eight pixels?

  • Yes, I do believe that is eight pixels.

  • So, similar to how we had it before--

  • I apologize if I keep hitting my mic.

  • I don't think I am.

  • I think I'm hitting my jacket.

  • But now the font object is smaller, it's not supermassive,

  • and we can get on with the actual implementation of the game,

  • of the moving around and the aliens and whatnot.

  • So the way that I liked to do it for the games course that I taught

  • was, I kind of liked the randomization approach to it.

  • And so there is a sprite generator--

  • and I don't remember offhand, actually, which website it was.

  • It's not a CSS sprite generator.

  • It's like a retro sprite generator.

  • Had to look for it.

  • I don't remember the exact URL offhand.

  • Is it this one, the Ludum Dare one?

  • Could be this one.

  • Sprite generator-- oh no, this is the Java one.

  • There's a sprite generator that's an actual web application.

  • So sprite-- pixel sprite generator--

  • pixel art sprite generator maybe.

  • Is it this one?

  • Nope, not this one.

  • I apologize.

  • I might have to find the URL for it.

  • Where is it?

  • There is a URL that actually makes aliens.

  • Oh, I think it's a robot sprite generator, maybe,

  • or alien sprite generator.

  • Crap, where did it go?

  • This is used to be like an instant top of the Google results search.

  • I might cheat and go back to the--

  • so I have the source code for the actual Space Invaders that I did.

  • I should.

  • Dev-- it's not in summer.

  • Crap, where was it?

  • [INAUDIBLE] project zero-- that wasn't a project.

  • I apologize.

  • I'm going to find this.

  • We're going to find this.

  • Sprite generator, alien-- is this going to work?

  • I hope they didn't remove it off of the website.

  • Ba, ba, ba ba.

  • Kind of embarrassing.

  • They had a whole website that was--

  • retro pixel art sprite generator.

  • Forsunlight saying hello, everybody.

  • Any good sprite generators out there?

  • So this is why prep is sometimes good.

  • This was like a top Google search result. I have no idea where it went.

  • Randomized sprites-- no, not ALTTP.

  • Is it this one?

  • Here it is.

  • OK, so I just had to type randomized sprites.

  • So, sprite generator wasn't good enough.

  • But this is what it is.

  • So, it's a website, IMG.uninhabitant.com/spritegen.html.

  • I can toss that link in the chat, or I can at least write it in the chat.

  • Unfortunately I'm not in the chat logged in on this account.

  • So IMG.uninhabitant.com/spritegen.html.

  • So you go to that link.

  • You can generate your own sprites if you want to generate them and follow along.

  • Do I like these ones?

  • These ones are pretty good, right?

  • And these aren't zoomed in, are they?

  • Zoom level one, size 16.

  • Do I want 16 or do I want eight?

  • So this is cool.

  • You can actually customize all of the parameters for the generation.

  • So down here-- oh, and you can choose the color palette, too.

  • And by the way, color palettes are a huge thing in sprite art.

  • If you're not familiar, color palette is basically a limited set of colors

  • that you can draw from to create your sprites.

  • And this was a physical limitation of hardware back a long time ago.

  • Nowadays, it's obviously not.

  • You can do whatever color you want.

  • But if you want a homogeneous, if that's--

  • I always don't know if it's homogeneous or homogeneous.

  • But if you want a homogeneous/homogeneous look

  • to your artwork, you can define a--

  • oh, Realcuriousqe, the video is about 30 seconds behind the chat for me.

  • Let me type this in.

  • It's already there.

  • Yeah, I'm just ahead of the curve, you know?

  • Just, that's just how we do it.

  • But no, palettes are a limited set of colors.

  • So you have eight colors, 16 colors, 32 colors.

  • Generally the smaller number of colors, the more distinguishable the art is

  • but the harder it is to make things look the way you want.

  • But these are all very famous color palettes

  • that you can choose from-- so NES, for example, Gameboy.

  • Dawn Bringers is a very huge palette in the online sprite art community.

  • So he has several different palettes of 16 and 32.

  • We used the Dawn Bringers palette in the games course

  • that I teach, Commodore 64 being another one.

  • And Arnie's is another really famous one, actually.

  • Arnies and Dawn Bringers are sort of at odds with each other, I think,

  • so they sort of compete with each other.

  • I like Dawn Bringers.

  • Colors per sprite, so this is colors--

  • not three colors total but just three colors per sprite

  • if you want to limit the number of colors

  • that each individual sprite can have.

  • It's a cool limitation.

  • I'm going to say four colors.

  • Background color index zero, that's fine.

  • We're going to say the size is going to be--

  • do I want eight pixel aliens or 16?

  • Chat, do we want eight pixel sprites or 16 pixel sprites?

  • You're logged in your Google account, says Bavich_knight.

  • Yes, I am.

  • It always happens to me too, [INAUDIBLE] blah, blah, blah, blah.

  • Eight, eight-- this is around the world, bits traveling.

  • Fatima says yes, eight.

  • So we've got three people saying eight.

  • Whole time it was my internet problem.

  • It was all in the streams, says Bavich_knight.

  • Yeah, the stream will take about--

  • it depends on how far away you are, I guess.

  • Here directly in this room it's about two seconds.

  • Between here and another place kind of locally, or within the states,

  • it's typically seven or eight seconds.

  • And I imagine super far away it'll be probably closer to 15, 20 seconds.

  • Yeah, New Zealand, 30 seconds.

  • So we have four people saying eight pixels.

  • So I'm thinking eight pixels probably.

  • So I'll go ahead and make that eight pixels.

  • And I think I actually did that for the Space Invaders game

  • that we implemented for the spring.

  • So I think it's apt.

  • Let's just make sure everything looks good.

  • No scalar, zoom level one, 16 tiles, four pixels apart--

  • and I think that that is--

  • actually, do I want spacing?

  • No.

  • Zero pixel spacing, I want to be able to slice these up.

  • All right, let's generate.

  • Whoa, and that is tiny!

  • OK.

  • So, if I save that image, save that in the right place.

  • Go to streams, Space Invaders.

  • I'm going to create a new folder here called Graphics.

  • And then I call this aliens.png.

  • And I just went wit whatever this first result is, and a lot of these

  • are going to look a little bit weird probably.

  • So Space Invaders, graphics, aliens.png.

  • Let's open that and let's zoom in, see what we got.

  • It's sort of like the lottery because we have--

  • wasn't the original Space Invaders entirely black and white, says

  • Realcuriousqe?

  • I think it was.

  • I think it-- well, not black and white as much as it was, I think,

  • black, white, and green?

  • Let's see.

  • Space Invaders-- black, white, and green.

  • So yeah, essentially, I guess, 2-bit color?

  • We're not going to go quite that low, I think.

  • We're still going to add-- make it look visually cool

  • and have different sprites.

  • But yeah, I think if we were going to adhere 100% strictly

  • to the game and its limitations, we would use just black and white sprites.

  • These are looking OK.

  • Some of them are a bit--

  • there's not a whole lot of detail, is the only problem.

  • They don't look like aliens.

  • We could make some of these work.

  • Like this one, for example, right here, this one could work, right?

  • And this one, actually this one?

  • This one looks almost exactly like the Space Invaders alien.

  • This one looks really good.

  • No read, Colton, I have to leave.

  • Will catch up on YouTube [INAUDIBLE] the day [INAUDIBLE]..

  • OK, Fatima.

  • See you later, thanks for joining.

  • The green was a filter on the screen though, as far as I know.

  • Oh yeah, that would make sense actually, because it

  • was within a limited portion of the screen down here.

  • That actually makes perfect sense.

  • So yeah, in that case then it was 1-bit color.

  • Yeah, they don't look like anything.

  • Jacob saying, let's do 16.

  • Yeah, probably.

  • I'm thinking that too, probably.

  • There's just not a whole lot to work with here,

  • so 16 probably makes sense, right?

  • Sadly.

  • I mean, we could make it work.

  • There's a few of them that do look OK, like this one looks OK.

  • This one looks like it actually looks like a UFO.

  • This one looks OK.

  • Some of these look like ships.

  • This one looks like a sideways UFO.

  • But I think it would get much better results.

  • So, tell you what.

  • Let's generate another one.

  • Let's go back to the website.

  • Let's go over here.

  • Let's go and say size 16.

  • Now, the only problem with this is because we're

  • running at such a low resolution, these 16 size sprites

  • are going to bee pretty big.

  • So what we could do is, we could render the game at--

  • could you take a screenshot of the font and use that as a PNG?

  • Oh, we definitely could.

  • We definitely could.

  • If we wanted to do that way we absolutely could.

  • I personally think it'll look a lot more fun if we have a different sprites,

  • and we can do some cool stuff with randomizing the aliens this way

  • and it will look a little bit less boring.

  • But yeah, you could absolutely do that if you wanted to.

  • The only problem is, then you're going to-- the screenshots are going to be,

  • because I'm taking a screenshot on my Mac, which is a retina display--

  • well, right now it's a 720.

  • It's going to be super, super big.

  • It's going to probably be like 200 pixels per alien--

  • 200?

  • Well, maybe not 200.

  • Depends on how small I create it.

  • I can create it pretty small but it's not going to be an even size.

  • So at the very least, I'll have to go into Asprite and then downsize it.

  • And by downsizing it, I might artifact it-- not artifact it,

  • but I might distort the sprite in a way that it doesn't

  • retain its actual crisp original look.

  • So typically that can be kind of tricky to work with.

  • But yeah, you could get it to work.

  • And with a little bit of touching up manually you could make it work.

  • I think it's a bit too much work, to be honest.

  • I think it'd be easier to find just the actual original Space Invaders sprites,

  • probably.

  • Let's try this.

  • Let's save image.

  • This is a little bit more interesting, too.

  • We can actually create our own aliens and figure out which ones we like.

  • What I like to do is randomize it.

  • So I get something like this and then just make them all random.

  • So that way we don't know what to expect.

  • Aliens16.png.

  • And so now if I open this, and I zoom in--

  • so, a million times better.

  • All of these are pretty distinguishable.

  • I mean, you do get a lot of them that look kind of samey.

  • Like, they all have sort of this mothership look

  • to them, this sort of weird hive look.

  • But they all look pretty unique and interesting now,

  • compared to the eight pixel ones, right?

  • 16 is too detailed.

  • You could even make an image out of the font by drawing it on the screen

  • and then using love.image.newimage, new image data.

  • Yes.

  • Yeah, yeah, yeah, you could do that, absolutely--

  • draw effectively a pixel or texture data on the screen

  • and then make an image out of it, yep.

  • That's actually a great way to do your own custom randomized

  • sprite generation, by drawing to a bit of image

  • data the extra individual pixels and then

  • creating a sprite from it that you can then

  • draw in otherwhere-- in other places.

  • Otherwhere being a new word that I just made up.

  • But do we think it's too detailed?

  • Jacobchaussen says it's a little bit too detailed.

  • I hate to spend a little bit too much time on this.

  • But this is also kind of the fun part of game development,

  • is choosing the assets and laying the artistic, the creative design out.

  • So it's not something that we should I think definitely pass over altogether.

  • Themetaleagle, hello.

  • Hello, good to see you.

  • Thanks for joining.

  • But if we think that 16 is too detailed, let me know.

  • We can maybe try 12.

  • We'll try 12 pixels.

  • We'll see what the in-between looks like, right?

  • So 12 pixels, generate.

  • I'm going to save this.

  • And then we can vote one more time on what everybody wants.

  • So we have aliens12 now.

  • So we have the aliens12, 12 pixels by 12 pixels.

  • I'm going to give everybody a chance to take a look at that.

  • Some good ones in here, definitely.

  • Oh, the sprite sheet Brenda tossed in the chat.

  • Oh, yeah.

  • So, that could work, Brenda.

  • It would be a little bit tricky because we'd

  • have to manually go into an image editor, determine the exact pixel

  • coordinates, and then-- we'll cover this,

  • but we're going to have to generate what are called quads.

  • And if you've followed GD50 before you might be familiar with this already.

  • But basically, a quad is a rectangular portion

  • of an image that defines, when you draw that image, the exact portion that gets

  • drawn to the screen.

  • But we would have to manually go through this and figure out the quads.

  • And if the image is larger than, say, 16 or whatever we'd have to scale it down

  • to draw it to fit our screen well.

  • JPguy, welcome!

  • Good to see you.

  • Borrow a phrase from Westworld, it doesn't look like anything to me,

  • says Andre.

  • It seems like a lot of work.

  • It is a bit of work.

  • But we talk about this in--

  • I did a seminar on Mario.

  • C4renny, eight for the minion aliens and 16 for the top level boss.

  • Is there an actual boss in the original Space Invaders?

  • I don't remember offhand.

  • I don't know if we'd have time to implement like a boss

  • behavior versus the minions.

  • That be cool feature.

  • If we do it over multiple streams we might

  • be able to add something like that.

  • It doesn't look like there is a--

  • oh, there is right here, the mothership I guess?

  • That'd be cool.

  • That's a cool idea.

  • Let's put that on the potential to do list.

  • These look like they're--

  • actually, the base sprites look like they're 12 by 12?

  • I think they're 12 by 12.

  • So, the 12 by 12 might be the most appropriate.

  • But yeah, see eight for the minion aliens, 16 for the top level boss.

  • If we're going to make a top level boss I'd probably make it even larger

  • than that, to be honest.

  • Probably make it like, maybe 24 by 24?

  • It's a good suggestion.

  • That's pretty cool, actually.

  • I personally think the 12 by 12 is pretty good.

  • Can the chat tell me what they think, what they like?

  • And I actually haven't watched Westworld so I'm not familiar with it

  • but I've heard great things about it.

  • So, just to ABC, this is the 12, this is the 16, so

  • a bit larger and a bit more detailed.

  • Give everybody a chance to take a look at that.

  • And then this is the eight pixel one, which I just called aliens.

  • So the eight is a bit small.

  • It'd be great if you're making like a Gameboy game or something.

  • I think that would look pretty good.

  • Majordafat, no Westworld spoilers, please.

  • 12 by 12, yeah, Asley says says 12 is good.

  • Brenda says 12 by 12 looks good.

  • Jacobchaussen says-- I'm assuming that he or she is referring to the 12 by 12.

  • I don't like colors.

  • They seem so saturated.

  • I think it's because they're all so zoomed in, yeah.

  • When we see it in the actual game I think it'll look a little bit better.

  • Twohourstrike, I vote for 12.

  • All right, it seems like 12-- yeah, Andre says 12.

  • Yeah, 12 is the way to go.

  • OK, so we got that setup.

  • We're good.

  • Let's go ahead and let me get rid of this.

  • The-- oops, sorry.

  • So, we know we want our sprite sheet then to be the sprite--

  • whoops, my microphones got caught on the table.

  • We know that we want the sprite sheet to be our 12 pixel by 12 pixel one.

  • So we're going to use that.

  • We're going to load that as an image file.

  • And that image file we are then going to chop up into pieces so that we

  • can render the individual aliens because if we were to just draw the image file

  • to the screen as it is, that is going to result in just drawing

  • this big collection of aliens on the screen which isn't

  • going to be productive for anybody.

  • So let's go ahead and do a couple of things.

  • First thing I'm going to do is, I'm going to create a new folder

  • called Source, S-R-C. This is going to be

  • where I put all of the Lua files besides main.lua, including constants.lua.

  • So I click and drag constants.lua into there,

  • which means now I have to require src/constants, not just

  • constants because it's not in the same level as main.lua anymore.

  • Within source I'm going to create a new file.

  • I'm going to call this dependencies.lua.

  • And this file is going to be the file where we keep

  • all of the libraries and image data.

  • Basically it's going to function as a require and assets

  • file module that we can then include in our main.lua

  • and we don't have to require constants and all of the different classes

  • that we might end up writing and all the images and sounds and all that stuff.

  • We're going to put that all into the dependencies file.

  • So I can say push equals require push.

  • I can say require src/constants.

  • And then I can say, gtextures--

  • and remember, that lowercase g means it's going to be global-- gtextures

  • equals, I'm going to make it a table.

  • And now a table-- so this is where we get into where

  • curly brackets are used in Lua.

  • A table is a sort of data structure that functions as a-- you

  • can make it use as an array, you can use it

  • as a dictionary, a Python dictionary, or a hash table

  • so you can associate keys with values.

  • It's a multi-purpose data structure and it's also

  • the backbone for how you get classes and objects to work.

  • Un3okapi says, hey, sorry to interject but I just

  • wanted to say I really appreciate and enjoy these Twitch sessions.

  • Thank you for taking your time to do these.

  • Thank you for joining.

  • I appreciate that you're tuning in and that you are enjoying them.

  • But the tables are used for basically putting data together

  • in a data structure.

  • Oh no, NASA just went live!

  • Which stream should I watch?

  • Put them both up.

  • Why not?

  • I mean, have a little bit of outer space.

  • It's appropriate because Space Invaders takes place in outer space.

  • So I feel like the two sort of go hand-in-hand.

  • Un3okapi, cool hair, dude.

  • Thank you.

  • Appreciate it, thank you so much.

  • OK, so gtextures equals--

  • these empty curly brackets is going to be our table definition.

  • So what I'm going to do is, using this symbol, or this-- sorry,

  • this square brackets syntax, I'm going to say this is going to be my key.

  • The key is going to be aliens equals.

  • And then I'm going to say love.graphics.newimage

  • graphics/aliens.png.

  • And what this has done is it's created a table where I can put data,

  • and it said the aliens string is going to be associated with this

  • love.graphics.newimage object, this image, located at graphics/aliens.png.

  • So now if I do something like gtextures aliens,

  • that's going to be a direct reference to that image object.

  • c4reni, thank you very much for following.

  • So that gtextures is now a table we can index.

  • Just like arrays, you can just index them by their keys.

  • So this is indexing that table at the key aliens.

  • If it were used as an array where the data does not have a key to associate

  • with every value but rather it's just storing data continuously,

  • you can index it numerically like you do with arrays in C--

  • 1, 2, 3, 4, 5, et cetera.

  • But we're going to be using this gtextures table as a reference

  • to all of our texture data.

  • And another thing that we want to do is, I'm

  • going to create a table called gframes.

  • And this is going to have a reference to gtextures aliens, 12 by 12.

  • This is going to have a reference to the result of a function called

  • generate quads, which we haven't implemented yet.

  • That's our own function.

  • And this function takes as arguments a texture So

  • in this case it's an image data object.

  • So in this case a reference to what we just looked,

  • the gtextures aliens image data, and then the size of the sprites

  • located in that texture, in this case 12 by 12 pixels.

  • And in order for this to work I also need

  • to require src/util, which we have not implemented yet.

  • But this is where we get into talking about sprite sheets.

  • And we haven't actually talked about sprite sheets yet in Lua and Love.

  • But sprite sheets are exactly what these are--

  • essentially just image data put together in one texture, one PNG file,

  • as opposed to having individual textures which we looked at,

  • for example, in tic-tac-toe.

  • And we didn't even use textures in Snake.

  • And we used individual textures also with memory cards.

  • It's easier to do it this way because we don't

  • have to actually split up the textures.

  • You programmatically, like we're going to do in a second.

  • But it is a bit unwieldy.

  • For example, if we wanted to do it that way with this and we

  • wanted to have the same number of aliens available,

  • this would be whatever this is--

  • I think it's 14 by whatever this is, 1, 2, 3, 4, 5, 6, 7, 8--

  • 16, 1, 2, 3, 4--

  • yeah, it's eight by eight--

  • sorry, 16 by 16 sprites which is--

  • I don't even know that is offhand, I don't know my 16 multiplication tables.

  • But it's a lot.

  • It's like 200 something sprites.

  • And that would mean, 200 and something png

  • files in a directory somewhere in here.

  • So rather than do that and have to manually go into my source file

  • and say, OK, that's one texture, OK, so alien2

  • is going to be love.graphics.image graphics aliens2,

  • it's much easier to be able to just have a single texture

  • and then split that up programmatically into what are called quads, or sprites

  • in a lot of frameworks and environments, and be able to draw those separately.

  • Be able to draw this image data but specify a quad, specify a sprite,

  • and then only draw that specific piece of the texture.

  • And it will have the effect of, as if we had

  • 200 and some odd individual textures that we're using.

  • But we're only using one.

  • We're just making it look as if we have multiple different sprites.

  • Let me make sure that I'm back in the stream chat here.

  • OK.

  • You know what?

  • You're totally right, says JP.

  • Yeah, well, you know, you've got to have a little bit of outer space.

  • Never hurt anybody.

  • OK, so I know that I want this function to generate these quads.

  • First, let's do a sanity check.

  • Let's go into love.draw.

  • Instead of drawing Space Invaders, let's go ahead

  • and say love.grapics.draw gtextures aliens,

  • because we can make a reference to that image data

  • so I can just call it within there.

  • Right, I haven't called the-- so, I put all of this into my dependencies file.

  • So I could say it require dependencies, like that.

  • And source dependencies, I apologize-- src/dependencies.

  • Push is not found.

  • Did I mess that up?

  • Oh, I did-- lib/push.

  • Sorry, util not found because I haven't created the util file.

  • Lots of little bugs here.

  • But now this should work.

  • So if I go into main.lua and run it--

  • god, generate quads also doesn't work.

  • OK, function generate quads end.

  • There we go.

  • So that was somewhat painful.

  • But you can see that we're drawing the texture to the screen as is.

  • And that's not the effect that we want.

  • We want to draw just individual sprites at a time.

  • And I'm also making a reference to the wrong sprite sheet.

  • We agreed we were going to use the 12 pixel one.

  • So I'm going to say that we're going to load

  • not the aliens.png which is the eight pixels, but the 12 pixel version,

  • so aliens12.

  • And when we do that, we can see that they do look much larger on the screen.

  • And they look like a pretty good size.

  • I can sort of visualize how this is going

  • to look once we've implemented the--

  • once we've actually split the texture into multiple sprites

  • and made it so that the enemies move around we have a ship and whatnot.

  • It's going to look decent.

  • We should also figure out which one of these

  • we want to be our ship, because we will need a ship sprite.

  • Which one of these would be good, actually?

  • If anybody has any preferences for which ship

  • we want to vote to be the one that becomes our actual ship.

  • This one looks pretty good, for example--

  • third row, last one.

  • Toss that in the chat, because we got to decide that.

  • Oh, 16 by 16, 256.

  • Yep, I should know that.

  • That's kind of embarrassing, actually.

  • How do you iterate through the image if the only information you have

  • is that the quads should be of size 12 by 12?

  • So we are going to figure that out right now, actually.

  • So going into util.lua I'm going to say utility functions.

  • And then remember we declared that we were

  • going to take in a texture and a width and height, right?

  • And I'm trying to remember exactly how I did this because I

  • implemented this for the game's course.

  • And we could figure it out on the fly.

  • I'm just trying to figure out if there was any particular specific special way

  • I did it.

  • There really wasn't.

  • So, we'll just figure it out as we go.

  • So what we need is, essentially what we should

  • expect to be returned from this function is a table, so a list in this case,

  • of quads.

  • And quads are just rectangles.

  • So if I go over to--

  • this is actually a somewhat perfect time to do a little bit of fancy--

  • sorry, draw.cs50.io. .

  • We'll do a little bit of fancy drawing onto the screen.

  • And excuse me while I grab my tablet so I can actually do this properly.

  • So I try to look for any excuse possible to do this.

  • But I have a handy dandy Wacom tablet right here.

  • And we're going to use CS50's handy dandy draw tool, draw.CS50.io.

  • I'm going to plug this in.

  • This should just work.

  • Take the pen out and let's do a little test.

  • Is this working?

  • Yep, perfect.

  • So I have a sprite--

  • or not a sprite.

  • In this case I have some textures.

  • I have aliens, right?

  • And these individual aliens are going to be my sprites.

  • Blah, blah, blah, blah, blah.

  • They all look the same for this example.

  • But our goal is to take this sprite information, this texture,

  • and split it up into multiple pieces.

  • And I would put this publicly but I feel like I might get

  • a lot of drawing and stuff on there.

  • But if you want to use this yourself, feel free to do so.

  • In fact, we can set up a draw.cs50.io/spaceinvaders.

  • If you go to draw.cs50.io/spaceinvaders, you will actually be able to see this

  • on your screen.

  • So anybody that wants to go ahead in there and draw and mess around,

  • feel free to do that.

  • I'll tune in there in just a second.

  • But if you just go to just draw.cs50.io on your machine without--

  • if you go onto it without specifying a URL,

  • you will actually just get a local version of the app

  • so that anything you draw is just on your machine.

  • It's not being broadcast anywhere.

  • And Nikolai, scared cold enough about draw.cs50.io.

  • Yeah, that might be-- we might have a couple of non kid friendly issues

  • with that.

  • Fifth one from the left, fourth one up, but the one you suggested

  • looks good to.

  • Fifth from the left, fourth one up?

  • Which one is that?

  • Fifth from the left, fourth one up.

  • Are you talking about from the top or the bottom?

  • So this one?

  • Fifth from the left, fourth one from the top, this green one?

  • Or are you talking about this one right here, this yellowish one?

  • OK, so 1, 2, 3, 4, 5, 1, 2, 3, 4.

  • So, this one right here then.

  • Oh, six-- oh, this one?

  • Oh, I see.

  • Oh yeah, that would be cool.

  • Yeah.

  • Yeah, that would be pretty cool.

  • We can make that one the alien one.

  • JPguy, I should choose Belgian looking space--

  • I keep getting out of the chat on my side computer here.

  • American looking spaceship near the bottom as well.

  • American looking one at the bottom, which one is that?

  • Near the bottom.

  • Which one was the American looking spaceship, JPguy?

  • How do you erase lines?

  • Oh, how do your erase lines!

  • So, if we go back to the--

  • I've got so many devices and stuff here.

  • Let me go to this and let me put this on a separate screen

  • so I can flip between them pretty easily.

  • So erasing, if I'm not mistaken you click and drag from the bottom.

  • Can't see super well.

  • Whoops.

  • How do you erase, actually?

  • Is it shift?

  • Oh, it's shift.

  • Sorry, so shift-- it's a little large, so be careful.

  • So shift click will erase, so I can do that.

  • But I don't want to do that right now.

  • Do I dare look into the tab and see what people are drawing?

  • Whoa!

  • Got a lot of erasing going on.

  • So people have stuff they don't want to see.

  • OK, I apologize.

  • We're getting a little bit distracted.

  • Da, da, da, da.

  • Brenda has a sword now to moderate.

  • Oh yeah, that's true.

  • She does have a sword.

  • And Brenda will use it fiercely, she will.

  • I know Brenda.

  • It had some colors but I miss looked, apparently.

  • 11th of the bottom, fourth or third.

  • 11th from the bottom--

  • 11th from the bottom, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11.

  • Wait, what?

  • I'm not sure which one you're referring to, JP.

  • But anyways, back to the discussion of splitting up sprites.

  • So, we have image data here.

  • And a quad is essentially just--

  • and if I can change color, actually, that would be super cool.

  • For some reason I can't change color super easily.

  • Yeah, I'm not sure why I can't change the color.

  • But if I could change the color--

  • if Dan were here he could assist me.

  • But essentially, a quad is just me saying I want to take this chunk.

  • I want to define a rectangle that means this chunk right here.

  • Oh and by the way, Maketsuk666 and Qaerasu, thank you very much,

  • both of you, for following.

  • And so this quad, so this is a quad, also known as a sprite in many circles.

  • Whereas this is known as a texture, or an image.

  • The texture or the image is the data that contains the sprites that you're

  • trying to display on the screen.

  • And what we have done so far is, we have had individual sprites like this where

  • it's equal to both a sprite and a texture

  • because we were just drawing the data as it is onto the screen, right?

  • But we don't want to do that when we want to have all of these sprites

  • together.

  • We want to say, I specify a quad here.

  • And it's going to have an x and a y.

  • So it's going to be x equals 0, y equals 0, width equals 12,

  • and height equals 12, right?

  • Because we want to specify a coordinate for the quad.

  • And remember, everything is top left oriented by default.

  • So this quad here is at x,y zero--

  • very top left.

  • The width is 12 and the height is 12.

  • Because all of our sprites in this texture data are 12 pixels by 12

  • pixels tall.

  • This sprite right here is very similar except its x is 12, or rather--

  • is it 12?

  • Yeah, it is 12.

  • Its x is 12 and its y is 0.

  • And then this one is 24, this one is 36, and so on and so forth

  • until you reach the end of your width.

  • And then you iterate per row as well.

  • Every y, you increase the y by 12.

  • So it becomes not zero but 12.

  • And then you rinse and repeat and do the same thing over and over again,

  • generating all these quads.

  • Go down to the next line and do it over and over again.

  • Now y is 24, x is 0, and so on and so forth.

  • Asley says she drew a masterpiece.

  • Let's see it.

  • Oh, that's-- what's that supposed to be, Asley, please tell me.

  • Oh, there's a--

  • OK.

  • Man, I forgot how you scroll.

  • Ugh.

  • Does anybody remember the scroll shortcut,

  • because I actually don't remember what it is?

  • Is it alt?

  • I don't want to delete the whole thing.

  • I'll feel terrible if I delete the whole thing.

  • Shift alt?

  • Yeah, I don't remember.

  • I don't remember the shortcut for how to actually pan the image.

  • But this is a--

  • first of all, I appreciate the artwork, thank you very much.

  • I do see that there's an arrow that's pointing to COL, which probably

  • implies that that's a picture of me.

  • So it's a beautiful picture.

  • But this is the gist behind how we algorithmically

  • take a piece of texture data and split it up

  • into multiple sub sprites, these little individual sprites

  • that we can then draw like they're their own separate images.

  • And so I'm going to go back to the code here.

  • And we can essentially think of it as a two dimensional

  • loop that's iterating y by x.

  • In much the same way that we would draw, for example, a row of tiles, or sorry,

  • a map of tiles along the x,y.

  • We can do the same kind of thing by splitting up the quads.

  • It's sort of the inverse of drawing everything to the screen.

  • But that's how we can think about it, just iterating row

  • by row, column by column, until we've basically extracted each quad

  • and then put it into a table that we then

  • return back to main which we can then reference

  • when we draw an individual sprite.

  • So, I'm going to say local quads is equal to an empty table.

  • And I know that at the end of this function

  • I'm going to return that table of quads.

  • Jacobchaussen says zoom out.

  • Can we zoom out?

  • Oh no, it went away.

  • What happened?

  • Chmod777, thank you for the subscription.

  • Appreciate the name as well.

  • OK, so I want to iterate for every y and x.

  • We can think about it the way that we thought about drawing grids of tiles.

  • So for y is equal 1 until, let's say local texture width, texture height,

  • is equal to texture get width, texture get height.

  • And these are functions that you can call on any image object.

  • So no, we've declared two variables called

  • texture width and texture height.

  • And we have called the get width and get height function on the texture

  • that we're passing in, which is going to be our texture PNG

  • file that we referenced earlier.

  • And then I can say local sprites wide sprites tall is going to be equal to--

  • and then this is where we can use our actual width and height that we

  • passed into the function, right?

  • I can say, texture width divided by width and texture

  • height divided by height.

  • And what this will do is, it will tell me

  • by dividing the actual width of the texture

  • by the size of the sprite, how many sprites tall and wide the image is.

  • So we have algorithmically figured that out by using a function

  • that Love has given us, which is this get width and get height function.

  • And we do have to specify the width and height of the sprite itself.

  • There is no real way for Love to know how big the actual sprites are

  • because it can't look at the image and say, oh, these sprites are

  • 12 pixels by 12 pixels, or they're 32 by 32 pixels wide, right?

  • That's something that visually you as a human have to tell this function.

  • And then the function can then say, OK, now

  • that I know how big the sprites are I can iterate over it,

  • I can calculate it, and then figure everything out.

  • So for y is equal to 1 until the sprites tall, do.

  • Then for x is equal to 1 until sprites wide, do, end.

  • And so this is iterating over every row, first, so going through the row,

  • and then going down to the next row, iterating over every column,

  • going to the next row, iterating over every column, sort

  • of scan line format the way that like CRTs typically operate, if familiar.

  • And so this is where we're going to have to actually create

  • the quad that represents that rectangle of our image

  • that we want to store in our table.

  • So, we would say table.insert.

  • And so this is how you add anything to any table in Lua.

  • Table.insert into quads--

  • I'm going to insert love.graphics.newquad.

  • And a quad-- and this is a nice thing about the Pixelbite plugin

  • as well, is it gives you all this documentation that you can see.

  • It tells me that it expects an x and a y.

  • So this is where the top left position is of the individual quad, which

  • is important.

  • And then it tells me it needs the reference height and reference

  • width of the image.

  • And this has to do with Open GL underneath the hood.

  • I'm not entirely sure 100% how that maps to this function.

  • But basically, it maintains a reference.

  • I looked at the source code at one point and understood,

  • but it's been almost a year.

  • But I can say, love.graphics.newquad.

  • And lets just say I'm going to need an x and a y.

  • It's not going to be actual x,y, because those are just going to be 1

  • to whatever--

  • 1 to 16 and then 1 to 16.

  • But as placeholders I'm going to put x, y there.

  • And then I'm going to say, texture get--

  • what is it?

  • Is it get size, get dimensions?

  • Lua-- or sorry, Love 2D image get dimensions?

  • I think it's get dimensions--

  • yeah, get dimensions.

  • Whoa, and that's way zoomed in.

  • And so what this does is, as its documentation says right

  • here on the wiki page, it returns two variables-- so

  • that's why there's a comma there-- width and height.

  • You call image get dimensions.

  • In this case image is capitalized as the object class,

  • but it can be on any image object, get dimensions.

  • So I can say texture get dimensions.

  • And even though I called this new quad function,

  • which takes in four arguments-- notice that it took four arguments, the x, y,

  • the reference width, and the reference height--

  • because this function, the get dimensions function,

  • returns two variables we're actually able to populate

  • a function that expects four arguments with three values--

  • the x, y that we're going to put in and then this texture

  • get dimensions function call.

  • Let me get-- whoops, didn't mean to do that.

  • I'm going to command B so we can see the whole thing on the screen.

  • Now, this x and y are not the variables that we want.

  • We want to actually figure out--

  • so, back to the amazing draw.cs50.io page here--

  • we want to figure out where our x and y are for each individual quad

  • a we're iterating through our array.

  • So remember, they were doing for y is equal to 1

  • until the number of tiles tall-- so that's 1,

  • 2, 3, 4, in this example case.

  • And then for each of those in a nested loop we're also doing,

  • for x is equal to 1 until the number of pixels wide-- so 1, 2, 3, 4--

  • and then y is equal to 2, 1, 2, 3, 4, y is equal to 3, 1, 2, 3, 4 on the x.

  • For each of those we want to determine what the x and y should

  • be at that particular part of the loop.

  • And we can do that by essentially just multiplying by 12,

  • because that's the size of the pixels.

  • So for our example our loop is set to one on the x and 1

  • on the y, that'll be the first index that we're at here because remember

  • typically loops in Lua are one indexed.

  • You can index them at zero, but the typical trends

  • are two initialized by one.

  • You started at one and then you can say--

  • we could probably initialize it at zero actually, for that loop,

  • just because it'll make it a little bit easier.

  • That way we won't have to minus by one before we do the multiplication.

  • Normally you have to minus by one before you do the multiplication when

  • you indexed by one, because everything in graphics is zero indexed

  • but Lua is one indexed.

  • So what we can do is, we can say when our x is equal to zero

  • and our y is equal to zero-- and I'll change it right now,

  • actually, zero and zero.

  • What we can do is basically say, love.graphics.newquad x times

  • 12, y times 12.

  • And then that will give us the position--

  • wait, quad, love.graphic.newquad, x, y, and then it

  • thought it also needed a size of the quad itself, right?

  • Am I getting that mixed up?

  • Oh, it is.

  • I'm sorry, there's actually six arguments.

  • I was wondering.

  • The function signature did look small.

  • We also have to specify the size of the quad,

  • because just the position is not enough information.

  • We do need the size of it as well.

  • And remember, magic numbers are not good generally.

  • So I'm going to replace this with alien size which is something

  • that I haven't declared yet.

  • So I'm going to go into constants and I'm going to say,

  • alien size is equal to 12.

  • Remember, that's how you avoid magic numbers.

  • Magic numbers are bad.

  • Try to avoid them.

  • It's not always 100% necessary depending on the context,

  • but it's usually good practice-- almost always.

  • So again, alien size, alien size.

  • I'm going to just make it easier to read by putting this on the next line.

  • So an x and y, a width and a height, and the image dimensions, which you can

  • just call with texture get dimensions.

  • And you can kind of just forget about what this is used for.

  • You can look at the C code and it maintains

  • a point a reference to the image data and does

  • some other stuff underneath the hood.

  • And that's why it's there.

  • But you don't really need to worry about this too

  • much to understand what's going on.

  • The important thing is that you understand the x, y, width,

  • and height of your quads.

  • That's the important bit.

  • So we're going to go into--

  • and by the way, let's also get the x and y to work correctly.

  • So I'm going to say x times alien size and then y times alien size.

  • And because we've laid out our double loop like this

  • and we're starting at zero, when we multiply by the alien size

  • we will get a quad that is at the right x,

  • y because we're doing it in 12 pixel increments

  • and we are making the quad 12 by 12 pixels as by specifying alien size,

  • alien size for the width and the height, and then texture get dimensions here.

  • And then we're inserting this new quad into this quads table here.

  • This quads table gets returned by the generate quads function.

  • And if everything goes according to plan, I can go into here

  • and say gframes aliens.

  • So remember, gframes aliens in our dependencies

  • is getting the result of this generate quads function.

  • And then remember we pass in gtextures aliens.

  • And let's also for good measure say--

  • oh, you know what I did?

  • Sorry.

  • Alien size-- I made a mistake.

  • This should be not alien size, this should be height.

  • And this should not be--

  • sorry.

  • This should not be alien size, this should be width.

  • This should not be alien size, this should be width.

  • And this should not be alien size, this should be height.

  • The reason that we're doing that--

  • and it was a bit of a brain fart on my part.

  • The reason that we're doing this is that this function is general purpose.

  • So now we've taken this function from being specifically intended

  • for alien splicing, alien cutting up the image,

  • to being usable for any image that we pass in.

  • And we can specify any width and height and it'll split it up

  • according to those parameters.

  • So that is the right way to do it.

  • Here is where you actually pass in alien size,

  • where you actually call the function.

  • So now we're actually using it for that intended specific use

  • case of the alien cutting up.

  • And I apologize.

  • There's a bunch of comments in the chat that I will respond to.

  • What happened there?

  • OK, do that again.

  • I will get to all those comments.

  • I apologize.

  • Just trying to make a little bit of room since we are--

  • this has been an hour and 40 and we're still a little bit behind here.

  • But, this is effectively how you cut up images and do it algorithmically

  • in a way that you have all your data lined up in a way that makes sense.

  • Now, with the image that Brenda showed us

  • earlier in the chat, which was a bit more--

  • I have it on another computer.

  • But, let's see, where's the [INAUDIBLE] picture at?

  • Brenda, if you wouldn't mind posting that--

  • was it Brenda that posted that?

  • It was Brenda, right?

  • Yeah, Brenda if you wouldn't mind reposting

  • that just so it's on my other machine.

  • I can click the link I think-- actually no,

  • it wouldn't work on that because it's not on the stream.

  • Sorry, scratch that.

  • I'm just going to go into images and just look up Space Invaders Deviant

  • Art.

  • That should pull it up, right?

  • Maybe not.

  • Not seeing it in here.

  • But if I can find something that looks similar--

  • so I'll tell you what.

  • I can show you the idea.

  • A sprite sheet, if we look at a spreadsheet that's

  • kind of all over the place.

  • So by the way, these are sprite sheets.

  • What we've been using is called a sprite sheet, where a bunch of your sprites

  • are put together in one sheet, one picture

  • if I didn't already specify that.

  • Trying to look for one that's got a bunch of different data

  • all over the place, that's not uniform to sort of showcase this idea.

  • I guess for example something like this.

  • So this is a bunch of sprites that are different sizes.

  • So notice that these ones are wide, wider than they are tall.

  • But these ones are all--

  • well, these first four, first eight rather, are pretty uniform.

  • But then these two are kind of wider than the other ones.

  • For sprites like these, and for the link, if you look at the link

  • that Brenda just posted in the chat, it's that same kind of idea.

  • For any sprite sheet that's not uniformly laid out,

  • you can't do what we just did.

  • You can't algorithmically define the individual sprites,

  • the individual quads, because they just don't chop up evenly.

  • They're not along some sort of grid, which we're doing in our examples.

  • These are on a very tight 12 by 12 pixel grid, and these are on a very tight 16

  • by 16 pixel grid, eight by eight pixel grid.

  • This grid is essential to be able to chop your sprites up algorithmically.

  • And so if you're doing this and you have a bunch of are in your game,

  • try to find a way to put everything on a grid

  • so that you can write some piece of code to chop up your sprites for you

  • and not have to manually lay out where all the sprites are.

  • This isn't always feasible because not all sprites are the same size.

  • For example, even some certain Mario sprites are different sizes.

  • NES Mario sprites have different sizes, different width and heights,

  • and they're laid out in sort of different weird ways.

  • And that is a kind of situation where you

  • have to manually lay everything out and figure out where the slicing occurs,

  • if not chop up your sprites manually in advance

  • and then load them individually.

  • But yeah, for doing most 2D games, most sprite work,

  • you can figure things out in a sort of grid like manner.

  • Now, before I get into the chat I'm just going

  • to make sure we got this working in drawing to the screen.

  • I'm going to go into main.

  • And now down here where I have the draw function,

  • remember in passing gtextures aliens as the image data.

  • So I still need to draw the image.

  • I'm still drawing the image no matter what.

  • The second parameter is this reference to gframes

  • aliens, which is the quad table, remember.

  • This table full of these rectangles that have an x, y, width, and a height.

  • And I need to index into it because I can't just

  • draw the quad table as it is.

  • I need to draw a specific quad.

  • I need to tell the love.graphics.draw function,

  • draw the sprite with this quad.

  • So draw like this window of the sprite, right?

  • And just for kicks I'm going to say one, so the very first

  • sprite which should be this one right here.

  • It can actually be kind of hard to see, this purplish looking one,

  • so I'm going to do the second one, so number two, this bluish looking one--

  • so, two.

  • And if I run this, fingers crossed, it works.

  • Wow, I actually wasn't expecting it to work.

  • That's actually pretty amazing.

  • Just because live coding is a little bit much.

  • But, it's simple and it works.

  • And now I will read all the messages in the chat.

  • And now, by the way, if that's not clear,

  • we have the capability to actually draw rows

  • of individual aliens and our spaceship, move it around,

  • while only using one texture for everything-- which is also more

  • performant for your GPU, by the way.

  • So, sorry, chat.

  • Got a lot of chat to catch up on here.

  • OK, shift works.

  • I drew a masterpiece draw.io.

  • I think I did see that.

  • We did see the masterpiece.

  • Zoomed out 25% or so, I think it got erased.

  • I did get erased.

  • Asley says, they couldn't handle my talent.

  • No, it was very impressive.

  • Actually, let's see what's there now.

  • Is there anything there now?

  • It's all gone.

  • Everything's erased.

  • That's so sad.

  • We had such an amazing masterpiece there.

  • It'll be in the video for all of eternity that we can look at it

  • and appreciate it.

  • Emoji is Asley--

  • Asley says she's the kappa face, and Bavich_knight's got the meat boy

  • in there.

  • Isotv-- oh, and by the way, we had a couple subscribers.

  • Bubullah and Xoxoff, thank you very much for following.

  • Isotv, just like printing the pyramid in Mario, yes.

  • It's very similar to printing the pyramid in Mario.

  • The same idea of taking two for loops, combining them,

  • and being able to do some operation iteratively, some two dimensional

  • operation.

  • It's something that you'll see time and time again in computer science.

  • It's something that you'll see time and time again in game development,

  • whether it's drawing maps, splicing tiles,

  • doing whatever-- laying out rows of enemies which we'll do in the future

  • as well.

  • Charles, is Lua like JavaScript?

  • Yes, in a lot of ways it actually is.

  • It uses very similar prototype inheritance model as JavaScript.

  • It uses anonymous functions in this very similar way to JavaScript.

  • So, a lot of code that you see, very promise like syntax

  • exists in Lua just like it doesn't JavaScript,

  • which you might get to in the future.

  • Probably not in this stream, but certainly in future.

  • Don't worry about it too much right now, says JP,

  • but I think the mic is crackling a bit or suffering from static.

  • Uh-oh, that's not good.

  • Hopefully I'm not brushing up against anything.

  • And I hope it's not suffering from too much static.

  • Oh, and let me--

  • apologies.

  • Tell me if this sounds any better.

  • Does that sound any better?

  • I think I might have forgotten to bypass the EQ, which should

  • make my mic sound a little nicer.

  • Dev, let me know.

  • I have a compressor on, just to limit the dynamic range of the mic,

  • and that might be distorting it a little bit.

  • So let me know about that as well.

  • Can it run in the browser like JavaScript, access the dom,

  • says Charles.

  • It cannot run in the browser and access the dom in the same way that JavaScript

  • can.

  • You can compile Love games and use those in the web browser using what's

  • called Mscript in, which basically takes your game and the Love binary,

  • compiles it into a form of JavaScript, and then executes it.

  • But you don't have dom control with that either.

  • Nicktheway says uptime.

  • What is uptime?

  • I have to figure out what that is-- uptime.

  • Oh, is that how long we've been up?

  • So we've been up an hour 53, I think?

  • Still somewhat new to Twitch, so a lot of these things are fairly new.

  • And Nicktheway aptly just followed.

  • Thank you very much for following.

  • What mic are we using?

  • We're using a Sennheiser--

  • what's this called-- EW100 G3 lav?

  • I am not a production expert so I could not tell you too much about it,

  • but it is a lav.

  • One day my lav-- will you been making some sort of platformer

  • or a dungeon crawl anytime soon?

  • Good question!

  • I would love to make one of those, either of those.

  • I made a platformer for the GD50 course, which by the way if you're unfamiliar

  • go to CS50.edx.org/games.

  • So that's the game of course that I taught.

  • I taught how to make a platformer, a Super Mario style

  • platformer with randomized levels, using a very cool sprite pack.

  • We didn't cover dungeon crawling and I personally

  • am a big fan of dungeon crawlers.

  • So I tink that'd be a really cool project to work on.

  • That would be a definitely multi stream project.

  • And this project itself is also going to probably be multi stream, multi-day,

  • just because it takes a while to--

  • we're covering a lot of somewhat new ground

  • today, actually, with quads and stuff like that,

  • which we haven't looked at before.

  • And I want to make sure that everybody understands where we're going

  • and can follow along.

  • Thank you, Onedaymylove, following as well.

  • That was a very funny sentence to say.

  • Are the sprites on a black square uniform with the background

  • or are they on their own?

  • So I missed five minutes and couldn't understand, Asley says.

  • The sprites are on a black background that we

  • are going to make the same color as that background in our game.

  • And we're going to do that for the purpose of avoiding

  • making that background alpha, just because that color I believe

  • with the limited palette is also a component color of many of the sprites.

  • I'm not 100% sure if that's the case.

  • But I believe that black color is part of many of the sprite's actual artwork.

  • So we don't want to necessarily convert the black color to transparent,

  • or do a fill transparency, because that will make some of the sprites

  • look a little bit wacky.

  • So what we'll do is, we'll just make the background of the game the same color

  • as the sprite.

  • And I think it already is.

  • It might be slightly off color.

  • And that will make it look like we're playing on a-- that we're

  • drawing the sprites transparently.

  • There isn't really ever going to be a case where

  • they overlap anything else so we don't really

  • have to worry about transparency.

  • So it should be fine.

  • But thank you for the question.

  • It's a good question.

  • I missed 10 minutes, says Bavich_knight.

  • It just froze.

  • Sorry about that.

  • Hope you're able to go back and scroll through it,

  • or catch what you missed on YouTube.

  • But we haven't gone into anything too intense because all we're doing

  • is just catching up on the chat at this point.

  • I am back, but your masterpiece is gone, Asley.

  • But I'm back again, Xoxoff.

  • But it's back again-- oh, is the masterpiece back again?

  • I do not see it on my screen.

  • I checked my PC volume.

  • It was much louder than what it's usually at,

  • that's why I also heard the crackle.

  • But at normal volume it's actually not even audible.

  • Oh, I wonder if your speakers are just distorting, because that's

  • possible-- hopefully not.

  • What did I do again to the mic?

  • I added a compressor-- not right now, but I just

  • bypassed-- we have an EQ and a mixer.

  • So I have a lab going into a mixer.

  • The mixer is applying EQ settings to the sound

  • that I'm outputting to the stream.

  • So basically, the sound is made up of different bands of frequencies

  • and the EQ is an eight band--

  • I think it's an eight band.

  • 1, 2, 3, 4, 5, 6-- it's a seven band.

  • So there are seven discrete sections of frequencies

  • that you can lower or accentuate, accentuate or attenuate.

  • And so EQ just takes out some of low frequencies like the HVAC

  • and accentuates some of the higher ones for a more crisp sound.

  • But there's also in the software a compressor to lower the dynamic range

  • and also make up some of the gain.

  • And so potentially it could distort at certain points,

  • although it shouldn't be per what I did to test the volume.

  • Maybe if-- Asley says she hears it now, so maybe there is a little bit.

  • So hopefully it sounds a little bit better now.

  • Otherwise, you can have a chatbot that keeps track of the uptime, says Isotv.

  • I'll look into that.

  • I'll look into that.

  • Still fairly new to Twitch, so there's a lot of stuff I should look into.

  • OK, if you can all hear the crackling I'm

  • going to go into the settings for the audio.

  • And I'm going to lower the output gain.

  • Tell me if that fixes it.

  • So does that sound any better?

  • Let me know.

  • I just lowered the makeup gain on the compressor.

  • Brenda says, no sound issues there.

  • Is there any way to separate sprites completely from the background,

  • says Asley.

  • You would use transparency.

  • So we're not doing it in this example.

  • But you would make your sprites with a transparent background in some editor.

  • A lot of games back in the day didn't have image formats

  • that had transparent backgrounds.

  • So what they would do is, they would--

  • hopefully it's not the mic itself, because I just lowered all the makeup

  • gain on the compressor.

  • So it should have fixed any distortion that existed.

  • I'm not sure.

  • I can potentially lower that EQ, the upper frequency

  • bands on the EQ and that might work.

  • But yes, you would draw your sprite with transparency in advance.

  • But games in the past didn't have transparency.

  • So let's see.

  • Like, some of these for example--

  • see this drawing here, this sprite image here of this gorilla?

  • It has a background that's very different than any color

  • that you find in the gorilla itself, and this is deliberately

  • so that there would be no clashing of the background color with the sprite.

  • And so what the game would do is, it would

  • check for any pixels that matched some sort of color key

  • and it would just not draw them.

  • It's sort of similar to how a green screen works, I guess, chroma keying.

  • But it would just basically do an, if color

  • is equal to blah, blah, blah, don't draw that pixel,

  • but much more efficiently than that using hardware.

  • But that's essentially how games used to work back in the day.

  • Now, the image format itself can store the transparency value

  • with what's called an alpha channel, the A, the RGBA.

  • And that basically tells the--

  • when open GL is rendering, whether to draw it

  • with the opacity or not effectively.

  • In the middle column from the fourth, bottom row, looks like a spaceship.

  • In the middle column--

  • 1, 2, 3, 4, 5, 6, 7, 8, so roughly around here.

  • Oh, this one?

  • This pink cyan looking one?

  • Yeah, that looks pretty good.

  • I like that one.

  • And I think someone else suggested-- what was it?

  • Which one was it?

  • It was another one of these.

  • Crap, I forget the exact one that someone mentioned.

  • But yeah, that's a good one.

  • Crackling sound is still there.

  • OK, I'll try to investigate the crackling sound afterwards.

  • I'm not sure what it is.

  • I apologize.

  • Hopefully it's not too distracting.

  • Oh, and shout outs to NASA for landing the Mars Lander.

  • People in the chat are--

  • I'm not following it right now, obviously, but people in the chat

  • are saying that it's landed.

  • So that's awesome.

  • You heard it today on CS50 on Twitch as well.

  • I'm going take a drink and then we're going to dive

  • into drawing a bunch of aliens, and our spaceship, and moving the spaceship.

  • See the Snapple there in the screen as well?

  • Yeah, stay hydrated, chat.

  • OK, so we haven't done a lot of coding.

  • We have done a fair amount of new conceptual work.

  • So today, the leap from going from individual textures to quad generation

  • is kind of a hard step for some folks.

  • And being able to go over it slowly and make sure everybody's on the same page

  • and being able to draw through the algorithm,

  • even though this now looks like kind of a mess,

  • it's kind of important that we understand how that works.

  • So that's why we took our time.

  • But now we're going to go into some stuff that's fairly straightforward--

  • not as groundbreaking, I guess, or as revolutionary as generating quads.

  • But that's a big piece that you'll use in probably any game going forward.

  • Markv101, thank you for joining.

  • Hello, good to have you with us.

  • Next idea for your game, says Andre, should be a Mars Lander game.

  • What is that game?

  • There is a game like that.

  • It was in-- was it just called Lander?

  • Lunar Lander?

  • Oh, it's a video game genre.

  • It's not even an individual game.

  • Oh, OK, it is an individual game but it's also a genre.

  • Something like this.

  • This is like vectorized landing of the Lander onto the moon.

  • Yeah, it'd be very appropriate for today if we were doing something like that.

  • I'd have to research how--

  • because this looks like it would probably

  • use a different collision formula.

  • It would have to actually calculate the vector angle, the-- no,

  • actually rather the surface normal of a vector of--

  • sorry, the normal of a--

  • the individual normals of the terrain, the terrain

  • vectors, and the surface normal.

  • Basically if you have a surface, imagine my hand is a plane,

  • the surface normal would be whatever arrow is coming out

  • of it towards the basically exterior.

  • And the surfaces tend to only have one normal for lighting calculations

  • in 3D engines typically, but you can also use it for various other things.

  • For example in Super Mario Galaxy--

  • let's load that real quick.

  • And I don't know if this has been officially confirmed by Nintendo,

  • but the world was made up by circular, or spherical, oblate spheroidal, masses

  • to simulate planetary interactions and just

  • to make it feel more like you're in outer space.

  • And so Mario could actually walk around 3D spherical objects

  • as if they were flat, right?

  • And the way that it's thought that that worked

  • was that you would just calculate the surface normal off

  • of any given part of the mesh and orient Mario that way on the terrain

  • so that his body was always kind of--

  • basically he was the surface normal.

  • His body was parallel with it.

  • And that gave it the appearance of him walking on the planet.

  • And so you would do kind of the same thing with this.

  • You would figure out, what's the surface normal of the individual vectors making

  • up the--

  • or I guess they'd be rays.

  • Would they be rays?

  • No, I guess they would be--

  • they'd be line segments but you could think of them as vectors.

  • You'd figure out the surface normal of all of these

  • and then you would just orient the lander kind of in the same way,

  • is my intuition.

  • I'm sure there are many different ways you could do it.

  • Kavabongo and Ki11ercrow, thank you very much for following.

  • So anyway, back to what we were about to do.

  • Let's take this new quad idea that we have implemented and draw some aliens.

  • Well, let's actually, let's draw a ship first.

  • We were going to decide what the ship was going to be.

  • So I'm going to, in my source folder--

  • do I want to make subfolders, or do I want to just make it all into one?

  • We can probably just do it all in one for today.

  • We don't have to go into separate subfolders.

  • I'm going to create a ship.lua class.

  • And what this is going to do--

  • Bavich_knight, normal is you could draw a perpendicular line coming out

  • of a plane surface, correct.

  • [INAUDIBLE] said I'm too lazy to go to bed.

  • Can't wait to start the CS50 games course after I

  • finish the web programming course.

  • This is so fun, says Isotv.

  • Awesome, thank you so much.

  • I'm glad you're enjoying it.

  • Quickly, make a robot that brings you water.

  • Oh, wait.

  • Hey, am I very late, says Oshkosh32.

  • Relatively-- we've been up for about two hours.

  • We haven't done a ton of coding because I've been taking it a little bit slow.

  • I've been looking at some conceptual stuff.

  • Scrin26, thank you for following.

  • We're looking at some conceptual stuff.

  • And I just realized the chat--

  • I don't think the chat's been up this whole time, which

  • is horrible by the way.

  • I apologize for that.

  • That should now be-- it should now be up.

  • Let me make sure.

  • Yeah, the chat hasn't been up this whole time.

  • That's terrible.

  • I apologize.

  • I think I must have hit something in the CS50, in the chat here or something,

  • and then it got rid of it.

  • But no, we haven't been--

  • you're not terribly late.

  • We basically just talked about how to splice a texture into subsprites.

  • And we set up our window.

  • We looked at a sprite generator, got a texture, decided on our resolution,

  • did a whole bunch of stuff like that, set up our window,

  • used push, went through the process of splitting up a texture into quads,

  • which are sprites--

  • essentially what are sprites, effectively-- drew it to the screen.

  • And now we're about to get into moving--

  • well, getting one of those sprites to be our player, moving that player,

  • and then doing the same thing with aliens.

  • Jobcoachin says, I'm still learning C. So wait, really?

  • We are doing Space Invaders-- kind of appropriate, says Asley.

  • Space for the lunar Lander game?

  • Is that what you mean?

  • There's the chat again.

  • Man, I hate the fact that I didn't have the chat up.

  • Ugh, man, because I love seeing it in the video.

  • And now it's not going to be in the video for like two hours.

  • Oh, well, you learn from your mistakes.

  • What are those on your fingers says, Callmegm?

  • Just rings I got on Amazon--

  • just a red, and a green, and a blue.

  • Fun story, I had a finger on my other--

  • sorry, my index finger ring, I had it on this index finger.

  • I took it off and I put it on my other finger,

  • on my left hand which you see as my right hand in the stream.

  • And my finger got--

  • well, it was too small for my other finger.

  • So this finger got swollen.

  • And because it got swollen I was unable to take the ring off.

  • I tried using soap and Windex and the string

  • technique or the floss technique.

  • It wasn't working.

  • My finger got too swollen.

  • My finger was about twice as big as my finger normally is.

  • So I had to go to the emergency room and get

  • the ring sawed off of my finger, which I had never known

  • was a thing that people do.

  • So now I have two rings that match, because I originally

  • got three rings in a set, and then one ring that's sort of a UV light sensor

  • ring that my best friend got me as a replacement for that.

  • And that was actually last Thanksgiving, because

  • very appropriate that we mention that.

  • It's a one year anniversary of going to the emergency room

  • to get a ring sawed off of my finger.

  • So that's a story.

  • OK, what happened to the chat?

  • Should have mentioned it earlier.

  • Yeah.

  • I have a keyboard shortcut on the keyboard here and it's C. If I hit C,

  • the chat disappears from the video.

  • And I must have hit it at some point and it disappeared

  • and I didn't notice it because I was so focused on what we're doing.

  • But yeah.

  • Better the ring than the finger, says Brenda.

  • I agree.

  • And yes, it was terrible.

  • But it was a fun, humorous experience.

  • I'm just glad that my finger didn't get amputated.

  • I'm glad that it didn't get so swollen and so blood starved for so long

  • that it had to get amputated.

  • That would've been like, the worst thing.

  • At least it would've been on my left hand, though.

  • So hey, I still have my fingers on my right hand.

  • Anyways, we want a class for the player.

  • So we want to have a ship that we can move left to right, just to get

  • started, demonstrating this quad technique that we've

  • looked at in comparison with moving something around,

  • moving an image around like we've looked at before.

  • Actually, have we moved images around before?

  • This would be the first time we've actually moved something

  • freely around because with tic-tac-toe we moved a cursor, a virtual cursor,

  • around.

  • With Snake, our Snake was constantly moving on its own

  • and we just manipulated its movement.

  • And with the memory card game, we just--

  • was that mouse driven?

  • Did we just clicked on the cards?

  • Yes, I believe it was just mouse driven.

  • So, this will be the first time we actually

  • move a sprite around with the keyboard.

  • So I'm going to say, player--

  • sorry, ship, this will be the player, is equal to class with brackets.

  • And what that's going to do--

  • and first of all, if you don't have the class library

  • they're unfortunately named.

  • But if you go to the H-U-M-P library, Love 2D,

  • and it's unfortunate that they named it that.

  • But it's one of the biggest libraries for Love.

  • Help Utilities for Massive Productivity, they have a class .lua within that

  • library.

  • Download that.

  • That class library will allow us to use object oriented programming

  • in our game.

  • And I already should have a copy of it already on my hard drive.

  • Actually it's in the folder here.

  • I'll just copy it from there.

  • I'm going to go into Space Invaders, into lib.

  • I'm going to copy it into my lib folder.

  • And then I'm going to go into dependencies.

  • And then above push, I'm going to say class is equal to require lib/class.

  • And now what this has allowed me to do is

  • almost like using a new syntax in Lua.

  • Class is an object that basically does a lot of the object oriented stuff

  • for you that you would normally have to do with meta

  • tables and other weird stuff in Lua.

  • It's a bit ugly.

  • But thanks to the class libraries, part of the H-U-M-P library,

  • you can just use this.

  • You can basically say, ship is going to be an object of type class, which

  • just means it's going to be an object.

  • And any ship object that we instantiate from this definition

  • will have the properties of a ship.

  • Asley said, do not read that as H-U-M-P. I know most people probably don't.

  • [INAUDIBLE],, are you using the 12 inch MacBook?

  • Is this a 12 inch MacBook?

  • Good question.

  • It is a 13 inch, from 2013.

  • It's a bit old school, relatively.

  • So now I've included this class--

  • class?

  • This class library.

  • I can say ship is equal to class.

  • I'm going to create a new class.

  • Jacobchaussen says, I'm missing too much code.

  • So I'm going to pass this time.

  • Sorry, I'll be faster next time.

  • No, definitely check it out on YouTube.

  • I'm trying to go kind of slow but also kind of relatively quickly

  • and not cover too much of the syntax just because we've

  • covered it in prior streams.

  • And this stream will be very long as it is.

  • We're already at two hours and we barely have much going in the stream.

  • But yeah, definitely tune in next time, tune in when you can, Jacobchaussen.

  • Good to have you with us.

  • Apologies if I am going a little bit too fast for some folks.

  • If you have any questions, specific questions about what we're doing,

  • as always toss them in the chat and I'll be happy to try and answer them

  • as we go.

  • And I apologize if I missed it, but scrin26, thank you for following.

  • Sorry, apologize if I already said that thank you for that.

  • But if not, thank you very much for following.

  • So ship is equal to class.

  • Now what we can do is, I can say a function ship init.

  • This is what's called a constructor.

  • I think we've talked about the basics of objects before,

  • but a constructor basically let's us say something is a ship with parentheses.

  • That'll make a new ship in our code.

  • Every ship that we want-- and there's only going to be one--

  • is going to update over time and it's going to draw over time.

  • And typically the naming convention is render even though Love uses draw.

  • Most engines will have render as their--

  • that I've seen, I'm sure it varies--

  • but they'll have render as the word.

  • And the init function, this is the constructor.

  • This is where we're going to set up the ship

  • to have the information it needs to perform its work.

  • And what the ship is going to want to do is basically just exist at the bottom.

  • And I can't draw too much at the bottom.

  • I'm going to reload actually, and bye bye to that because I don't know

  • how to scroll the screen right now.

  • But our ship is going to be here at the bottom.

  • It's going to have a sprite.

  • So I know that I'm going to want to draw this sprite.

  • So it's going to at least need to have a reference to what

  • sprite we want to use.

  • And I think Babic and Asley suggested specific sprites that we

  • can use for the ship in the chat.

  • But it's also going to, because it's going to move left to right

  • it's going to need to have an x and it's going

  • to have a y, and obviously of course a sprite.

  • In this case, that's going to be a quad, right?

  • And because our table that we created earlier is numerically indexed,

  • this sprite or quad can really just be a number--

  • one to however large the table is, the table of sprites.

  • And this information is what all of the aliens as well are going to have,

  • but they're going to have slightly different behavior.

  • And if we wanted to be really super good at engineering our application

  • and proper, we would make a base class probably called entity.

  • And that entity class would have an x and y and a sprite

  • and maybe some other information.

  • And we would then create a subclass.

  • We would have something like entity as the parent class,

  • where every entity is anything that we can see.

  • Or rather, it's a little bit hard-- you can't

  • see it super well because of the chat.

  • But this entity class can then split off and have

  • children classes, child classes.

  • In this case we would have a ship and an alien.

  • So notice that the ship comes down from the entity and the alien

  • comes down from the entity.

  • These are children and this is the parent.

  • Now, I'm just saying well we could do.

  • We could do this.

  • It would be a bit too much work, I think.

  • But this is something that we should think

  • about going forward because we will probably

  • implement more complicated games.

  • And for a lot of games this kind of hierarchy, this object hierarchy,

  • makes sense.

  • And ship, you could then have multiple ship types and multiple alien types

  • and they would share the information that their parents all have.

  • Scroll is shift and three fingers or five fingers.

  • Let's do it that way, entity as base class and then subclasses.

  • We're going to avoid that just because it's a little bit too much,

  • and we're not getting a whole lot from the entity.

  • We will potentially tackle that when it actually makes sense,

  • I think, for a later--

  • no, we will deal with entity, actually.

  • We'll deal with entity.

  • That makes sense.

  • So entity.lua, this will allow us to demonstrate

  • how to use inheritance with this library which kind of makes

  • sense to demonstrate.

  • Entity based class, anything that moves and has a sprite.

  • So entity is equal to class.

  • And then in the init function we're going to say, self.x is equal to x,

  • and self.y is equal to y, and self.sprite is equal to sprite.

  • Where sprite is a number, so one to whatever the--

  • 256, because that's how many sprites are in the--

  • is that the 12 by 12?

  • Yeah, that's how many are in the 12 by 12 table.

  • And an x and y to be its position.

  • And that's all we need for the entity class for now.

  • The ship is going to inherit from entity by using this underscore

  • underscore includes equals entity.

  • And this is specific to the class library that we're using.

  • And this is all you really have to remember in order to make

  • a class a subclass of something else.

  • So in this case, this ship class is saying that it

  • is a child class of the entity class.

  • It's going to inherit everything that entity

  • has, all of its functions and all of its data, while adding some of its own.

  • And I have to remember if we have to actually--

  • do we actually have to call init?

  • I think maybe we might have to.

  • I'm not 100% sure.

  • We'll figure that out in just a second.

  • Oh, actually no because what we do is, we could just--

  • now what we can do is, we can just call init off of ship.

  • And because entity, the entity class, already specified an init function

  • it will allow us to get this behavior for free.

  • We don't have to actually implement it in the ship class.

  • Same thing for the alien class, actually.

  • So I'm going to create a new file called alien.lua.

  • And alien class inherits from entity, moves toward ship, and can shoot.

  • So, alien is equal to class.

  • And just like we did before with the ship,

  • I'm going to say underscore underscore includes equals entity function

  • alien update function alien render.

  • And now we have two classes, two separate classes,

  • that their behavior is going to branch.

  • The ship is going to be controlled by the player.

  • And we'll be able to check for keyboard input and move it around.

  • The alien is going to be autonomous and it's going to be AI controlled.

  • But it's going to be very simple.

  • It's going to move left to right and then when it gets to a certain point

  • it's going to move down.

  • Then when it gets to a certain point it's

  • going to move left, and then down, and then right, and then down, and then

  • left, and then down, and then right, in this sort of infinite loop

  • until it gets to the bottom of the screen.

  • And then when it collides with the player,

  • we're going to get a game over function--

  • we're going to get a game over result, the game over state in our game.

  • And so that's what we're doing here.

  • I'm going to get another sip.

  • My mouth is a little dry.

  • Asley says, is self similar to this in JavaScript?

  • Yes, it is.

  • And self as well in Python.

  • Truesound, hey from Australia!

  • Thank you for joining us.

  • Thanks for the awesome stream.

  • Out of interest, where in the series would you

  • recommend someone new should begin?

  • Thank you very much for joining, Truesound.

  • I would recommend looking at the Snake and--

  • actually, probably the memory card and tic-tac-toe

  • are a little bit easier than Snake.

  • Check out Snake as well.

  • Snake is a two part stream.

  • But the tic-tac-toe and the memory card game are very easy to get into.

  • A lot of the other videos that we do are not game related

  • and are not as from scratch implementational.

  • So like, the stream that David and I did on Python

  • and then regular expressions are a little bit more

  • conceptual and do dive into some programming stuff.

  • But they are separate.

  • So the dependencies between those are not really there.

  • So wherever you want, but game specific stuff I would probably

  • do tic-tac-toe or memory card.

  • And Asley herself actually suggested memory card, so that was awesome.

  • And I'll say it again.

  • If you have any ideas for games in the future,

  • definitely toss them in the chat.

  • All right, cool.

  • So we have the alien class, we have the ship class,

  • and we have the entity base class.

  • So the base class means a class that other stuff

  • can take the attributes of and then become a more specialized version.

  • So a Honda Accord is a special version of a car.

  • A car would be the base class, it's an abstract idea.

  • An entity is an abstract idea.

  • Automobile is an abstract idea of which a car is a subclass

  • and a Honda Accord is a subclass of a car.

  • And then a Honda Accord EX would be a subclass of the Honda Accord.

  • But the EX might be a property of that Honda Accord rather than a subclass.

  • But that's kind of the idea.

  • Asley said, I'm not the first one to suggest it but I'd really

  • love to see the typing test game.

  • I'll think about that one.

  • That would be fun.

  • I would actually like to do that.

  • And that one wouldn't be too hard, either.

  • But yeah, so we've looked at the idea of object oriented hierarchy now.

  • So again, just to recap and make it a little bit more

  • clear what we're talking about, we have the entity based class.

  • And so this would be base class, or parent.

  • And then these would be subclasses, or children.

  • And I can't write super well on the edge here looks like--

  • children.

  • And this is like day one object oriented programming stuff.

  • But that's essentially what we're doing.

  • And object oriented programming is very prevalent in games

  • so I would encourage you to try to understand what this means and think

  • about ways that you could create your own object hierarchies,

  • think about the real world as object oriented

  • to get your mind used to the idea.

  • And then think about how you can structure your own code

  • to be object oriented because this way you can save yourself a lot of work.

  • We talked about it earlier, how now the ship doesn't

  • need to have its own x, y definition, the alien doesn't

  • need to have its own x, y definition.

  • They both don't need to have their own sprite definition.

  • It's a simple example.

  • I was kind of hesitant to use it just because there's not a lot of data

  • that we're trying to save here.

  • But the idea is simple enough to illustrate the concept.

  • And the concept is very handy, especially

  • as you work on large code bases.

  • So that is object oriented programming, day one.

  • And we might do a stream on more complicated uses

  • of object oriented programming.

  • This concept of the child class adopting what the parent class has

  • is called inheritance.

  • So, I'll write it here.

  • This is inheritance because these are inheriting from the entity.

  • They're inheriting the attributes and the functions of the entity class.

  • And there's other ideas, like polymorphism and composition

  • that we can take a look at in another stream where they become pertinent.

  • But that is the idea.

  • I'm interested in more than games but I do love games.

  • Really appreciate the advice.

  • Yeah, absolutely.

  • Thank you, Truesound, for joining.

  • Glad you're enjoying it.

  • If you're starting from the beginning of CS,

  • CS50.edx.org if you aren't already taking that, says Brenda.

  • Yes, shout outs to CS50.

  • Can you come to the same game without using object oriented programming,

  • like only using functional programming, says Un3okapi?

  • Yes, you can.

  • And if you mean functional programming in the sense of like Haskell or F

  • sharp or functional JavaScript for example, yeah,

  • absolutely you could do it with that.

  • Or you could do it with procedural programming,

  • if you're referring to procedural programming or imperative programming,

  • being like your data is encapsulated in functions that you call

  • and your logic goes top down, which is what C is.

  • And you can actually do it in that as well, because most games actually were

  • all implemented in C back in the day.

  • It was C-- assembly, and then C. There were really no ubiquitous OOP languages

  • in game development prior to the late '90s--

  • I mean the mid '90s, just because C++ was relatively expensive

  • for the console hardware at the time, although it was used in the mid

  • '90s to late '90s for DOS programming and stuff like that.

  • But if you mean--

  • either way, functional or imperative slash

  • procedural, which the two names kind of get mixed up with each other

  • but they're very different.

  • You can make games in both of them.

  • You can make games however you want.

  • All programming kind of, at the end of the day,

  • is just a different way of thinking about solving the same problem.

  • So if you can get comfortable in a particular environment

  • you can do pretty much anything in that environment.

  • Studying a bachelor of computer science at Deakin University in Australia,

  • but I figured CS50 would be good supplement material to that.

  • Well, thank you for tuning in.

  • I'm glad that you are finding it to be so.

  • Polymorphism is where I am stuck in Java.

  • Well, take some time to get it, says Bavich_knight.

  • Polymorphism is an interesting idea.

  • It is essentially just being able to use an interface

  • to talk to objects as if they are all sort of the same kind of object.

  • This applies really well in the context of--

  • like, generic programming is kind of using

  • that idea where you can have lists that use the different data

  • types, that contain different data types but they work the same way.

  • You can have, for example, a monster base class

  • that your function does things to, regardless

  • of whether it's a goblin monster or a elf monster or a demon monster.

  • Like, no matter what it is, because it inherits from Monster,

  • any function that operates on monsters also

  • operates on goblins, elves, demons, et cetera, as long

  • as it implements that parent class.

  • Anything that operates specifically on goblins

  • won't affect elves, demons, et cetera, because polymorphism

  • doesn't apply to sibling classes.

  • It only applies to the classes that implement

  • from a particular common parent.

  • And that's what polymorphism is, just basically allowing different classes

  • to sort of function, behave, differently according to the same interface,

  • or behave similarly but differently using the same interface.

  • It's a bit of a weird thing.

  • You kind of have to actually use it to understand it completely.

  • But it's pretty simple once you get the hang of it.

  • And you'll see it quite a lot.

  • Staypeaceful, thank you very much for joining.

  • Started creating a Pong game in Python.

  • Ooh, Pygame, yeah, that's--

  • well, Pygame might be what you're using.

  • You might be using something else.

  • You might be using PyGL or something like that.

  • So, yeah Python would be great to make some games in sometime as well.

  • Un3okapi, got it mixed up, yeah.

  • Functional programming is very fun as well.

  • So check that out.

  • Functional programming is super cool.

  • I want to get better at that.

  • Functional programming is definitely a different way of thinking.

  • Hi, Colton, thank you very much for the work you are doing, Unsigned.

  • I started in Edx but I got stuck in Pong because I

  • couldn't find the file font.ttf.

  • So If you could please guide me would be great.

  • A big merci from Paris, says Unsigned.

  • Font.ttf just means, I think you just need to have any font.ttf file

  • in your project, so font/font.ttf.

  • Go to dafont.com if you don't have the specific font that we downloaded.

  • So dafont.com, go to pixel bitmap fonts, go to any font.

  • I think we use Press Start to Play in the course, which is on the first page

  • actually if I can find it.

  • Right-- not this one, sorry.

  • Which one did we use?

  • We used-- I forget offhand which one exactly we used.

  • But just name it font.ttf.

  • Put it in a font/font.ttf folder or in the base directory where your main .lua

  • is if the string is just font.ttf, and that will load it.

  • OK, cool.

  • So, let's go ahead and do some actual drawing of stuff.

  • So, ship.lua, we're going to--

  • also, another cool thing.

  • Because all of the ship and the player--

  • sorry, the ship in the alien class don't really

  • have different logic in terms of how they render stuff we can just say,

  • entity render, define an entity render function,

  • and just say love.graphics.draw gtextures aliens and gframes aliens.

  • And then remember, this is where we can actually

  • make it different for each individual alien or each individual ship.

  • We can just say, self.sprite.

  • And then we want to say self.x and self.y.

  • So this function here will take whatever this current entity that's calling it

  • and use its self.x, its self.y, and its self.sprite, and draw it on the screen.

  • So now what we can do is, first we have to go into dependencies

  • and we have to actually include all these files.

  • So in dependencies.lua require a src/alien,

  • require src/entity, and src/ship.

  • And what I like to do is alphabetize everything.

  • So notice that we're requiring the library stuff first.

  • So this is actually something-- this is not an alphabetical thing, but more

  • of a semantic detail where I have the libraries being loaded first

  • so that they're at the very top.

  • And then all of my own code is loaded after that.

  • And everything here is in the same directory,

  • which is the source directory.

  • But every module that we're importing follows--

  • it's in alphabetical order, so alien, constants, entity, ship, util--

  • just easier to scan through the list and see whether we're missing a module

  • or not.

  • Because if you have things out of order it's

  • very hard to mentally sift through all of your requires,

  • especially if this were like 10 times longer than this.

  • It can be a bit overwhelming.

  • So I'm going to go into my main.lua and I am going to create a ship.

  • So, I'm just going to say ship is equal to ship.

  • And we're going to put its x, y--

  • we want to be at the bottom of the screen approximately.

  • So we can say virtual width divided by two minus alien--

  • do we have, is it alien size?

  • What is the-- alien size.

  • Minus alien size divided by two.

  • And then that's going be at virtual height minus 32.

  • It's an arbitrary amount.

  • Could make it 24 as well.

  • Let's do 24.

  • And then it also takes in a--

  • because remember, we inherited from entity.

  • So notice that alien doesn't have an init function.

  • Ship doesn't have an init function.

  • But entity has in an init function.

  • And because any alien and ship is also an entity,

  • because we did that includes equals entity,

  • it'll have access to the init function.

  • The init function being this ship constructor here.

  • This ship with parentheses, this is the same thing as the init function.

  • This is just the way that the class library works.

  • So I can specify, then, as my third parameter, if I'm not mistaken,

  • the sprite.

  • And we didn't actually decide yet what we wanted our sprite to be.

  • So let's go back into the sprite image.

  • We had some suggestions in the chat.

  • I think the last one I saw was Bavich_knight say this one right

  • here, the cyan one.

  • I think Asley also recommended another sprite.

  • I'm not sure--

  • I thought it was sort of like a small yellow--

  • oh this one, right here.

  • So between the two.

  • So let's vote in the chat, between the two, the contenders are this one,

  • so we'll call them red, so red ship, this is Asley's ship.

  • And then we'll get a little bit of a competition here.

  • And the blue slash teal pale ship, the cyan one, between those two.

  • That'll be our player ship.

  • Cast your votes.

  • So JPguy saying red ship.

  • Jacobsen, red ship.

  • Oh, we got a blue.

  • Unsigned saying blue.

  • It's two to one.

  • Blue-- oh, it's even, 2-2!

  • Uh-oh, blue came in the lead.

  • Blue came in the lead!

  • Oh, it's 4-2.

  • All the people who say red, pizza's on me.

  • Oh, that's compelling isn't it?

  • Red, so 3-4 it looks like.

  • Sorry 3-5, 3-5.

  • 3-6, 4-6.

  • Tell you what.

  • We'll do it fun.

  • First of all, let's figure out what index these sprites are located at.

  • So, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16--

  • because we iterated through our entire sprite sheet, row by row,

  • and we just table dot inserted and we just went to the next line, da da da,

  • went to the next line, da da da, they're ordered 1, 2, 3, 4, 5, 6, 7,

  • 8, da da da up until 16.

  • And then it goes to the next line 17, 18, 19, 20, 21, 22, 23, 24.

  • So what we can do is, we can basically figure out which row it's on.

  • So in this case, Asley's is on the fourth row, right?

  • So, let's say we wanted to use Asley's which I don't think won.

  • I think Asley's was--

  • it was 4-6, or 4-7.

  • Unfair.

  • Jacobchaussen says.

  • People are now asking, what pizza?

  • What pizza?

  • What pizza is Asley going to get?

  • We're going to say, if we want Asley's ship index,

  • ship index is going to be equal to.

  • So hers is on the fourth row.

  • So basically what we need to do is, we need to multiply 16 by 1

  • and then add the x offset, right?

  • So multiply 16 by the number of rows.

  • I guess before the actual--

  • before this one, the number of rows, so in this case it would be three.

  • So three rows plus 1, 2, 3, 4, 5, 6, right?

  • So, 16 times 3 plus 6.

  • Right?

  • So, 16 times 3 plus 6--

  • so 16 being the number of aliens per row and three being the number of rows

  • before our alien and six being the x index of that row.

  • And then I'm going to say, this is ship index right here.

  • So if I load this and I run this, is it not visible at the bottom?

  • It might not be.

  • Oh, you know why?

  • Because we're not rendering the ship.

  • So we actually have to call ship render.

  • So is it up here, right?

  • Yep, ship render.

  • So now it's still not rendering.

  • So, let's make sure that it is--

  • let's try and render it.

  • Let's set it up.

  • The screen might be too small to see it, actually.

  • So let's say 64.

  • Let's make sure that I am seeing it appropriately.

  • Oh, wait.

  • No, I did that right.

  • Yeah, I did that right.

  • Right?

  • No?

  • Uh-oh, live coding time!

  • What did we get wrong?

  • So virtual width divided by 2 minus the alien size divided by 2.

  • This is correct.

  • So that's the x position that we're going to draw the ship at.

  • Entity draw self.x, self.y.

  • Yep, that's correct.

  • Lua knows I didn't win and refuses to render.

  • But we're drawing your ship.

  • This is your ship.

  • OK, so let's figure this out.

  • So 16 times 3 plus 6, that's the ship index.

  • Virtual height minus 64.

  • So that should be in the middle of the screen.

  • Love.graphics.draw aliens.

  • Ship-- oh, this is why.

  • So, if you define an empty render function in the subclass

  • it will overwrite the entity render function.

  • And that will make it draw nothing, which is not productive.

  • So now we have the ship.

  • Now it's there on the bottom except it's the wrong ship, unfortunately.

  • So where did we go wrong?

  • It looks like it's--

  • wait, is it this one?

  • 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16.

  • 1, 2, 3, 4 5, 6.

  • Did I do the math on that wrong?

  • I don't think so.

  • Let's see, 1, 2, 1, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5, 6, 7, 8 [INAUDIBLE]..

  • So why is that not drawing the ship index, the ship, the correct ship?

  • So if I add--

  • OK, so let's add nine to that.

  • See if it changes.

  • Why is it-- is my math wrong?

  • That's the right ship.

  • Are there 17?

  • Are there?

  • 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16--

  • no there are 16.

  • I count 16.

  • 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16.

  • I count 16.

  • No, the sprites are not padded.

  • The sprites are not padded at all.

  • Huh.

  • What in the world?

  • 16 times 3 plus 9.

  • What?

  • We didn't screw that up, did we?

  • Oh.

  • So this is why I like to start for loops in Lua

  • by one, because the loops are inclusive.

  • So we actually created quads that are one tile past the edge for each row.

  • It's not that it was zero.

  • It's not that the table was zero indexed.

  • It's that the quad generation was zero indexed.

  • So what we needed to do was, we actually needed to say,

  • until sprites told minus one, because the loops are inclusive,

  • for one until some range.

  • And it includes that range.

  • It's not a less than or equal to--

  • or, not a less than, it's a less than or equal to for loop.

  • So that was the bug.

  • So modify, if you're following along, your loop to be minus one there.

  • And now if we go back to main.lua and make that six, boom.

  • It works.

  • So that was fun.

  • You'll also notice that the background color is black

  • and the sprite background color is a slight purplish look.

  • The reason, Andre, is because they one index everything so it

  • has the same effect for a lot of algorithms.

  • The reason that it's less than for most algorithms in C and other languages

  • is because it's zero indexed.

  • The bug, Asley, was the ba ba ba ba ba-- in our util.lua.

  • Because we decided to zero index this loop and I one index in the course.

  • But we zero indexed it just to make the math here for the calculating

  • the quad a little bit easier.

  • You don't have to minus one on the x and y anymore.

  • But we do have to minus one from the sprite's tall and sprites wide

  • to the end of the loop because it's inclusive.

  • It's not exclusive like it is in for loops and like a less than loop in C.

  • It's like a less than or equal to loop.

  • So you want to make it minus one because we

  • were going past the edge of the texture and basically creating

  • an invisible sprite every 16 sprites.

  • So we were essentially filling our sprite table

  • with empty image data-- not useful.

  • But now we have a sprite.

  • So let's move it.

  • Let's move the-- oh, sorry, sorry, sorry.

  • I wanted to humor both both people that decided

  • to contribute an idea for their--

  • so, shout outs to Alsey and Babic.

  • Their names are now in the source code.

  • Ship index Babic will be--

  • and am I spelling that right?

  • I apologize, Babic, if I'm spelling your name wrong.

  • Nope, I'm spelling it right.

  • Babic decided we wanted to use the sprite down here, way at the bottom.

  • Where is it though?

  • Right here, this one.

  • So it's actually kind of like the opposite.

  • It's the very bottom here.

  • So, which row is that?

  • That's 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12.

  • So it's 12 and then 1, 2, 3, 4, 5, 6, 7, 8, 9--

  • 12 and nine.

  • So now if I wanted to use Babic's I would say, ship index Babic.

  • And there's Babic's ship.

  • So shout out to Babic.

  • But we can do it even better.

  • We can say, ship index equals math.random 2 is equal to 1

  • and ship index Asley or ship index Babic.

  • This is a pattern for the ternary operation

  • that you would see in C or Java, which is the question mark colon.

  • So now we have a random chance of getting either of these two.

  • So math.random 2 will give us either one or two.

  • And if it's one, then ship index Asley, or ship index Babic.

  • Easy.

  • So, 50/50 chance, one or the other.

  • And what we're going to do is make sure that we seed our random number

  • generator.

  • So math.randomseed os.time.

  • And then if I run this, this time is Babic.

  • This time it was Babic.

  • This time it Babic.

  • This time it was Babic.

  • Hopefully I didn't get this wrong.

  • Did I get this wrong?

  • Maybe I did.

  • No, the random is equal to in ship index Asley or ship index--

  • oh, sorry, because I didn't actually write ship index in here.

  • That'd be my bad.

  • There's Asley's, there's Babic's.

  • So now we get both.

  • Both of the ship contenders are in the game.

  • Yes, I apologize.

  • I'm a little-- the chat is now catching up to let me know that I was wrong.

  • I caught the bug quickly enough.

  • But thank all of you for letting me know.

  • JPguy with the-- what's the name of that emoji?

  • Crap, I forgot.

  • Pog Champ.

  • Game knew which ship was better, since Isotv.

  • Ooh, burn on Asley.

  • But yeah, so now we can humor both sides using awesome random number generation

  • and say a 1 in 2 chance that it's either or, right?

  • So now we have Babic or Asley.

  • We don't have to hard code one or the other.

  • Now what I want to do is, I want to test to see whether the user has

  • pressed left or right on the keyboard so we can move the ship left or right.

  • And thank you Rangero T-W-T, Range-o-tweet,

  • if that's how you pronounce your name, for following.

  • Thank you very much.

  • Change that index there.

  • Hides all the pizza from Isotv, says Asley.

  • OK, so I want to say if the user's pressed left or right,

  • move the ship left or right.

  • Now, what we've normally been doing is in

  • love.keypressed we've been doing that.

  • Love.keypressed is a callback function that executes only

  • when the key has been pressed one time and will not

  • trigger when you hold it down.

  • What we want to do is hold the key down and move left or right.

  • So, Love has a handy feature, a handy function,

  • called love.keyboard.isdown which can take a string key.

  • So you can say, if love.keyboard.isdown left then--

  • remember if statements need thens--

  • ship.x is equal to ship.x minus ship speed times delta time.

  • And we haven't defined ship speed.

  • But remember, delta time is how we scale any movement operations such

  • that if one frame has elapsed, we'll move one frame's worth, one

  • sixtieth of a second's worth, of that whereas if two frames have passed,

  • it'll be twice as much, the delta time will be twice as much,

  • so it'll move twice as much the amount.

  • So it will effectively scale to however much time

  • has passed since the last frame, which won't

  • be much of a problem in this example.

  • But when you do have games that are more complicated and a lot of time

  • can potentially pass between an individual frame

  • and you want it to run smoothly and consistently on different people's

  • computers, you want to scale it by delta time.

  • If you don't, this will run as fast as the CPU is capable of running it

  • and that will not serve us any good.

  • Now, this is a design decision.

  • You can say, do I want to put ship speed in the ship class?

  • Or do I want to put it in the constants.lua?

  • And I don't know if I have strong feelings on it.

  • But probably putting it in constants.lua will be what we do.

  • And let's say I want to move-- every second I want to move 80 pixels.

  • I'm not sure how good that's going to be.

  • A second is a fair amount of time and that's about a third of the screen.

  • That might be too slow.

  • Let's set it to 100.

  • We'll see how that feels.

  • So remember, since this is getting multiplied by delta time,

  • this is effectively how much time the ship move per second--

  • 100 pixels per second.

  • So now that works.

  • If-- and let's say else if here--

  • love.keyboard.isdown right, then.

  • And I had a bug where I did--

  • there's a subtle bug where you can do elseif and that creates a new block

  • and triggers a syntax issue.

  • So be careful about doing that.

  • Elseif is different syntax in else if.

  • Elseif as one word can trigger scoping issues differently than else if.

  • I don't know if I said that right.

  • The two are different.

  • Ship.x is equal to ship.x plus ship speed times delta time.

  • So now if this works, which it doesn't.

  • The reason that it's not working is because I'm not actually

  • calling the update function in main.

  • And that's important.

  • We want to actually do that.

  • I'm going to go to main.

  • And I'm going to, in my update function-- notice

  • that love.update takes in delta time.

  • So you can pass that delta time to anything you want.

  • And any class or any object that needs to do these overtime operations

  • can scale that operation with that same delta time value, that same float,

  • right?

  • So I can say, ship colon update delta time.

  • And now I can move my ship left to right.

  • Now unfortunately, there's a bug where it moves past the side of the screen.

  • We don't want that to happen.

  • That fortunately is pretty easy to fix.

  • I can just say math.--

  • what is it?

  • Math.

  • It's going to be the greater of these.

  • So, math.max will always set the value to the greater of two values.

  • It will return whatever the greater is of two values.

  • And basically by saying the max of zero or this subtraction on the ship.x,

  • we're basically saying if it goes less than zero,

  • if we set the x to negative 1, well math.x is going to say

  • that 0 is greater than negative 1.

  • So it's always going to only set it to zero if we try

  • to move beyond that point to the left.

  • So it's effectively clamped our value within the left border of the screen.

  • And I do the same thing with math.min to virtual width minus alien size--

  • or alien size is fine because the ship's the same size.

  • Do the same thing with math.min because math.min

  • will return the lesser of two values.

  • So if I'm smaller, if I'm at an x-coordinate that's less than

  • the virtual width minus alien size, which will be taking into consideration

  • the alien being 12 pixels and reaching the right side of the border,

  • we don't want it to go farther to the right than that--

  • the value of that is going to be less than the ship

  • increasing its x by some value if we reach the edge of the screen.

  • And so it clamps it to the right side.

  • And my hands are in the wrong spot because I'm flipped--

  • right, left.

  • But that's what math.max and math.min--

  • those are hard to say, especially when your mouth is dry.

  • Those are hard to say but those are the functions

  • that allow you to restrict a value from exceeding

  • some value in the negative or positive direction-- math.min, math.max.

  • And so now I should be able just move left like that.

  • Pressing left, can't go any farther than that.

  • Pressing right can't go any farther than that.

  • So we've effectively clamped our value within the edge of the screen.

  • So we're getting and closer to the Space Invaders actual implementation.

  • After pizza, liquid beverage [INAUDIBLE]..

  • I would guess the ship because the aliens

  • have their own specific vertical speed, right?

  • I apologize I don't remember what I asked.

  • Keep the information encapsulated.

  • Hopefully we don't run into another wall passing entity like with Pong.

  • That was unfortunate.

  • 3D physics can be quite challenging.

  • But Ereney did a great job helping us fix that.

  • That was awesome.

  • I think I missed that stream, but I had the same thing

  • happen in the Pong version in Love 2D in the course, says Majordufai.

  • Oh, yes, because in the course if you--

  • we don't implement interpolated collision detection.

  • So if-- I appreciate Bavich_knight, three sodas for Colton.

  • If you don't interpolate your collision detection

  • and you have something increasing in speed, which is what we did in Pong.

  • If you kept playing the game long enough the ball

  • would just keep going faster and faster and faster.

  • If it gets to a certain point between one frame and another frame

  • it'll actually move beyond the paddle.

  • And so you won't be able to do an A, A, B, b collision

  • check between the two objects because they don't ever overlap.

  • It moves so much in one frame that they never touch.

  • So you need interpolated collision detection for a case like that.

  • And interpolated collision detection just means between frame A and frame B,

  • if the distance between them is larger than the size of the object

  • then you need to basically check for every object size,

  • check the gap of every object size between the object and the target--

  • sorry, between the object and its current position between the two frames

  • and then check for A, A, B, B on each of those points.

  • And it's a more sophisticated collision system.

  • And you're thereby adding collision checks, more collision checks than one

  • every frame which can get expensive.

  • But that's how you do more realistic collision detection

  • and that's how you would want to ship ultimately

  • something that can function properly for an actual release,

  • if you're going to release your game.

  • Otherwise you have a bug.

  • But yes, good point Majordufat for mentioning that.

  • OK, cool.

  • So we have ships.

  • Sorry, we have one ship.

  • And we have a ship that can actually randomly change

  • to accommodate both Asley and Babic's artistic decision, so two ships.

  • Now what we need to do is decide how to make aliens appear.

  • We're approaching the three hour mark.

  • We're probably going to keep going for a little bit

  • longer so we can kind of cement this, because we're at a point where--

  • I don't think we can comfortably leave the stream with as much

  • as we've implemented today.

  • But we have the ship moving.

  • The next big piece would be having aliens

  • appear, so having a bunch of aliens in a grid at the top of the screen,

  • like we do in Space Invaders.

  • And then another important piece of the puzzle

  • is having the ship be able to fire projectiles.

  • And the projectiles are fairly easy.

  • The aliens are fairly easy.

  • We might be able to do that within the stream,

  • and then maybe finish the next stream with actually making the aliens move

  • down, have different levels, have a score, and all that sort of thing--

  • and be able to die and lose lives, and have lives,

  • and have a screen that tells you how many lives you have.

  • That could be a good part two of the stream.

  • But today we'll try and get all the aliens

  • on the screen with the laser shooting from the ship

  • and call it a stream for today.

  • So, alien is going to be the class that we use for this.

  • And what I think would be the best way to do

  • this is to simply have a table of aliens that we can just

  • iterate over and render, right?

  • So I can say--

  • actually, let's do-- let me go up here and here?

  • I think it's aliens.

  • So I'm making his global.

  • And I'm actually not defining them as galiens,

  • just because in this particular context it's a little bit--

  • doesn't feel right.

  • I guess technically you'd probably want to do it, galiens, gship.

  • But we're not going to use them throughout our project.

  • We're only going to use them in main.lua.

  • So it doesn't really necessarily make sense, but you could go either way.

  • But I'm going to create a table.

  • And basically all I want to do is, I want to say for y is 1 until--

  • how many aliens do we want wide and tall?

  • How many was it in the actual Space Invaders game?

  • Let's go into this, Space Invaders.

  • We have 1 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 4, 5, 6, 7, 8, 9, [INAUDIBLE]..

  • Looks like 11 between both of those screen shots.

  • So we'll do 11, 11 ships wide by five tall.

  • OK, so ships tall, it's going to be five.

  • Do for x equals 1 to ships wide, do-- and ships tall, that'll be five.

  • Ships wide will be 11.

  • So we can go into constants.

  • We all need util any more.

  • We can get rid of that.

  • I don't know if we'll need entity anymore.

  • I'm going to just close that.

  • Ship we'll leave open for now.

  • Alien we'll leave open because we will need that.

  • And dependencies we will need in a little bit.

  • So constants, ships wide equals 11 and ships tall equals five.

  • Remember, avoid magic numbers.

  • So, generate rows and columns of aliens.

  • So again like I said before, the 2D loop, the iteration, this pattern,

  • we've seen this many times.

  • We saw it before when we did Snake, when we had the grid.

  • We saw this in the memory card game where we had cards laid out.

  • We saw this in the--

  • oop, what did I have?

  • Yes, not ships wide says Brenda, aliens wide.

  • Yep, you're right.

  • Thank you very much--

  • aliens tall, aliens wide.

  • Let's fix that.

  • Yes, ships, since it's not the ship, yes.

  • Yes, correct.

  • You get 256 sprites, well, minus the two for the ships,

  • from which you can choose, right?

  • So if you convert a random int in one 256 position of the grid

  • it makes it more readable and less of a headache to implement.

  • Makes it more readable and less of a headache to implement.

  • [INAUDIBLE]

  • JPguy, we are getting to selecting the sprite

  • but I'm not sure what you are referring to because this particular part here

  • is going to create the alien objects.

  • Oh, well, that's even easier.

  • That's even easier, yeah.

  • No, yeah, to generate a random alien yeah,

  • we just need to pick a number between one and 256.

  • Absolutely.

  • But what we're going to do for now, we're just going to create a new ship.

  • So table.insert aliens.

  • We're going to insert into the aliens.

  • I got something in my eye.

  • Ouch.

  • That hurt a little bit.

  • Into the aliens table we're going to insert a new alien object with the--

  • and we're calling the constructor, the alien with parentheses.

  • And I'm going to say we want to generate them in a grid.

  • So we're not going to worry about the perfection of the grid at this moment.

  • We're not going to make sure it's perfectly centered and aligned.

  • We're just going to say, x--

  • [INAUDIBLE] off of x?

  • Oh, you know what I should do also?

  • Is get rid of this arbitrary draw call here,

  • love.graphics.draw, because it was just drawing an alien in the top corner.

  • Sirthranduil56, thank you very much for following.

  • We'll start off at the top left.

  • So we'll say x times alien size and y times alien size.

  • And then this is what JP was referring to.

  • We're going to say math.random 256.

  • And what we really should do is say, aliens--

  • is that what we want to do?

  • Do we have any constants in here?

  • We have the width and height but we haven't made this constant.

  • So we'll just say 256.

  • 256 for now is fine.

  • And so what that's going to do, that will now give it a random sprite value.

  • So we are creating a table of 55 aliens.

  • We are giving them a random--

  • or, not a random x.

  • We're giving them an x and y that's deterministic by this nested for loop

  • we've created.

  • So it'll create a grid.

  • They'll be right on each other, so they're not spaced out.

  • They're not padded, which we probably want to fix.

  • We can do that.

  • We can do that fairly easily.

  • We're going to not only generate them, but we have to actually render them

  • as well in our draw function.

  • So not only we're going to render our ship,

  • we're going to also render in a loop, draw all aliens, again

  • following this 2D pattern that we've seen time and time again.

  • For y is equal to 1 aliens tall do--

  • or actually, no.

  • We don't have to do that.

  • Because each individual alien is keeping track of its own x,

  • y we can do something even simpler.

  • We can use iteration.

  • You can use Lua's pairs enumeration function, iteration function.

  • So we can say for blank alien in pairs aliens do.

  • And if you're unfamiliar with what this is,

  • this is how Lua does iteration over a collection-- iteration

  • when there's only one collection type in Lua which is the table.

  • And so it receives a key value pair for every index in this function call

  • or every result of this function called pairs.

  • This function called pairs is part of Lua and it takes a table as an argument

  • and it will give you every key value pair in the table.

  • And we don't care about the key because we only did table.insert here.

  • Table.insert just inserts things starting at one.

  • So all the keys are going to be 1, 2, 3, 4, 5, 6, 7, blah, blah, blah,

  • blah, until we're at 55.

  • We don't care about the key.

  • We care about the alien itself.

  • The value is the object, the actual alien object.

  • So I can just say, alien render at that point.

  • Because remember, alien-- and we have to make sure not

  • to overwrite the render function.

  • Alien inherits from entity, and entity has a render function

  • that just draws itself, its x, y, and the sprite that it has reference to.

  • So super, super basic.

  • It's just going to maintain a reference because we specified a random sprite

  • index here as part of the constructor for the alien object.

  • You'll have a reference to that.

  • Each individual alien object has a reference to that, self.sprite,

  • and has its own self.x and self.y.

  • So we can therefore draw it.

  • So if I do this, I have a bug.

  • Main 59 alien render--

  • render.

  • Did I not to--

  • include equals entity, yep.

  • Mm-hm.

  • Entity does have a render function, yep.

  • Something is wrong.

  • What did I do?

  • Table.insert into aliens blank in pairs aliens do--

  • uh-oh.

  • Live coding, here we go again.

  • Attempt to call method render a nil value.

  • Did I-- I did include alien, right?

  • Yep, I did.

  • OK, it's definitely inheriting from entity.

  • Alien is doing that, includes equals entity.

  • The init function-- yeah, it is inheriting from the init function.

  • What's going on?

  • In pairs of aliens to alien render, yep.

  • There's a render function.

  • This is very strange.

  • We can do it, chat.

  • We can figure it out.

  • Let's make sure-- so it's saying it's trying to call the method render which

  • is a nil value, which means that the alien object

  • that it's getting from pairs aliens doesn't have a render function.

  • But that's not-- wait.

  • Aliens is here.

  • It's global.

  • We have access to it.

  • This is where I want to have--

  • Twohourstrike, should it be called class with the curly brackets

  • instead of the curly brackets?

  • No, you do need the curly bracket.

  • So in Lua, if a table or--

  • what is it?

  • How does the exact syntax go again?

  • If you have a function that takes a table as its only argument,

  • you can call that function using dictionary syntax.

  • Sorry, I keep saying dictionary interchangeably with table.

  • You can use these curly brackets as the function call.

  • So for example, I have a function called hello which takes in a table,

  • in print tab.text.

  • So let's assume that I wanted to call hello and pass it in a table

  • then like that, which has a key called text that has the value of the string,

  • hello.

  • So calling this function will basically print whatever that table's text

  • field is, which is hello, right?

  • So it'll just print hello.

  • However, part of Lua allows you to actually do this.

  • If your only argument to a function is a table,

  • you can just call hello with the curly brackets.

  • And it's the exact same thing.

  • And that is what the class, class, does is, its only argument is just a table

  • and so therefore you can call class with just the curly brackets.

  • Do we need the parentheses around the alien in the for enum loop?

  • Yes.

  • Yes.

  • The-- oh, wait, sorry, in the underscore alien?

  • No.

  • No, you do not need parentheses around these two.

  • These will work just fine.

  • Why is alien not rendering?

  • That is so-- that bothers me.

  • OK, we have a subtle bug here that we need to figure out.

  • Oh!

  • Nope, I figured it out.

  • It's stupid.

  • Well, it's not stupid.

  • It's a good thing to take into consideration.

  • Because alien was imported before entity,

  • the alien constructor-- this still gets called.

  • This gets called when we require it.

  • When we call require, this executes this line.

  • And when you see this dash dash includes equals entity,

  • it's going to look for this thing called entity

  • but because it actually came before this,

  • it's not going to know what that is.

  • And so it's going to be nothing.

  • It's going to be nil.

  • So this actually needs to go up above this.

  • Entity, when you load base classes because the way the library works,

  • you need to import that first.

  • And then what do you know?

  • It works.

  • But yeah, that was the bug that we ran into.

  • Be careful when you're doing that.

  • Base classes do need to be imported first.

  • JPguy says, damn.

  • All right, well again, that was cool.

  • Now we have aliens!

  • Now we have random aliens rendering to the screen, right?

  • Good thing you discovered that.

  • I would never have found it.

  • That is, yeah.

  • It's something that I struggled with at one point, I think.

  • It was a subtle issue.

  • Yeah, it can be tough to reconcile the alphabetical stuff with that.

  • But it's not too big of a deal often, because it's not usually

  • huge dependency chains where a bunch of stuff out of order

  • relies on other stuff out of order.

  • It's kind of like, we can kind of do that and kind of make them separate.

  • And so now it's alphabetical and we've sort of separated the idea

  • of what those are--

  • these being dependent classes and these being parent classes.

  • But yeah.

  • Quick call it entity AE.

  • I don't-- oh, AE entity, yes.

  • Yeah, yeah, that's beautiful.

  • Good thought, good thought.

  • OK, so we've got our aliens all running to the screen.

  • And the other problem is, if you're running it, if you're running the code,

  • you can see that the color is very different.

  • You can especially see it now that we have all of those ships rendering.

  • It may or may not be easy to see on stream.

  • I can certainly see it on my screen here.

  • And you can probably see it if you're running it on your screen at home.

  • So what you can do--

  • on a Mac at least, and because you're on a Windows machine--

  • if you're going to Windows machine you won't be able to do this as easily.

  • But you can't require entity in alien, says Math08.

  • You can.

  • You can certainly do that.

  • Putting it all in one place is better practice,

  • but yes you can require it in alien if you want to.

  • And I don't recall offhand whether Lua re-requires it at a certain point

  • and either overwrites it or includes it twice.

  • I think if it knows that it's already required it,

  • it'll be smart enough to not do it twice.

  • It's been a while since I've looked at it.

  • But yeah, that'd be another way to do it too.

  • You can require entity in alien so that you

  • don't have to worry about the dependencies getting screwed up

  • like that.

  • But then you're searching through potentially dozens or hundreds of files

  • looking for proper dependencies.

  • So it can be kind of a double edged sword,

  • so I'd be careful about doing something like that.

  • Oh,

  • Jacobchaussen says, why not change the game background to match it.

  • Well, good thing you brought that up.

  • That's actually exactly what we're going to do right now.

  • So I'm going to render the game.

  • I'm going to use an app on my Mac called Colors.

  • I'm going to click on this, click on my little handy dandy color picker,

  • click on that pixel.

  • It's going to tell me somewhere--

  • well, it should have.

  • It used to.

  • Why-- well, now I feel like kind of an idiot.

  • Normally, this application tells you what the color is, spectrum.

  • Thank you very much, Meeedo--

  • what is that?

  • I can't read that.

  • Meeedooe, thank you very much for following.

  • Crap, where's the-- normally there's a--

  • it gives you the hex code.

  • Where did the hex code display go?

  • Developer?

  • Grayscale slider, RGB sliders--

  • oh, there we go.

  • 20, 10, and 30.

  • So those are the alpha--

  • sorry, the RGB components of that background color.

  • So twice as much red as green, three times as much blue

  • as green, and therefore a little bit more blue than red.

  • It adds up to be kind of this off purplish color, which

  • you can't actually see individually on the color picker here

  • by itself because it's not juxtaposed against the pure black background.

  • But you can certainly see it if you're looking at the black background

  • with the sprites.

  • So, what we're going to do, take that color picker.

  • And then I'm going to--

  • so, it's 20, 10, and 30.

  • So what we can do is, get rid of this.

  • 20, 10, 30 RGB, 20, 10, and 30.

  • I can quit Colors, or at least get rid of it.

  • Let's quit it.

  • Now, Love 2D changed the way they did RGB with 11.1.

  • It used to be that you could just literally write in 20, 10, 30

  • in your Love.graphics.setcolor.

  • Now we actually have to do it a slightly different way.

  • So here's what we're going to do.

  • I'm going to say, Love.graphics.clear.

  • Love.graphics.clear will just clear the screen,

  • will just wipe the screen with a given color.

  • So, 20, 10, 30 was how we used to be able to do it.

  • We can't do that anymore.

  • Now we have to basically say, what is it?

  • It's over one, so it would be 20 divided by 255 and then 10 divided by 255

  • and then 30 divided by 255.

  • You don't have to put the parentheses there necessarily.

  • But that is how you now have to do it, because now

  • the love.graphics.clear, love.graphics.setcolor,

  • all those functions, they take in numbers from zero to one.

  • So by dividing all of those numbers that we just

  • got by 255, which is the upper bound for any of those numbers,

  • we get a value from zero to one.

  • So if it's 255, it'll just be one.

  • If it's 20 it's going to be whatever the fractional amount is over 255.

  • So that will give us the color that we want.

  • If we render the background now, it is indeed

  • the same sort of purple black color and everything looks homogeneous.

  • Not homogeneous, consistent.

  • So, yes.

  • Lua requires once, says Twohourstrike.

  • OK, good to know.

  • How can we stop Lua from rendering the same aliens twice?

  • Well, a couple ways you can do that.

  • You could have a table within which every time you generate a new alien,

  • you just insert that value and then you check to see on every iteration

  • whether that alien index exists in the table.

  • So just fill a table with numbers and basically do

  • a check to see if that number is inside the table.

  • Good question.

  • And you could optimize for speed by setting

  • the actual index, the actual key of the table to that number,

  • rather than making them values.

  • So that way you can do a simple almost constant time check to say,

  • if index table bracket five, which will return a value.

  • You can set those all to true and then that

  • will end up giving you the correct Boolean value for that.

  • But yes.

  • I don't think we'll implement that in this case.

  • But you could certainly add it fairly easily.

  • I would encourage you to try and implement it yourself actually and let

  • me know if you can or if you have any luck doing so.

  • Nestleeric, or Nestleeric says, finally caught a CS50 stream.

  • Feels bad, man.

  • Yeah, thank you very much for joining.

  • Glad you came.

  • It's about to end fairly soon.

  • We're going to finish a couple of things.

  • We're going to do the projectiles, or shooting up towards the screen,

  • and then maybe lay the aliens out a little bit nicer.

  • And then we'll have the foundation upon which we can actually do the game

  • behavior for the next stream.

  • And this stream was a little slower and didn't

  • cover quite as much, we didn't get it quite as far, I should say,

  • in the game implementation as we have done for prior streams.

  • But this stream is a little more complicated.

  • We've been covering new stuff, like the texture splitting and stuff like that.

  • So it's therefore in classes I've talked about object oriented programming

  • and using that and getting more modular with the design of our game.

  • But I'll post this on GitHub and everybody

  • can mess around with it a little bit.

  • And then on the next stream, which probably will be--

  • it's going to be tough this week because we have the hackathon,

  • so Nick and I are streaming tomorrow.

  • And then Andy and I--

  • Andy Chen, who is going to talk about biostats in r, the programming language

  • r if you're familiar, he's going to come in on Wednesday.

  • Jacobchaussen, sorry host, what's your name?

  • My name is Colton Ogden, so thank you for joining for today's stream.

  • You've been in here for the whole stream.

  • It's been a pleasure having you.

  • We're not done just yet, but just to give you

  • a sense of what we're doing for the week.

  • We have that CS50 hackathon this week on Thursday,

  • which is a very busy, very long event.

  • We probably won't stream on Thursday.

  • And it's an all nighter so probably won't stream on Friday as well.

  • And then it's the weekend.

  • We don't typically stream on the weekends.

  • The week after that I think we'll probably have time to finish it up.

  • If not this week, definitely next week we'll finish it up.

  • But we'll at least get it off the ground so that you can mess around

  • with the code if you want to before the next stream,

  • and I encourage you actually to tinker with it just to get a--

  • try and see you would do it compared to how I would do it for the next stream.

  • OK, so we've done all of that.

  • Aliens are now getting drawn to the screen.

  • We have the ship moving.

  • We have the same color background so everything

  • looks good, looks consistent.

  • So what we need to do next is shoot stuff.

  • We want our ship to be able to move, and not only move

  • but also shoot bullets, shoot lasers, shoot projectiles.

  • And I'm just going to make a projectile class.

  • These top level comments aren't super helpful in this instance,

  • but generally you want a top level comment

  • detailing how your class operates.

  • And the projectile itself you could think of as an entity.

  • It has an x and a y.

  • However, it doesn't have the same size as everything else.

  • And I'm not actually going to draw it with a sprite.

  • So, I think I'm going to make it its own separate class without deriving

  • from entity.

  • We're not going to derive from entity.

  • We're not going to worry about inheritance in this case.

  • Create an init function, our constructor.

  • We will need a update function.

  • And we will need a render function.

  • And we will also need to make sure that we require it

  • so that it can actually be used.

  • And so now, what we want to do is basically say, in our main.lua--

  • and we could do this differently elsewhere.

  • We could do this in the player class.

  • But the Player class will therefor, if we want to modify the list of aliens,

  • which actually we do anyway, so.

  • Essentially what we're going to want, the projectiles

  • are going to be their own objects.

  • And the projectiles are going to have a velocity.

  • And it's going to be negative or positive on the y-axis.

  • Shouldn't projectile be required after ship,

  • assuming that the projectile will fire at the ship's position

  • and that will need access to that information?

  • No, actually it will not.

  • The only reason that we need to require the--

  • it's good instinct, yes, and as I said, it's good thinking.

  • It is good instinct.

  • But technically we don't need to do that.

  • The reason that we needed to, for example, include the--

  • I forget what it was, alien?

  • We needed to include entity before alien, is

  • because this code, this line right here, executes on require.

  • So when require actually imports this file this line gets executed.

  • And that includes looking for this thing called entity

  • because we make a reference to in this call right here,

  • in this table definition.

  • However, if we only make a reference to a projectile in a function--

  • so in this case, any of the ship's functions or the alien's functions--

  • that code does not get executed on require.

  • So the symbol, projectile or whatever, if the projectile symbol itself gets

  • called-- which it will because we need to instantiate a projectile

  • in the update function--

  • that doesn't get called on require.

  • So by the time that actually gets executed,

  • require has gone through every single module and required it in advance.

  • Does that make sense?

  • It's different when you're calling it from a function versus when

  • you're actually calling this top level includes statement.

  • It's a little bit of a different use case.

  • But good intuition, good intuition.

  • So, in the ship class, basically in ship update--

  • you could do this in a couple of different ways.

  • You could do this in main.

  • I could do this in love.keypressed.

  • If I do this in love.keypressed, it's a global operation.

  • Pressing space is not something that the ship really does.

  • It's more the global game object.

  • So because projectile isn't vital to make ship compile or vise versa,

  • the order doesn't matter.

  • Got it.

  • Essentially, yes.

  • There is no technically compiling going on.

  • It's more, the time at which it looks for the symbol projectile is

  • different in the context of it being called in a function versus it

  • being at the top level of the module.

  • When you require a module everything gets interpreted top to bottom.

  • But function bodies don't get called.

  • They only get called when the function itself gets called with parentheses.

  • The function bodies are just, it basically

  • just tells Lua that this function exists in this place

  • but it isn't run through the code.

  • It's just saying, when you want to run through the code, when

  • you want to call this function, it's here, it's in this location,

  • if that makes sense.

  • Hope that makes sense.

  • So it's kind of not ideal to look at love.keypressed, the global callback

  • function, as the source of firing projectiles.

  • For escape it kind of makes sense because you're

  • looking at the whole game and trying to escape the whole game, as not the ship

  • but kind of the player of the game.

  • It's kind of a player action.

  • The ship action, even though you're controlling the ship,

  • it's not as wide reaching.

  • You're only controlling one ship and the ship

  • should have control over when it fires the projectile.

  • And this kind of comes down to how you sort of see the game.

  • And there's multiple different ways you could see the game and program this.

  • What I'm going to do is, I'm going to do it in the ship class.

  • I'm going to say, if love.keyboard.waspressed--

  • and this function doesn't exist, by the way.

  • We're going to make this function ourselves.

  • If love.keyboard.waspressed space then table.insert projectiles projectile up.

  • Now, this might look a little bit strange--

  • rather, not up.

  • Not just up but also x, y up.

  • And this x, y should actually be self.x, self.y up.

  • A couple of things here.

  • So first of all, we don't have access to this projectiles table.

  • And we could do this in multiple ways.

  • We could have a global projectiles table which

  • is in our main.lua, which is one way you could do it

  • and it would be fine for a game like this.

  • You can also pass in projectiles to the update function.

  • And this is a bit more of a better engineered approach to doing it.

  • And this is probably how I would encourage you to do it.

  • I would say in main.lua, therefor, we can

  • say local projectiles equals an empty table.

  • And now this projectiles table is in our main.lua but is not global.

  • We can't edit this arbitrarily across modules.

  • This is only visible within main.lua.

  • So we've tightened the scope on its accessibility, which

  • is important for something that is going to be

  • accessed by multiple things in different modules.

  • We're making it harder to screw it up, making it harder

  • just willy nilly add stuff to it.

  • And ideally the ship should be this as well,

  • and the aliens should be this as well.

  • So I can actually say, local aliens is equal to that

  • and then get rid of this, and then local ship.

  • And we're not going to instantiate the ship in this case.

  • But we'll instantiate it in the load function, as we've done.

  • And let's go ahead and, in our update function

  • remember I specified that the ship should also

  • update with the projectiles passed in as a parameter.

  • So now we can do that.

  • We can say projectiles.

  • So now the ship, when it updates, not only will it

  • be able to get the DT from the update function

  • it will also get the projectiles table and it'll

  • be able to make changes to that projectiles table.

  • Which means we can add projectiles to the projectiles table.

  • Now, when we add a projectile to the projectile table what

  • we want that to mean is that each of these projectiles

  • should update as well.

  • And by update, this will typically just mean moving up or down,

  • depending on whether they're going up or going down.

  • And as we saw in the ship class we specified

  • in the constructor for the projectile object

  • here that it gets the string up, because if we're a ship

  • and we fire a projectile we always want that projectile

  • to go up towards the aliens.

  • And we want it to take an x and a y as well.

  • So this is how we get access to information that's in our main.lua,

  • but within our ship class.

  • So we're modularizing our game a little bit more by doing this and passing

  • a bit more information across functions, but we're

  • tightening things up a little bit.

  • Yeah, uptime-- we should get an uptime bot.

  • It's been up for three and a half hours approximately.

  • We'll probably finish before the four hour mark with projectiles.

  • And then on the next stream we'll finish everything up

  • with the gameplay, the different screens.

  • We can use a state machine, actually.

  • It'll be a great way to introduce the idea of a state machine

  • into our game engine-- our game engine?

  • Our game here.

  • The state machine just being a way to move

  • between different states of our game, whether we're at the title screen,

  • whether we're at the actual playing the game,

  • whether at the, like, lost of life, et cetera--

  • game over.

  • We'll look at that, because we'll have time on the next scene

  • to do all of those fancy things.

  • But here we're passing in the projectiles table.

  • We're going to be able to add to it here.

  • So now I actually have to define what a projectile is,

  • how to render it, et cetera, right?

  • So what I want to do is probably just love.graphics.line because a projectile

  • really, really needs to be a line, just a vertical line.

  • Whether it's going up or going down it's going to look the same, right?

  • So love.graphics.line.

  • It's going to take in an x and a y, so self.x, self.y.

  • And it's going to have a--

  • it takes in another two arguments as well, the second x and the second y,

  • meaning where the endpoint of that projectile is.

  • An Isotv, yes, good intuition.

  • Can we use the projectile table to have the enemies shoot at us?

  • Absolutely, and we will.

  • We will be doing that eventually.

  • That is good, good intuition.

  • So let's first of all fill out the constructor definitions.

  • We have an x, a y, and a orientation.

  • And we can say self.x equals x, self.y equals y,

  • self.orientation equals orientation.

  • And the draw function should also, by the way, set its color appropriately.

  • And let's, just for the sake of ease, just

  • say pure red-- that's it, just R001.

  • So we'll just say 1 0 0 1.

  • That's full red-- zero green, zero blue, full opacity.

  • And then we want to set it back to white.

  • White is the default color for drawing operations in Love.

  • So, 1 1 1 1.

  • And then once we've started drawing the line at self.x,

  • self.y, we're going to say, self.x plus projectile-- oops, sorry.

  • We're going to say, just at self.x--

  • this is going to be the same x-coordinate, but self.y

  • plus the projectile length.

  • And projectile length is a constant we haven't defined yet.

  • So we can therefore define it.

  • Projectile length is going to be equal to, let's say five pixels.

  • And what I want to do actually is, when I press spacebar as the alien

  • I don't want to just instantiate the projectile on the player.

  • I won't actually instantiate it above the player.

  • I want it to look like it's shooting out from the player

  • because if I instantiate it at just where the player's x, y is,

  • it's going to spawn on top of the player.

  • It's going to look like the player's shot like from the middle of itself.

  • It's going to look kind of weird, and especially

  • if we do flexible collision detection where the projectile and the--

  • where the projectile and the--

  • ba ba ba ba--

  • where any projectile can interact with both the ship and any alien,

  • we're going to want to make sure we don't spawn the projectile on top

  • of the player or we'll kill ourselves, which is not ideal behavior.

  • And actually I just realized, because we're using A, A, B, B eventually

  • to do the collision detection for this, I'm

  • going to make the projectile a rectangle--

  • love.graphics.rectangle fill.

  • And now instead of saying an x and a y and then a second x and a y,

  • I'm setting an x and y and then a width and a height.

  • So in this case, the width is going to be one

  • and the height is going to be five.

  • It's going to start at x, y, the player's x, y.

  • And it's going to be one pixel wide by five pixels tall.

  • But I want to make sure that I set that to minus--

  • sorry, not on the x, on the y-- minus projectile size--

  • is it projectile size?

  • Projectile length.

  • Projectile length-- wait no, this is the draw function.

  • This is not where I want to do this.

  • Sorry.

  • Projectile length, yes.

  • So that is good.

  • So this is good.

  • I apologise if the chat is making it hard to see what's going on there.

  • I want to draw a rectangle of type fill at self dot--

  • and it's going to be a red rectangle because we're

  • setting the color to red right before it at self.x, self.y, width of one,

  • projectile length height-- so five pixels tall.

  • And then in the ship class, this is where

  • we're going to actually subtract the projectile length

  • from the y of the spawn position of the projectile, right?

  • And then in our main.lua now, just like we drew all of the aliens--

  • actually, I'm going to draw, before I draw the aliens,

  • I'm going to say for_projectile in pairs projectiles do projectile render.

  • And now every time I hit spacebar, I should get a projectile

  • that-- sorry, one more thing, one more thing.

  • We have to actually move the projectile.

  • So now if I hit spacebar, it will spawn a projectile and it will draw it,

  • but it won't actually move anywhere because it's not getting

  • an update operation applied to it.

  • So that's important.

  • We have to do that.

  • So I can say, if self.orientation is equal to up, then--

  • or I guess direction would probably be better?

  • Let's change that to direction.

  • Orientation kind of implies like a rotation, so let's direction--

  • self.direction, the direction it's moving.

  • So if the direction is equal to up, so if we're going in up direction,

  • then I can say self.y is equal to self.y minus projectile speed times

  • delta time.

  • Projectile speed is not a constant we've defined so let's do that.

  • Projectile speed is equal to, let's say, 120.

  • I don't know if that's good or not.

  • I don't know if it's balanced or not.

  • This is game balancing, this aspect of choosing variables that you think

  • will work, choosing values that you think will work, and then sort of fine

  • tuning them as you go to make sure that they're not too overpowered or too

  • underpowered, too frustrating.

  • So we've done that.

  • And then else if--

  • or I guess I should say else, because there's not

  • going to be any situation in which the direction of the projectile

  • is going to be not up or down.

  • So self.y is equal to self.y plus projectile speed times delta time.

  • And now if I run this, hopefully it should work.

  • Was not-- oh, right, we didn't do the key press thing that I talked about.

  • That's an important piece of the puzzle.

  • So Love 2D does not give you the ability to do single key press checking

  • outside of the main.lua function.

  • In the main.lua function you can go to your love.keypressed function here,

  • this love.keypressed key, and then check to see

  • whether a key was pressed on the current frame, or the last frame.

  • And that's what we're doing with Escape.

  • But it doesn't work if you're trying to test for this, the single press

  • behavior, inside of another module because there's no way to check

  • for love.keypressed for that given key.

  • You have to actually extend this class, the love.keyboard namespace

  • with your own functions or figure out some way to do it.

  • The way that I like to do it, and I believe I saw this in a forum

  • a long time ago and I decided to adopt it,

  • is you say, love.keyboard.waspressed index

  • key is equal to true in that key press function,

  • because remember this gets called in main regardless every single frame.

  • So I press spacebar, this will fire in main.

  • It just won't do anything if I haven't specified any logic for key

  • being equal to Space.

  • We've only specified if the key is equal to Escape we should quit.

  • But this actually fires for every single key press at all times for anything

  • we do.

  • It doesn't have any logic, so it's just empty function calls essentially

  • until we've defined some of our own custom logic.

  • So we can say, love.keyboard.waspressed key is equal to true.

  • And this is a table that we're creating called Was Pressed,

  • part of the keyboard namespace.

  • You can add your own stuff to any namespace you want to just like that.

  • It doesn't exist right at this moment in time,

  • because we haven't actually defined it.

  • So what we want to do is, in our love.load say,

  • love.keyboard.waspressed is equal to empty table.

  • And this doesn't exist in Love by default.

  • Love.keyboard exists and it has a lot of its own stuff, but was pressed?

  • Love.keyboard.iskeydown, for example, is a function that exists.

  • It's part of Love.

  • Was Pressed is nothing.

  • It's not a function or a table.

  • It's something that we're implementing right now ourselves.

  • So I can say, love.keyboard.waspressed is equal to an empty table.

  • Then, in our love.keypressed callback, whenever we press a key we can say,

  • love.keyboard.waspressed key is equal to true.

  • However, as some folks may be thinking, this

  • could cause issues because as soon as it happens once it'll always be true.

  • So if you want to check to see whether it's true at any time after that,

  • it's not really going to be meaningful.

  • So what we need to do--

  • I'm just making sure I didn't actually turn off my belt

  • pack, which it doesn't look like I did.

  • What we need to do is, we need to reset this every frame.

  • So every frame I need to say, love.keyboard.waspressed

  • should be back to an empty table.

  • And we can do that by saying, love.keyboard.waspressed

  • is equal to empty table.

  • And now it'll just get reverted back to an empty table

  • once we've applied all of our updates.

  • And all of our updates should be what has the checking

  • to see whether there's anything in this table.

  • So once you've done all that stuff, it doesn't matter.

  • We can then just clear it.

  • We don't need that information anymore.

  • It's used, it's done, it's gone, right?

  • I believe that is everything.

  • Oh, nope, sorry!

  • One last very important thing that we need to do

  • is, we need to actually define the function, love.keyboard.waspressed.

  • This function does not exist in Lua.

  • So we define it ourselves.

  • Could we also use false instead of an empty table, says Asley?

  • No, because we want to be able to check to see whether multiple different keys

  • have been pressed.

  • You could have a frame where any given key is set--

  • whether space is set, A is set, Enter is set.

  • If we just set it to true, any of those keys

  • will set it to true, and so any condition

  • that checks for any keyboard input will be true and that's not what we want.

  • We want specifically to check to see whether Space is checked,

  • or Escape is checked, or maybe some other key, left or right,

  • are checked, because those will get fired when we press them.

  • If we press left or right and if we set the table equal to true,

  • then if you press left or right we'll also shoot

  • and we won't move because left and right will also be checked, right?

  • Well, actually in that case love.keyboard.isdown would fire,

  • so it'd be a little bit different.

  • But every time we pressed left or right it would fire, it would be true.

  • And we're going to index into it that table anyway so it wouldn't work.

  • We need it to be a table that we can index into.

  • So all I'm going to do here is say, return love.keyboard.waspressed--

  • oh sorry, keys pressed, key.

  • And I apologize.

  • This should be keys pressed, and this should be keys pressed,

  • and this should be keys pressed.

  • I apologize if that's confusing.

  • Keys pressed is the table.

  • I apologize.

  • I mentally made an error here.

  • Love.keyboard.keyspressed is the table.

  • That's the table of keys--

  • sorry, that's why I think Asley said what she said about,

  • was pressed being a Boolean.

  • This should be called keys pressed.

  • I made a mistake.

  • Love.keyboard.keyspressed is going to be a table.

  • There's going to be all of the keys that were pressed on the last frame,

  • because we're going to, anytime somebody presses a key, record

  • it in that table with this line here-- love.keyboard.keyspressed at index key

  • is equal to true.

  • So if somebody presses Shift, then love.keyboard.keyspressed shift

  • is going to be true.

  • If someone presses spacebar, love.keyboard.keyspressed space

  • is going to be set to true.

  • So we can then say, if love.keyboard.waspressed space--

  • because what we're going to do, this function, love.keyboard.waspressed,

  • this is the actual function that's going to return true or false.

  • Love.keyboard.waspressed key takes in a key parameter.

  • And we can say return the Boolean that's at key

  • indexed into that keys pressed table.

  • So if someone says love.keyboard.waspressed shift,

  • it will return whatever love.keyboard.keyspressed shift is.

  • And if it's nothing, if nobody's recorded shift in the table,

  • it's going to be equal to nil.

  • And nil and false are interchangeable for how we're going to use it,

  • for an if statement.

  • So that is sort of the dichotomy between those two,

  • between the was pressed table and the keys pressed--

  • sorry, the was pressed function and the keys pressed table.

  • So let me know if you have any issues with that, if I wasn't clear.

  • I did make the mistake between the two but hopefully

  • I was able to explain it clearly enough.

  • This, therefore, allows us then on line 14 in the ship class

  • here to say, if love.keyboard.waspressed space, because now whenever

  • we press space in main.lua it will record that in the table,

  • table.insert into projectiles a new projectile self.x,

  • self.y, minus projectile length up.

  • And then in main.lua what we need to do also, one very important thing,

  • is for_projectile in projectiles pairs projectiles

  • do projectile update delta time.

  • And then, ba ba ba ba, make sure that's going well.

  • We have them rendering, we have them updating.

  • Now if I run this, this should work.

  • Whoops, global ship at line 11.

  • Oh, sorry, I wrote ship.x.

  • It should be self and I happened to get lucky in that I named--

  • see, this is why global variables are kind of an issue.

  • I named ship.

  • We had previously ship as a global variable in the main.lua module.

  • Because of that, here where I wrote ship.x and then it changed its x value,

  • it was actually manipulating that global ship value

  • which it shouldn't have been doing.

  • It should have been manipulating its own x value.

  • So here changing it to self.

  • But that wasn't a terrible problem.

  • But that's an example of where you can easily get global variables causing

  • issues with each other.

  • Now if I move left to right and I hit spacebar,

  • well, now I get projectiles that go through the screen.

  • The only problem is that these projectiles

  • will go on forever and ever and ever and keep rendering and keep updating.

  • So we could theoretically have like, hundreds of projectiles--

  • thousands, millions, I mean infinite, however many

  • until your computer exploded, right?

  • Which would be a lot because these aren't taking up very much memory, all

  • of these projectiles.

  • But it is iteratively updating and rendering

  • all of them, every single frame.

  • So you want to be careful of doing stuff like that.

  • What we're going to actually do is use what's called an object pool.

  • Actually, well, not really an object pool.

  • But we're going to enforce the lifetime of these projectiles

  • such that when the projectile goes beyond the edge of the screen

  • after up or bottom, it will just delete itself, remove itself from the table.

  • Or, main will clear it from the table, right?

  • But yeah, I mean, that's the basis for getting the ship rendering

  • and the projectiles rendering.

  • But there is a much more efficient way that we can

  • do it involving lifetime management.

  • Hopefully it won't cause a stack overflow, says Bavich_knight.

  • Yeah, I don't think in this case it would cause a stack overflow.

  • I think this would be a--

  • this is heap memory, so I don't think it would get a stack overflow.

  • I'm not sure exactly what issue you would get after a certain point.

  • But yeah, all of those things are not good.

  • Looks so cool, says Asley, yes.

  • And then JPguy says, alrighty.

  • Alrighty indeed.

  • We're at the 3:50 mark.

  • I'm going to commit all this code to GitHub.

  • It's been a long stream.

  • We've been taking things kind of slow and that's part of the fun of it.

  • And hopefully it's been fairly digestible.

  • I can try to go a little bit faster next time.

  • But I think we covered a fair amount of ground.

  • We covered projectile-- or not, well, we did just cover projectiles.

  • But we covered moving stuff continuously,

  • which we haven't really done.

  • I guess we did it in Pong for the Unity session, which is little bit different.

  • Same idea, but we haven't actually done anything like this in Love yet.

  • So it's actually been cool.

  • It's been very fun but my brain doesn't work anymore.

  • Lua is a stack language.

  • It's a language that runs on top of C, so yeah, by virtue of that it is.

  • You can get stack overflows with Lua because

  • underneath the hood you're still running the same memory

  • model for your application.

  • Twohourstrike, you are overwriting love.keyboard.waspressed table.

  • Yes.

  • Yep, overwriting it, setting it back to an empty table.

  • I like the interaction but I can understand

  • that you want to finish the project during streams.

  • Yeah, yeah.

  • No, I do.

  • I do like finishing the project.

  • Some projects are just infeasible to finish over the course of one stream,

  • honestly, for four hours.

  • Some of them, like if we were to make a dungeon crawler, that's like,

  • that could take weeks of continuous streaming.

  • And even if we were to stream like eight hours a day, some of those

  • could take a long time.

  • But by the way we are contemplating doing like a eight hour

  • super stream at some point, probably in the spring,

  • like a Python super stream or maybe a C super stream.

  • So if you're interested in that, definitely let me know.

  • That would be covering all of the basics of Python

  • for someone who has zero experience, or JavaScript

  • for someone who has zero experience.

  • Lua we've kind of touched on it a couple times.

  • A couple of the streams that we've done have sort of

  • built up the language and the syntax.

  • I tried to go over the lot of that for the Snake stream a while back.

  • But yeah, it's something that we could definitely do.

  • I think that'd be a lot of fun.

  • A lot of people get really exhausted doing streaming for that long.

  • I don't really get that exhausted to be honest with you,

  • if we can keep it casual.

  • I would get exhausted sticking to the script, I think.

  • That'd be the worst.

  • This is much better for me to do long continuous streaming

  • than it is to do a rigorous outlined sort of thing.

  • Having an objective and working towards it, it's also more fun.

  • But that's just me.

  • Let me know what your thoughts are.

  • It seems like everybody's having really positive things to say, though,

  • which is super awesome.

  • Thank you guys so much.

  • The pace was really nice for a newbie, says Unsigned.

  • Good!

  • I'm glad that it was-- because I felt like I was going too slow

  • but I'm glad that you felt the pace was good.

  • Favorite stream so far, says Asley.

  • Awesome, thank you so much.

  • Onedayinmylife says, I would not mind at all if you streamed for eight hours.

  • Yeah, that would be a lot of fun.

  • I think we'd have to do like a Python super stream for that or something

  • that a lot of people would like a lot.

  • I don't know.

  • We'll think about it.

  • This was so enjoyable and educational even though I have never heard of Love.

  • The video was so cool.

  • I'll definitely watch the second part of this.

  • Awesome, yeah, thank you so much, Jabcochasen, Jabe Co Chasen.

  • However you pronounce your, name definitely

  • let me know so I can say it right.

  • Jpguy, 24 hour coding stream, ugh.

  • If I can call in some ringers I think we could do that.

  • If we like David code for a few hours and I code for a few hours--

  • that's essentially what the hackathon is though, coming up on Thursday.

  • Kudos to Colton for doing this long without a break.

  • Yeah, thanks.

  • I'm glad I didn't drink a lot of fluid in advance because this would be rough.

  • Iso says, eight hours streams would be so awesome

  • but can't even imagine how taxing it might get.

  • It really depends on what you're doing, because I would

  • get super taxed if this were like a--

  • if I had like a strict script to follow and like, pages and pages of stuff

  • to go through and there was no conversation and no casual feel

  • to the atmosphere, this would be--

  • eight hours would be terrible.

  • But if we're just having fun and having a conversation

  • and making a game together and working toward something loosely,

  • but like on a path and having goals but not worrying too much

  • about whether we're sticking strictly to a timeframe, I could go forever.

  • It's not a big deal, right?

  • I think explaining it is what's making it slow.

  • John Blow, I watch his streams, dude gets a lot done in two hours.

  • Yeah, yeah, no, John Blow is super talented.

  • I'm waiting.

  • I'm super eager to see his programming language Jai, by the way.

  • I'm very eager to see that and try that out.

  • Yeah, he's very talented.

  • I think if this was just me coding and just saying, ah, blah blah blah,

  • doing whatever, I probably wouldn't be making Space Invaders first of all.

  • This is largely to be educational.

  • But if it were just like casual no explanation,

  • I think I could get a lot done, too.

  • But that's not super useful for a lot of people, I think.

  • I think this is good to converse and make stuff together.

  • Super stream for JS would be good.

  • We'll be in force, says Bavich_knight.

  • Awesome.

  • Yeah, we'll definitely consider doing--

  • we'll consider doing both of those.

  • You say the last name right.

  • Job Coachuson-- Cochasin.

  • J from Java.

  • Jobcochason, you say the last name right.

  • Cochason or Cochuson?

  • Andre, I can't really say fully about today.

  • I was busy but I was here on and off.

  • But the way you do these streams is great.

  • Awesome, thanks Andre.

  • Glad you think so, appreciate it.

  • Is a good stream.

  • Do you plan on going over entity component system in love 2D and Lua?

  • Entity component system, maybe?

  • It's something that we do a lot in Unity.

  • I would be happy to touch on it at some point maybe

  • for a more complicated game.

  • That's really not something that's meant for a game like this.

  • Like, a game like this does not need an entity component system.

  • It's way overkill.

  • But something like an RPG would benefit hugely from an entity component

  • system, and Unity games generally.

  • And Unity makes it really easy to do it.

  • So Unity is a great environment to test that out and talk about it.

  • We can talk about it more in another Unity stream, perhaps.

  • Brenda says, we should bring back the Breakout in C, piece it as a stream.

  • Yeah, that'd be addressing.

  • Yeah, that'd be cool.

  • We should take a look at it.

  • I'm not a huge fan of the Sanford Portable Library, though.

  • It's a little bit weird.

  • I feel like it's cumbersome.

  • And it's not super widely used.

  • I'd probably prefer doing Breakout in Love.

  • But yeah, good, good, good point.

  • Maybe just for history's sake we could do it.

  • Another interesting concept of a less interactive based stream,

  • the development of a full fledged game in real time

  • where a whole team is just working and communicating without--

  • mouse is in the way--

  • looking at the chat.

  • Yeah, maybe.

  • I feel like that'd be boring for a lot of people.

  • I feel like not a lot of people would watch that.

  • Only people that are super engaged, I think, in the process of doing it

  • would be interested.

  • But I can't imagine very many people would want to see that.

  • And also, how we would display like having multiple people's screens

  • and being to see what people are doing?

  • I feel like that'd be like a camera in a room looking

  • at a bunch of people on the computer and just a bunch of conversation.

  • I'm not sure.

  • It's a cool, interesting idea.

  • I think it would maybe work if you could see multiple people's

  • computers at the same time.

  • Yeah, one day can't wait to try out Jai.

  • Yeah, that'd be awesome.

  • The language looks cool.

  • I'm excited to check it out.

  • Is there any particular reason why you choose Lua as a language,

  • says Unsigned?

  • Mostly because I really like the Love framework.

  • It makes it super easy to make games.

  • And the language is pretty nice.

  • It's also very often used in the game industry, so a lot of engines

  • use it as their language, their glue language.

  • It's all over the place.

  • Isotv, are we having another stream tomorrow?

  • Yes.

  • We are having a stream with Nick Wong and he's

  • going to be talking about setting up a web server with AWS.

  • So if you want to create a web application or a lot of different stuff

  • in the cloud as opposed to your own physical system, we'll talk about AWS

  • and using an Apache server, using Ubuntu Linux.

  • And we'll talk about a bunch of other stuff.

  • And knowing me and Nick and how we do our streams,

  • it'll probably go off on a lot of interesting tangents

  • and explore a lot of cool ground.

  • So tune in for that one.

  • Let us know what you want us to talk about.

  • Love a Python super stream, says Otter.

  • Yeah, me too.

  • I think that'd be cool.

  • I think coding videos without comments are boring.

  • Cannot watch them, much prefer these.

  • Yeah, me too Asley, I agree.

  • I think it's much more interactive.

  • I don't think a lot of people want to watch me sit

  • and just code and kind of mutter to myself for eight hours.

  • I think this is a lot more entertaining.

  • And then JPguy agrees.

  • Makes it easier to understand if you can ask.

  • Yep, exactly.

  • And it's good feedback for me to know what

  • I should talk about more, as opposed to just kind of gloss over, you know?

  • Andydicomona says some Unity would be brilliant.

  • Yeah, we'll talk about it another time.

  • Jabcochasin, good to have you.

  • Thanks for tuning in.

  • It's 2:00 AM, wow.

  • So yeah, thank you for joining us.

  • We'll catch you on the next stream.

  • Mocroonderjebed, I'm not sure if I'm pronouncing that right at all.

  • Probably not, but thank you very much for following.

  • Yeah, not the most interesting content to livestream.

  • If I was going to livestream idle stuff, I'd

  • livestream gaming because I like gaming a lot more.

  • I think that's more entertaining.

  • Not on CS50's dime, but probably on something that I would--

  • maybe for a private stream or something.

  • Although we do have the Super Mario stream

  • that we did with David because that felt appropriate.

  • So check that one out.

  • We did that last week.

  • That was super fun.

  • We beat all of Super Mario Brothers One on stream.

  • And David did most of the game playing.

  • And Kareem also did an excellent job being his sidekick for that.

  • 10:00 AM for Brenda, about 3:00 for Babic Wow, the world is a crazy place.

  • What time will the stream begin tomorrow, says Beerman5000.

  • The stream tomorrow will be at 3:30 PM Eastern Standard Time.

  • So a little bit later than today's stream.

  • It'll go for about two hours.

  • I'll stick around for a couple more questions.

  • We are just hitting the four hour mark now.

  • But if you have any other questions, definitely let me know.

  • And we'll call it a day.

  • Oh, I was going to commit everything to GitHub.

  • Shame on me.

  • Let me make sure I'm in the right spot.

  • I'm not.

  • Let's go into Space Invaders, get init, make a new repository,

  • do the horrible act of Git add dot.

  • Git commit initial commit, which is--

  • actually we'll do ships and aliens rendering with projectiles.

  • And then Git remote at origin.

  • I got to actually create the repository so I'm going to go to GitHub

  • and create that.

  • Do I have a rubber duck?

  • Ooh, not in here, which is kind of terrible.

  • Do I have a rubber duck in here?

  • This is like the one room that CS50 has that does not have a rubber duck, which

  • is kind of embarrassing.

  • The best we have is the CS50 Muppet.

  • will he stay up?

  • He will.

  • I should have had this on the stream with me the whole time.

  • Aw, man, I regret that.

  • This is the best I have.

  • It'll function as a rubber duck if you need it to.

  • OK, let's create a new repository if we have nothing on there that's private.

  • I don't think so.

  • Space Invaders invaders stream, live coded implementation of--

  • Jellybelly1991, thank you for following.

  • Live coded implementation of Space Invaders on Twitch.

  • Ba ba ba ba ba ba ba, public.

  • It's going to be public so all of you can clone it, mess with it.

  • Get the Git URL here.

  • Git remote at origin--

  • I spelled origin wrong, which is not what you want to do.

  • Git remote at origin, blah, blah, blah.

  • Get push upstream origin master.

  • So now all of the files that we just looked at and created today

  • are on GitHub.

  • So I'm going to toss this in the chat.

  • Testing, testing, testing.

  • Testing, testing, testing.

  • All right, that was very strange.

  • So the reason that it crashed is that Facebook events--

  • we crossed a stream to Facebook.

  • And because we crossed stream to Facebook,

  • the event was a specific length of time.

  • And the event closed at 5:00 on the dot.

  • So what we need to start doing is, make the events

  • longer than broadcasting amount of time.

  • Well, I guess maybe after an hour beyond the broadcast amount of time

  • it'll terminate.

  • So, apologies for that.

  • We also have bad gateway stuff in the stream there.

  • So let's just go ahead and get rid of that and that.

  • As beautiful as that looks--

  • it doesn't look beautiful.

  • I'll finish saying all the stuff in the chat.

  • I apologize about that.

  • That was not something that I anticipated happening, but it's OK.

  • We're going to end on a good note.

  • We're not going to let the stream die just like that, right?

  • I did not spill the drink.

  • The stream Facebook basically said, nuh-uh and terminated our streaming.

  • And the script that we use for that broke and therefore stopped

  • cross streaming to Twitch and to Facebook.

  • So, yeah.

  • That was that.

  • And yeah, I wasn't answering the chat because I

  • was trying frantically to figure out how to get it back up and running.

  • But we're good.

  • We made it.

  • No PC crash, everything is great.

  • I apologize if it's echoing.

  • I'm not sure why it's echoing.

  • But, yes, just so that we have this at the end of the video

  • and it doesn't end in a very awkward way we'll take this as our farewell.

  • And I'll say, thank all of you for joining us for this long stream.

  • This was CS50 on Twitch.

  • This was Space Invaders part one, so part two on the next stream.

  • Again, we'll be making the aliens centered,

  • making them move left to right and down, making them shoot autonomously--

  • but only the bottom row, because if the top rows shoot projectiles down

  • they'll shoot the aliens that are right below them and kill them

  • and that's not good.

  • So only the bottom row can shoot.

  • We'll figure out how to do that algorithmically.

  • We'll figure out how to get lives and score,

  • and whatever other-- oh, yeah, the state machine stuff,

  • that should take about three or four hours, right?

  • So this little mini stream is only about a few minutes long.

  • But yeah, this was CS50 Twitch, Space Invaders.

  • Thanks to all of you for coming to join us today.

  • This was a lot of fun.

  • I'm looking forward to the next one.

  • Join us tomorrow for the Nick Wong stream on AWS.

  • And then join us on Wednesday for some r and some biostatistics.

  • It's going to be a lot of fun.

  • I know nothing about r, so that's going to be great.

  • It's going to be very educational for me as well.

  • Oh, and what's his name, the muppet?

  • CS50 Muppet I think is his official name.

  • I'm not 100% sure.

  • But yes, thank all of you.

  • Have a wonderful rest of your day.

  • And I will see you on the next stream.

  • Good bye.

COLTON OGDEN: All right, hello world.

字幕與單字

單字即點即查 點擊單字可以查詢單字解釋

B1 中級

SPACE INVADERS FROM SCRATCH (Part 1) - CS50 on Twitch, EP.17 (SPACE INVADERS FROM SCRATCH (PART 1) - CS50 on Twitch, EP. 17)

  • 1 0
    林宜悉 發佈於 2021 年 01 月 14 日
影片單字