Learniverse

Pong in Python erstellen: Ein Anfängerleitfaden

00:00

Hello, everybody, and welcome to another YouTube video.

00:12

In today's video, I'm going to be showing you how to make the famous game Pong in Python.

00:17

Now, this is a great project for beginner or intermediate programmers.

00:21

We are going to be using a module called PyGame to accomplish this.

00:25

However, you do not need to know PyGame, and the features we're going to use to

00:28

our very limited.

00:30

A lot of what we need to code out is the logic related to moving the ball around the screen,

00:34

having it bounce off the different paddles, implementing the score,

00:38

all of that type of stuff, and you're going to learn a lot in this project

00:41

if you are not, say, an expert Python programmer already.

00:44

With that said, let me give you a quick demo, and then we'll actually start writing some code.

00:48

So in front of me, I actually have the finished code for this project.

00:52

Whenever I do a tutorial, I code it out first, and then I reference that code

00:55

while I'm teaching it to you guys.

00:57

And all of the code that we write in this video will be available in the description.

01:00

Anyways, let me just run this here, and then we can have a look at the finished product.

01:06

Okay, here we are.

01:06

So this is Pong.

01:07

We have two paddles.

01:09

You can move one paddle with W and S, and the other paddle you can move with the arrow keys,

01:14

and you also would be able to implement this as a single player game if you wanted to code

01:18

like an AI for one of the paddles, which would be pretty easy to do.

01:21

You can see this is kind of the basics.

01:23

We have an implementation of Pong, and then of course they're scoring at the top,

01:27

and I've just made it so that when you get to 10, then the game is over.

01:31

I'm not going to play through the entire thing, but there you go.

01:33

That is the project, and I'm going to show you how to make it.

01:37

So with that said, let's get into the code after a quick word from our sponsor.

01:41

Thanks to Backtrace for sponsoring this video.

01:44

Backtrace provides application monitoring as well as error and crash reporting for games.

01:49

We've all been there, excited to launch a brand new video game just to be tormented

01:53

by crashes, bugs, and an overall bad user experience.

01:56

Backtrace wants to help limit that by providing a platform that gives game developers the best

02:01

error and crash reporting with the most complete and helpful information.

02:05

Backtrace works with any platform, any engine and at any scale, and provides 24-7 monitoring

02:11

so you can retain more players and get better ratings.

02:14

Backtrace helps you fix issues fast by providing accurate call stacks,

02:17

regression detection, querying and analytics, and integration with Microsoft Teams,

02:22

Discord Slack, and more.

02:24

You can get started with Backtrace today and manage up to 25,000 monthly errors

02:28

with one month retention and 10 gigabytes of storage completely for free.

02:33

Check it out from the link in the description, and thanks again to Backtrace for sponsoring this

02:38

video.

02:38

All right, so let's go ahead and get started.

02:41

The first thing we need to do is just set up our environment and install the Pi Game package.

02:46

Now, again, I want to reiterate here that you do not need to know Pi Game for this tutorial.

02:51

I will show you the limited features from it that we are going to use.

02:54

Now, if you want to learn more about Pi Game and make some more advanced games,

02:57

I have tons of tutorials on my channel.

02:59

So feel free to check those out.

03:01

You can probably just go on YouTube and search Pi Game,

03:03

tech with Tim, and you'll see like 10, 20, 30 different videos,

03:07

all going through different Pi Game projects.

03:10

All right, with that said, let's get this set up.

03:12

So right now, I'm in visual studio code.

03:14

This is the editor I'm going to use for this video.

03:17

Feel free to use whatever you want.

03:18

You can use the default idle from Python.

03:20

You can use sublime text.

03:22

Really doesn't matter.

03:23

I'm just going to use VS code.

03:24

Now, I'm using Python version 3.9.

03:27

You can use pretty much any version as long as it's above the 3.6.

03:32

Other than that, what we need to do here is open up a terminal or a command prompt and install

03:36

Pi Game.

03:37

Now, to do that, we're going to type in the command,

03:39

pip install Pi Game like that.

03:42

Now, I already have this installed, so I'm not going to run it.

03:45

But for you guys, run this command.

03:46

It should install Pi Game.

03:48

Now, this command does not work sometimes.

03:50

If it doesn't work, try the following Python.

03:53

And then you're going to do hyphen m and then pip install Pi Game.

03:56

If that doesn't work, try Python 3, hyphen m pip install Pi Game.

04:00

And finally, if that doesn't work, try pip 3 install Pi Game.

04:04

Now, if none of those commands work for you,

04:06

I have two videos, one for Mac and one for Windows.

04:09

I will put them up on the screen and they show you how to install Pi Game

04:12

for the respective operating systems.

04:14

Okay, so we now have Pi Game installed and we can actually start writing some code.

04:19

Now, we want to create Pong.

04:20

So the first thing we're going to do here is just import Pi Game.

04:23

We're going to set up what's known as a display.

04:25

So in Pi Game, we have a main kind of window or display.

04:28

And that's where we draw everything too.

04:30

Once we have the display, then we'll implement things like the paddle, the ball,

04:34

the scoring, a handling collision, all of that type of stuff.

04:38

So I'm going to import Pi Game at the top of my program.

04:41

And now I'm going to set the width and the height for my window.

04:44

Now, you're going to notice here when I'm coding everything out,

04:46

that I'm putting everything in variables.

04:48

This way our game will be dynamic and you can simply change the value of a variable

04:52

and everything will just work and adjust according to that.

04:55

So rather than using kind of hard-coded values,

04:57

we're going to put everything inside of variables,

04:59

use the variables for everything which will make it a little bit more complicated to code out.

05:04

However, it's going to be really nice because if you want a bigger window or a smaller

05:07

window or a larger paddle or whatever, you just change the variable.

05:11

So for the width and the height, I'm going to go with 700 and 500 for right now.

05:16

By the way, this is a way that you can declare kind of two variables on the same line in Python.

05:21

Okay, so now that I have that, I'm going to set up my window.

05:24

So I'm going to put this in a variable called win in all capitals.

05:28

Whenever I do something in all capitals, I'm making a constant,

05:30

meaning that this variable is not going to change.

05:33

So to do this, I'm going to say pi game dot display dot set underscore mode.

05:38

And then inside of here, I'm going to put a tuple and I'm going to pass the width and the height.

05:44

And I guess at this point in time, it's a good idea to mention that you should have some

05:47

familiarity with Python. Of course, you don't need to be an expert.

05:50

You can be a beginner, but you should know things like if statements while loops for loops,

05:54

because I'm not going to explain all of the very basics.

05:57

Anyways, to set up a window of this, so we do pi game dot display dot set underscore mode.

06:01

And then we pass a tuple, so just the brackets like this with width and height.

06:05

Great. Now that we have our window, we can make a caption for it.

06:09

So the caption is just going to be the title of the window.

06:11

And to do that, we do pi game dot display dot set underscore caption.

06:16

And for the caption, I am just going to call this pump.

06:20

Okay, so this will just be the title at the top of the window when it's actually loaded up.

06:24

So now that we have this, what I want to do is implement what's known as the main loop

06:27

of my program or the event loop of my program, which is actually going to display the window

06:32

and then draw something onto it. So I'm going to define a function here.

06:36

I'm going to call this main and inside of this function, I'm going to declare a few variables

06:40

that we're going to use to actually kind of show the display and handle all of the events that

06:45

are occur. So I'm going to make a variable here called run. I'm going to make this equal to true.

06:50

And I'm going to do a while to appear and say wild run.

06:53

Now whenever we have a pi game game, I guess pi game program, we need a main loop.

06:58

And the main loop is just a loop that's constantly going to be running that's handling everything

07:03

related to our game. So it's handling collision. It's moving the ball. It's allowing us to move

07:07

the paddle. So that's what this is right here. So inside of this main loop, I'm going to write the

07:12

following for event in pi game dot event dot get. Now this will get all of the events like

07:18

clicking your mouse, clicking the keyboard, closing the window. That's what this loop is doing

07:23

here, looping through all of the different events that have occurred. We're going to handle those

07:27

events and then do something. So in here, the first event that I want to check is if we are actually

07:32

quitting the window. So I'm going to say if event type is equal to pi game dot quit with all

07:37

capitals for quit here, then I'm going to say run is equal to false. And I'm going to break out of

07:42

this for now. What this is going to do is check if we hit the red button in the top right hand

07:48

corner of our window. So the close button, if we hit that, we want to stop the main loop. So we

07:52

actually end up closing the program. And then we want to break. Now outside of my while up here, I'm

07:57

going to say pi game dot quit. And quitting is just going to quit pi game and close the program for

08:02

us. Okay, awesome. Now, one thing I need to do here is right after our import pi game. I need to

08:07

initialize it. So I'm going to say pi game dot init. You should run this whenever you import pi

08:12

game just directly below it. It just initializes a few things that you need. I will use this later

08:18

or this will allow us to do some things later. Okay, so here we go. We have a basic program.

08:22

We have main. We have run equals true. We have our while loop here, which is going to be the main

08:26

event loop inside of this. We're checking all of the different events. And then what I'm going to do

08:32

here is call the main function. So I'm going to say if name is equal to main, then call main. Now,

08:37

what this does is ensure that we are running this module to call this function. So essentially,

08:42

if we were to import this module, so the solution dot pi file, then what would happen is this

08:47

would not run because the name of this would not be main. Now, I'm not going to explain

08:51

exactly how this works, but it really just makes sure that you're only going to run this main

08:55

function. If you directly run this Python file, not if this Python file was imported from

09:00

another project or from another file. Okay, hopefully that makes sense. But when we do this,

09:06

we should see a pi game window pop up. There won't be anything on the window. It'll just be a

09:09

black screen, but that's the thing we need to start out with. Okay, so there we go. We can see it

09:13

it says pong. We have our pi game window. And when we click the exit should quit,

09:17

great, there we go. It quits. Okay, so that's our starting thing. Now, the next thing I'm going

09:22

to do is implement something known as a clock. Now, a clock is going to regulate the frame rate

09:26

of our game. So that it's going to run at the same pace on every single computer. So I'm going

09:31

to say clock is equal to pi game dot time clock. And then inside of here, I'm going to say clock

09:37

dot tick. And I'm going to pass this in all capital FPS variable, which I'm going to define up

09:43

here as 60. Now, the FPS is the frames per second. And when you put this inside of a wall loop,

09:48

it makes sure that you cannot run faster than 60 frames per second or 60 ticks per second,

09:55

which means that this wall loop here is going to run a maximum of 60 times per second. So that

10:00

if you're on a really fast computer, it's not going to be running quicker than if you were on a slow

10:04

computer. Hopefully that makes sense, but that's why we want the clock. It just regulates the speed

10:08

of this wallet. Now, it's worth noting that if you're on a very, very slow computer, this wall loop

10:13

may run slower than the FPS that you're putting here. This is simply limiting the amount of times

10:17

it can run. It's not making it run 60 times per second. So on almost all modern computers, it will run

10:23

at least 60 frames per second or I guess exactly 60 frames per second. But on a very slow computer,

10:28

you may run under this. And so you may see some lag in your game if it's a really slow computer.

10:33

Just want to note that because some people have mentioned that in my previous pie game tutorials.

10:37

Okay, so now we have our clock. And the next thing I want to do is implement something to actually

10:42

draw some stuff onto the screen. So I like to handle all of my drawing in a separate function,

10:47

so it's really easy to see where I'm drawing everything. So I'm going to make a new function here,

10:51

and I'm just going to call this draw. And this is going to take in one variable, which is going to be

10:55

the window that we want to draw on. Now inside of here, all I'm going to do for now is fill

11:01

the window with a specific color just to show you how that works. So I'm going to say wind up

11:05

fill. And then here I have to pass an RGB value. Now RGB is red green blue. Now I could just pass

11:11

the RGB value directly in here, but I like to define all of my colors or RGB values as variables.

11:17

So I'm going to make one called white. And this is going to be equal to 255, 255, 255. And then I'm

11:23

going to make one called black. And this will be equal to zero, zero, zero. Okay, so those are my two

11:28

colors up here. And what do I want to fill the window with? Well, we are going to fill it with black,

11:33

but for now, I'll just put whites. We can actually see what's showing up. Now whenever we do some

11:38

type of drawing operation in pi game, we need to update the display manually. And then it will

11:44

actually do all of the drawn. So when I do something like a wind up fill, this is filling the entire

11:49

window with white. So it'll change the background color essentially to white. But for this to actually

11:54

happen, I need to save pi game, dot display, not clear, but dot update. Now this will update the

12:01

display and perform any of the drawing operations that we've done. So maybe I've done a few other

12:06

drawing operations. So I'm going to do all of those and then update the display and updating the

12:11

display is kind of the most intensive part. So doing the actual drawing does not take very long,

12:15

but updating the display where it applies all of the drawing. That's going to take the longest.

12:19

So you only want to do this after you've done all of your drawing. Okay, I'll continue

12:24

to explain that in a second. But for now inside of my wall loop, I want to call this draw function.

12:29

So every single frame or continually redrawing the window. So let's call draw here and let's pass

12:35

to it the all capital win, which is going to be the window here that we want to draw on.

12:40

Okay, hopefully that makes sense. Let's run the program now and see if we're getting a white

12:44

screen. Okay, so notice we're getting a white background. Perfect. That is what we wanted because

12:49

we are filling the window with white. Now I'm just going to change this to black

12:54

because we actually want a black background. I just wanted to show you how wind up fill works.

12:58

So now that we've done that, what I'd like to do is implement B paddles. So I want to add a

13:02

paddle on the left side and a paddle on the right side. And then I want to see the paddles

13:06

actually be able to move when we hit the different keys on the keyboard. So I'm going to make a

13:10

class here. And I'm going to call this paddle. And the reason why we're going to do this

13:16

is because we're going to have multiple paddles. And we want their movement and different properties

13:21

to be stored as an object so that we don't have to kind of repetitively code this up.

13:25

Now if you're unfamiliar with object oriented programming, I'll explain kind of the basics

13:29

of what I'm doing here. But I do have a ton of videos on my channel explaining object

13:33

oriented programming in Python. Okay, so for the panel, I'm going to say define a knit.

13:39

Now this is essentially what's going to be called when we initialize a paddle or create a new

13:43

paddle. And what I want to take in for the paddle is an x, y, width and height. Now our paddles

13:49

is just going to be a rectangle. One will be on the left hand side, one will be on the right hand

13:53

side. And they're going to have different x and y coordinates on the screen. And we're going to

13:57

change the y coordinate based on where we're moving, right? So if the user presses the up arrow

14:01

key, want to move it up, they press the down arrow key, want to move it down. So I'm going to say

14:05

self dot x is equal to x. Self dot y is equal to y. Self dot width is equal to width and self

14:12

dot height is equal to height. Now these are the attributes or properties of this paddle,

14:17

which means that each paddle I create will have different x and y and different with the height,

14:22

corresponding to what we passed here when we created the paddle. So there we go. We have our

14:26

initialization for the paddles. Now I want to write a method on the paddles, which is essentially

14:31

a function you can call on them called draw. Now draw is going to do exactly what it says.

14:36

It's just going to draw the paddle. Now our paddle is going to be a rectangle. It's going to have

14:40

the color of white. So let's define a class attribute here called color. And let's just make this

14:45

equal to white because this will be a constant. It's not going to change. So inside of draw,

14:51

I want to use the window to actually draw my paddle on the screen. So I'm going to say actually

14:57

pigame. Let's make sure the indentation is correct. Pigame dot draw. And then not dot circle,

15:04

we want dot rectangle like that. And I keep messing up my indentation. So let's fix that.

15:11

And when I'm drawing a rectangle with python, well, this how you do it, pigame dot draw,

15:14

dot rectangle. And I need to pass to it where I want to draw it, which is going to be the window,

15:19

right? And then I need to pass a color. Well, the color is going to be self dot color. That's

15:25

going to reference this right here, which is equal to white. And then I'm going to pass a rectangle.

15:30

Now a rectangle is an x, y, width and height. So in pigame, when we draw something, we draw from

15:35

the top left hand corner. So in pigame, 0, 0 is the top left hand corner, okay, of the screen.

15:41

So if I draw it something like 10, 10, that's going to be 10 pixels, sorry, right. And then 10

15:46

pixels down. And then if we're drawing something like a rectangle, for example, the x, y,

15:51

that we're drawing the rectangle at is the top left hand corner of the rectangle. And then the

15:55

width and height is well, the width and height of the rectangle based on the top left hand corner.

16:00

So you'll see what I mean here when I draw this, but I'm going to do self dot x, self dot y,

16:03

self dot width and self dot height. And that's all I need to draw the rectangle. Okay.

16:09

So now we have our paddle. So let's create two pals and let's draw them. So I'm going to go

16:14

here. And I'm going to say my left paddle is equal to a paddle and I need to pass this in x, y,

16:19

width and height. So for the x, I'm just going to make this 10, so be 10 pixels off the

16:25

left hand side border of the screen. Then we're going to pass a y, the y I want to be directly

16:32

in the middle of the screen. So we're going to say height, which is the height of our window.

16:37

We're going to integer divide this by two, just to get a whole number. And then we're going to

16:41

subtract this by whatever the height of our rectangles going to be or the height of our paddle.

16:46

So I'm going to make a variable up here. I'm going to say paddle. Yeah, paddle underscore height

16:52

and paddle underscore width. And this is going to be equal to just let me look at my screen here,

16:58

120. And I realized here that I probably want to go with first and then height second just to stay

17:04

consistent with width and height up there. So I'm going to say paddle width, paddle height,

17:07

and we're going to make this 20 and 100. So that's the values for our width and our height.

17:13

Okay. So we're going to use that now here. And we're going to say paddle height divided by two.

17:18

Now to explain to you why we want this, let's just quickly open up paint. And I can show you.

17:23

So let's zoom in a bit. Let's say this is our window. Okay. Now as I said, here is going to be

17:28

zero zero. Now I'm drawing with my mouse. So just excuse me, but let's write this zero zero. Now

17:34

our height is going to be all the way down here. So height is h. This will be h. Okay. So if our

17:40

height is something like I guess we have 500, then this coordinate right here would be zero comma

17:46

500. So the middle of this is going to be height over two, right? So they have h over two.

17:51

But the issue is if I start drawing my rectangle here, I'm going to draw it like this because the top

17:56

left hand corner is where I start drawing it from. So what I need to do is draw the top left hand

18:00

corner so that my rectangle will be perfectly center. So this will be the center of the rectangle.

18:06

Hopefully that makes a bit of sense. But to find this position here where we want to start drawing

18:10

the rectangle from, we need to know the height of the rectangle because if the height of the

18:14

rectangle is say 100, then what I'm going to do is take whatever the height of my window is divided

18:19

by two. And I'm going to subtract half of this height, which is going to be 50. And that will tell me

18:25

where I need to start drawing my rectangle so that it's perfectly center in the screen. Okay.

18:30

That hopefully, again, that makes a bit of sense. We're going to take the height over two.

18:33

We're going to subtract the height of our rectangle over two. And then that tells us the correct

18:37

height to draw a rectangle at such that it's perfectly in the middle of the screen. Okay. So let's

18:41

close this here and let's now implement that. So this is going to be height over two minus

18:46

paddle height over two. Okay. I guess we already have that. And then what we want for the width

18:51

in the height is just going to be the paddle width and the paddle height. Now let's copy this

18:55

because it's going to be very similar for our right paddle. So here I'm going to say right

18:59

paddle except all I'm going to change is where I want the x to be because this is going to be

19:05

different. And I'm going to say this is going to be the width. And then this is going to be

19:08

subtracted by 10, subtracted by. And then this is going to be the paddle width like that. Now

19:15

again, the reason for this is that I actually have to go in paint to explain this. If we want

19:20

our paddle to be say 10 pixels off the right border, okay, then what I need to do is make

19:26

the x coordinate be here, right? So let's say we want this to be 10 kind of a gap between the

19:31

right border. Then I need to account for the width of this rectangle as well as kind of the padding

19:36

I want between the right border. So what I'm doing is I'm taking whatever the width of the screen

19:41

is, which is going to be right here, okay? So this would be width and then zero, this position.

19:46

So I'm taking the width. I'm subtracting from the width this 10, which is the padding that I want.

19:51

And then I'm subtracting the width of the rectangle. And that's telling me the exact

19:55

x coordinate that I want to put this paddle at. And then the height is going to be the same thing.

19:59

That's why I've left it the same. Okay, hopefully that makes sense. That is what we have for

20:04

the right paddle. And now what I want to do is draw the two paddles on the screen. So to do

20:09

this, I'm going to pass to my draw function a list that contains both my paddles. So I'm going to

20:14

say a left paddle and a right paddle. Now I'm going to go to draw. I'm going to take in paddles

20:20

like that. And I'm going to use a for loop to draw both of the paddles. So I'm just going to say

20:24

for paddle and paddles, paddle dot draw. And then we'll pass to this the window. Now why am I

20:32

getting there here indentation? Okay, let's move that over by one. And now we're good. All right,

20:37

so the reason I'm doing a list is just because I'm going to do the same thing to draw both paddles.

20:41

So we can just do a for loop and draw both of them and maybe some some time down the future we

20:45

add a third paddle, a fourth paddle. Now we just pass in the list and it will draw all of them

20:49

for us. Okay, so let's now see if our paddles are showing up. And let's draw this. And we got an

20:55

issue. Pigeom dot draw has no attribute rectangle. Am I spelling rectangle incorrectly? Let's see,

21:02

pigeom dot draw dot rectangle. Um, hmm. Ah, my apologies guys. This needs to be wrecked. Not

21:11

rectangle. Uh, that's actually how you draw the rectangle is with rect not recting. Okay,

21:16

let's try this. Let's run. And there we go. Now we have our two paddles. They are perfectly

21:21

center in the screen and they're at the correct X coordinates. Now we want to move the paddles.

21:26

So let's figure out how we can do that. Okay, so to move the paddles, we need to change their Y

21:32

coordinate, right? Move it up and move it down. Now we need a velocity to move the paddles at.

21:38

So essentially how much should we go up or down when the user hits a specific key? So I'm going

21:42

to add a velocity here on my paddle and make this equal to four. Now notice anything that's going

21:48

to apply to all of my paddles, I'm putting as a class attribute, meaning I'm defining it here

21:54

rather than inside of the initialization or inside of a method. So I'm doing Bell equals four.

21:59

Now I'm going to implement a method on my paddle. And I'm going to say define move self. And I'm

22:06

going to say up is equal to true. Now what we're going to do here is call this method on the

22:10

paddle. And if I pass up equals true, we're going to move the paddle up. If I pass up equals

22:16

false, we're going to move the paddle down by the velocity. So I'm going to do here say self.y

22:21

and then this is going to be plus equals and then the self dot velocity. But that's only going

22:28

to be the case if up is equal to false. So I'm going to say if up, then we'll do something.

22:35

Otherwise do this. Let me just copy this and then I will explain what's going on here.

22:39

Okay, so if self.y, then minus equals self. So if we are going up and we want to move the paddle

22:46

up, then to move the paddle up, we need to subtract from the y coordinate, whatever the velocity

22:50

is, right? So we'll do that here. Otherwise, though, we need to move the paddle down. So we'll say

22:55

self.y plus equals whatever the velocity is. So as the y value increases, we're going down as

23:01

the y value decreases, we're going up. So let's now move the paddle up and down. Okay, so now that we

23:07

have this, we need to actually call this. We're only going to call this when we are pressing the up

23:12

or down arrow key. Now to do this, we're going to have to get the keys that the user is pressing

23:18

and then allow the paddle to move when they press a specific key. Now for this game, I'm making a

23:23

two player. So we're going to have W and S allowing the left paddle to move. And then we're going

23:27

to have the arrow keys allowing the right paddle to move. Now again, you could implement an AI for

23:32

Pong. Maybe we'll do a video where we'll implement AI for Pong. Let me know if you want a specific

23:36

video on that. But for now, we're just going to do it with two players. So I'm going to say that

23:40

keys is equal to pi game dot key dot get underscore pressed. And this is going to give us a list

23:45

containing all of the different keys that have been pressed. Specifically, it's actually going to

23:49

give us a believe a map. I'd see there a map or a list either way I'll show you how we can access

23:54

and check if a key was pressed. So I'm saying keys equals pi game dot key dot get underscore

23:58

press. Now what I want to do is make a separate function that will handle moving the paddles for

24:03

me because it's going to be a good amount of logic. And I don't want it to kind of clog up my main loop

24:08

so I'm going to call a function and this will be handle underscore paddle underscore movement

24:15

like that. We're going to need to pass to this the keys and we're also going to pass to it

24:20

the left paddle and the right paddles that we're able to move them. Okay, so let's make a function

24:26

now. Let's say define handle paddle movement. Let's take in our keys and let's take in our left

24:32

paddle and our right paddle. Okay, so inside of here, we're going to check if the user is

24:37

pressing the WRS key and move the left paddle and then the arrow keys and the right paddle.

24:41

So I'm going to say if keys and then this is going to be pi game dot and this is a capital K

24:47

underscore W. Notice this is a lowercase W. So if we are pressing the W key, then we want to move

24:54

the left paddle up. So we're going to say left paddle dot move up is equal to true. Okay, and then we'll

24:59

say if keys and this will be pi game dot K underscore S, then we want to do the same thing,

25:07

but we want to move it down. So left paddle dot move and then not down equals true, but this is

25:11

going to be up is equal to false. Okay, this is now handling the movement of our left paddle.

25:18

Now let's copy this and do the same for the right paddle except we're going to do this with

25:22

the arrow keys. So just a note here when you want to check a specific key, if it's a letter key

25:26

or yeah, I guess a letter key, then you're just going to do a lowercase of whatever the letter is.

25:30

So a Q W, whatever. If it's something like the shift key or the enter key, it's usually in all

25:35

upper cases. So for the arrow keys, we're going to say key underscore up or K underscore up and for

25:41

the down arrow key, it's going to be K underscore down in all caps. Now all we have to do here is

25:46

change this to be the right paddle and this one to be the right paddle as well. Okay, so now

25:52

this should actually be working, handling our paddle movement. So let's see if this is working by

25:57

running our code. Okay, so when I run my code now, I can move my paddles, but notice that my paddles

26:03

actually go off the screen. So now we need to implement something so we're not going to be able to

26:07

move the paddle off the screen. So to do that, I just need to check to see that if when we move the

26:12

paddle, it's going to go off the screen or not. If it's going to go off the screen when we move it,

26:16

then we're not going to let the user move it, right? So what I'm going to do here is say,

26:20

we will allow us to move the paddle if we are going up. So for hitting the W key and

26:26

the left paddle dot Y and this is going to be minus the left paddle dot velocity

26:34

is greater than or equal to zero. Okay, so if left paddle dot Y minus the velocity because that's

26:42

how much we're going to subtract from it when we move it is greater than or equal to zero,

26:45

which is the top of the screen, then we'll let it move. However, if it's not going to be greater

26:50

than or equal to zero, so it's going to go off the screen even by a slight amount, then we're

26:54

not going to let you move. Okay, now let's do the same thing down here, except we're going to have

26:58

to check if you're going to hit the bottom of the screen. So we're going to say and the left paddle

27:02

dot Y. This time we're going to add the velocity, right? So plus the left paddle dot bell,

27:07

we also need to add though the paddle height. So I'm going to say plus left paddle dot,

27:13

and this is going to be height like this. And we're going to check if this is going to be

27:16

less than or equal to the height of the screen. So the reason we need this is because the

27:21

Y that we're referencing is the top left hand corner of our paddle. So we're moving up,

27:26

it's fine to check that because that's the top of the paddle. But the bottom of the paddle is

27:30

the left paddle dot Y plus whatever the height of the paddle is, right? Because that's going to

27:35

give us where the bottom of the paddle actually is on the screen. If we didn't have this,

27:39

then what would happen is we'd be able to move it all the way down until it was just barely off

27:44

the screen because that's when the Y coordinate is at the very bottom. So we need to add the height

27:48

to make sure that we're not going to look like we're moving off the screen, right? And now we're

27:52

checking if it's less than or equal to the height, not greater than, right? Because if it is less

27:57

than the height, then that's fine. We can continue to move, otherwise it's off the screen.

28:01

Okay. So that's what we're doing. Now we're just going to check the exact same thing here.

28:05

I accept for the right paddle for these ones. So I'm just going to change this to be the right

28:09

paddle and the right paddle and then same thing with moving down. So let's copy this and put it here

28:17

and now let's go right paddle, right paddle and right paddle. Okay. Perfect. So now this should

28:26

make it so we cannot move off the screen because we're only going to move if we are not going

28:30

to move off the screen. Okay. So let's run this and see what we get and notice now that it stops

28:35

at the very bottom of the screen and stops at the top of the screen. Let's just check the opposite

28:39

and it is all good. Our paddles now do not move off the screen. Nice. Now that we've done that,

28:44

what I would like to do is draw a line in the middle of the screen just because I think that looks

28:48

nice. I want to draw a dashed line or a dotted line and I will show you how we do that. So let's

28:54

go inside of our draw function. Just need to reference my cheat sheet here because this is a

28:58

little bit complicated to do. So I'm going to say 4i in range. We're going to start at 10 pixels.

29:05

We're going to draw up to the height and the increment 4r4 loop is going to be height over 20.

29:11

Now the idea here is that I want to draw a bunch of rectangles to represent kind of a dashed

29:16

or dotted line. Now I want the space between the different rectangles to be the same and I want

29:22

the rectangle, I guess, height to be identical for every single rectangle. So what I want to do is

29:28

draw one rectangle, not draw rectangle, draw another rectangle, not draw rectangle and kind of have

29:32

a gap between each of them. So that's what this 4 loop is going to do and you'll see how I implement

29:37

that. So I'm going to say if i mod 2 is equal to 1, then continue. Now essentially what this means

29:45

is that if i is an even number, then I'm going to continue. So I'm going to skip this iteration

29:50

and I'm not going to draw a rectangle. Otherwise, though, I will draw a rectangle and the way I'm going

29:55

to draw it is the following. I'm going to say pi game dot draw dot rect. I'm going to draw this

29:59

on my window. The color is just going to be white so we'll draw it white and then the x is going

30:04

to be in the middle of the screen. So to do this in the middle of the screen, we're going to say

30:09

width over 2 but we need to subtract half of the width of the rectangle for the same reason we did

30:15

that with the height when we were initializing the y of the paddle. So now if we're looking at

30:19

it horizontally, right, if we want to draw it right in the middle of the screen, then the x coordinate

30:24

can't be directly in the middle. It needs to be whatever half the width of the rectangle is

30:29

to the left of the middle so that it looks like it's directly in the middle. So I'm going to say

30:33

width over 2 minus 5 because the width of my rectangle here, I'm going to make 10. Actually,

30:38

let's see if that's what we're doing. I think yeah, that's fine. Okay. Now for the y coordinate,

30:44

I'm going to make this i. Now the reason I'm making it eyes because I'm saying I want to have

30:49

20 rectangles on the screen, right? So when I say height over 20, that means that we're going to do

30:54

this for loop 20 times because we're going up to height and we're starting at 10. So we'll do

30:59

it either 20 or 19 times. Either way though, the reason I'm doing eyes because we're going to be

31:04

essentially picking what y value to draw at based on whatever the for loop is currently at. So

31:10

we're going to start at 10, then we're going to skip one, then we're going to be at whatever height

31:14

over 20 times 2 plus 10 is because that's how much we're incrementing the for loop by every single

31:20

time. And so this will make it so our rectangles are evenly spaced out because that's how much we're

31:24

incrementing the i by every single time. So I'm using i for my height. So width over 2 minus 5 i,

31:30

then the width of my rectangle is going to be 10. Notice this value here is half of the width,

31:35

right? And then the height of my rectangle is going to be height over 20 because that's how much I'm

31:39

incrementing the for loop by. So I need to make sure that's my height so that we're getting kind of

31:44

the correct spacing for our rectangles. I understand it's a bit complicated. This is how you do a dash

31:49

line. There is some other ways to do it, but they take up a lot more codes. So I'm going to do it

31:53

in this way. Okay. So let's just see if this is going to work now before we go any further.

31:57

Let's draw this and notice now we get a nice dashed line or dotted line through the middle of

32:02

the screen. The top and bottom spacing might be slightly off. But for me, this looks fine. Now you

32:07

could make this a solid line if you want. That would be a lot easier. But we're going to go with

32:10

dashed for now. Okay. So I think that is all good. Now what I want to do is implement the ball. So

32:18

we want a ball that's going to be moving on the screen. Now let's just go into paint here and

32:22

quickly discuss kind of some theory behind this because this is not trivial to do. So we want a

32:27

ball and this ball needs to move in two directions, right? It's going to be moving in the Y direction

32:33

and in the X direction. Now it's also going to collide with paddles. We'll talk about the collision

32:37

in a second. But for now we want the ball to move around the screen and to be able to collide with

32:43

something like the ceiling. Now to move it as I was saying, we need a velocity in the Y direction

32:47

and a velocity in the X direction. Now we'll start by moving the ball just in the X direction.

32:52

And based on where it hits the paddle, we'll change its Y velocity. We'll just understand that we

32:57

have kind of two components of movement in the X direction and in the Y direction. And we're going

33:02

to have to calculate what those velocities are and then move the ball by that velocity every single

33:07

frame. So hopefully that makes a little bit of sense. But that's kind of the idea here behind

33:11

the ball. And I just want to explain that because that's what I'm about to start coding out.

33:15

So just like we had a class for our paddle, I'm going to do one for the ball.

33:18

We don't necessarily need one, but it's just going to make things a little bit simpler.

33:22

So I'm going to say class ball. I'm going to say define underscore underscore init.

33:27

We're going to take in a self X Y and a radius. Okay, we're going to do a circular ball.

33:34

I know some pong games do a rectangular. I guess you can't really call ball, but rectangular

33:39

object moving around. We're going to go with a circular one. So for here, I'm going to say self.x

33:44

self dot Y equals Y self dot radius is going to be equal to radius. And then self dot X

33:53

underscore vell is going to be equal to vell. It's actually going to be equal to something called

33:58

max vell, which I will implement in a second. And we're going to say self dot Y underscore vell is

34:03

equal to zero. I'm going to implement my max velocity. So I'm going to say max velocity is equal

34:09

to and we'll go with five. Now, the idea here is that I want to initialize the X velocity as

34:14

whatever the maximum velocity is in the positive direction for a velocity, we can have positive

34:19

or negative. And that will change the direction that we're moving. Right. But I'm going to make

34:23

this positive, meaning it's going to be going actually to the right first, I believe. Yeah,

34:28

should be going to the right. Anyways, I'm initializing the X velocity as the maximum velocity,

34:33

meaning that we're going to be moving to the right at the maximum velocity when the program starts.

34:37

Then once it hits the paddle, we will simply reverse the X velocity and calculate the Y

34:42

velocity based on where it hit the paddle at. But the maximum velocity is sung us with the

34:47

max one possible velocity is in either direction. So we'll always be moving at the max

34:51

velocity in the X direction. But the Y direction velocity is going to change depending on where

34:57

we hit the paddle because we're going to have to change the angle at which we want to move the

35:00

ball. Okay, again, I noticed getting a little bit confusing, but hopefully that makes a tiny

35:05

bit of sense. Now we're going to implement a method called draw. So very similar to our paddles.

35:10

We're just going to say self win and we're going to go in here and say this will be pigame

35:19

dot draw dot and then circle. We're going to pass our window. We're going to have a color

35:25

which will define up here as just white. Again, just doing this so we can very easily change the

35:29

the color and then we want a radius. So we're going to pass the window drawn, the color,

35:35

the radius and the X and Y position. Now I'm actually not sure if this is correct.

35:41

I think we have to do the X and Y before we do the radius. So we're going to do self dot X

35:45

self dot Y. Make sure that's in a tuple and then the radius comes after and I think that is

35:50

correct. Perfect. Okay, so now we have draw. We have initialization and let's implement move while

35:56

we're at it because this is pretty straightforward. So we're going to say define move. And all

36:00

we do to move is we move the X by the X velocity. So self dot underscore X self dot X underscore

36:07

velocity and then self dot Y plus equals the self dot Y underscore velocity. And so that's how

36:14

we move the ball. This is our draw. I think that is all good for now. And the reason we can do

36:19

plus equals is because if the velocity is negative, then that will be equal to minus equals, right?

36:24

It'll just move it in the other direction. Okay, so now we have our ball. We need to initialize

36:28

our ball. So let's go in where we have our left and right paddle and let's make the ball and say

36:33

the ball is equal to ball. Now what's nice about the ball is that the X and Y position forward is

36:39

the center of the ball, meaning that if we want to put it in the center of the screen, we can just

36:43

actually calculate the direct middle and then place it there rather than having to do kind of

36:47

the calculations here we did by subtracting, you know, half the width and that type of stuff.

36:52

So for the X and Y position of my ball, I'm going to put it directly in the middle of the

36:56

screen. So I'm going to say width over two. And then I'm going to say height over over two.

37:01

Now the reason I'm doing two division signs here is because this is integer division. It just

37:06

going to give me the rounded division because I can't draw at a floating point position. All right,

37:11

so we're going to go height over over two. And then lastly here for the radius, we're going to

37:15

make a variable. We're going to call this ball underscore radius. And for now we'll go with a

37:20

radius of something like seven. And we can of course change that later on if we want. So let's

37:25

now pass the ball underscore radius. Now we want to draw the ball. So we're going to have to pass

37:31

that to our draw function. So we'll pass the ball. We're going to take in the ball here in draw.

37:37

And it's very easy to draw this because of the method we have. We're just going to say ball

37:41

dot draw and draw it on our window. Great. So now we have our ball. This is the class. And I think

37:47

that's actually all we need for right now. So let's run the program and see what we're getting.

37:52

And we got an issue. Let's see what the errors says. Max Bell is not defined. My apologies.

37:58

We need to add a self dot max bell here rather than just max bell because I have to reference it

38:03

from the class. Okay, let's try this now. And we got another issue says ball object has no

38:09

attribute max bell. Ah, we need an actual L here or an uppercase L rather than a lowercase one.

38:16

Let's see if we get any other errors. Okay, there we go. So the balls in the middle of the screen

38:21

is not moving right now because we're not calling the move function or the move method story.

38:26

But once we call that, we'll see that the ball actually starts moving on the screen. Then we

38:29

need to handle collision. So let's move the ball to do that. We're going to go to under actually

38:37

where do I want to move the ball? Yeah, it's going to do it right here. I'm just going to call ball dot

38:42

move inside of my main loop here. And now we're going to be moving the ball every frame by whatever

38:47

it's velocity is. Okay, so let's run this now. And let's see and notice the ball is moving to

38:52

the right. Of course, it's going to go off the screen because we're not handling any collision.

38:57

Let's run it one more time in case you missed it. You can see the ball starts moving to the

39:01

right. Now if we change the vibe, why velocity would move on an angle, but for now we're just moving

39:05

it in the x direction. So that's what's happening. Okay, so now that we've done that, we need to

39:09

start handling collision. Now I will admit this is not the easiest thing in the world to do,

39:14

but of course, I'm going to try my best to explain it to you. And you will have, you know,

39:18

collision handled by the time of this is done. So let's go into paint again and let's just talk

39:22

about how we're going to handle collision. First of all, with like the ceiling and then we'll talk

39:27

about the panels. So we have this right here. Okay, now let's say we have a ball and let's say it

39:35

trajectory is here. Okay, so it's kind of moving up in this direction and this direction

39:40

and the average of the components makes it's the angle it's moving at is here. So if the ball hits

39:45

here and it's going in this direction with the y, all we actually need to do to make it bounce

39:51

off of the wall is we need to kind of bounce it off on the exact same angle that it hit the wall

39:56

out, right? So if you have like a wall like this and you hit like this, you go here, right? Pretty

40:01

straightforward. If you hit coming pretty straight on, you're going to come out going pretty straight

40:05

on as well. If you head out of huge angle, you're going to come off at a huge angle. So that's

40:09

how the collision is going to work works either in the X or Y direction. Now when we're talking

40:13

about the ceiling, all we actually need to do to implement this is we just need to change the

40:17

direction of the Y velocity. So here, this Y velocity would actually be negative because we're going

40:23

upwards. So to make it bounce off, all we do is swap whatever the current Y velocity is to the

40:29

positive direction and then that moves us down. Hopefully that makes sense. That's all you need

40:34

to do to actually handle collision with the ceiling, which we'll do shortly. Now that's the easy part.

40:39

Collision with the paddle is a little bit more difficult because we're not going to do this in kind

40:42

of a physics real way. So let's say we have our two paddles here. Now in Pong, the way that the

40:48

collision works, at least my understanding of the way that the collision works is you're going to

40:52

bounce the ball off of the paddle based on where the ball hits the paddle, not based on the angle

40:58

that is coming in it. Now if the ball was coming at an angle like this, if we're talking about

41:02

real physics, we should just bounce it off at the exact same angle. Now the reason why we don't

41:05

want to implement it like that is because that means our games are always going to be the exact same

41:09

assuming you can line up the paddle. You never can change the direction of the ball. Whatever direction

41:14

it hits the paddle out is the direction it's going to come off at. So we need a way to actually

41:17

manipulate that so we can have a game that's playable. So the way that I'm going to do this is I'm

41:22

going to figure out how to move the paddle based on its direction from the center of the paddle.

41:27

Or sorry, not move the paddle, how to move the ball based on its kind of displacement or distance

41:31

from the center of the path. So if the ball hits here, then I want to bounce it off on an angle

41:36

like this. Okay. If the ball hits here, then I want to bounce off on an angle like this.

41:41

If the ball hits in the direct center of the paddle, then I want to bounce it like that.

41:45

So the further away from the center it is, the higher the angle is I'm going to bounce it off on.

41:50

So we're going to have something along the lines of this and we'll calculate this using a

41:54

custom function that'll show you how to write. But that's the idea here with the ball.

41:58

So that's going to be more complicated to do. But when the ball hits like here,

42:02

we're going to bounce it off pretty much in the center because this is almost directly in the

42:06

middle, right? So we'll bounce it at tiny bit higher than that. But that's kind of how we're going

42:10

to do the collision with the paddles. So let's say we have a paddle here. Okay. This is the middle

42:16

of our paddle. This is going to be the x, y coordinate. And then we have a ball. And this is the center

42:21

of the ball. So let's just go through some of the math here. So we first need to figure out where

42:25

the middle of this paddle is. So we can calculate the displacement between this and this.

42:31

Okay. So to do that, we're going to take the y coordinate, which is right here. So let's

42:35

just call this y one. Let's put a y one here. And we're going to add to this half of the height of

42:42

the paddle. So h over two. Okay. So we're going to add h over two. Again, I'm using my mouse here.

42:49

This is pretty hard, but this is what's going to give us the middle. So we can say this here is

42:54

equal to M. Okay. So this is M the middle. Now, once we have M, all we're going to do is subtract

43:01

M from the y coordinate of our ball. So we can call this y two. Okay. So we're going to take M

43:07

and we're going to subtract y two. Now, if this gives us a negative value, that means we are above

43:13

M. If it gives us a positive value, that means we are below it. So once we have the displacement,

43:18

we can call this d, we need to figure out what the velocity should be in the y direction based

43:23

on this displacement. That's where it gets a little bit more challenging. And I'm going to dive

43:27

into that math in a second. But for now, we understand how to calculate the displacement.

43:31

Once we know the displacement, we just need to make it so that when you're at the maximum

43:34

possible displacement in the, you know, up direction or the down direction, you're going to move at

43:40

the maximum possible velocity. Whereas when you're at say a zero displacement, you move at a zero

43:46

velocity in the y direction. Okay. Hopefully I'm not confusing you guys too much. I just wanted to

43:51

give a quick rundown because now we're going to implement the collision, which as I've said is fairly

43:56

complicated. So let's do a function here and we're going to say handle underscore collision. Now

44:02

to handle the collision, we need the ball, the left paddle and the right paddle. Okay. Now what's

44:09

nice is that we only need to adjust the y velocity of the ball really. That's the only thing

44:13

we're going to do here, but we need to handle it on the left paddle, right paddle and the seal.

44:17

So let's start with the ceiling because that's the easiest. So we're going to say if the ball dot x

44:24

are actually not x, we only care about the y because we're going up and down. We don't care about

44:28

the left, right collision right now. So we're going to say if the ball dot y plus the ball dot

44:33

radius is greater than or equal to the height of the window, then we're just going to say ball dot

44:40

y underscore val multiply equal by negative one. So simply going to reverse the direction.

44:46

Now we're going to say L if the ball dot y plus and it's actually minus sorry minus the ball

44:52

dot radius is less than or equal to zero, then ball dot y underscore val. This is going to be

45:00

multiplied equal by negative one. Now that's actually all we need to handle the collision with

45:05

the seal. So let's just look at this one here. This is saying if we're going to hit the bottom

45:09

of the ceiling, right? So the height, we're checking the ball dot y, which is the center of the

45:13

ball plus the ball dot radius. It's important you add the radius. If you don't do that, it's only

45:18

going to check for collision with the center of the ball. We don't want that. We want it with like

45:22

the edge of the ball, which is the radius, right? So if that's the case, then we just what is it

45:27

change the direction, reverse the direction. Now we do the exact same thing in the other direction,

45:30

except this time we need to subtract the ball dot radius, not at it because we're checking up,

45:35

not down. Okay. There you go. We're now handling collision with the ceilings. Now after we

45:41

check that, we need to check if you're hitting the left panel or the right panel. Let's start with

45:45

the left panel. So we're going to first check the direction of the ball because we're only going

45:50

to see if we're hitting the left panel. If we're moving left, right? So if the x velocity is negative,

45:56

that means we're moving left, then we'll check if we're colliding with the left panel. Otherwise,

46:00

there's really no point in doing that. So I'm going to say if the ball dot and it's going to be

46:04

x underscore velocity is less than zero, then I'm going to check if we're colliding with the

46:10

left panel. Otherwise, I'm going to check the right paddle. So I'm just going to add a comment.

46:15

So to check if the ball is colliding with the paddle, we need to check with the x and y coordinate

46:20

and check if the y coordinate is within the range of where the paddle is on the screen.

46:24

So essentially, if the y value of the ball is greater than the y value of the paddle,

46:31

but less than the y value of the paddle, plus the height of the paddle,

46:35

that's going to tell us if it's where the paddle is on the screen, essentially.

46:38

Then once we check that, so if the y coordinates are correct, if it's in the right range,

46:42

we need to check if the x coordinate is the same as the edge of the paddle. That's essentially

46:47

what we want to look at. So I'm going to say if the ball dot y, we're going to say is greater

46:51

than or equal to the paddle dot y, because remember, this is the top left hand corner of the

46:56

paddle. And the ball dot y is this is going to be less than or equal to the panel dot y plus

47:06

the panel dot height. So that's the first thing that we want to check. Now after we check that,

47:11

we want to check if the x coordinates are correct. Now I could do this on the same line,

47:15

but just so it doesn't get too messy, I'm going to do another if statement. And I'm going to say

47:18

if the ball dot x, and this is going to be, I need to think about this for a second, minus the

47:25

ball dot radius. And we're going to check if this is less than or equal to the paddle dot x plus

47:34

the paddle dot width. Okay. Let me check my cheat sheet to make sure I did this correct. I think

47:41

I did looks good to me. Okay. So the reason we're doing this, let's go to paint quickly,

47:46

is because we're checking the left paddle. So if this is the paddle right here, we know the top

47:51

left hand corner, x, y is here. And we know the edge of the paddle in terms of the x coordinate is

47:56

going to be the x plus whatever the width is. So that's what we want to check. Now we have our ball.

48:02

This is the center of the ball. So we need to account for the radius, which is what we're doing.

48:06

So we're taking the ball dot x, we're subtracting the radius, which gives us the edge of the ball.

48:11

And we're checking if that edge is less than or equal to this edge right here. If it is,

48:17

we're just going to change the direction of the x, and that will then change how we move the

48:21

ball off of the paddle. Okay. So let's try this out. Let's go here. And for now, all we're going

48:27

to do is change the x velocity. We'll deal with the Y velocity later. So I'm going to say ball dot

48:32

x underscore. Well, multiplied equal by negative. Okay. So it's going to change the direction.

48:37

So now we move from the left to the right. Okay. So that is handling the collision for the

48:43

left paddle. Now handling for the right paddles a little bit different. So we're going to say,

48:47

if the ball dot Y, we actually can copy this for the Y. So we'll do this, except we're going to check

48:54

paddle. I keep saying paddle. Sorry, this needs to be the left underscore paddle. This needs to

49:00

be the left underscore paddle. This needs to be the left underscore paddle. My apologies, guys,

49:06

fix that. So this will be left underscore paddle. And then for here, this makes it actually

49:12

easier. We just make this right paddle. Okay. So right paddle and right paddle. Okay. So now

49:18

we've checked the Y for the right paddle. Now we need to check the X. The X is a little bit different.

49:23

We're going to say ball dot X plus ball dot radius. And we're going to check if this is greater

49:28

than or equal to the right paddle dot X. Okay. And if it is, we're going to say ball dot X

49:35

underscore. Well, multiplied equal by negative one. Okay. So the reason why this is a little bit

49:40

different for the right paddle is because when we're moving to the right, we're going to be

49:43

checking the left edge of the right panel. And that is represented simply by the X coordinate of

49:48

the right paddle because that's the top left hand corner. Whereas when we're moving to the left,

49:52

we're checking the right edge of the left paddle, which means we had to add the width. Now,

49:56

the reason we're adding the radius is because we're moving to the right. So the radius is going

50:00

to be to the right side that we're checking rather than the left, whereas here we were subtracting

50:04

the radius. Hopefully that makes a little bit of sense. But I think this is going to be good to

50:09

allow us to move the ball left and right on the paddles. Let's check this out. And then we'll

50:13

deal with the Y, which is a bit harder. Okay. So let's see this now. It should bounce off the paddles.

50:19

Okay. So it didn't bounce off the paddle, which means I made a mistake here. Let me check the

50:23

mistake and I'll be right back. All right. So I found the air. This is kind of a silly one. I'm not

50:27

calling this function. So I read this wrote this function, but I didn't actually call it. So of

50:31

course, the collision is not going to be handled. So we need to call this now. So after we move the

50:35

ball, then we'll handle the collision. So we'll say handle. And then this will be collision like

50:40

that. And we're going to pass ball, left panel and right panel. Okay, figures crossed. Hopefully

50:46

this should work now. Let's run this and let's see if it bounces off. There we go. So it bounces

50:51

off. And notice that it doesn't really matter where I have the paddle. It's just going to bounce

50:55

off at the same direction. Because that's all we're doing right now. Now if I move the paddle,

50:59

it should just go off the screen and it does because while it's not going to collide with the

51:03

wall, we haven't implemented that. Great. So there we go. That is now dealing with the collision.

51:08

Now we want to deal with the collision in the Y direction. Again, a little bit more complicated.

51:13

We need to calculate the displacement between the ball and the center of the paddle and then

51:18

determine the angle that we want to bounce it off on. Now we don't actually need to use trigonometry

51:22

because of the way that I've implemented this, but you're going to see the math is not not super

51:26

straightforward. So the first thing we need to do is calculate the middle Y of the panel. So we're

51:32

going to say middle underscore Y is equal to. And then this is going to be the, in this case,

51:38

it's the left panel. So the left paddle dot Y. And then this will be plus the left paddle dot

51:42

height divided by two. Okay. That's fine. Now the next thing we want to do is calculate the

51:47

difference in Y between the ball and the middle of the Y panel or the middle of the left

51:52

paddle. So I'm going to say difference in Y is equal to. And this will be the middle Y subtracted

52:00

the ball dot Y. Now that we've done that, we need to figure out essentially how much we need to

52:05

divide this value by to determine what the velocity should be. So let's go back to paint here and

52:10

let's deal with some more math. So we have a max velocity. So let's call this V. Okay. The max velocity

52:16

is equal to, I believe we had five. Okay, that was a rough five. That's better five. So I just

52:21

call this mx for max velocity is equal to five. Now what we need to do is make it. So when we're at

52:27

the maximum possible displacement, that's when we get this maximum velocity, right? So if we're

52:32

hitting the very, very edge of the paddle, so we hit right here, that's when we get a maximum velocity

52:37

of five. Now when we don't hit this, we want it to be a little bit less, right? So I want the velocity

52:43

to maybe only before when we hit here. So essentially, how do we figure this out? Well, what we need

52:48

to do is figure out what value we need to divide whatever the distance is to make it. So the

52:54

maximum possible value we can get is five. And then any other value we get will be smaller than five.

52:59

I understand this is a bit weird, but we want it so that the distance or the displacement

53:04

divided by some value gives us five when we're at the maximum possible displacement value.

53:08

And then when we're not at the maximum, it gives us something a little bit less than five.

53:12

And as we get closer to the middle, it gives us a smaller value that should reach zero.

53:16

So our range is zero to five. We need to take our displacement and then squeeze it in the values

53:21

zero to five. Hopefully this following a little bit, again, not the easiest math in the world,

53:27

but we're going to have a maximum velocity of five. Okay, that's our MV. And our maximum

53:31

displacement, okay, is going to be equal to half of the panel. So if we're taking the displacement

53:37

from right here, then the maximum possible displacement we can have is that the center of the

53:41

ball is right here at the very edge of the paddle, which is just going to be half the height of

53:46

the panel. Okay, so our maximum displacement is height of the paddle divided by two. So we have

53:52

these two values. And now we need to figure out what I'm going to call a reduction factor. And

53:57

the reduction factor is how much we take the displacement between the paddle and the what he

54:04

call it and the ball and divide it by. Okay, so now we also have D. So let's write a variable D.

54:10

Let's go back to this. No, I don't want to pencil. I want brush. Okay, D. So we have D

54:16

this equal to the different distance between the middle of the paddle and the the ball.

54:21

So the way that we figure this out is we say that our reduction factor, which I'm going to call R.

54:25

So we want to have D over R is equal to MV when specifically D is equal to MD. So when the

54:37

displacement is equal to the maximum possible displacement that we can have and we divide it by R,

54:43

we want to get the maximum velocity. That's what I'm saying here. Now it doesn't matter if

54:47

it's positive or negative because we'll get either the maximum positive or maximum negative velocity.

54:51

Anyways, that's kind of the equation that we have. Now fortunately, we can solve for R because we

54:57

have a value for D and MV. Now once we solve for R, we just use R as the reduction factor. And

55:03

then that's going to give us what we need for the velocity for our ball. So if we plug in D,

55:08

which is going to be MD, which is just H over two, then we have H over two over R is equal to MV

55:16

and we know MV, which is five. Now H over two is going to be variable based on the height of the

55:20

paddle, but I think we actually know this value is 50. Anyways, I'll show you how we solved just using

55:25

the variables. So if we have H over two over R is equal to five and we're looking for R,

55:31

then what we need to do to actually solve this is we need to do the phone. We're going to have to

55:35

flip R and H over two. So we're going to say R over H over two is equal to one over five. Okay,

55:45

because what we do to one side we need to do the other side, then we're going to take H over two

55:49

and we're going to multiply it by the one right here. So we're going to have H over two over five

55:53

is equal to R. Okay, so it's going to be whatever the distances, the maximum distance over five.

56:00

In this case, it would be just be our max velocity so that could potentially change

56:03

is equal to R and then we take in the future, whatever the displacement is,

56:07

divided by R and that gives us the value. I know that was a lot. I'm sure it's not 100% clear.

56:13

Once I write this, maybe it'll make a bit more sense, but I just want to go in and try to explain

56:16

how that works. Okay, so now I'm going to calculate the reduction factor. So I'm going to say

56:20

reduction factor is equal to this is going to be left paddle dot height divided by two. Okay,

56:29

divided by two. And then we're going to take all of this and we're going to divide this by

56:34

the maximum velocity of the ball. So I'm going to say ball dot max underscore vell like that.

56:38

Okay, now we have the reduction factor. Now that we have this, we need to use this to calculate

56:42

the Y velocity. So I'm going to say the Y velocity is equal to the difference in Y divided by the

56:48

reduction factor. Okay, so now this is going to squeeze our difference in Y within the range of

56:53

negative 525, which is now going to allow us to update the Y velocity. So now I can say ball,

57:00

the Y value is equal to the Y value. Okay, now it turns out that we do the exact same thing here

57:06

with a few minor changes inside of this function. We just need to change the left paddle to be

57:13

right paddle and it will give us the exact same result. Now there's there's a lot of repetitive

57:18

code here. Theoretically, we could maybe write a function to calculate this for us. But for now,

57:23

I'm just going to put it inside of here, because I think this is fine. So let's run this now and see

57:27

if it's working. So if I look at this paddle here, it's actually bouncing in the incorrect

57:33

direction. Okay, I need to fix that. Yeah, same with the other paddle. So it's giving us the

57:36

reverse of what it should be. So I'll show you how we can fix that. But it is bouncing on an angle,

57:41

which is what we want. So the reason it's giving us the reverse of what we want is essentially

57:45

because we just need to multiply the Y velocity by negative 1. I'm going to say negative 1 by Y

57:49

velocity and negative 1 multiplied by Y velocity. How did I mess that up twice? Okay, let's

57:56

rewrite this negative 1 multiplied by Y velocity. Now it should give us in the other direction.

58:02

You can look at the math and you'll probably figure out pretty quickly why it's giving it to us.

58:05

But it's because we're taking the middle line subtracting from ball Y. If we do ball Y and

58:09

subtract by middle Y, then we don't need to do this. But I think this makes more sense. So that's

58:13

what I'm doing it this way. Anyways, let's try this. Let's see what we get. Okay, now it's bouncing

58:20

in the correct direction. Nice. That's what we wanted. Notice when it hits the edge of the paddle,

58:24

it's going to bounce more down. Okay, there we go. We got it to bounce down. Nice. Awesome. And it

58:30

bounced off the ceiling completely fine. So this is working as I anticipated. Now what I want to do

58:36

is I want to make it so when it goes up the screen, we actually increment some type of score

58:40

and display them. Okay, so let's get started on that. Our collision is working properly.

58:45

As you notice, the closer we got to the center, the more the ball bounced off straight

58:49

and the further away from the center, the more we had an angle, that's why I was doing all this math.

58:53

That's kind of how that works. Okay. So now we want to implement some type of score. So to do that,

58:57

we need two variables. We're going to say left score and right score. So the left score will be

59:02

equal to zero. And the right score will be equal to zero as well. Now to check the score,

59:09

we just need to see if the ball moves off the left or the right hand side of the screen.

59:14

So I'm going to say if the ball dot X is less than zero, then this means that the right

59:20

player scored because it came off the left hand side of the screen. So we're going to say right

59:24

on a score score plus equals one. L if the ball dot X is greater than and this will be

59:33

the width of the screen. And then we are going to say left score plus equals one.

59:41

Now that we have both the scores, we can pass those to the draw function. So I'm going to say left

59:45

score like this and right score. And then if I go to my draw function, I can now take it in the

59:53

scores. So we'll say left score, right score. And we want to draw them on the screen. Now to draw

59:59

them on the screen, I need something like a font, right? I need to actually draw a text on the screen.

01:00:02

So to do that, I need to write a font. So to make a font, you can do the following score,

01:00:07

underscore font is equal to pi game dot font dot s y s fonts like that. Now this takes in the type of

01:00:15

font, which I always just use as comic sands. And then the size of the font, which I'm going to go

01:00:20

feel free to modify these values, but this is the font you want. And this is the size of the font.

01:00:25

And I use this font object to actually render text that you put onto the screen. So inside of my

01:00:30

draw function here, I'm going to use score font. And I'm going to draw this at the top just so that

01:00:36

the ball can be drawn over top of the score. So whatever I draw first will be drawn first, meaning

01:00:42

that whatever I draw last is going to be on the very top. So I want to draw the ball last,

01:00:46

it will be over top of my score. Okay. So the way that I do this is I say the left score text is

01:00:54

equal to the score font. And then I call dot render. And I pass to this the text that I want to

01:01:00

render, which is going to be an f string containing the left score. Okay. And then I'm going to

01:01:07

pass one. And I'm going to pass the color, which is just going to be white. Now one stands for

01:01:12

anti aliasing, just always make this one. Okay. So you do the text anti aliasing, the color,

01:01:17

and that's what we have. Now f strings allow you to embed expressions directly inside of a string.

01:01:21

So I'm just doing the score here directly inside of the string to avoid having to convert it to

01:01:25

a string using the string function. Now for the right score, it's going to be the exact same thing

01:01:29

except right score. Okay. So now this actually gives me a drawable object. Now that I have a

01:01:35

drawable object, I want to draw it on the screen. So I'm going to say wind up blit. And I'm going to

01:01:40

to blit the left score text and then I need to pass an x and y location for it. Now I want the

01:01:46

left score text to be exactly in the middle of the screen on the left half of the screen.

01:01:51

So this is actually fairly easy to do, but I'm going to say width divided by four,

01:01:55

not divided by two because I'm trying to put this on kind of the first quarter of the screen

01:02:00

or the first half of the screen in the center. So I'm going to say width over four. And I'm going

01:02:04

to subtract this from the left score text dot get underscore width over two. Okay. And then for

01:02:13

the height, I'll just pick a height of like 20 pixels. Now we'll do the exact same thing for

01:02:17

the right text and then I'll explain why I'm doing this calculation. So this is going to be

01:02:21

right score. But for the right score, I want this to be in the middle of the right hand side of

01:02:26

the screen. So I actually want it to be three quarters of the width of the screen. Right. That's

01:02:31

the middle of the right hand side of the screen. And then I'm going to subtract that from the

01:02:35

right score tax dot get width over two. So for this, I'm going to do width. And I'm going to multiply

01:02:41

this by three over four. Okay. So hopefully that makes sense. I think I can actually just do it

01:02:46

like this and say width multiplied by three over four. And then minus the right square to get

01:02:52

underscore width over two, that should work properly. So to go to paint to quickly explain this again,

01:02:57

if we want this to be in like, let's do this, we have half the screen, the middle of this half

01:03:04

is right here. Okay. So this is width over four. That gives me this X position. Then I have my text.

01:03:09

Now if I draw my text here, it's going to go like that. I don't want it to be like that. I want

01:03:13

it to be directly in the middle. So I need to draw it like this. So I'm going to take half the width

01:03:18

of the text and subtract that from this position. That gives me the top left hand corner for where I

01:03:22

I need to draw. Now exact same thing over here. This is three over four width, right? So I take

01:03:28

that, subtract it from half of the width of the text I'm drawing. And I get it directly in the

01:03:33

center of the screen. Okay. And of course, this is how you get the width of the text object you

01:03:37

used to get with. Perfect. So that should now draw my score. So let's see if this is going to work.

01:03:43

Okay. Wait. I think I'm in the Python terminal here. Let's just quit that. Yes. Okay. Let's

01:03:47

rerun and notice now that if we score, this goes up and it's going to continue going up because

01:03:55

I don't reset the ball. So I need to reset the ball. You can see that is in the drawing in the middle

01:03:59

of the screen. And it's changing based on what the number is, right? Okay. So how do we do this now?

01:04:05

So once the ball goes off the screen, we need to reset the ball. So I'm going to put a method

01:04:09

on my ball. It's called reset. So I'm going to say define reset. And what I need to do in here is

01:04:14

I need to reset the Y velocity as well as the X velocity and then change the X and Y position to

01:04:20

be originally what it was set. So I'm going to add some new values here. I'm going to say this is

01:04:25

equal to self dot original underscore X. And this is equal to self dot original underscore Y.

01:04:32

Now let's make those lower cases. So the idea here is when I initialize my ball, I'm going

01:04:37

to store what the original X and original Y value was in a separate variable. So that's how you do

01:04:42

this here. And then I'll change the X and Y as I go through the program, but I'm storing the

01:04:47

original X and the original Y. So I can reset the X and Y to be equal to the original X and

01:04:52

original Y when I reset. So I'm going to say self dot X is equal to self dot original X. Okay.

01:04:58

And then we're going to say self dot Y is equal to self dot original Y. Then I'm going to reset

01:05:04

the Y velocity to be zero. Okay. And I'm going to say the self dot X velocity multiplied equal by

01:05:10

negative one. Now the reason I'm doing this for the X velocity is if I go off the screen going left,

01:05:15

then I want the velocity of the ball to be hitting my opponent when the ball resets. Okay.

01:05:20

Now same the other way around. If I go off the screen going right, then I want the ball to go

01:05:25

left and hit my opponent's paddle first. You could change this if you want by just making it

01:05:30

equal to the max belt or not even changing the X. Well, you could do that. That'd be fine.

01:05:35

But I'm just going to reverse the direction. So if it just went off your screen, then it will go

01:05:39

to the other person. Hopefully that makes a little bit of sense. That's what I'm doing with

01:05:43

the X velocity here. Okay. So that's reset for the ball. So now if they score one or reset,

01:05:49

so I'm going to say ball dot reset and ball dot reset. Okay. Easy enough. Let's try this

01:05:57

and see what happens. Okay. So let's score. And now notice it comes off and hits my opponent's

01:06:03

paddle. So that's what I'm trying to do just to give my other player some time to recover.

01:06:07

So if we score, now it comes off on that side. Okay. Let's score on the other side and see if

01:06:12

our score goes up. Okay. Score goes up and then it comes back to me. All right. Now again,

01:06:17

you can change that if you want, but that was kind of my idea. Now one thing we could do is also

01:06:21

reset the paddles. When we score, that might not be a bad idea. For now, I'm not going to do that,

01:06:26

but I think I've showed you how you would go about doing that. Just implement the same logic on the

01:06:30

paddles and then call reset on left paddle and right paddle. Okay. Nice. Now that we have that,

01:06:36

the last thing I need to do is handle winning the game. So if the left player wins, I want to

01:06:40

say, you know, left player wins. If the right player wins, I want to say right player wins. So

01:06:44

I need to first come up with a score that I want to end the game at. So I'm going to say the winning

01:06:48

underscore score is equal to 10. And now we want to check if either player has a score of 10

01:06:54

after we increment the score. So I'm going to go here. And I'm going to say if the left score is

01:06:59

greater than or equal to the winning score, then we want to do something. And I'll say,

01:07:04

L if the right score is greater than or equal to the winning score, then we want to do something.

01:07:09

Now, the first thing that we want to do is we want to say ball dot reset. Okay. And we want to

01:07:14

say ball dot reset here as well. Now, I actually want to reset the paddles of someone wins because

01:07:18

we're just going to play a new game. So let's actually implement the reset method on the paddles because

01:07:23

I guess we're going to need that anyways. So let's go to our paddles. And in the same way that we

01:07:27

did this for our ball, we're going to say self dot original X and self dot original Y. And then

01:07:35

we'll just implement reset. So define reset self self dot X is equal to self dot original X and

01:07:44

self dot Y is equal to self dot original Y. Okay, paddle reset done very easy. So if one player wins,

01:07:52

I want to say left underscore paddle dot reset, right underscore paddle dot reset,

01:07:59

I and say nice, left paddle reset writes paddle reset. Now, the thing is this is pretty

01:08:05

repetitive. So we could try to wrap this in a way where we're only going to write this code once.

01:08:10

In fact, let's actually do something. I'm going to say reset. Actually, I'm going to say one

01:08:16

is equal to false. And then inside of here, I'm going to say one equals true. Okay. And one equals

01:08:25

true. And then I'm going to say if one do this. So this is just handling all our resets in one

01:08:32

place now. So we just have a Boolean telling us, okay, did we win or do we not? Well, if someone won,

01:08:36

then we'll do the reset. And then inside of the left score and right score, if statement,

01:08:40

we'll handle specifically what to do with the left player one and specifically what to do

01:08:44

if the right player one. Now, actually what I want to do is put some text on the screen,

01:08:48

show it for five seconds saying, Hey, left player one, right player one. And then just immediately

01:08:52

reset the game. So to do that, I'm just going to render some fonts. I'm going to say win text

01:08:57

is equal to an actually, yeah, we could just do win text. We could say left player one,

01:09:06

exclamation point, we can say win underscore text is equal to right player one. So now that

01:09:13

we have this in a variable, what I can do inside of one is I can use that variable to render

01:09:18

text depending on who actually want. So I can say my win underscore. Yeah, I'll say win. Actually,

01:09:27

let's just say text is equal to. And then this is going to be the score font. We could make a new

01:09:32

font. I'm just going to use the score font dot render. We're going to render the win text one.

01:09:38

And then we're going to render this in white. And we're going to blip this to the middle of the

01:09:42

screen. So I'm going to say win in all capitals. Dopplet. And I'm going to blip the text. And then

01:09:49

I'm going to blip this at when are I'm going to blip this at height. Nope at width over two minus

01:09:57

the text. Get underscore width over two. And it's going to be at height over two minus. And then

01:10:04

this is going to be the text dot get height over two. Okay. So we're centering in the X position

01:10:13

and the Y position. Then I need to update the display. I'm going to say pi game dot display dot

01:10:18

update. And I'm going to say pi game dot time dot delay 5000 and 5000 is going to be five seconds.

01:10:27

This is the number of milliseconds that I want to display the program. But let me run through

01:10:31

this because I know I want quickly. We're saying the text is equal to score font dot render. So

01:10:35

we're just rendering a drawable object. The text we're rendering is whatever we put here. Just so

01:10:39

we're not repeating a bunch of code and doing this in both places. Right. I'm rendering this with

01:10:43

anti-aliasing one, the color white. I'm then blidding this directly in the middle of the screen.

01:10:47

I've talked about how we do the middle calculation many times. So I won't go through this again.

01:10:51

We're going to update the display so that it instantly shows. Then we're going to delay by five

01:10:55

seconds. We delay by five seconds. Then we reset everything. Now when we reset, we also need to reset

01:11:01

the score. Right. So we're going to say left score equals zero and right score equals zero.

01:11:06

And I think that's actually all we need to do for reset. Then the game will restart and everything

01:11:10

will just work as expected. Then when you hit X, of course, the game is going to end. All right.

01:11:14

So I think that's actually all good. That should really wrap up the program. Let's run this though

01:11:19

and give it a test and see if it's working. So let's just see if we can score 10. So all this

01:11:24

kind of left this run. And then once it's done, I'll be right back and confirm that it's working.

01:11:28

Okay. So we're at a score of nine. Let's see now if this is going to work. Okay. It says

01:11:32

right player one. Perfect. And then it should restart the program. Let's see. Perfect.

01:11:37

Research. Awesome. Okay. So that is punk. We have finished the game now. As I promised,

01:11:43

hopefully you learned a lot in this video. I just covered collision. We covered some more advanced

01:11:48

math drawing, you know, kind of separating the program out and how we have different functions

01:11:53

handling different stuff. Yeah. I think this is a fun program. Again, great one for beginner

01:11:58

or intermediate programmers. And I am going to end the video here. I will end off by saying

01:12:03

that I do have a course programming expert.io can check it out from the link in the description.

01:12:08

Use discount code Tim. This course is designed for beginner or intermediate programmers looking

01:12:13

to get better at programming. This teaches programming fundamentals, object oriented programming,

01:12:18

advanced programming, software engineering tools, all kinds of great stuff,

01:12:21

check it out from the link in the description. It's definitely a great resource, especially

01:12:25

if you guys want to support me. With that said, I will end the video here. I hope you guys enjoyed.

01:12:29

If you did make sure to leave a like, subscribe to the channel and I will see you in another one.

00:00

Einführung in das Pong-Tutorial

00:44

Demo des Pong-Spiels

02:41

Einrichten der Umgebung

03:36

Installation des PyGame-Moduls

06:27

Erstellen der Hauptschleife

16:00

Die Paddel herstellen

17:20

Zentrieren der Paddel

21:30

Implementierung der Paddle-Bewegung

24:15

Verarbeitung der Paddelbewegungslogik

28:45

Eine gestrichelte Linie zeichnen

32:52

Verständnis der Ballgeschwindigkeit

33:15

Eine Ball-Klasse erstellen

35:10

Die Bewegung des Balls implementieren

39:20

Umgang mit Kollisionsmechaniken

49:22

Implementierung der Ballkollision

51:10

Berechnung des Paddel-Kollisionswinkels

58:30

Hinzufügen eines Punktesystems

01:04:04

Zurücksetzen der Ballposition

01:06:07

Verarbeitung der Spielgewinnlogik

01:07:44

Implementierung der Paddle-Reset-Logik

01:08:52

Gewinner-Spieler-Nachricht anzeigen

01:11:04

Spielbedingungen zurücksetzen

03:39

Wie installiert man PyGame mit pip-Befehlen?

06:50

Was ist der Zweck der Hauptschleife in einem Spiel?

11:00

Wie füllt man die Fensterfarbe in PyGame aus?

13:14

Warum Klassen für Schläger in unserem Pong-Spiel verwenden?

17:30

Wie kriegen wir die Paddel richtig in die Mitte vom Bildschirm?

26:20

Welche Logik sorgt dafür, dass die Paddel nicht vom Bildschirm verschwinden?

28:53

Wie zeichnet man eine gestrichelte Linie in einem PyGame-Fenster?

33:39

Wie definieren wir die Y-Geschwindigkeit des Balls?

36:05

Welche Methode stellt sicher, dass der Ball sich korrekt bewegt?

39:20

Wie wird die Kollisionserkennung mit Schlägern gehandhabt?

49:22

Wie gehen wir richtig mit den Kollisionen zwischen Ball und Schläger um?

51:26

Welche Berechnungen bestimmen den Abprallwinkel vom Schläger?

58:36

Wie setzt man ein Punktesystem im Pong-Spiel um?

01:06:40

Wie wird die Gewinnbedingung im Spiel überprüft?

01:07:46

Was macht die Paddle-Reset-Funktion während des Spiels?

01:08:58

Wie zeigst du die Nachricht des Gewinner-Spielers auf dem Bildschirm an?


AnimationFehlersuchePygameEreignis (Datenverarbeitung)AlgorithmusPython (Programmiersprache)Entwicklung von VideospielenObjektorientierte Programmierung2D-ComputergrafikErgebnis (Sport)Eingabe/AusgabeKollisionserkennung

Beschreibung

In diesem Video zeigen wir dir, wie du das beliebte Arcade-Spiel Pong in Python mit dem PyGame-Modul erstellen kannst. Wir starten mit einer kurzen Demo und gehen dann ins Programmieren. Du musst PyGame nicht vorher kennen, da wir es langsam angehen und die Grundlagen abdecken. Unser Ziel ist es, dieses Tutorial sowohl für Anfänger als auch für fortgeschrittene Programmierer zugänglich zu machen. Am Ende wirst du viel über Programmiergrundlagen gelernt haben und wie du sie anwenden kannst, um ein spassiges Spiel wie Pong zu erstellen.