pygame -- game making case

Game making based on pygame

Development tool: vscode

1, Window making of pygame

2, Game case 1: tank battle

3, Wizard test

4, Game case 2: greedy snake

5, Game case 3: Flying

6, Game case 4:2048

1, Window making of pygame

Basic introduction: setting window size and window name
Import pygame module
Set window name: pygame.display.set_caption("hello world")
Set window size: pygame.display.set_mode((640,480))
Reference code:

import pygame
from pygame.locals import *
import sys
def hello_world():
   pygame.init()
   pygame.display.set_mode((640,480))
   pygame.display.set_caption("hello world")
   while True:
       for event in pygame.event.get():
           if event.type==QUIT:
               pygame.quit()
               sys.exit()
           pygame.display.update()
if __name__=="__main__":
   hello_world()

The operation results are as follows:

###2, Game case 1: tank battle
Basic introduction: use pygame to develop a user controlled tank movement game
1. First make a free mobile tank to know its principle
Reference code:

import pygame,sys
from pygame.locals import *
def play_tank():
    pygame.init()
    window_size=(width,height)=(640,480)
    speed=[1,1]
    color_white=(255,255,255)
    screen=pygame.display.set_mode(window_size)
    pygame.display.set_caption("Tank Battle")
    tank_image=pygame.image.load(r'tankU.bmp')
    tank_rect=tank_image.get_rect()
    while True:
        for event in pygame.event.get():
            if event.type==pygame.QUIT:
                pygame.quit()
                sys.exit()
            tank_rect=tank_rect.move(speed)
            if(tank_rect.left<0) or (tank_rect.right>width):
                speed[0]=-speed[0]
            if(tank_rect.top<0) or (tank_rect.bottom>height):
                speed[1]=-speed[1]
            screen.fill(color_white)
            screen.blit(tank_image,tank_rect)
        pygame.display.update()
if __name__=="__main__":
    play_tank()

The operation results are as follows:

2. The function to control the movement of the tank through the direction key, and the speed ﹣ offset function to control the distance of the tank movement

def control_tank(event):
    speed=[x,y]=[0,0]
    speed_offset=1
    if event.type==pygame.KEYDOWN:
        if event.key==pygame.K_LEFT:
            speed[0]-=speed_offset
        if event.key==pygame.K_RIGHT:
            speed[0]=speed_offset
        if event.key==pygame.K_UP:
            speed[1]-=speed_offset
        if event.key==pygame.K_DOWN:
            speed[1]=speed_offset
    if event.type==pygame.KEYUP:
        if event.type in[pygame.K_UP,pygame.K_DOWN,pygame.K_RIGHT,pygame.K_LEFT]:
            speed=[0,0]
    return speed

Reference code:

import os,sys,pygame
from pygame.locals import *
def control_tank(event):
    speed=[x,y]=[0,0]
    speed_offset=1
    if event.type==pygame.KEYDOWN:
        if event.key==pygame.K_LEFT:
            speed[0]-=speed_offset
        if event.key==pygame.K_RIGHT:
            speed[0]=speed_offset
        if event.key==pygame.K_UP:
            speed[1]-=speed_offset
        if event.key==pygame.K_DOWN:
            speed[1]=speed_offset
    if event.type==pygame.KEYUP:
        if event.type in[pygame.K_UP,pygame.K_DOWN,pygame.K_RIGHT,pygame.K_LEFT]:
            speed=[0,0]
    return speed
def play_tank():
    pygame.init()
    window_size=Rect(0,0,640,480)
    speed=[1,1]
    color_white=(255,255,255)
    screen=pygame.display.set_mode(window_size.size)
    pygame.display.set_caption("Tank Battle")
    tank_image=pygame.image.load('tankU.bmp')
    back_image=pygame.image.load('back_image.jpg')
    tank_rect=tank_image.get_rect()
    while True:
        for event in pygame.event.get():
            if event.type==pygame.QUIT:
                pygame.quit()
                sys.exit()
            cur_speed=control_tank(event)
            tank_rect=tank_rect.move(cur_speed).clamp(window_size)
            screen.blit(back_image,(0,0))
            screen.blit(tank_image,tank_rect)
            pygame.display.update()
if __name__ == "__main__":
    play_tank()

The operation results are as follows:

3, Wizard test

Basic introduction: the word "animation wizard" is handed down from old computers and game consoles. These old game consoles can't quickly draw and erase graphics to make sure the game works properly. These game consoles have some special hardware, which is specially used to deal with game objects that need to move quickly. These objects are called animated sprites. They have some special limitations, but they can be drawn and updated very quickly Nowadays, generally speaking, the speed of the computer is fast enough, and it can deal with objects like animation sprites well without special hardware. However, the word "animation wizard" is still used to refer to all animation objects in 2D games.
pygame.sprite.Sprite is a class used to implement sprites in pygame. It does not need to be instantiated when it is used, but only needs to inherit it, and then write out its own classes as required, so it is very simple and practical.
1. All sprites are inherited from pygame.sprite.Sprite when they are re established. To create sprites, you need to design your own sprite class
Example: create a tank Wizard
Reference code:

import pygame,sys
pygame.init()
class Tank(pygame.sprite.Sprite):
    def __init__(self,filename,initial_position):
        pygame.sprite.Sprite.__init__(self)
        self.image=pygame.image.load(filename)
        self.rect=self.image.get_rect()
        self.rect.bottomright=initial_position
screen=pygame.display.set_mode([640,480])
screen.fill([255,255,255])
fi='tankU.bmp'
b=Tank(fi,[150,100])
while True:
    for event in pygame.event.get():
        if event.type==pygame.QUIT:
            pygame.quit()
            sys.exit()
    screen.blit(b.image,b.rect)
    pygame.display.update()

The operation results are as follows:

Case: Wizard test
Reference code:

import pygame
from pygame.locals import *
class MySprite(pygame.sprite.Sprite):
    def __init__(self,target):
        pygame.sprite.Sprite.__init__(self)
        self.sprite_surface=target
        self.image=None
        self.master_image=None
        self.rect=None
        self.topleft=0,0
        self.frame=0
        self.old_fram=-1
        self.fram_width=1
        self.fram_height=1
        self.first_fram=0
        self.last_fram=0
        self.columns=1
        self.last_time=0
    def load(self,filename,width,height,columns):
        self.master_image=pygame.image.load(filename).convert_alpha()
        self.fram_width=width
        self.fram_height=height
        self.rect=0,0,width,height
        self.columns=columns
        rect=self.master_image.get_rect()
        self.last_fram=(rect.width//width)*(rect.height//height)-1
    def update(self,current_time,rate=60):
        if current_time>self.last_time+rate:
            self.frame+=1
        if self.frame>self.last_fram:
            self.frame=self.first_fram
            self.last_time=current_time
        if self.frame!=self.old_fram:
            frame_x=(self.frame%self.columns)*self.fram_width
            frame_y=(self.frame//self.columns)*self.fram_height
            rect=(frame_x,frame_y,self.fram_width,self.fram_height)
            self.image=self.master_image.subsurface(rect)
            self.old_fram=self.frame

pygame.init()
screen=pygame.display.set_mode((800,600),0,32)
pygame.display.set_caption("Wizard test")
font=pygame.font.Font(None,18)
framerate=pygame.time.Clock()
cat=MySprite(screen)
cat.load("sprite2.png",92,95,4)
group=pygame.sprite.Group()
group.add(cat)
while True:
    framerate.tick(10)
    ticks=pygame.time.get_ticks()
    for event in pygame.event.get():
        if event.type==pygame.QUIT:
            pygame.quit()
            exit()
        key=pygame.key.get_pressed()
        if key[pygame.K_ESCAPE]:
           exit()
    screen.fill((0,0,255))

    cat.update(ticks)
    screen.blit(cat.image,cat.rect)
    pygame.display.update()

The operation results are as follows:

4, Game case 2: greedy snake

Basic introduction: by pressing the WDAS key on the keyboard, the snake can move to eat food, making the snake longer. When the snake touches the border, it will die, and the interface will show game over
1. Set the initial position of the object
2. Judge whether to eat food, 1 for eating, 0 for not eating
3. Control the movement direction of the greedy snake, and add a section of the snake's body if it is eaten (judge whether the coordinates of the head of the snake are equal to the coordinates of the food)
4. Set game interface
Reference code:

import pygame,sys,time,random
from pygame.locals import *
pygame.init()
fpsClock=pygame.time.Clock()
playSurface=pygame.display.set_mode((640,480))
pygame.display.set_caption("Snake game")
redColor=pygame.Color(255,0,0)
blackColor=pygame.Color(0,0,0)
whiteColor=pygame.Color(255,255,255)
greyColor=pygame.Color(150,150,150)
snakePosition=[100,100]
snakeSegments=[[100,100],[80,100],[60,100]]
raspberryPosition=[300,300]
raspberrySpawned=1
direction='right'
changeDirection=direction

def gameOver():
    gameOverFont=pygame.font.Font('simfang.ttf',72)
    gameOverSurf=gameOverFont.render('Game Over',True,greyColor)
    gameOverRect=gameOverSurf.get_rect()
    gameOverRect.midtop=(320,10)
    playSurface.blit(gameOverSurf,gameOverRect)
    pygame.display.flip()
    time.sleep(5)
    pygame.quit()
    sys.exit()

while True:
    for event in pygame.event.get():
        if event.type==QUIT:
            pygame.quit()
            sys.exit()
        elif event.type==KEYDOWN:
            if event.key==K_RIGHT or event.key==ord('d'):
                changeDirection='right'
            if event.key==K_LEFT or event.key==ord('a'):
                changeDirection='left'
            if event.key==K_UP or event.key==ord('w'):
                changeDirection='up'
            if event.key==K_DOLLAR or event.key==ord('s'):
                changeDirection='down'
            if event.key==K_ESCAPE:
                pygame.event.post(pygame.event.Event(QUIT))
    if changeDirection=='right' and not direction=='left':
        direction=changeDirection
    if changeDirection=='left' and not direction=='right':
        direction=changeDirection
    if changeDirection=='up' and not direction=='down':
        direction=changeDirection
    if changeDirection=='down' and not direction=='up':
        direction=changeDirection
    if direction=='right':
        snakePosition[0]+=20
    if direction=='left':
        snakePosition[0]-=20
    if direction=='up':
        snakePosition[1]-=20
    if direction=='down':
        snakePosition[1]+=20

    snakeSegments.insert(0,list(snakePosition))
    if snakePosition[0]==raspberryPosition[0] and snakePosition[1]==raspberryPosition[1]:
        raspberrySpawned=0
    else:
        snakeSegments.pop()
    if raspberrySpawned==0:
        x=random.randrange(1,32)
        y=random.randrange(1,24)
        raspberryPosition=[int(x*20),int(y*20)]
    raspberrySpawned=1
    playSurface.fill(blackColor)
    for position in snakeSegments:
        pygame.draw.rect(playSurface,whiteColor,Rect(position[0],position[1],20,20))
    pygame.draw.rect(playSurface,redColor,Rect(raspberryPosition[0],raspberryPosition[1],20,20))
    pygame.display.flip()
    if snakePosition[0]>620 or snakePosition[0] < 0:
        gameOver()
    if snakePosition[1] > 460 or snakePosition[1] < 0:
        gameOver()
    for snakeBody in snakeSegments[1:]:
        if snakePosition[0]==snakeBody[0] and snakePosition[1]==snakeBody[1]:
            gameOver()
    fpsClock.tick(10)

The operation results are as follows:

5, Game case 3: Flying

Basic introduction: at the beginning of the game, a group of extraterrestrials appear. They move down the screen. The player's task is to shoot bullets to kill the enemy. Every time an enemy is killed, the player accumulates one point. When the enemy is not eliminated by the player before landing, the game is over.
1. Game initialization

SCREEN_WIDTH=480
SCREEN_HEIGHT = 800
TYPE_SMALL=1
TYPE_MIDDLE=2
TYPE_BIG=3

2. Define bullets

def __init__(self, bullet_img, init_pos):
    pygame.sprite.Sprite.__init__(self)
    self.image = bullet_img
    self.rect = self.image.get_rect()
    self.rect.midbottom = init_pos
    self.speed = 10

3. Define player class
1. Set basic parameters of players

def __init__(self, plane_img, player_rect, init_pos):
    pygame.sprite.Sprite.__init__(self)
    self.image = []                                 # List used to store player's plane pictures
    for i in range(len(player_rect)):
        self.image.append(plane_img.subsurface(player_rect[i]).convert_alpha())
    self.rect = player_rect[0]                      # Initialize the rectangle of the picture
    self.rect.topleft = init_pos                    # Initialize the coordinates of the upper left corner of the rectangle
    self.speed = 8                                  # Initialize the player's aircraft speed. Here is a certain value
    self.bullets = pygame.sprite.Group()            # A collection of bullets fired by a player's plane
    self.is_hit = False     

2. Firing bullets

def shoot(self, bullet_img):
    bullet = Bullet(bullet_img, self.rect.midtop)
    self.bullets.add(bullet)

3. Judge whether it is beyond the boundary

def moveUp(self):   #upper
   if self.rect.top <= 0:
       self.rect.top = 0
   else:
        self.rect.top -= self.speed
def moveDown(self):   #lower
    if self.rect.top >= SCREEN_HEIGHT - self.rect.height:
        self.rect.top = SCREEN_HEIGHT - self.rect.height
    else:
        self.rect.top += self.speed
def moveLeft(self):  #Left
    if self.rect.left <= 0:
        self.rect.left = 0
    else:
        self.rect.left -= self.speed
def moveRight(self):   #right
    if self.rect.left >= SCREEN_WIDTH - self.rect.width:
        self.rect.left = SCREEN_WIDTH - self.rect.width
    else:
        self.rect.left += self.speed

4. Define enemy human

class Enemy(pygame.sprite.Sprite):
     def __init__(self, enemy_img, enemy_down_imgs, init_pos):
         pygame.sprite.Sprite.__init__(self)
         self.image = enemy_img
         self.rect = self.image.get_rect()
         self.rect.topleft = init_pos
         self.down_imgs = enemy_down_imgs
         self.speed = 2


     def move(self):
         self.rect.top += self.speed

5. Set up game mechanism
Delete the bullets when they move out of the screen, deal with the collision between the enemy aircraft and the player's aircraft, and control the player's movement
6. End of game

Reference code:

import pygame
from sys import exit
from pygame.locals import *
import random
SCREEN_WIDTH=480
SCREEN_HEIGHT = 800
TYPE_SMALL=1
TYPE_MIDDLE=2
TYPE_BIG=3

class Bullet(pygame.sprite.Sprite):
    def __init__(self, bullet_img, init_pos):
        pygame.sprite.Sprite.__init__(self)
        self.image = bullet_img
        self.rect = self.image.get_rect()
        self.rect.midbottom = init_pos
        self.speed = 10

    def move(self):
       self.rect.top -= self.speed

class Player(pygame.sprite.Sprite):
     def __init__(self, plane_img, player_rect, init_pos):
         pygame.sprite.Sprite.__init__(self)
         self.image = []                                 # List used to store player's plane pictures
         for i in range(len(player_rect)):
             self.image.append(plane_img.subsurface(player_rect[i]).convert_alpha())
         self.rect = player_rect[0]                      # Initialize the rectangle of the picture
         self.rect.topleft = init_pos                    # Initialize the coordinates of the upper left corner of the rectangle
         self.speed = 8                                  # Initialize the player's aircraft speed. Here is a certain value
         self.bullets = pygame.sprite.Group()            # A collection of bullets fired by a player's plane
         self.is_hit = False                             # Is the player hit

     # Bullet launch
     def shoot(self, bullet_img):
         bullet = Bullet(bullet_img, self.rect.midtop)
         self.bullets.add(bullet)

     # Move up, you need to judge the boundary
     def moveUp(self):
        if self.rect.top <= 0:
            self.rect.top = 0
        else:
             self.rect.top -= self.speed

     # Move down, you need to judge the boundary
     def moveDown(self):
         if self.rect.top >= SCREEN_HEIGHT - self.rect.height:
             self.rect.top = SCREEN_HEIGHT - self.rect.height
         else:
             self.rect.top += self.speed

     # Move left, need to judge the boundary
     def moveLeft(self):
         if self.rect.left <= 0:
             self.rect.left = 0
         else:
             self.rect.left -= self.speed

     # Move right, need to judge boundary
     def moveRight(self):
         if self.rect.left >= SCREEN_WIDTH - self.rect.width:
             self.rect.left = SCREEN_WIDTH - self.rect.width
         else:
             self.rect.left += self.speed

class Enemy(pygame.sprite.Sprite):
     def __init__(self, enemy_img, enemy_down_imgs, init_pos):
         pygame.sprite.Sprite.__init__(self)
         self.image = enemy_img
         self.rect = self.image.get_rect()
         self.rect.topleft = init_pos
         self.down_imgs = enemy_down_imgs
         self.speed = 2


     def move(self):
         self.rect.top += self.speed

pygame.init()
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
pygame.display.set_caption('Python Fight a plane battle')


background = pygame.image.load('resources/image/background.png').convert()

game_over = pygame.image.load('resources/image/gameover.png')


plane_img = pygame.image.load('resources/image/shoot.png')

player_rect = []
player_rect.append(pygame.Rect(0, 99, 102, 126))        # Player plane picture
player_rect.append(pygame.Rect(165, 234, 102, 126))     # Player explosion picture

player_pos = [200, 600]
player = Player(plane_img, player_rect, player_pos)


bullet_rect = pygame.Rect(1004, 987, 9, 21)
bullet_img = plane_img.subsurface(bullet_rect)


enemy1_rect = pygame.Rect(534, 612, 57, 43)
enemy1_img = plane_img.subsurface(enemy1_rect)
enemy1_down_imgs = plane_img.subsurface(pygame.Rect(267, 347, 57, 43))


enemies1 = pygame.sprite.Group()


enemies_down = pygame.sprite.Group()


shoot_frequency = 0
enemy_frequency = 0


score = 0

clock = pygame.time.Clock()


running = True


while running:

    clock.tick(60)
    if not player.is_hit:
        if shoot_frequency % 15 == 0:
            player.shoot(bullet_img)
        shoot_frequency += 1
        if shoot_frequency >= 15:
            shoot_frequency = 0


    if enemy_frequency % 50 == 0:
        enemy1_pos = [random.randint(0, SCREEN_WIDTH - enemy1_rect.width), 0]
        enemy1 = Enemy(enemy1_img, enemy1_down_imgs, enemy1_pos)
        enemies1.add(enemy1)
    enemy_frequency += 1
    if enemy_frequency >= 100:
        enemy_frequency = 0

    for bullet in player.bullets:
        # Moving bullets at a fixed speed
        bullet.move()
        # Remove bullets after moving out of the screen
        if bullet.rect.bottom < 0:
            player.bullets.remove(bullet)

    for enemy in enemies1:
        #2. Move enemy aircraft
        enemy.move()
        #3. Handling of collision effect between enemy aircraft and player aircraft
        if pygame.sprite.collide_circle(enemy, player):
            enemies_down.add(enemy)
            enemies1.remove(enemy)
            player.is_hit = True
            break
        #4. Delete enemies after moving out of the screen
        if enemy.rect.top < 0:
            enemies1.remove(enemy)

    #How to deal with the effect of enemy aircraft being hit by bullets
    #Add the hit enemy object to the destroy enemy Group
    enemies1_down = pygame.sprite.groupcollide(enemies1, player.bullets, 1, 1)
    for enemy_down in enemies1_down:
        enemies_down.add(enemy_down)

    # Drawing background
    screen.fill(0)
    screen.blit(background, (0, 0))

    # Draw player plane
    if not player.is_hit:
        screen.blit(player.image[0], player.rect) #Draw the normal plane
    else:
        # Effect processing after player's plane is hit
        screen.blit(player.image[1], player.rect) #Draw the exploded plane
        running = False

    # Display of the effect of enemy aircraft being hit by bullets
    for enemy_down in enemies_down:
        enemies_down.remove(enemy_down)
        score += 1
        screen.blit(enemy_down.down_imgs, enemy_down.rect) #Draw out the exploded enemy plane


    # Display bullets
    player.bullets.draw(screen)
    # Display enemy planes
    enemies1.draw(screen)
    # Draw score
    score_font = pygame.font.Font(None, 36)
    score_text = score_font.render('score: '+str(score), True, (128, 128, 128))
    text_rect = score_text.get_rect()
    text_rect.topleft = [10, 10]
    screen.blit(score_text, text_rect)

    pygame.display.update()

    # Process game exit
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            exit()

    # Get keyboard events (up, down, left and right buttons)
    key_pressed = pygame.key.get_pressed()

    # Handle keyboard events (move aircraft position)
    if key_pressed[K_w] or key_pressed[K_UP]:
        player.moveUp()
    if key_pressed[K_s] or key_pressed[K_DOWN]:
        player.moveDown()
    if key_pressed[K_a] or key_pressed[K_LEFT]:
        player.moveLeft()
    if key_pressed[K_d] or key_pressed[K_RIGHT]:
        player.moveRight()

# Show final score after Game Over
font = pygame.font.Font(None, 64)
text = font.render('Final Score: '+ str(score), True, (255, 0, 0))
text_rect = text.get_rect()
text_rect.centerx = screen.get_rect().centerx
text_rect.centery = screen.get_rect().centery + 24
screen.blit(game_over, (0, 0))
screen.blit(text, text_rect)

# Show score and process game exit
while 1:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            exit()
    pygame.display.update()

The operation results are as follows:

6, Game case 4:2048

Basic introduction: through the up and down key to make the same number stack, until there is no same number between adjacent, the game is over.
1. Set game interface, 4X4 matrix

PIXEL = 150
SCORE_PIXEL = 100
SIZE = 4
screen = pygame.display.set_mode((PIXEL * SIZE, PIXEL * SIZE + SCORE_PIXEL))
pygame.display.set_caption("2048")
block = [pygame.Surface((PIXEL, PIXEL)) for i in range(4)]
# Set color
block[0].fill((152, 251, 152))
block[1].fill((240, 255, 255))
block[2].fill((0, 255, 127))
block[3].fill((225, 255, 255))
score_block = pygame.Surface((PIXEL * SIZE, SCORE_PIXEL))
score_block.fill((245, 245, 245))
# Set font
map_font = pygame.font.Font(None, PIXEL)
score_font = pygame.font.Font(None, SCORE_PIXEL)
clock = pygame.time.Clock()
show(map)

2. Update screen

def show(map):
    for i in range(SIZE):
        for j in range(SIZE):
            # Background color block
            screen.blit(map.map[i][j] == 0 and block[(i + j) % 2] or block[2 + (i + j) % 2], (PIXEL * j, PIXEL * i))
            # Numerical display
            if map.map[i][j] != 0:
                map_text = map_font.render(str(map.map[i][j]), True, (106, 90, 205))
                text_rect = map_text.get_rect()
                text_rect.center = (PIXEL * j + PIXEL / 2, PIXEL * i + PIXEL / 2)
                screen.blit(map_text, text_rect)
    # Score display
    screen.blit(score_block, (0, PIXEL * SIZE))
    score_text = score_font.render((map.over() and "Game over with score " or "Score: ") + str(map.score), True,
                                   (106, 90, 205))
    score_rect = score_text.get_rect()
    score_rect.center = (PIXEL * SIZE / 2, PIXEL * SIZE + SCORE_PIXEL / 2)
    screen.blit(score_text, score_rect)
    pygame.display.update()

3. Use up, down, left and right to control the game

pressed_keys = pygame.key.get_pressed()
if pressed_keys[K_w] or pressed_keys[K_UP]:
    map.moveUp()
elif pressed_keys[K_s] or pressed_keys[K_DOWN]:
    map.moveDown()
elif pressed_keys[K_a] or pressed_keys[K_LEFT]:
    map.moveLeft()
elif pressed_keys[K_d] or pressed_keys[K_RIGHT]:
    map.moveRight()

4. End of game

def over(self):
    for r in range(self.size):
        for c in range(self.size):
            if self.map[r][c] == 0:
                return False
    for r in range(self.size):
        for c in range(self.size - 1):
            if self.map[r][c] == self.map[r][c + 1]:
                return False
    for r in range(self.size - 1):
        for c in range(self.size):
            if self.map[r][c] == self.map[r + 1][c]:
                return False
    return True

Reference code:

import random
import sys
import pygame
from pygame.locals import *

PIXEL = 150
SCORE_PIXEL = 100
SIZE = 4


# Class of map
class Map:
    def __init__(self, size):
        self.size = size
        self.score = 0
        self.map = [[0 for i in range(size)] for i in range(size)]
        self.add()
        self.add()

    # Add 2 or 4, with 1 / 4 probability to produce 4
    def add(self):
        while True:
            p = random.randint(0, self.size * self.size - 1)
            if self.map[p // self.size][p % self.size] == 0:
                x = random.randint(0, 3) > 0 and 2 or 4
                self.map[p // self.size][p % self.size] = x
                self.score += x
                break

    # The map moves to the left, and other directions can be moved by proper rotation to return whether the map is updated or not
    def adjust(self):
        changed = False
        for a in self.map:
            b = []
            last = 0
            for v in a:
                if v != 0:
                    if v == last:
                        b.append(b.pop() << 1)
                        last = 0
                    else:
                        b.append(v)
                        last = v
            b += [0] * (self.size - len(b))
            for i in range(self.size):
                if a[i] != b[i]:
                    changed = True
            a[:] = b
        return changed

    # Rotate the map 90 degrees counter clockwise
    def rotate90(self):
        self.map = [[self.map[c][r] for c in range(self.size)] for r in reversed(range(self.size))]

    # Judge the end of the game
    def over(self):
        for r in range(self.size):
            for c in range(self.size):
                if self.map[r][c] == 0:
                    return False
        for r in range(self.size):
            for c in range(self.size - 1):
                if self.map[r][c] == self.map[r][c + 1]:
                    return False
        for r in range(self.size - 1):
            for c in range(self.size):
                if self.map[r][c] == self.map[r + 1][c]:
                    return False
        return True

    def moveUp(self):
        self.rotate90()
        if self.adjust():
            self.add()
        self.rotate90()
        self.rotate90()
        self.rotate90()

    def moveRight(self):
        self.rotate90()
        self.rotate90()
        if self.adjust():
            self.add()
        self.rotate90()
        self.rotate90()

    def moveDown(self):
        self.rotate90()
        self.rotate90()
        self.rotate90()
        if self.adjust():
            self.add()
        self.rotate90()

    def moveLeft(self):
        if self.adjust():
            self.add()


# Update screen
def show(map):
    for i in range(SIZE):
        for j in range(SIZE):
            # Background color block
            screen.blit(map.map[i][j] == 0 and block[(i + j) % 2] or block[2 + (i + j) % 2], (PIXEL * j, PIXEL * i))
            # Numerical display
            if map.map[i][j] != 0:
                map_text = map_font.render(str(map.map[i][j]), True, (106, 90, 205))
                text_rect = map_text.get_rect()
                text_rect.center = (PIXEL * j + PIXEL / 2, PIXEL * i + PIXEL / 2)
                screen.blit(map_text, text_rect)
    # Score display
    screen.blit(score_block, (0, PIXEL * SIZE))
    score_text = score_font.render((map.over() and "Game over with score " or "Score: ") + str(map.score), True,
                                   (106, 90, 205))
    score_rect = score_text.get_rect()
    score_rect.center = (PIXEL * SIZE / 2, PIXEL * SIZE + SCORE_PIXEL / 2)
    screen.blit(score_text, score_rect)
    pygame.display.update()


map = Map(SIZE)
pygame.init()
screen = pygame.display.set_mode((PIXEL * SIZE, PIXEL * SIZE + SCORE_PIXEL))
pygame.display.set_caption("2048")
block = [pygame.Surface((PIXEL, PIXEL)) for i in range(4)]
# Set color
block[0].fill((152, 251, 152))
block[1].fill((240, 255, 255))
block[2].fill((0, 255, 127))
block[3].fill((225, 255, 255))
score_block = pygame.Surface((PIXEL * SIZE, SCORE_PIXEL))
score_block.fill((245, 245, 245))
# Set font
map_font = pygame.font.Font(None, PIXEL)
score_font = pygame.font.Font(None, SCORE_PIXEL)
clock = pygame.time.Clock()
show(map)

while not map.over():
    # 12 is the experimental parameter
    clock.tick(12)
    for event in pygame.event.get():
        if event.type == QUIT:
            sys.exit()
    # Receive player action
    pressed_keys = pygame.key.get_pressed()
    if pressed_keys[K_w] or pressed_keys[K_UP]:
        map.moveUp()
    elif pressed_keys[K_s] or pressed_keys[K_DOWN]:
        map.moveDown()
    elif pressed_keys[K_a] or pressed_keys[K_LEFT]:
        map.moveLeft()
    elif pressed_keys[K_d] or pressed_keys[K_RIGHT]:
        map.moveRight()
    show(map)

# Game over
pygame.time.delay(3000)

The operation results are as follows:

Tags: Mobile Python

Posted on Fri, 13 Mar 2020 02:08:02 -0400 by saranya