TLDR: Best to go over the video as I go through a lot in real-time.
A lot of people get stuck in the planning of a game and although I recommend planning, when it comes to learning
you should get in the habit of trying to implement your ideas as quickly as you can in order to test out if your
ideas have potential.
Basically brute force coding is a method in which you get something working without doing any planning on how you
write out your classes and functions.
In this case so far we have planned a rough idea of our game, and we have not planned out what the code will look
like, or the classes we will be needing.
In this episode I go over writing everything inside a single class and recommend you watch it to follow along what
I do.
The one thing I want you to notice is your ability to read the code. Is it hard to read? Is there too much going on?
Lastly, if you want to make changes to the code, is it hard to add or remove features in the code.
Well, here is the finalized code you can find on github.
# full code for creating a working pong game through the brute force methodextendsNode2D# statesenum GAME_STATE {MENU, SERVE, PLAY}
var isPlayerServe = true
# currentstatevar currentGameState = GAME_STATE.MENU
# screen valuesonreadyvar screenWidth = get_tree().get_root().size.x
onreadyvar screenHeight = get_tree().get_root().size.y
onreadyvar halfScreenWidth = screenWidth/2onreadyvar halfScreenHeight = screenHeight/2# ball variablesvar ballRadius =10.0var ballColor =Color.white
# paddle variablesvar paddleColor =Color.white
var paddleSize =Vector2(10.0,100.0)
var halfPaddleHeight = paddleSize.y/2var paddlePadding =10.0# font variablevar font = DynamicFont.new()
var robotoFile = load("res://Roboto-Light.ttf")
var fontSize =24var halfWidthFont
var heightFont
var stringValue ="Start a game by pressing the spacebar"# ball variableonreadyvar startingBallPosition =Vector2(halfScreenWidth,halfScreenHeight)
onreadyvar ballPosition = startingBallPosition
# player paddleonreadyvar playerPosition =Vector2(paddlePadding, halfScreenHeight - halfPaddleHeight)
onreadyvar playerRectangle =Rect2(playerPosition, paddleSize)
#ai paddleonreadyvar aiPosition =Vector2(screenWidth - (paddlePadding + paddleSize.x),
halfScreenHeight - halfPaddleHeight)
onreadyvar aiRectangle =Rect2(aiPosition, paddleSize)
#string variablevar stringPosition
# delta keyconst RESET_DELTA_KEY =0.0const MAX_KEY_TIME =0.3var deltaKeyPress = RESET_DELTA_KEY
# ball speedvar startingSpeed =Vector2(400.0,0.0)
var ballSpeed = startingSpeed
var playerSpeed =200.0#scoringvar playerScore =0var playerScoreText = playerScore as Stringvar playerTextHalfWidth
var playerScorePosition
var aiScore =0var aiScoreText = aiScore as Stringvar aiTextHalfWidth
var aiScorePosition
const MAX_SCORE =3var isPlayerWin
func _ready() -> void:
# print(get_tree().get_root().size)
font.font_data = robotoFile
font.size = fontSize
halfWidthFont = font.get_string_size(stringValue).x/2
heightFont = font.get_height()
stringPosition =Vector2(halfScreenWidth - halfWidthFont, heightFont)
playerTextHalfWidth = font.get_string_size(playerScoreText).x/2
playerScorePosition =Vector2(halfScreenWidth - (halfScreenWidth/2) -playerTextHalfWidth, heightFont +50)
aiTextHalfWidth = font.get_string_size(aiScoreText).x/2
aiScorePosition =Vector2(halfScreenWidth + (halfScreenWidth/2) - aiTextHalfWidth, heightFont +50)
func _physics_process(delta: float) -> void:
deltaKeyPress += delta
match currentGameState:
GAME_STATE.MENU:
if(isPlayerWin == true):
changeString("Player wins! press spacebar to start a new game")
elif(isPlayerWin == false):
changeString("Ai wins! press spacebar to start a new game")
if(Input.is_key_pressed(KEY_SPACE) and
deltaKeyPress > MAX_KEY_TIME):
currentGameState = GAME_STATE.SERVE
deltaKeyPress = RESET_DELTA_KEY
playerScoreText = playerScore as String
aiScoreText = aiScore as String
GAME_STATE.SERVE:
setStartingPosition()
update()
if(MAX_SCORE == playerScore):
currentGameState = GAME_STATE.MENU
playerScore =0
aiScore =0
isPlayerWin = true
if(MAX_SCORE == aiScore):
currentGameState = GAME_STATE.MENU
playerScore =0
aiScore =0
isPlayerWin = false
if isPlayerServe:
ballSpeed = startingSpeed
changeString("Player Serve: press spacebar to serve")
if!isPlayerServe:
ballSpeed =-startingSpeed
changeString("Ai Serve: press spacebar to serve")
if(Input.is_key_pressed(KEY_SPACE) and
deltaKeyPress > MAX_KEY_TIME):
currentGameState = GAME_STATE.PLAY
deltaKeyPress = RESET_DELTA_KEY
GAME_STATE.PLAY:
changeString("PLAY!!!!!")
if(Input.is_key_pressed(KEY_SPACE) and
deltaKeyPress > MAX_KEY_TIME):
currentGameState = GAME_STATE.SERVE
deltaKeyPress = RESET_DELTA_KEY
ballPosition += ballSpeed * delta
if ballPosition.x <=0:
currentGameState = GAME_STATE.SERVE
deltaKeyPress = RESET_DELTA_KEY
isPlayerServe = true
aiScore +=1
aiScoreText = aiScore as Stringif ballPosition.x >= screenWidth:
currentGameState = GAME_STATE.SERVE
deltaKeyPress = RESET_DELTA_KEY
isPlayerServe = false
playerScore +=1
playerScoreText = playerScore as Stringif ballPosition.y - ballRadius <=0.0:
ballSpeed.y =-ballSpeed.y
if ballPosition.y + ballRadius >= screenHeight:
ballSpeed.y =-ballSpeed.y
if(ballPosition.x - ballRadius >= playerPosition.x and
ballPosition.x - ballRadius <= playerPosition.x + paddleSize.x):
var paddleDivide = paddleSize.y/3if(ballPosition.y >= playerPosition.y and
ballPosition.y < playerPosition.y + paddleDivide):
var tempBall =Vector2(-ballSpeed.x, -400.0)
ballSpeed = tempBall
elif(ballPosition.y >= playerPosition.y and
ballPosition.y < playerPosition.y + paddleDivide*2):
var tempBall =Vector2(-ballSpeed.x, 0.0)
ballSpeed = tempBall
elif(ballPosition.y >= playerPosition.y and
ballPosition.y < playerPosition.y + paddleDivide*3):
var tempBall =Vector2(-ballSpeed.x, 400.0)
ballSpeed = tempBall
if(ballPosition.x + ballRadius >= aiPosition.x and
ballPosition.x + ballRadius <= aiPosition.x + paddleSize.x):
var paddleDivide = paddleSize.y/3if(ballPosition.y >= aiPosition.y and
ballPosition.y <= aiPosition.y + paddleDivide):
var tempBall =Vector2(-ballSpeed.x, -400.0)
ballSpeed = tempBall
elif(ballPosition.y >= aiPosition.y and
ballPosition.y <= aiPosition.y + paddleDivide*2):
var tempBall =Vector2(-ballSpeed.x, 0.0)
ballSpeed = tempBall
elif(ballPosition.y >= aiPosition.y and
ballPosition.y <= aiPosition.y + paddleDivide*3):
var tempBall =Vector2(-ballSpeed.x, 400.0)
ballSpeed = tempBall
if(Input.is_key_pressed(KEY_W)):
playerPosition.y +=-playerSpeed * delta
playerPosition.y = clamp(playerPosition.y, 0.0, screenHeight - paddleSize.y)
playerRectangle =Rect2(playerPosition, paddleSize)
if(Input.is_key_pressed(KEY_S)):
playerPosition.y += playerSpeed * delta
playerPosition.y = clamp(playerPosition.y, 0.0, screenHeight - paddleSize.y)
playerRectangle =Rect2(playerPosition, paddleSize)
if ballPosition.y > aiPosition.y + (paddleSize.y/2+10):
aiPosition.y +=250* delta
if ballPosition.y < aiPosition.y + (paddleSize.y/2-10):
aiPosition.y -=250* delta
aiPosition.y = clamp(aiPosition.y, 0.0, screenHeight - paddleSize.y)
aiRectangle =Rect2(aiPosition, paddleSize)
update()
func _draw() -> void:
draw_circle(ballPosition, ballRadius, ballColor)
draw_rect(playerRectangle, paddleColor)
draw_rect(aiRectangle, paddleColor)
draw_string(font, stringPosition, stringValue)
draw_string(font, playerScorePosition, playerScoreText)
draw_string(font, aiScorePosition, aiScoreText)
func setStartingPosition():
aiPosition =Vector2(screenWidth - (paddlePadding + paddleSize.x),
halfScreenHeight - halfPaddleHeight)
aiRectangle =Rect2(aiPosition, paddleSize)
playerPosition =Vector2(paddlePadding, halfScreenHeight - halfPaddleHeight)
playerRectangle =Rect2(playerPosition, paddleSize)
ballPosition = startingBallPosition
func changeString(newStringValue):
stringValue = newStringValue
halfWidthFont = font.get_string_size(stringValue).x/2
stringPosition =Vector2(halfScreenWidth - halfWidthFont, heightFont)
update()
Transcript
Hello, Godot Tutorials is not sponsored by or affiliated with the
Godot Game Engine. You can also
download the GitHub file project in the
link in the description
down
below. Let's start
with brute
force coding.
So in this case, we left
off in the last episode with a game
status, in this case, menu server play.
However, our
game doesn't really do anything, so let's go ahead and actually do something. So first towards the bottom, I'm going to go ahead and create a variable for
starting the player
both.
So in this case, I went ahead and created a variable called Ball
Speed, and I set it
to four hundred in the X direction and zero on
the Y next.
Let's actually go ahead and get our ball moving. So in this case, we want to head into our game state for play and actually move the ball.
Now, in this case,
we're going to go ahead and change the position of our ball. So ball position and we're just going to say plus equals ball speed. Keep in mind that this is a vector, too, and we're just going to multiply both the X and Y values by Delta.
OK, so now that
we have the ball moving, let's also make sure that we are actually updating our graphics to the scene and we're just going to put update towards
the bottom. Now, if we go
ahead and press play, you can see that are both actually moving. Next, let's go ahead and add collision checks to the side of our screen. So underneath here, I'm going to go ahead and add that code now.
And basically, we're checking the left side of the screen, if our position is less than
zero, we're going to go ahead
and change our current state of the game.
After changing the current
state, we're also going
to reset the Dota key press.
And then lastly, we're going to set the players serve, and that's because we need to change the direction of our ball. And basically in this line of code, what we're saying is if our ball position has touched the edge, basically if the center of our ball has touched the edge, we're going to go ahead and change the current game state to serve state. We're going to go ahead. Reset that, though, to keep press, to make sure that our player isn't pressing too quickly. And lastly, we're going to change the direction
of the ball and make sure that if the
opponent scored the
point, it is the player's
serve and vice versa. And basically, we can just go ahead and copy this for the AIA and we can just say if Beau is greater than or equal to and in this case, we're going to say the screen with. Then we do everything again, except we change this value to full, so is player service equal to full because the player scored the point and now the EHI gets to
serve and we can
check if this code works.
And as you can see there at work, however, or ball hasn't reset its position, so let's go ahead and do that now.
So in this case,
we need to create two different variables, one for the ball position and one for the starting ball position. So on the top, you can see here we already have the ball position. However, because we are changing this value in order to reset it, we need to pass it a new value. So right now, because, again, we're
forcing our code,
we're just going to go ahead and create a starting position value.
We're going to go ahead and assign that starting ball position value into our ball position value, and now every time we change the ball
position, we can simply
just pass it in our starting ball position value to reset the ball position to the center of the
screen. So in this
case, let's go ahead and head back to our game state. In this case, we're going to go into the serve state.
And at the
very top, what I'm going to do is I'm going to just change the ball position back to the starting
position. So pole
position will be equal to the starting position of
our ball. And right
here in our serve state, we ended up resetting the value of our
position. And if we go
ahead and test that out, you can see that as the game plays, it resets. However, the direction
hasn't changed
yet. So let's go ahead and actually change the code a little bit in order to change the direction
based on which side of the
screen the ball has made
contact with in this case.
Let's go ahead and actually add a new value.
So right under the ball speed,
we're going to go ahead and create a starting ball position speed so similar as to what we did or the starting ball position.
In this case, what we're going to do is just pass that into the ball speed so now we can change our ball speed and we can reset the starting
position of our ball
speed when the game ends and we can change the direction by just adding a negative sign. So in this case, because we're dealing with the X axis or starting speed, in this case the speed of 400, we can say
that the starting speed when the player
is serving will go in the positive X direction.
And when the player
loses and the eye gets to serve, we add the negative and we
move to the left. So let's go ahead and do that. Now, in this
case, what we're going to do is head back to the serve states and towards the bottom. We can actually change our direction. So let's make sure we change the direction before player input has set.
And basically what we're saying is
if it's the players turn to serve, move the
ball in the positive X direction and change the string to make
sure that it shows to
the player who is serving and we can do the same
thing if it's
not the player serving. You can do that with the exclamation point. This flips the bullying values. So in this case, it turns into truth so we can enter if statement.
And in this case
we can just add the negative sign and we can say Aizer. We can also get rid of this because we no longer need it. And so when we actually start our game and we press spacebar, you can see that it lets us know that it's the player, sir. And now, because we scored a point, it's now the serve. And we can see that when it touches the end over here, what it does is it resets it back to the middle and now we can go back and forth. And this is how we can use a little bit of states to change direction, to change what the game is doing and so forth.
Now, before
moving on, I'm going to go ahead and change something. I accidentally misspelled position. So let me go ahead and fix that right now. And now we can move on. So in this case, we have our game moving back and forth when it hits the edge of the screen. However, it doesn't really do anything. We need to add collision
between our ball and our paddles.
So let's go ahead and add that we can head back to the game
state for play
and towards the bottom. We can actually add that in.
So let's go
ahead and do that right now.
Now, in this case, let me explain quickly what's happening first, we're taking our position on the X value in this case, because it's a vector to it comes with both an X position and a Y position. We're taking the position. We're subtracting bow radius because we want to make sure that this point is on the left side of the ball. And we're comparing that to basically our player pedal's position. So in this case, player position, that X making sure that we are at least within range in the X axis and we're doing the same thing, we're making sure that this left
point on our ball position is
also less than the total size of the paddle,
basically the
width of our paddle. And we're testing the ball position on the
y axis, making sure
that we are in between the player paddles
y axis and
adding the paddle
size to make sure
that on the x axis we're between the x width of
our pedal and on the Y
axis, we're between
the height of
our paddle. Then we take the inverse of the ball speed. And so the inverse is just the opposite of what it is. And by adding the negative side, that is exactly what we are doing. We are increasing the ball speed. Now, in this case, we can go ahead, copy paste this and we can essentially do the same
thing for the
pedal now because this is to the left of our boat.
We need to use the plus
sign to get this new position on the boat to the right side of the ball. And so now we have a right point on our ball and we need to compare that to the position. And so we can just simply copy and paste that. Go ahead, run our code.
And when it
runs, you'll notice that it actually reflects between the two
pedals. Now, in this case,
this is great to know that we have this collision, but our game isn't doing anything really, especially for the player, because they cannot move. So let's go ahead and create that. So first, we're going to head over here and just anywhere in the code, we're going to go ahead and actually create the player movement. So in this case, we can just click player speed and we can assign that a value of some sort, maybe in this case, three hundred.
But in my case, I'm
going to call it two hundred. Once that's done, we can head back to the game state in our play state and towards the bottom we can actually add the code. And in this case, it's just going to be a simple input is key prest kind of thing, and we're going to make sure that we can move up or down. So in this case, if
key W
because we want our player to move up and I'm just going to pass in the simple pass and then we can test again if our player is moving down. And in this case the same thing is key prest. However, for the scan code we're going to say
s and in this case I'm going to pass.
And basically what we're trying to do is if our
player presses
the key, we move up and if our player presses the esky,
they
move down. So let's go ahead and do that now. So in this case, we're just going to change
the Y value of our
player position and in this case, player position that way. And we have to compound the speed. And in this case, since our player speed is a positive value and because
down grows in
the positive value to go
up, we need to give
a negative value. And so we can do that passing in Delta, of course. And we also need to change the player rectangle position.
And in this case,
we can just say rec
to and in this
case just say player position and Petto size. And that's it for the player position when we want to move up and we can do the same thing when going down, but we just omit the negative side. So now what we're saying is if we press w we go
up, we
update our player rectangle so it makes sure that it draws properly to the screen. And so actually, if we go ahead and run the game.
I press up, I go up, I press down, I go down. However, two things, our panel goes beyond the game screen. I'll show you how to fix that later. And more importantly, our ball isn't really moving anywhere besides straight in a line. So as you saw, there are bubbles moving left and right and it really didn't change in direction. So I'm going to add some spaces because I'm going to work a little bit on this code. But basically what we need to do is if it hits the top portion of our pedal, we move up.
If it hits the middle of our pedal, we move straight. And if it hits the bottom portion of our pedal, we move at a downwards angle. Now, there are many ways to do this.
However, I'm going to go
take the route that, in my opinion, I think a beginner would do. And then towards the end of the episode, we'll take a look at perhaps a better way of implementing it further down an episode in this series. So what I'm going to do first is I'm going to test against the X position. And if the X position matches true, we're going to test against the Y position different values of our Y position. And then based
on which
if statement, because I'm going to use F statements where this
example catches
true, we're going to change the ball speed. And so let's go ahead and do that.
So in this case,
I'm going to get rid of that at a parentheses at that and we're just going to move everything inside. I'm also going to add another if statement here at the parentheses to make sure that we can actually press enter or an error throws. And basically what this does is it does the same exact thing. We aren't really doing anything differently. This still has the intended behavior, basically, if we run the game, it's still going to collide. Nothing has really changed programmatically.
What I do want to
do is test against different if statements and we're going to actually check that out right now. So first, I'm going to create a
variable for pedal because I want
to divide our pedal into equal sections. So in this case, three sections.
And because we're doing it on the Y axis, we get the pedal size on the Y axis, divide that by three and we create this variable paddle that we can test against. So we need to add three statements, one for each portion of the paddle that we're dividing with this three here.
And we're
going to say is if both player position that Y starts at the top of our Y position and if four positions y value
is less, then the starting
position of our player position, plus the paddle divide. Now, by adding the paddle position, what we're saying is the top portion of our player paddle, we want to do something, but we're moving straight here and I don't really want that. And so I'm just going to create this temple position value and I'm just going to vector two.
And not
only will this hold the ball speed on the x axis, what we're going to do is we're going to actually
go up by
four hundred pixels. And so we're going to have this angle. And then from this value, we're going to go ahead and pass that to our ball speed. Now, what we're seeing with this, if statement is if this expression is true, we're hitting the third or the top portion of our pedal and we would like it to move upwards at an angle. We can actually copy and paste this and do several things with it. First, we need to change this into an if statement. That way, if we fail the first
expression, we move on to
the second expression, if we fail the second expression, we move to the third expression, so forth. And because we're dealing with paddle divides, we can actually multiply it. So multiply by two multiplied by
three, we can change
the values
of the ball speed. In this case,
what we're saying is if we hit the middle, we move our y axis in a straight line. And lastly, we can get rid of the negative. And if we run this, what should happen is when the ball makes contact with our player pedal, we just move back and forth and notice here, if I were to actually up, it will go up. However, there's no collision at the top and bottom. And so we're going to work on that later. But let's test if it actually goes down. And there it is. Now, we can do the same thing for the position in this case. I'm just going to copy all of this.
Just create three statements. I'm actually going to borrow the variable paddle, bring that down here and we can essentially
do the same
thing, can actually just do that here.
And we can actually take this value here and replace them on down here.
And last but not least, we need to do the statement, so if we add the
if normally I would not
recommend writing your code like this because one, it's not dynamic.
And two, lots of if
statements are hard to
maintain and there are better
solutions for changing the direction of our board and making it dynamic.
However, let's just
go through this
process as a beginner. And so
for the
first shot
of writing the Pong game, this is actually
really good because it
actually shows that you're thinking about the game design in a way. Regardless, let's move on.
So in this case,
we need to add some type of collision between the top and the bottom. And so if we look at our code here, we can actually
do that towards the
top. And so I'm going to read it over here and we're actually just going to test the ball position.
So if your
position
was subtracted
by the bow radius and we make sure that that is less than
zero, then what
we're doing is we're just going to change the direction. However, if our position on the Y axis plus the ball radius is greater than or equal to the screen height, what we do is we're going to invert
the y axis
again. And that's actually pretty simple to do. All we're doing
is we're just changing
the Y axis and we're inverting
it by the same
value. And that's actually pretty simple to do.
So now when we
have our ball and it touches the top edge of the screen, we just invert the Y value and we do the same thing for the bottom, and that's where we get the bouncing of
that.
And so if we actually run this game.
And we go ahead and actually move it, you can see that it starts
bouncing and when it reaches the edge
of the screen, we actually change the direction that we
serve. So basically, now
that we've covered our collisions on the top and bottom portions of our screen, let's go ahead and actually
have our a paddle
move towards the
ball.
And so a good place to put this coat in is towards the bottom. And what we're going to say is basically, if a position that
way, we're basically
just going to give it the opposition's y
value. And of course,
because we would like this centered, we're just going to call the Y portion of our pedal size the height. We want to give our pedal divide that by two and now our position will be centered wherever the ball moves. Also, keep in mind that because everything's inside the rectangle,
in order to have
this update properly, we need to pass any new value to our rectangle. And we just call the new eye position, followed by the panel size. And now when we actually run
the game
in the first half hour, pedals not going to move. But now as the ball moves, we actually get.
Now, as you can see here, as the ball keeps
moving, our enemy
is moving with the ball, and we're going to keep it like this to help us with coding later on.
But basically,
we have our game and it reset itself. And that's because we're not really chasing the ball. We're just giving the player paddle the white position of our ball. Now, there is a problem with our current code. Basically, our player paddle or a paddle can go beyond the player screens height. Basically, if we move up or we move down, we can
basically make our paddle
disappear. And this is not what we intend for our player. So let's go ahead and use the clamp method from Godot to limit the player paddle and the paddle to the game screen. So clumping our values is fairly easy.
The game engine
provides us the Klemp method. So in this case, what we say is we want to clamp or a position. The first argument requires a value we wish to clamp our minimum and maximum values to in this case, we're saying we would like to clamp the position that we value between zero point zero, which is the top of our screen and the screen
height, minus
the paddle size on the y axis. And when we run our game, what you should see is that our values
are clamped to the game screen.
So our pedal
moves but doesn't
go beyond. However, we need to do the same thing for the player pedal. So let's go ahead
and do that now. In this case,
I'm just going to copy and paste this.
We're actually going to put this
in between here and we're going to change the position value, but we're going to keep everything the
same. And now when
we run our game, what happens is our player is going to be clamped to the screen. So as I'm pressing up, I don't go beyond
and as I press down, I don't go
beyond the bottom. Now, whether or not you agree with where this is heading, at least our game is being built. And that's the most important thing, that the game is being built.
And so our game looks almost complete.
So let's go ahead and add some scoring. So towards the top, I'm going to go ahead and add some scoring. And in this case, we need some variables. One, to hold the players score. And then we also need something to hold the players score cortex. And in this case, we can just say player score
as a string
so we can convert our integer
value into a string
value and we need some other things as well. So let me go ahead and do that.
In this case, we need to calculate the width, the center of our string value, whether it be a single digit number or a double digit number. And lastly, we also need to make sure that we have the position of our player cortex. Basically, we're doing the same thing we did for the top of the screen, but
moving it towards the
center on the left side for the
player and the center on the right side for the
opponent. In this case, we can just copy and paste that, give it new names, in this case a score and a score tax and of course, a text half with
and a
score position. And of course, we need to do one more thing, need to make sure that we convert our score integer value into a string value, which we passed to the score text variable. Now that we have these values, let's go ahead and actually do something with it in this case displayed to the screen. So when we head over to the ready virtual method, because we initialize our font, font data
and font
size, we can actually go ahead and add these values to
the screen. So in this case,
let's go ahead and worry about the
00:23:03:00 - 00:23:05:21
player text position and we're actually
just going to do the same thing. We're going to get the string size and in this case, we want the player score. Text and we're actually just going to worry about its exposition, divide that by two, and what we're saying is basically we get the width of our player text divide that by two, we get a value. Which represents the middle then. Next we get the player score position, we make sure that it's a vector too, and that we have a half screen width and we actually subtract that by the half screen width divided by two.
And then on top of that, we actually have to subtract the player, text half wit, and then we also get the font height and we're going to add a little bit of padding, in this case, 50 padding.
In this case, what
we do is we get the same thing for the text, half with as well. And we can do the same thing. We get the string size.
We make sure
we pass in the score
text and then we divide that by two
in order to get the middle position of our string. In this case, the
player and the enemy score. And then we get
the score position
and we
pass it in a vector to and we do the opposite actually of how we position the player in this case. We do want the half screen with.
But instead
of subtracting, what we need
to do is add it and then
we add it by another half screen will divide that by two. And again, the reason
for that is if we add
half by half, we're centering ourself on the right side of the screen, but we also have to take into consideration the eyes have position and we need to subtract it. And on top of that, we have
a height font and we're
going to add 50. Now, lastly, what we need to do is we need to actually update all of this inside or draw method. And so far or draw method is calling this set starting position function.
And we will talk
about that a little later. But regardless, we need to
Pasadena font and a
position and the value in which we wish to draw our string onto the screen. So in this case,
what we're going to say is that we want our
player score
position
and we want our player score
tax and we can
do the same thing for the bottom as well, or a score
position and
to score
text. And now when
we run the game, you can see that our things actually appear, but
they don't update.
And that's because we need to actually add on to the values.
Not to change the
values is quite simple. All we have to do is go into our collision for the
left
and right sides of our game screen and that would be here if pole position that X is less than zero and pole position that X is greater than screenland, then we actually need to add our scores. And so in this case, if we're less then then what that means is that are actually scored a point. We're going to compound the value of one. And of course we need to change our score that text and we can just see a score as string.
Then we can also
do the same thing for the other side of the screen. In this case, we say player score plus equals
one and
player score tax will equal our players
score as string.
And now when we run
this game,
what we should see is that. Our score changes and the same thing will be true for the EHI if we are able to score a point
against it
now. Next, let's go ahead and tackle the
problem of the
starting position. Basically, we aren't resetting anything and that's not good. We need to be able to reset things. We need to be able to reset it every time the
player or opponent loses a point. And so let me go ahead and
show you, as you can see here, if I move my player character towards the bottom, it should be centered. And the same thing for the enemy, a pedal as well. If I were to have it move and as you can see,
nothing has been center. And when it's a serve,
we should be able to reset everything. So let's go ahead and do that right now. Now, as you can see
here, this doesn't
really define what's happening. All we're doing is we're using this method to update everything in sight. So let's go ahead and actually
put this in here inside the draw
method. That would be the most appropriate thing to do. So a function extract. And instead of having all this here, what we will do is actually reset the position
of our eye, the position
of our ball and the position of
our player. So let me go
ahead and do that right now. We can start with the eye position. And of course, basically this code will look familiar to you because it's basically the same thing we
did earlier in the series.
Basically, we need to make sure that this goes inside our rectangles, so that is a risk to data
type person, the
newly established or reset it a position and of course, the petal size. And we can do the same thing for the player position as well.
And lastly, we can do the same thing for the starting position as well.
So now that we have everything here, we can actually reset everything. So let me go ahead, copy paste this. If we go to the top, the most appropriate place to put it in is the server. So let me go ahead and replace that right now.
And on top of that,
when we play the game, what happens is if something were to move, I get reset, player makes a score and let me test me. So.
And there we go, everything gets reset and in a sense, we have a complete game, sort of basically we need to do a few things. One is we need to give the player a chance to win.
And two,
we need some type of goal, some type of endpoint. Basically, our game goes on
forever and that's just not OK. So in this
case, let's go ahead and actually create some type of end point. So over here, in this case, let's create a constant and we're going to call it max score and we're going to give this a value of three. So our game ends when someone has reached three and we want to see who has won.
So in this case, we're creating
a boolean value variable is player win and it will either hold true or
false. We're going to keep this empty. Now, on
top, we have this string value which is displayed at the top of our screen. It says,
Hello, world, wherever.
We're going to give some
instructions, start a
game by pressing
the
spacebar. Now, what we're going to do is we're actually going to give good instructions to the player, because when they're in the menu screen, they have no clue how to get out of it. We made this game so we know we have to press the spacebar, but the player playing your game has no clue. So in the menu, we're going to just get rid of this chain string.
And when we run the
game, you should see start a game by pressing the
spacebar. It could be better,
but for now, this
is a great start.
However, what we're going to do is we're going to add some additional things we're going to say if is clear when
we
actually want to do something. So let's make sure that we test for true. And then what we can say is we can actually change the string and we can actually just let the player know that they want. So player
wins and then again,
press spacebar to start a new
game and you can do
the same thing for the value of force. So in this case, if player win is FOSE, then it means the wings. And so we can congratulate the A.I. and press spacebar to start a new game. And if the player starts a new game, is player win is known, so it will not be true or false. And so this if statement will be passed.
So you can either
leave it as is or you can turn it into an if statement regardless. It will still have the same outcome. When we press play, it will say start a game by pressing the play player serve.
And play the game, but that's not
all we need to do a little more. So let's go ahead and do that. So in this case, we need to make sure that when the game has finished that we actually figure out who won and then reset all the scores after. So in this case, to manage player score, let's go ahead and do that in the serve state. And if Max score is equal to player score or we're going to do is we're going to end the game. And same thing here. If Max Score is equivalent to the ACE score, basically whichever one reaches three wins the game and we have to jump back to the menu state.
So in this
case, what we can do is actually say current game state will be equal to the game state of the menu screen and we can do the same thing for the bottom as well. And we can just basically reset everything, so player score zero, a score becomes zero and is player one is actually equal to true and we can do the same thing for the bottom as well. So in this
case, whether
player wins or enemy wins, we
go to the main state, we change our score to zero, and we make sure that we
change. The bullying in this case, is player win state to true or false? And actually the enemy should be false. Now, lastly, when in the menu state, we wish the player to see the final score.
However, we wish
to change all that when we move
into the serve state.
And so up here, I'm going to add an update to force a
call to the
draw method.
Now, our update
doesn't really do anything because even though we change the player scores, we still need to change the text. So if we head to the menu
state and in the
input, we can actually change that. So in this case, we're score 2x
equal
players score
as
string and we can do the same thing for score text of the as well.
And now if you run our game.
You can see that the Edwins press spacebar to start a new game, we can see the player score, but when we press spacebar, notice how we
reset and everything
looks good. Lastly, it's a little unfair
that our enemy A.I. is perfect
when chasing the ball. So let's go ahead and actually add a
chasing
A.I.
effect instead
of a perfect chasing
affect. And if we head
towards the bottom, this is our code
here that positions
our paddle perfectly to the ball. Instead, we want our A.I. to chase the bull's eye position. And so what we can say is if both are positioned,
why is greater
than A.I. positioned?
Why?
And let's go ahead and
add a buffer, because if we don't,
you might notice some
jittery. And so divide
that by
two plus
10, 10 being our buffer. What we say is that I position the one plus equals a speed. In this case, our speed will be two hundred and fifty and we pass in the Delta time.
Now in this
case, we can go ahead and copy and paste that as well because we can just do the opposite
direction. So if our
ball is
higher than the
center of our ball position, making sure that we subtract
ten since we're moving up, then we can say
that our A.I. will have a negative speed. Now, as you can see here, our enemy pedal is actually chasing the ball except when it reaches the buffer zone. Now, if we keep doing this, what we'll see is eventually we should be able to win. And as you can see here, we do have the ability to
win player wins,
Pressplay, spar a serve and play.
And that's the great thing, the way we
wrote our code. Basically, whoever lost in the last match gets
to go first.
What I'm going to do is I'm going to go ahead and clean up some of the code. So in this case, players serve press spacebar to start or excuse me, in this case to serve. And we're going to actually do the same thing for the A.I. string as well.
And that's
basically it. So ask yourself this question. Based on the code that we've written
so far, is our code
maintainable and is our code readable? And with the techniques I showed you in previous episodes, you should be able to come out to a conclusion.
But that's not to
take away from what we've done so far, especially if you're a beginner. If this is the kind of code you've written, believe it or not, this is amazing because we actually got something done. We actually have we have a menu state, we have a serve state. And then lastly, we actually have the game play state where we actually chase the ball. On top of that, we have
a basic a ay
to play against. It's not the most perfect A.I., but it's something
it's a step
above creating a second player.
But regardless, this
code that we've written is not good enough to show off when doing an interview, because keep in mind that the goal of our project was to show off during an interview to use this inside of our portfolio that we're proud enough to
submit with
a resume. So in the next episode, let's go ahead and take a look at how we can tackle at creating a better game. Well, thank you for subscribing and thank you for clicking the like button. I look forward to seeing you in the next episode.
Have an amazing day.
Why are you writing everything inside a single class?
The pong series is to be a guide on how to make a game from beginning to end.
For this specific episode in the pong godot basics series, I wanted to show that you don’t have to worry about
writing code correctly.
Just go out there and make the game you want, learn how to code as properly as possible as you are moving forward.
People who buy your game don’t bother caring how you wrote your game, just that you have a game that works and is
lacking any glitches and/or bugs.
Will you be refactoring or breaking up the code into individual classes?
Yes, in a future episode I will go over refactoring based on features.