字幕列表 影片播放 列印英文字幕 COLTON OGDEN: All right. Hello, world. This is CS50 on Twitch. My name is Colton Ogden. Today we're going to resume what we did last week with Minesweeper. Prior to today's stream, we had a lot of awesome language chat in the, uh-- well, language-- we had a lot of language discussion in the chat, a lot of folks from different parts of the world. Going to shout out-- [INAUDIBLE] long discussion, here. Shout out to everybody who popped in early. So let me just make sure I'm going to the right place. [INAUDIBLE]-- regulars, of course. Acid Jack, who said "Greetings from Germany," and we had a little bit of a German discussion. Learned that "nabend" means "guten abend." It's a shorthand version of that, which is awesome. Who else do we have, here? We had-- let me scroll down-- [INAUDIBLE],, from Uzbekistan-- so, some representation from Uzbekistan, which is awesome. We have, in addition to that-- Not Sure, of course. We have [INAUDIBLE],, representing the Hindi language-- didn't specify the country, but Hindi. [INAUDIBLE] namaste. [INAUDIBLE] actually was the one who said "namaste," so, apologies. And then [INAUDIBLE]. And speaking of [INAUDIBLE],, happy belated birthday, [INAUDIBLE].. We missed saying happy birthday to you on Friday. I don't remember if it was Friday that you were sick or Thursday that you were sick. Hope you're feeling much better, but happy birthday. Happy belated birthday. Sorry that I missed it on the actual day itself. Hope you had an amazing birthday, and hope you're feeling fantastic again. Mission Vision-- greeting from Austria. There we go. A lot of European representation today, which is awesome. We're going to find a list of upcoming Twitch broadcasts. That's facebook.com/CS50. They're all listed as events and will also be listed as video, live video events, in addition to that. People are talking about where they've been to in Europe. So, awesome. I think we're all caught up. We had a lot of awesome prestream chat. But, yeah, we're all set. So last week what we did-- I'm going to switch to my computer, here-- boom. We talked about the game Minesweeper, and we implemented a similar, beginning version of it-- not the full game, not the whole gameplay loop, but it looked something similar to this-- If I can get this working. So this is just the grid, kind of by itself. The last feature that we implemented actually was being able to highlight a given rectangle on the screen, so that visually you can see where you're trying to click on a given tile-- which is pretty important. You know, visual feedback like that. Subtle little things add up. So the next thing, I guess, the next big feature, would be-- and probably going to be the majority of today's actual-- the more challenging aspect of today's stream is going to be the recursive sort of reveal loop that goes on and, when we click a tile, showing all the tiles that we-- assuming we haven't clicked on a bomb, which would be unfortunate. But if we haven't clicked on a bomb and we click on a blank tile or a numbered tile, if it's a numbered tile we just reveal the number. If it's a blank tile, we reveal all the blank tiles that are adjacent to it and recursively keep revealing tiles until we reveal numbers or blank tiles. Right? And so that is the gist of what we have to implement, today, the core of what we have to implement, today. Nice things to also implement, per what some folks mentioned last time, would be flags. So, in the actual game, you can click on a given tile to indicate that it's a bomb, that you've predicted that's a bomb, based on the neighboring numbers and whatnot, so that you don't accidentally click on it in the future. Which would be unfortunate. We can even make it such that, if you even try to click on a flagged tile, it just won't let you do that, if it's flagged. It'll just be completely error-proof, in that way. And then having a game-over screen, if we do click on a bomb-- so, you know, showing that we've lost, showing how many points we had, and then maybe allowing us to restart the map. So these will be all features that we could try to implement today, as we go along. And probably the biggest piece would be the reveal loop to the game. So that's probably what we're going to start with, today. I think if we bite that off first, everything else will be kind of easy. [INAUDIBLE] says "Hello from Gujarat, India." Awesome! Hello. Thank you for joining us. We got some-- [INAUDIBLE] I'm not sure what language that is. [LAUGH] [INAUDIBLE] says "genuinely blessed." That's awesome. Well, again, apologies we didn't wish you a happy birthday on Friday. It would have been much better, but it was indeed Friday, right? If I'm not mistaken? But, yes, happy belated birthday. OK, cool. So this is the game I'm going to. So, again, we had some little sort of debug output, at the bottom of the window, there, the x-y of our cursor, the highlighting tile, whether it was true or not, and then the actual grid index. And that's kind of a common thing, in games. You know, it's not always super-easy to write to a console, you know, to write to a terminal like this and debug your game at the same time. It makes sense, a lot of the time, to actually integrate the output of your game, the debugging output, into the window itself. So, in this case, this is actually drawn text, using a font, just like we would have drawn anything else. And it's not CLI output, in the normal debugging sense. This is a different type of output. But it works better, and it allows us to more instantaneously see things, too. Because we were making a change every time we move the mouse, and doing that through the CLI would get ugly and weighty. It's just much easier. You've probably seen it in many games that have a debug menu or a debug mode. And that's kind of the purpose of that, to actually integrate the debugging output into the executable-- make your life a lot easier, if you're testing things. Games like Skyrim and Fallout actually let you examine variables at runtime, when you're playing the game, through a special integrated console. And that's cool, too. And that gives you a lot of freedom. You can actually mess with the game objects and do all sorts of really crazy fun stuff. Let me just make sure that I haven't missed anything in the chat. Cool, cool. All right! Awesome. Well, I'm glad we have a healthy number of folks already, so let's get implementing the next feature. So what we have so far, again, is this grid of squares. And my goal is, when I click any of these squares, I want it to-- the first step, the very first thing that we should do, is we should just reveal it. Right? So just set Reveal to True. And that should be pretty easy. Right? So let me just go over to-- it should be in the game grids. So, if we recall, the game grid had an update function, and in the update function we essentially had-- we were checking the x pause and y pause of the mouse. And that's where these two variables are, here, up top. The x pause and y pause both get returned from the push:toGame function, which basically gets the love.mouse.getposition function. So this returns our actual mouse in its native pixel size-- so, in our 1,280-by-720p window, it'll give us the 1,280-by-720p pixels, the coordinates for our mouse, and-- But push, remember, it's a virtual resolution, so that actually isn't going to map evenly to our 1,280p-by-720. And so, instead, we wanted to convert that 1280-by-720 into this 384-by-216 pixel size. And we do that using the-- foo go back to the game grid. We did it with the push:toGame function. So that takes in native resolution and gives us our virtual-resolution x-y mouse coordinate. So you can actually interact with our game and pretend sort of like we're using it at a native resolution, but we're actually just spoofing it, using texturing-- using a stretch texture, rather. So, in here, we're already sort of looking for the mouse. And what we want to do is we want to check basically on click. And normally how we do that is we override the love.mouse-- I believe it's love.mousepressed. So this function, love.mousepressed. And it takes in a key, I believe. And I'm not 100% sure, so what I'm going to do-- and this is what I encourage you to do, as you're developing in Lua and Love2D-- is to go to the Love2D docs. So I would type in "Love2D mouse"-- uh, what would it be? "mousepressed, I guess-- one word. Because that's the name of the function. You can see, here, it's the first link in Google. Going to click on that. And it actually takes in a x, a y button is touch and presses. Interesting. OK. So why is it returning an x and a y, if it just-- interesting. Oh, OK, no, I was getting confused. So these are all values that it gives you back. So, just like-- how do we say-- just like the love.keypressed function gives you the key back, so that you can use it in your function, this gives you not only just the button-- so, for example, 1, I think, by default is left-click-- Yeah, it says right here. 1 is the primary mouse button, so primary mouse button is usually left-click. 2, being the secondary mouse button, that's right-click. 3, being the middle mouse button-- And if you have a mouse with a ton of buttons, you'll get more indices that you can access through this API. But we only really care about button. But if we wanted to, if we wanted to say, OK, is the x and the y within a certain bounds, and have we pressed a certain button? We have access to that in here. But we're not going to really worry about that too much, right now. All I want to do is say "love.mousepressed," and then I just want the-- so, "x, y, button, istouch," and "presses." All right, presses is cool, too, because that actually lets you detect whether or not it's a double-click versus a single-click. And this might be important for certain games. It's more of a GUI feature than anything else, but, I mean, games like-- even I've seen it in, like, Minecraft, for example. Like, you double-click a specific block, it does something different than a single-click. We don't care about that. We just care about the button. So what I'm going to do is I'm actually going to do something very similar to what we've done before, with keeping the ability to press keys outside of main.lua, which is a thing that you need to do a lot of the time. So normally you would have this function, right, love.keypress, which takes in a key, and you can define what behavior you want to have happen when a particular key is pressed. But this only works in main.lua. You only have access to this love.keypressed function in main.lua. And so, if I wanted to check for a single key press outside of main, I need a function that I can use globally-- a different kind of function. --our streaming server did, so Facebook probably just went down. YouTube and Twitch should be back up, but let me know in the chat if you can hear me.