Monday, 29 May 2023

Let's study programming by making games: Pygame Unit 0


"Hello Python World!"

Pygame Tutorial 0


Greetings, hello and welcome to Merlin's relaxing space of learning and
creative past times around the world of coding, digital art and general
nerdy-ness.

Today we are going to start off our informal class (no pressure at all) with a
teeny-weeny bit of Python. No, I am not referring to the infamous and
dangerous snake species, although this kind of python does have snakes in its
neat logo and may be likewise as intoxicating (in a positive way).

The Python I am talking about is the general purpose programming language that
really spread out all around the world, both in the corporate and the open
source community after its release in 1991 by its designer Guido van Rossum.
Nowadays you can find it almost anywhere in the computer science and tech
world mainly due to its beginner friendly structure that does a lot data
hiding and blackboxing as compared to languages like C or C++, as well as the
great variety of libraries and modules that are available for almost any
conceivable programming problem out there.

It is therefore no wonder that the Python language is often spoken in the
same breath with big modern buzzwords such as 'Machine Learning', 'Artificial



 

 

 

Intelligence', 'Data Science', 'Robotics', 'Cybersecurity' and many more. So
in any way, whether you wish to pursue a professional career in those or
similar fields or simply love to tinker with technology in a creative way,
feel free to download your personal Python copy from python.org free of cost.

And although we might not be writing code for future moon- and mars
colonization missions, interstellar spaceship propulsion or your run of the
mill sentient super computer, we still may benefit from knowing at a least a
few technical details. Similarly, it may not be necessary to know every
function of the inner workings of an automotive combustion engine, yet knowing
for example the key differences of a diesel, gasoline, or electrical motor
definetely may come in handy.

Anyways, learning a programming language can at times become quite the tedium, just like all things learned by theory, practice, repetition, memorization and so on. However if we wrap everything into a meaningful narrative and
combine it with something that provides visible results, we might smoothen the
otherwise bumpy ride and even have some fun at the same time.
Gamification is another magic word in the learner's community - learning by
using techniques employed in games. In our case we'll not only play games but
also indulge in the challenge of making games.




In order to do that we'll have one of Python's most enjoyable modules named
Pygame to our disposal which basically is a library of functions, classes,
methods - tools that allow us to manipulate graphics and sound with relative
ease. Though not as powerful as say engines like Godot, Unity and Unreal, to
name a few, it is a good didactic tool teaching game programming routines that
also apply to other systems. Pygame is especially useful in getting the ropes
of 2D and pseudo 3D game programming akin to the "golden age" of videogames
with its arcade machines, as well as the era of NES, SNES and Sega
Genesis/Megadrive homeconsoles. And depending on one's experience and skill
level interesting self-made games are in one's reach.

Alrighty then! Once you've made your mind, pip install the pygame library in
your windows command line and we're ready to go!


Ok, without further ado, let's christen our dev-journey with the simple
one-liner almost everybody starts out with. Let's just keep the tradition
alive, shall we?

Just type:


print("Hello World!")

into your favorite text editor, save it as hello.py and run it with the Python

interpreter. Easy, isn't it? It is similar to other code lines you might
have encountered some other time, for example:

cout << "Hello World!" << endl;

in C++ or:

console.log("Hello World!");

in JavaScript. Both require some 'boilerplate code' beforehand to make them
work, which in Python is simply abstracted away.


Anyhow, now that we have done our duty to tradition, let's mix it up a bit
with our custom pygame hello world program.

Let's start by creating the basic pygame window. First we have to import the
pygame module.


import pygame

Additionally we will also import the sys module in order to call sys.exit() at
the end of the program, enabling us cleanly shut the python interpreter down
once we exit the program.

import sys

Our next line will initialize pygame by calling:

pygame.init()

Now we are going to define the size of our prospective screen in pixels:

SCREEN_WIDTH = 1024
SCREEN_HEIGHT = 768


I've written those variable names in capitals just to denote that these values
are not to be changed during program run time.

Next we'll have to create a display surface:

screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))

This line stores the display surface object returned by the .set_mode() method
which takes our screensize values as arguments for further use.

But technically these few lines should be enough to show something on screen.
Feel free to run your interpreter. And if you watch closely, you should notice
a black window flashing and then disappearing after a few fractions of a
second. A good sign, but not actually what we are looking to achieve. We
somehow have to keep this window open.

In order to do that we need something that is called 'game loop' or 'main
loop'. A loop is a structure that iterates as fast as possible through all the
lines of code it contains in repetitive succession until an exit condition is
met.

First we'll define a boolean variable called 'run' and assign the value 'True'
to it.

run = True
while run:
    # do something
    # draw something
    # calculate something
    # check collision
    # update movement
    # take input

    pygame.display.update()
    # alternatively pygame.display.flip()



This is followed by the while key word followed by the boolean condition and a
colon. After that we repeat through all the lines of code we've put into the
loop indented by one level (usually 4 spaces). All lines that are preceded by
a # symbol are considered comments and therefore ignored by the interpreter or
compiler.

At the very end of our main loop we put our pygame.display.update() method or
as an alternative, the pygame.display.flip method. In layman's terms this line
updates all the changes made in the top section of the main loop in order to
draw it to the screen. As an analalogy just visualize drawing an image onto
one side of a piece of cardboard and after being done flipping it to the
front, enabling your friend to see what you have drawn. Only difference that
this usually happens as fast as your computer can possibly run (which can even
be too fast requiring a system of frame rate independence or at least frame
limiting to properly animate).

Ok, one step further. We finally have a black surface in the proper size we
defined beforehand in our SCREEN_WIDTH and SCREEN_HIGHT constants. The only
problem we have now is the inability to quit out of the loop and end the
program from within itself. Only we can do is use the task manager or force
quit the interpreter. Not ideal if we'd rather use a button or the X in the
upper right corner of the window.

What we need now is an event handler, something that listens for inputs that
we can grab and links them up with the exit condition of our loop.


run = True
while run:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            run = False
    

    pygame.display.update()
pygame.quit()
sys.exit()


With the event handler in form of a for loop that iterates through all
possible pygame events, we use an if statement to isolate the event.type ==
pygame.QUIT. this event refers to a mouseclick on the window close button in
the upper right. Once we click on the X, the run variable is set to 'False'
and we exit loop deactivating pygame with the quit method and exiting the
system.

Neat, now we've got the absolute bare bone frame work for our game window. But
we're far from done yet. Let's display something. Our print() statement we've
used earlier won't do us any good in this case, however.

What we basically got to do is loading a font stored either in our folder
structure or one of the standard windows fonts or whatever is installed as
part of the operating system. We'll do the latter this time.

Somewhere above our main loop we'll add this line:

font_60 = pygame.font.SysFont("Comic Sans MS", 60)

The SysFont() method takes the name of the font as first argument, and the
desired pixel size as an integer value as the second argument. The returned
font object can now be stored in a variable for further use. In this case we
called it font_60.


Now in order to properly use this font object, let's create a custom draw_text
function which we can then call in our main loop.

def draw_text(font, text, x, y, color):
    text_img = font.render(text, True, color)
    text_img_rect = text_img.get_rect(center = (x, y))
    screen.blit(text_img, text_img_rect)



This function takes the font object we just created, the input and output text
we want to draw, the x and y coordinates, and the color of the text.

The next line within the body of the function basically rasterizes the font we
feed in, turning it into a pixel image. The font.render() method takes the
text we entered, set's the anti-aliasing to either True or False (so, either
smooth or pixelated edges) and the color we fed in.
From this image we take a rectangle which comes handy in exact positioning as
we assign our x and y coordinates to center handle point of the rectangle.
Depending on how we want to place the image, we may choose between following
points to manipulate: center, topleft, midtop, topright, midright, bottomright,
midbottom, bottomleft, midleft.

The last line in the function body "blits" (bit block transfer) the image to
the display surface 'screen' at position of text_img_rect.


Before we call the draw function in the main loop, let us define some colors
somewhere at the top.

CYAN_BLUE = ("#4B8BBE")
SHANDY = ("#FFE873")


In this case we used hexadecimal values but color names or RGB values (0-255)
can be plugged in as well.


Now that we have them, let's return to our main loop.

run = True
while run:
    # we can fill the background with a color
    screen.fill(SHANDY)
    
    # call the text function to print message to pygame window
    draw_text(font_60, "Hello Pygame World!",
        SCREEN_WIDTH // 2, SCREEN_HEIGHT // 2,
        CYAN_BLUE)

    
    # event handler
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            run = False
    

    # screen update
    pygame.display.update()

# exit program
pygame.quit()
sys.exit()



Ok, this should give us a slight pygame-esque variation to the standard "Hello
World!" program. No worries, these are the simple beginnings. In our next
lesson we'll continue with a little bit more motion, animation, collisions and
more. See you around and have a good one. 

And keep playing and tinkering without fear of making mistakes - all part of the learning process.
Here is a screen shot of our complete starter code. As you might notice, there are a few additional lines. But you surely won't have trouble figuring out their meaning. We'll go into detail at a later point anyways.







No comments:

Post a Comment

Pygame Unit 04 - Make An Invaders Game: Part 1

Pygame Tutorial 04 - Let's make an Invaders style shooter Part 1 Now that we have some of the basics down in previous tutorials, let...