Use Python to write a fun game, not as complicated as imagined

When it comes to the little game of Happy Matching, I believe everyone is familiar with it. It won the player’s favorite mobile stand-alone game award in 2015. The popularity can be seen. In this article, we use Python to make a simple match. Fun games.

Many people learn python and don't know where to start.
Many people learn python and after mastering the basic grammar, they don't know where to find cases to get started.
Many people who have done case studies do not know how to learn more advanced knowledge.
For these three types of people, I will provide you with a good learning platform, free to receive video tutorials, e-books, and course source code! ??¤
QQ group: 828010317

achieve

The composition of Xiaoxiaole mainly includes three parts: the main body of the game, the scorer, and the timer. Let's take a look at the specific implementation.

Let's first look at the Python libraries required for the game.

import os
import sys
import time
import pygame
import random

Define some constants, such as: window width and height, number of grid rows and columns, etc. The code is as follows:

WIDTH = 400
HEIGHT = 400
NUMGRID = 8
GRIDSIZE = 36
XMARGIN = (WIDTH - GRIDSIZE * NUMGRID) // 2
YMARGIN = (HEIGHT - GRIDSIZE * NUMGRID) // 2
ROOTDIR = os.getcwd()
FPS = 30

Then create a main window, the code is as follows:

pygame.init()
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption('消消乐')

Take a look at the effect:

Then draw an 8 x 8 grid in the window, the code is as follows:

screen.fill((255, 255, 220))
# 游戏界面的网格绘制
def drawGrids(self):
    for x in range(NUMGRID):
        for y in range(NUMGRID):
            rect = pygame.Rect((XMARGIN+x*GRIDSIZE, YMARGIN+y*GRIDSIZE, GRIDSIZE, GRIDSIZE))
            self.drawBlock(rect, color=(255, 165, 0), size=1
# 画矩形 block 框
def drawBlock(self, block, color=(255, 0, 0), size=2):
    pygame.draw.rect(self.screen, color, block, size)

Take a look at the effect:

Then randomly put various puzzle pieces in the grid, the code is as follows:

while True:
    self.all_gems = []
    self.gems_group = pygame.sprite.Group()
    for x in range(NUMGRID):
        self.all_gems.append([])
        for y in range(NUMGRID):
            gem = Puzzle(img_path=random.choice(self.gem_imgs), size=(GRIDSIZE, GRIDSIZE), position=[XMARGIN+x*GRIDSIZE, YMARGIN+y*GRIDSIZE-NUMGRID*GRIDSIZE], downlen=NUMGRID*GRIDSIZE)
            self.all_gems[x].append(gem)
            self.gems_group.add(gem)
    if self.isMatch()[0] == 0:
        break

Take a look at the effect:

Then add the scorer and timer, the code is as follows:

# 显示得分
def drawScore(self):
    score_render = self.font.render('分数:'+str(self.score), 1, (85, 65, 0))
    rect = score_render.get_rect()
    rect.left, rect.top = (55, 15)
    self.screen.blit(score_render, rect)
# 显示加分
def drawAddScore(self, add_score):
    score_render = self.font.render('+'+str(add_score), 1, (255, 100, 100))
    rect = score_render.get_rect()
    rect.left, rect.top = (250, 250)
    self.screen.blit(score_render, rect)
# 显示剩余时间
def showRemainingTime(self):
    remaining_time_render = self.font.render('倒计时: %ss' % str(self.remaining_time), 1, (85, 65, 0))
    rect = remaining_time_render.get_rect()
    rect.left, rect.top = (WIDTH-190, 15)
    self.screen.blit(remaining_time_render, rect)

Take a look at the effect:

When the set game time runs out, we can generate some prompt messages, the code is as follows:

while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            sys.exit()
        if event.type == pygame.KEYUP and event.key == pygame.K_r:
            flag = True
    if flag:
        break
    screen.fill((255, 255, 220))
    text0 = '最终得分: %s' % score
    text1 = '按 R 键重新开始'
    y = 140
    for idx, text in enumerate([text0, text1]):
        text_render = font.render(text, 1, (85, 65, 0))
        rect = text_render.get_rect()
        if idx == 0:
            rect.left, rect.top = (100, y)
        elif idx == 1:
            rect.left, rect.top = (100, y)
        y += 60
        screen.blit(text_render, rect)
    pygame.display.update()

Take a look at the effect:

After talking about the related parts of the game graphical interface, let's look at the main processing logic of the game.

We use the mouse to manipulate the puzzle pieces, so the program needs to check whether the puzzle pieces are selected. The code is implemented as follows:

def checkSelected(self, position):
    for x in range(NUMGRID):
        for y in range(NUMGRID):
            if self.getGemByPos(x, y).rect.collidepoint(*position):
                return [x, y]
    return None

We need to exchange the positions of the puzzle pieces selected continuously by the mouse. The code is implemented as follows:

def swapGem(self, gem1_pos, gem2_pos):
    margin = gem1_pos[0] - gem2_pos[0] + gem1_pos[1] - gem2_pos[1]
    if abs(margin) != 1:
        return False
    gem1 = self.getGemByPos(*gem1_pos)
    gem2 = self.getGemByPos(*gem2_pos)
    if gem1_pos[0] - gem2_pos[0] == 1:
        gem1.direction = 'left'
        gem2.direction = 'right'
    elif gem1_pos[0] - gem2_pos[0] == -1:
        gem2.direction = 'left'
        gem1.direction = 'right'
    elif gem1_pos[1] - gem2_pos[1] == 1:
        gem1.direction = 'up'
        gem2.direction = 'down'
    elif gem1_pos[1] - gem2_pos[1] == -1:
        gem2.direction = 'up'
        gem1.direction = 'down'
    gem1.target_x = gem2.rect.left
    gem1.target_y = gem2.rect.top
    gem1.fixed = False
    gem2.target_x = gem1.rect.left
    gem2.target_y = gem1.rect.top
    gem2.fixed = False
    self.all_gems[gem2_pos[0]][gem2_pos[1]] = gem1
    self.all_gems[gem1_pos[0]][gem1_pos[1]] = gem2
    return True

Every time we exchange puzzle pieces, we need to judge whether there are three or more puzzle pieces in a row. The code is implemented as follows:

def isMatch(self):
    for x in range(NUMGRID):
        for y in range(NUMGRID):
            if x + 2 < NUMGRID:
                if self.getGemByPos(x, y).type == self.getGemByPos(x+1, y).type == self.getGemByPos(x+2, y).type:
                    return [1, x, y]
            if y + 2 < NUMGRID:
                if self.getGemByPos(x, y).type == self.getGemByPos(x, y+1).type == self.getGemByPos(x, y+2).type:
                    return [2, x, y]
    return [0, x, y]

When three or more puzzle pieces appear, these puzzle pieces need to be eliminated. The code is implemented as follows:

def removeMatched(self, res_match):
    if res_match[0] > 0:
        self.generateNewGems(res_match)
        self.score += self.reward
        return self.reward
    return 0

After eliminating the matching puzzle pieces, we also need to randomly generate new puzzle pieces. The code implementation is as follows:

def generateNewGems(self, res_match):
    if res_match[0] == 1:
        start = res_match[2]
        while start > -2:
            for each in [res_match[1], res_match[1]+1, res_match[1]+2]:
                gem = self.getGemByPos(*[each, start])
                if start == res_match[2]:
                    self.gems_group.remove(gem)
                    self.all_gems[each][start] = None
                elif start >= 0:
                    gem.target_y += GRIDSIZE
                    gem.fixed = False
                    gem.direction = 'down'
                    self.all_gems[each][start+1] = gem
                else:
                    gem = Puzzle(img_path=random.choice(self.gem_imgs), size=(GRIDSIZE, GRIDSIZE), position=[XMARGIN+each*GRIDSIZE, YMARGIN-GRIDSIZE], downlen=GRIDSIZE)
                    self.gems_group.add(gem)
                    self.all_gems[each][start+1] = gem
            start -= 1
    elif res_match[0] == 2:
        start = res_match[2]
        while start > -4:
            if start == res_match[2]:
                for each in range(0, 3):
                    gem = self.getGemByPos(*[res_match[1], start+each])
                    self.gems_group.remove(gem)
                    self.all_gems[res_match[1]][start+each] = None
            elif start >= 0:
                gem = self.getGemByPos(*[res_match[1], start])
                gem.target_y += GRIDSIZE * 3
                gem.fixed = False
                gem.direction = 'down'
                self.all_gems[res_match[1]][start+3] = gem
            else:
                gem = Puzzle(img_path=random.choice(self.gem_imgs), size=(GRIDSIZE, GRIDSIZE), position=[XMARGIN+res_match[1]*GRIDSIZE, YMARGIN+start*GRIDSIZE], downlen=GRIDSIZE*3)
                self.gems_group.add(gem)
                self.all_gems[res_match[1]][start+3] = gem
            start -= 1

Then repeat this process until the game time is exhausted and the game is over.

Finally, let's take a look at the game effect dynamically.

to sum up

In this article, we use Python to implement a simple puzzle game. Those who are interested can further expand the game, such as adding levels.

Guess you like

Origin blog.csdn.net/Python_sn/article/details/111169607