Small knowledge, big challenge! This article is participating in the creation activity of “Essential Tips for Programmers”

preface

In the next few episodes, I will take you hand in hand to achieve the magic Tower from scratch this little game (is the old friends often play that picture

The development tools

Python version: 3.7.4

Related modules:

Pygame module;

And some modules that come with Python.

Environment set up

Install Python and add it to the environment variables. PIP installs the required related modules.

Introduction of the principle

First, we went to the start screen of the original game and found something like this:

Specifically, the idea is to define a button class to simulate the function of the three buttons in the original game: “Start game”, “Game description” and “Leave game” :

"Button class"
class Button(pygame.sprite.Sprite) :
    def __init__(self, text, fontpath, fontsize, position, color_selected=(255.0.0), color_default=(255.255.255)) :
        pygame.sprite.Sprite.__init__(self)
        self.text = text
        self.color_selected = color_selected
        self.color_default = color_default
        self.font = pygame.font.Font(fontpath, fontsize)
        self.font_render = self.font.render(text, True, color_default)
        self.rect = self.font_render.get_rect()
        self.rect.center = position
    Update function: continuously update to check whether the mouse is on the button.
    def update(self) :
        mouse_pos = pygame.mouse.get_pos()
        if self.rect.collidepoint(mouse_pos):
            self.font_render = self.font.render(self.text, True, self.color_selected)
        else:
            self.font_render = self.font.render(self.text, True, self.color_default)
    Bind to screen
    def draw(self, screen) :
        screen.blit(self.font_render, self.rect)
Copy the code

The main idea is to constantly check if the mouse is in the corresponding button area, and if so, change the color of the button (red in this case), otherwise use the default color (white in this case) to indicate to the player that it is clickable.

Then, we instantiate it three times to add these three buttons to the game’s start screen:

"Game start screen"
class StartGameInterface() :
    def __init__(self, cfg) :
        self.cfg = cfg
        self.play_btn = Button('Start the game', cfg.FONTPATH_CN, 50, (cfg.SCREENSIZE[0] / /2, cfg.SCREENSIZE[1] - 400))
        self.intro_btn = Button('Game Notes', cfg.FONTPATH_CN, 50, (cfg.SCREENSIZE[0] / /2, cfg.SCREENSIZE[1] - 300))
        self.quit_btn = Button('Leave the game', cfg.FONTPATH_CN, 50, (cfg.SCREENSIZE[0] / /2, cfg.SCREENSIZE[1] - 200))
    "External call"
    def run(self, screen) :
        # found
        font = pygame.font.Font(self.cfg.FONTPATH_CN, 80)
        font_render_cn = font.render('found'.True, (255.255.255))
        rect_cn = font_render_cn.get_rect()
        rect_cn.center = self.cfg.SCREENSIZE[0] / /2.200
        # Magic Tower
        font = pygame.font.Font(self.cfg.FONTPATH_EN, 80)
        font_render_en = font.render('Magic Tower'.True, (255.255.255))
        rect_en = font_render_en.get_rect()
        rect_en.center = self.cfg.SCREENSIZE[0] / /2.350
        # (Ver 1.12)
        font = pygame.font.Font(self.cfg.FONTPATH_CN, 40)
        font_render_version = font.render('(Ver 1.12)'.True, (255.255.255))
        rect_ver = font_render_version.get_rect()
        rect_ver.center = self.cfg.SCREENSIZE[0] / /2.400
        clock = pygame.time.Clock()
        while True:
            screen.fill((0.0.0))
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    pygame.quit()
                    sys.exit(0)
                elif event.type == pygame.MOUSEBUTTONDOWN:
                    if event.button == 1:
                        mouse_pos = pygame.mouse.get_pos()
                        if self.play_btn.rect.collidepoint(mouse_pos):
                            return True
                        elif self.quit_btn.rect.collidepoint(mouse_pos):
                            pygame.quit()
                            sys.exit(0)
                        elif self.intro_btn.rect.collidepoint(mouse_pos):
                            self.showgameintro(screen)
            for btn in [self.intro_btn, self.play_btn, self.quit_btn]:
                btn.update()
                btn.draw(screen)
            for fr, rect in zip([font_render_cn, font_render_en, font_render_version], [rect_cn, rect_en, rect_ver]):
                screen.blit(fr, rect)
            pygame.display.flip()
            clock.tick(self.cfg.FPS)
    "Show game introduction"
    def showgameintro(self, screen) :
        font = pygame.font.Font(self.cfg.FONTPATH_CN, 20)
        font_renders = [
            font.render('Tower game.'.True, (255.255.255)),
            font.render('the game footage from: http://www.4399.com/flash/1749_1.htm..True, (255.255.255)),
            font.render('The backstory of the game is that the princess is captured by the demon king, and the warrior needs to go to the demon tower to rescue it.'.True, (255.255.255)),
            font.render('Python Project Lion.'.True, (255.255.255)),
            font.render('Wechat official account: Python Project Lion.'.True, (255.255.255)),
            font.render(All Rights reserved..True, (255.255.255)),
        ]
        rects = [fr.get_rect() for fr in font_renders]
        for idx, rect in enumerate(rects):
            rect.center = self.cfg.SCREENSIZE[0] / /2.50 * idx + 100
        clock = pygame.time.Clock()
        while True:
            screen.fill((0.0.0))
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    pygame.quit()
                    sys.exit(0)
                elif event.type == pygame.MOUSEBUTTONDOWN:
                    if event.button == 1:
                        mouse_pos = pygame.mouse.get_pos()
                        if self.play_btn.rect.collidepoint(mouse_pos):
                            return True
                        elif self.quit_btn.rect.collidepoint(mouse_pos):
                            pygame.quit()
                            sys.exit(0)
                        elif self.intro_btn.rect.collidepoint(mouse_pos):
                            return
            for btn in [self.intro_btn, self.play_btn, self.quit_btn]:
                btn.update()
                btn.draw(screen)
            for fr, rect in zip(font_renders, rects):
                screen.blit(fr, rect)
            pygame.display.flip()
            clock.tick(self.cfg.FPS)
Copy the code

The other extra code is to display the game’s title and other information, which is very simple and will not be discussed in detail

Now, what does the interface look like when the game starts

Specifically, we can define what the game map should look like in a text file, like the one below, where each number represents a game element:

I have also collected the game materials that I found online.

So, we can write a parser class for the game map file, like this:

Game map Parsing class
class MapParser() :
    def __init__(self, blocksize, filepath, element_images, offset=(0.0), **kwargs) :
        self.count = 0
        self.switch_times = 15
        self.image_pointer = 0
        self.offset = offset
        self.blocksize = blocksize
        self.element_images = element_images
        self.map_matrix = self.parse(filepath)
    "' resolution ' ' '
    def parse(self, filepath) :
        map_matrix = []
        with open(filepath, 'r') as fp:
            for line in fp.readlines():
                line = line.strip()
                if not line: continue
                map_matrix.append([c.strip() for c in line.split(', ')])
        return map_matrix
    Draw the game map to the screen.
    def draw(self, screen) :
        self.count += 1
        if self.count == self.switch_times:
            self.count = 0
            self.image_pointer = int(not self.image_pointer)
        for row_idx, row in enumerate(self.map_matrix):
            for col_idx, elem in enumerate(row):
                position = col_idx * self.blocksize + self.offset[0], row_idx * self.blocksize + self.offset[1]
                if elem+'.png' in self.element_images:
                    image = self.element_images[elem+'.png'][self.image_pointer]
                    image = pygame.transform.scale(image, (self.blocksize, self.blocksize))
                    screen.blit(image, position)
Copy the code

The parse function actually reads the text file storing the game map information, and the draw function actually binds the corresponding game element pictures to the map for display according to the read map information. In addition, the three variables image_pointer, switch_times, and count are used to achieve the scene element flashing effect in the original map, like this:

Based on this principle, we can easily draw the original map in all layers of the Tower, and define the game map file as shown below:

The effect is shown below:

Ok, to sum up, this is the main implementation of the magic Tower game in each layer of the initial screen, this period of complete source code see personal home page introduction to obtain

This is the end of the article, thank you for watching Python28 small games, next article to share the magic Tower small games!

To thank you readers, I’d like to share some of my recent programming favorites to give back to each and every one of you in the hope that they can help you.

Tomorrow I will take you to further reproduce the magic Tower this small game, interested partners can pay more attention to ~