Thursday, 15 June 2023

Let's Study Programming by Making Games: Pygame Unit: 02 - bouncy_text.py

 

bouncy_text.py



Hi there! Welcome again to tutorial lesson 02 of Python and Pygame. Before we start out with our first larger project tutorial project (working title: "ASCII'n Vaders"), we'll continue going over some more basics and movement. In the last lesson we got our "Hello Pygame World!" text string moving from right to left and then rinse and repeat.

This time our objective is to bounce it around within the borders of our screen surface. Here I have included listing within our source file bouncy_text.py or whatever you may name it:


#bouncy_text.py
import pygame, sys

pygame.init()
SCREEN_WIDTH = 1024
SCREEN_HEIGHT = 768
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
clock = pygame.time.Clock()
FPS = 60

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

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

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)
    return text_img_rect



text_x, text_y = SCREEN_WIDTH // 2, SCREEN_HEIGHT // 2
text_x_speed = 5
text_y_speed = 2
text_x_dir = 1
text_y_dir = 1

run = True
while run:
    clock.tick(FPS)
    pygame.display.set_caption(f"Hello Pygame World | FPS: {clock.get_fps():.1f}")
    screen.fill(SHANDY)

    text_rect = draw_text(font_60, "Hello Pygame World!", text_x, text_y, CYAN_BLUE)
    



    x_check = text_rect.right < 0 or text_rect.left > SCREEN_WIDTH
    y_check = text_rect.bottom < 0 or text_rect.top > SCREEN_HEIGHT
    if x_check:
        text_x_dir *= -1
    if y_check:
        text_y_dir *= -1



    text_x += text_x_speed * text_x_dir
    text_y += text_y_speed * text_y_dir


    


    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            run = False
        if event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE:
            run = False

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



Ok, I hope you took a good look. Nothing special so far if you have some familiarity with any programming language and Python's syntax in general. Let's go over the lines of code that are different from our last lesson.

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)
    return text_img_rect



The first slight but change we've introduced introduced in here is the return statement within our text draw function. This enables us to get the rectangle data out of the function to be used within our main loop as an easy means to check where exactly our text is position at a given moment in time and compare it to the coordinates of our screen borders.

text_rect = draw_text(font_60, "Hello Pygame World!", text_x, text_y, CYAN_BLUE)

Said rectangle will be captured in a variable called text_rect. The arguments within the function brackets stay pretty much same. Nothing new here.

Now we come to the actual section where the positional checking takes place.

x_check = text_rect.right < 0 or text_rect.left > SCREEN_WIDTH
y_check = text_rect.bottom < 0 or text_rect.top > SCREEN_HEIGHT
if x_check:
    text_x_dir *= -1
if y_check:
        text_y_dir *= -1



In here we check whether the right hand side of the text rectangle is less than 0 or the left hand side is greater than our screen width. So in either case the expression will return true and stored in a boolean variable we named x_check which as the name suggests accounts for the x - axis or the x coordinates of our text rectangle.

Of course the same has be done with the y - axis now only comparing the bottom of the rectangle with the top of the screen as well as checking if the rectangle top has gone beyond the bottom of the screen.

The next two lines are pretty straight forward. If the x_check evaluates to true, it is going to reverse the text_x_dir directional variable by multiplying it with negative one. If it is headed right say has a value of positive one, it is going to be reversed to negative one and vice versa, giving us a simple back bouncing effect.
Same principle holds true with the y_check, reversing the direction whenever the text has gone either past the top or bottom of the screen. Both directional variables of course had to be defined beforehand in the space above our main game loop, underneath our other initials regarding speed and position of the text rectangle.

text_x, text_y = SCREEN_WIDTH // 2, SCREEN_HEIGHT // 2
text_x_speed = 5
text_y_speed = 2
text_x_dir = 1
text_y_dir = 1



Just between our visibility check code and the even handler, we'll place our movement code which updates the text rectangles x and y position respectively to blit it at a new position with each main loop iteration, by multiplying the speed values with the respective directions and storing it back in each positional variable.

text_x += text_x_speed * text_x_dir
text_y += text_y_speed * text_y_dir


And tadaa! If you hit the run button our text will whoosh around the screen and bounce back once it is offscreen, just like one of those antiquated CRT-screensavers from the 90's and earlier. (Yes, don't ask. I am that old already).


Ok, that's a short one for now. But it is gonna get more exciting as we go along. In the next lesson we'll learn why object oriented programming is quite a practical thing if you don't want to repeat the same code over and over again, especially if you want to draw many objects to your screen (what real games generally do).
Bye for now. Have a good one. And have fun practicing Python! I'll also throw in a cartoon or two next time to keep the motivation up :)



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...