In this episode I want to go over a few things I wish I knew when I started out programming.
Rules for beginners
The first thing I want to impart on you is to just get something done.
It’s like my favorite quote from Nike, “Just do it”; along with my favorite quote from
capture the flag competitions, “Try Harder”.
First steps to improvement
Before you go about improving the pong game or any game for that matter, first understand the
why’s, of how your game’s code works as it currently stands.
In a sense you need to understand what exactly is going on with the code you’ve just written.
It’s good to learn by copying other peoples code as long as you take the time to see and read
what exactly the code is doing and how your game works.
From their you can seek to improve on a specific category of your game
AI (Artificial Intelligence)
User Interface
Gameplay
Where to start
There are two things I want to focus on when refactoring the code of our current pong game:
Collisions
AI (Artificial Intelligence)
Collisions in game programming
Collisions are broken into two processes, checking for an action and determining a reaction.
Detect if a collision between two objects has happened (action)
Determine what needs to be done after a collision has been detected (reaction)
Detecting a collision is mathematical, and the easiest part of collisions (geometry & vector math)
Determining what happens after a collisions happens is purely a creative process and in a sense the hardest
thing to implement in a collisions' system.
Collision #1: ball & wall
To detect the collision of the ball with a wall, we will be implementing a point-to-point collision.
A point-to-point collision is the easiest form of collision detection in game programming.
This is because all you need to do is see if the x and y values (z value in 3D games) between to points are exactly the same.
# Action is checked by an if statement, the collision of two pointsif point1.x == point2.x AND point1.y == point2.y:
# Reaction implementation happens here
From a point-to-point collision, we can modify it a little for game programming and check that
our ball has either touched or exceeded the bounds of our “walls”, the edges of the screen.
# Top Wall & Ball Collision Detectionif ballPosition.y - ballRadius <=0.0:
# change the direction ball goes in# Left & Ball Wall Collision Detectionif ballPosition.x - ballRadius <=0.0:
# change the direction ball goes in# Bottom Wall & Ball Collision Detectionif ballPosition.y + ballRadius >= screenHeight:
# change the direction ball goes in# Right Wall & Ball Collision Detectionif ballPosition.y + ballRadius >= screenWidth:
# change the direction ball goes in
For now this is the code breakdown for checking collisions between the top/bottom/left/right portions of the wall.
The have the same checks, just different reactions based on how you would like the ball to react.
Collision #2: ball & paddle
The next important collision we have in the game is between the ball and paddle, which is a rectangle-to-point collision.
A rectangle-to-point collision just checks if a single point on the 2D/3D plane resides inside a rectangle.
This is one of the easier collision detections to implement in game programming.
# Break down important geometric information into variables
rectLeft = rect.position.x
rectRight = rectLeft + rect.size.x
rectTop = rect.position.y
rectBottom = rectTop + rect.size.y
# Action checkif ( point.x >= rectLeft && point.x <= rectRight AND
point.y >= rectTop && point.y <= rectBottom):
# Reaction Implementation
This is a fairly straight forward way of implementing a rectangle-to-point collision.
Understanding the AI
For the game we have created, we’ve implemented a simple “Chasing” AI algorithm.
Chasing/Evading AI
Chasing & evading AI algorithm has two parts:
Initiate the chase
Create the effect of the chase
# Initiate the chaseif ballposition.y > aiPosition.y + (PaddleSize.y/2+10):
# create the effect of the chase
aiPosition.y +=250* delta
Where to learn more about collisions
Game programming requires an understanding of vector math and for that I recommend learning more about
linear algebra.
Linear algebra helps when wanting to create, modify, and understand collisions detection and reactions in game programming.
Game Designer vs Game Programmer
In this series I wish to teach you that game programming is different from game design.
Even though I will be focusing on the game programming aspects of game development, I hope to also teach some very basics of game design in this article.
Even though game development requires both game design and game programming, understand that they are two completely different roles.
Game Designer
A game designer develops compelling and engaging rules for games. They’re the creative vision behind the scenes.
Game Programmer
A game programmer provides the technical solutions to carry out the vision of the game.
What should I learn?
As a solo or independent game developer, I recommend that you have a general understanding of both in order
to create games that both captivate and intrigue people who play your game.
Game Programming & Game Design Specializations
To understand what we may need to learn when creating games, let’s first understand what kind of specializations there are for both
game programming and game designing.
Game Programming
In small companies, such as solo development or indie studios, it is generalists that are highly sought out as they
are capable of having a general understanding of all aspects of their given field.
However, if you are looking to work at bigger companies, they are looking for specialists to help build out their games visions.
Smaller studios look for jack of all trades while bigger studios look for a master of one.
Here are some game programming specializations:
Rendering Programming
Gameplay Programming
Animation Programming
QA Programming
UI Programming
AI Programming
Network Programming
If you are looking to develop your own games as a solo or independent developer, look to having a baseline understanding of all the listed roles.
If you dream of working at a bigger studio, look to not only have a genera baseline understanding of all the roles, but in addition to that look to become a
master at a single role.
Game Design
The same concepts and ideas touched on in game programming also applies to game design.
At bigger game companies they look to hire a master of one, while smaller game studios look to hire a jack of all trades.
Here are some game design specializations:
Game Designer
Level Designer
Combat Designer
Economy Designer
UI Designer
Narrative Designer
AI Designer
As a solo developer, I recommend having a baseline understanding of all these roles.
Improving your games design
Even though I want to focus purely on the game programming aspects of game development in the pong Godot Basics Series, here are some
tips on improving your games
Game Design 101
Ask yourself the following questions:
Is my game simple enough to learn?
Is my game hard enough to master?
Is my game fun?
If the answer to any of these questions is NO, then you need to go back and change something about your game.
These questions are inspired by Bushnell’s Law.
Bushnell’s Law (Nolan Bushnell, founder of Atari):
All the best games are easy to learn and difficult to master. They should reward the first quarter
and the hundredth.
Lastly game design is not something that has a correct or wrong answer; this is because game design is an artform.
However, game design has rules and frameworks that we can follow to improve and inspire our own works.
Transcript
Hello, Godot Tutorials is not sponsored by or
affiliated with Godot
Game Engine. Before we begin, Keep in mind my rule for beginners, which is get something done first and then worry about improving it afterwards. To put it simply, just
do it, then
try harder. Let's go over the first steps to
improvement before improving
your pong game for your portfolio in an interview setting. First, understand the how and why your game works as it currently stands.
How and why
does the code work the way it is
written? From there, you
can seek for improvement on a specific category of
your game.
Categories include a user interface,
gameplay and so forth.
Now where do we start?
And in order to
start improving yourself, you need to understand three
things states,
conditions and our
A.I. because we
went over states in a previous episode. I will not go over that. In this episode, however, I will focus more on conditions and artificial intelligence.
First, let's go over
collisions in game programming. Collisions are broken into two processes. The first is detecting EFFI collision between two objects has
happened and it will
usually return Back a Value of true or false?
You can consider
this
an action. The second
thing we need to determine is what needs to be
done after
a collision has been detected. In this case, we need to figure out what the reaction is going to be.
Now, normally, detecting a
collision is a mathematical
process, basically your
geometry and vector
math, linear algebra.
And generally
the
reaction or what to do after a collision happens is a creative process. But by
default, most
people want to mimic real world collision
physics. First, let's understand
the collision between the ball and the wall at the top bottom left and right portions of
the screen. Now the ball and
what collision is a point to point
collision. And as a matter of
fact, it is the easiest form of collision detection we
have. Basically, all we
are doing
is saying if the X and Y
values between two points
match, for example, if one dot X is equivalent
to point to dot X, and if point one that Y is equivalent to point to dot
Y, then
we actually need to do something. Now, this is a point to point collision between the X and Y coordinate values. However, in our game we are doing a point to point collision detection along a single axis, either the X axis or the Y axis.
So in this
case, all we are doing is tricky collision between the Y axis. In this case, the ball position y along with
the zero and the ball
position, the Y again, in this case with
the
screen
height. One thing to
keep in mind is that we are testing
against two collisions
at the same time, even though the ball is moving
away from
one
collision point. And on top of that
we are using the equivalent or greater then and the equivalent or less than symbols, because when dealing with float
values, they are
inconsistent when
using mathematical upgraders. Now, let's go
ahead and take a look at a visual example. As you can see here, we have our ball. However, we are only checking the collision point on top of the ball, the ball position
Y minus
the radius and pole position Y plus the radius. So we are detecting collision between the upper point of our ball with the top of the screen. And we are checking the collision of the ball's bottom point with the bottom of the screen.
So in this case,
we have a ball moving up. Our top pole position is at one hundred and the top ball is zero. And therefore ball doesn't collide with a wall point, change nothing.
And as a matter of
fact, even though our tuple is equal to one because it's not zero, we still do nothing at this point. And it's only when our top ball has the same value as our top wall, which is zero, then we change the direction. And again, the same thing
applies when the
bottom point of our ball touches the bottom was
point.
Then we change direction in the opposite direction. However, at this point we do nothing because our ball point does not touch the bottom was point.
So in this case,
you can see here that our action is a point to point
collision. In this case,
our action is the IF statement. However, our reaction is to change the direction of our
ball without
changing
its speed and to flip
a vector value along in excess
negate the value
on that
excess.
In this case, to flip a vector along the Y axis negate only the Y value. So in this case, our vector is pointing down
zero one
and if we multiply. R y value by negative one, we get the
inverse, which is zero negative one, which points for our current
game engine
upwards and you can do the
same thing in the opposite direction as well. Negative one multiplied by negative one will give you a positive one value.
And we can do
this in the X axis as well. If we are pointing in the positive X direction,
multiply it by negative
one to get our vector pointing in the opposite direction. So inverse seeing our vectors can give us the ability of changing direction
without changing
the speed. Now the second collision is between the ball and the left and right side
of the wall. So there's a lot
going on here right now. But we can just remove the
noise and we can see
that if our ball position on the
x
axis is less than zero, we just simply stop the game. We change the game state and the same
thing on the
other side. If pole position dot x is greater than or equal to the screen width, we change
the game state. So in this case, the action
is
if the ball
touches the screen and the reaction is to change the game
state. Now I have
a visual example up here. You can see that we have a left wall point, which
is zero and the right
will point,
which is ten, twenty four and our
right ball point is at seven
hundred. And as
long as our ball point does not touch
the point,
we continue to move along. And as a matter of fact, our role continues to move forward.
And it is only
when the role is equal to the right wall that we stop
the game. And this is a
point to point collision
between points on the
x axis. Only the third type of collision we need to understand is between the
ball and the pedal. And the ball on
the pedal is basically a point to rectangle collision. And basically what we're doing is detecting if a single point lies inside of a
rectangle and it is one
of the easier collision detection
formulas when it comes to
collision detection. Let's go ahead and take a look at a rectangle two point collision detection formula in this case. First, we need to decide what our rectangles leftmost position is, and that is basically our rectangles position along the X axis and then our game engine, that is the top left. Then to calculate the rectangles right position, we need to
figure out where our
rectangles starting position on the X axis
is and then add the
rectangles size along the x axis. And so in this case, you can see that it's rectangle left plus the rectangle size on that x axis.
And we do the
same thing for the rectangle, top and bottom as well. In this case, rectangle top is just or rectangle starting position on the Y axis and rectangle bottom is the starting
position on the Y axis, plus the
rectangle size along that
y axis. And if this
looks familiar,
that is because in the
game engine we are using to create our rectangle, we need to pass in two
vectors. The first vector is the
position and the second
vector is the size
of our
rectangle. Once we
figured out the area of our rectangle and it's positional value, we can actually create our formula for detecting collision between a point and a specific rectangle quite
easily.
Now this is our point here.
It's this blue circle
inside
of our pink rectangle.
And in this case, if our
point X position
is greater than or equal to or rectangles left
value, and if
that
same point X position is
less than or equal
to the
rectangles right. Position, and if that points
Y value is greater
than or equal to our rectangles top position. And if that
same points y value
is less than or equal to our rectangles bottom position,
then our point is in fact colliding
or inside of our
rectangle. And if that
is the case, we need to do
something else, do nothing. And in most
cases you want to again return back a boolean value of true
or false. Now, let's
go ahead and take a look at our
current collision formula.
In this case. You can
see we're looking
at the ball positions, x value in this case,
our point. And we
are comparing it to the
player's position that
X, which
is our paddle, and we are
comparing our ball
positions X value,
which again is our point, and we are comparing that to our rectangles,
not only
the starting position on the X axis, but we are also checking the size on that
X axis. So as you can
see
here, this
is our first check between the X
values. We're also doing the
same thing down here,
albeit a little messy. And in this
case, we're taking the ball positions y value, testing it against the starting
position of our
player paddle. And we're testing that same point. Position for our board and comparing that to the players position, plus the
size, however, you'll notice here that
our paddle divide is a value comparing the values over
here. And in this
case, what we're saying is that our
variable paddle
divide is basically the paddle size divided by three. And you can see that our code is starting to get a little messy.
Basically what we're
doing is we're taking
that paddle value and then we're
multiplying by two and three based on it for first if statement
fails. And so we
do have a collision detection
between rectangles.
However, we are
checking between three
different
rectangles. The first rectangle
is being checked here. The second rectangle is being checked in. Our second else if statement and our third rectangle is being checked and our
last if statement. And so you can see
here that our code is a
little messy, but that's OK
because at least we are understanding our
code for now. Next, let's
understand the current state of our. Now, in this case, we've implemented a simple chasing A.I. which is called Chasing and Evading. Chasing and Evading has two parts. First, we need to initiate the chase. Then we need to create the
effect of that chase. So in this case,
we use the simple technique of updating or a pong paddles center, coordinate value and have it chase our balls y coordinate value. If the ball moves out of
range of our
A.I. paddles a center by 20
pixels. In this case, that 20
pixel comes
from these 10 values
here. And the comparison of our center value comes
from the high
position that y value plus the paddle size that Y divided by two, which gives us
our center. And so in this
case, what we're saying is that from the center go down by 10 and from the
center go up by 10. And so we have
this dead zone of 20 pixels in the center where our paddle will not move if our ball in the Y
position has those values. And so
to visualize this again or if statement is our initiation
phase and what
is inside the if statement basically are a position, moving is the
effect. And in this case,
we are moving at two hundred fifty pixels a second. And so in this case we have our ball here.
And if
our ball center position on the
Y value is outside
the dead zone or in this case above the dead zone, then our paddle will chase upwards.
However, if our ball position on the
Y axis is below the dead
zone, then we
go ahead and chase downward. And if our ball position
is inside
the dead zone, then our paddle
does not move. So basically what you need to
learn to improve your understanding of collision detection is basically understanding or in this case, learning linear algebra, more specifically
vector math. And again,
vector math helps when dealing with
collisions and the
reaction to those collisions if
you want physics like reaction. Now, what
else should you do
to improve? Well, besides
understanding what you've written or copy and paste, it really depends on the
goal of what
you're trying to do. For example, if you're making a game for your
kids, young
children
or even older children, I'm sure ninety
nine percent of the time they don't really care what's going on
underneath the game.
Another scenario is if you're making a game to sell and most players don't care the code you've written, they just want to know if the game is fun. However, if you are making a game for a portfolio,
your interviewer
may look at
your code, may ask
you questions on game design and game
programming, and from there,
the inner workings of your game starts to matter. So let's look at what an interviewer is
looking for in the realm
of game programming,
at least. And it really
depends on the company. If you're going to big companies like Ubisoft
or the larger
companies are looking for specialization.
However, if you're
getting an interview at an indie studio, basically anything under 10 employees, they are most likely looking for a jack of all
trades.
Generally speaking, if we're trying to cover everything between big companies and small
studios, then you need
to focus on three things game design, communication and
programming. And the
bigger the
company, the more
they're looking for specialization between programming or game
design. They now, again,
remember
your goal, which is
showing your code off at an interview. And so you must showcase three things your level of programming, basically math and problem solving skills and code readability.
Next is
your ability to
communicate and attitude with stress. And lastly,
is your level of understanding on game design,
however, if you're going for a
job in programming, this
will be either the
basics or
irrelevant. Now, in an interview
setting, the interviewer is trying to rate your skills and programming, communication and game design skills. And so we need to write our code in a way that shows that we do understand these things.
How do we
figure out
what needs improving?
And basically just put yourself in the interviewer shoes.
They want to know if
they can trust you enough to leave you alone to code the game out. And so ask yourself questions. Interviewers may ask if they saw your code at its current state and basically what they are trying to figure out about you is finding your limitations.
They want to
know what your goal is and how you overcome that wall and to give you a basic idea of the interviewer's agenda. They're just basically trying to rate
you one to 10.
In my example, I have one to five basically between weak and strong. And in this case, I have three categories programming, communication, game design. And ultimately, they want to give you a rank, either you or a strong hire, a weak hire, a weak no or a strong no ever. Let's move on to some game design basics and game programming
basics that you need
to understand. And first, let's understand the difference between a game designer and a game programmer. A game designer develops compelling and engaging rules for games.
They are the creative vision.
Behind the
scenes, game
programmers provide the technical solutions to carry out the vision of
the game. One thing to
note, in
my opinion, as a solo
developer, it's good to understand both. They complement each other. They help each other out.
With game
design, you can understand what you need to build, and with game programming you can understand the limitations of what you can accomplish within a certain time
frame. Now, to
give you some ideas of specializations between game programming and game design, I've listed just a few common ones for game programming. You have rendering gameplay animation, quality assurance, user interface, artificial intelligence and
networking, or network programming for game
design. You have your general game designer, level designer, combat designer, economy designer. On top of that, you have user interface design, narrative design and
artificial intelligence design. Now, as
a solo developer, which of these should you focus on?
And again, I recommend
that you have a basic and general understanding of each individual role because it can help you out when making more complex games. But in this case, what should you learn to improve
the current pong game? And I've
highlighted these basically you need to improve on the gameplay programming, the user interface
programming and the
artificial intelligence
programming. And on
the game design
side, we need to understand game designing, the user interface design aspects
and artificial intelligence design as well. Now let's take a look at improving our game design.
So these are the three game design
101 things you need to
understand to make a good game. And the first
is, is your game simple to learn and is your game hard to
master? And of course, lastly, even though your
game is simple to learn and hard to
master, is your game fun? And these are the
three questions you need to ask yourself. And they all need to be.
Yes.
And this is basically game design 101.
Summarize and let's
take a look at a quote. All the best games are easy to learn and difficult to master. They should reward the first quarter and the hundred.
And this
is Bushnell's Law
from Nolan
Bushnell, the founder of
Atari. Now, let's ask
these three questions
again for our current game. Is my game
design simple enough to learn?
And no, it's
actually a little
confusing. NEC's is my
game design hard enough to master. And no, it's not.
We only have
three areas for detecting
collision. It's really easy to get our
ball to hit
at an angle. And lastly,
is my game fun? And this is great because this question is subjective. But to find this answer, you must play your game and iterate repeatedly. Basically getting player
feedback and player feedback
is essential. So what makes my game hard to learn? And basically it's our UI design. Our UI does not clearly state what the players should do when
the game starts.
As a matter of fact, all it says is play with exclamation points.
In this case, the
simple solution is to at least tell the player what buttons they need to press to get. What type of result move up by pressing w move down by pressing
s w equals move up
as equals, move down
anything but
our current state, which is to display the player because in our case we created the game. So we know we need to press. W.A. what a new player didn't make this game and they'd have no clue. Our keyboard has a three zero three nine movement. Can be any of those buttons, including the arrow buttons. And most
cases the
player will move for the arrow buttons and because we didn't program our buttons,
they'll find out it
doesn't move the pedal. And if they play games a lot, they may move to.
S and if not, they're are completely clueless. Next, let's
figure out what makes our game simple to Mester. And on the game design
side are Padel
only has three areas that changes the ball's
direction. And basically
no skill is involved except for hitting three areas of our pedal,
which a beginner
could master in a matter of
minutes. And on top of
that, our design is a little lackluster. And what I mean by that is our high speed is not
only static, but our a
pedal only chases the ball at a single speed. There's no variation. As a matter of fact, it's hard for the
player to win against
or
easy depending
on the speed we apply to our pedal. So once game design issues have been identified. Ask yourself what should I do to improve it?
And just keep in mind
that there are
no perfect answers
to this question because game design
is an art form. To get an answer,
you need to let other people play your game and give you feedback. Now, because we're creating a game for our portfolio, we don't really need to test with other players as long as we understand some basics.
But if you're making a
game to sell, you need player feedback.
Do not trust your own bias, feedback or biased
feedback from friends and family, acquaintances and co-workers as well. Now, on the programming side, how can we improve ourselves? And basically we need to ask ourselves the question,
what is good code?
And again, good code is subjective. Different programmers have different answers. However, let me give you my answer and that is good.
Code is readable and scalable, maintainable.
Now, let's go ahead and ask that question. Is my current code for the Pong game readable? Well, is it? And the answer is no. And you can ask yourself questions. Do you use magic numbers? Are you utilizing functions, classes, constants, variables effectively?
Are there
code duplications inside
your code?
Can certain things be refactored inside or outside of something? And so you just need to sit down and look at your code and make notes, actually write it down on paper and see what needs improving.
Take a few
days off
from working on
your code. Come back and see if you are
confused or not. And in this
case, I've identified some problems with the
code as is,
for example, we use an if
statement to detect
collision and maybe we can refactor collisions out into a function.
Since collision detection
is common in game programming, we don't need
to create a rectangle
to point
collision all the
time. And as a matter of fact, this
if statement is not a
rectangle collision, it is a
point to point collision that checks
true or false.
And then we move onto another point to point collision to check if they
are true and false. And so we can refactor these point-to-point collisions
out and replace it with something else. On top of that,
we have code duplication. Basically, we create a variable tempo, we assign it a vector value, and then we change our ball speed to that temporary
full speed, effectively changing our ball speed. And you can see it's duplicated.
On top of that, we are using magic numbers. Magic numbers, again, are literal, hard coded values inside our code. This is an easy fix. Refactor it out into a variable. And lastly, this variable pedal device feels off.
Something about it feels off.
I feel like we can do something better. And even if we keep magic numbers and set or code, we could actually get rid of this line instead of Petto divide multiplied by two. We could just say petalled that size y multiplied
by zero
point thirty three, which would be inside our first if statement and then petal size Y multiplied by zero point sixty
six. And then on the
last statement padel size that y and that would be the same as what we've written here and we can actually remove this variable padel
divide. But again, this was set
up purposely
for this example slide show.
But sometimes your code does feel off and you just got to listen to your gut instincts and see if there's another way we can implement what we are currently doing. Now, the second question we need to ask ourselves is if our code is scalable and maintainable, scalable code is a more complex topic. However, I'd like to combine scalable with maintainable and in our case,
it's not because everything
is done inside of a single
class. And so basically
we need to refactor responsibilities out into their own individual classes. For example, we need a bulk class that
handles all creation,
a pedal class, a text
class and even
a collision
class. So we don't
have to write all these statements or since collisions are
very common and we don't know if we need to
create a third object that
needs to be tested for
collision against another
object. And this is
an M the list goes on maybe a class to handle playing
music. Regardless, for the rest
of this series, I want to focus on the following, refactoring out to multiple
classes, basically creating different scripts, different
gdscript I want to add. Make changes to the ball and we will use vector math, in this case rotation and increasing vector magnitude. There is a simpler way
to create dynamic
ball changes without vector. But again, because we're creating code for a portfolio, we need to show that we at least understand vector math.
Next, I want
to add randomness to the chasing speed while maintaining some level of consistency to the
randomness. And lastly,
I want to add finishing touches to the game by adding
sound and music. Now I want
to note one thing. The original Pong
game had compounding
values on the speed value. Basically, the speed value
of the ball increased
the longer the game
went on. But in this case,
because we're using an A.I. for our second player instead of a human player, I feel game design
wise that increasing the
speed is not the way to go. However, again, going back to game design, you have to decide what you want to add or remove and what you think will make the game better. Well, that's all I have for you in this episode. Thank you so much for joining me. Thank you for clicking the subscribe button and thank you for clicking the like button. I look forward to seeing you in the next episode. Have an amazing day.