2D Game Development - sy2.Python-pygame

Python's pygame game development

Use pygame module in python to develop 2D games.

Pygame is a cross-platform Python module designed for electronic games.Contains images, sounds.Created on the basis of SDL, allows the development of real-time video games without being tied down by low-level languages such as C or lower-level assembly languages.Based on this assumption, all required game functions and concepts completely simplify the bitwise game logic itself, and all resource structures can be provided by advanced languages such as Python.

This experiment is a validation assignment with the code given by the teacher.
Development Scenario: Python 3.7.4 + Pygame1.9.6
Development Tools: PyCharm 2019.3.3 x64

Basics

Install pygame and type in cmd instructions based on python

pip install pygame


The picture above is because I have already installed it, prompting me that I have already installed it.If the network is not good, it is recommended to go to the official or mirror site to download the package, and then cd to the folder where the package is located, enter:

pip install pygame-1.9.6-cp37-cp37m-win_amd64.whl  #Version by itself

Verify that python is installed and enter it in cmd

python

pygame window making

Set the window size and name as follows:

import pygame
from pygame.locals import *
import sys

def hellow_world():
    pygame.init()
    pygame.display.set_mode((640, 480))
    pygame.display.set_caption("hellow world!")
    while True:
        for event in pygame.event.get():
            if event.type==QUIT:
                pygame.quit()
                sys.exit()
        pygame.display.update()

if __name__ == "__main__":
    hellow_world()

Execution results:

Tank Battle

Use the keyboard to move tanks and pygame to develop games.
The code is as follows:

import os, sys, pygame
from pygame.locals import *

# Control 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

# Set parameters to start the game
def play_tank():
    pygame.init()
    window_size = Rect(0, 0, 700, 650)
    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('images\\tankD.bmp')
    back_image = pygame.image.load('images\\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()

Execution results:

Source material:

ccsprite

In game development, objects that display images are often referred to as Sprite elves.A fairy is a graphic that has size, color, pattern, can be moved, and can interact with other graphic objects.
Tank elves (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 = 'images/tankD.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()

Execution results:

Wizard test (code):

import pygame
from pygame.locals import *
class MySprite(pygame.sprite.Sprite):
    def __init__(self, target):
        pygame.sprite.Sprite.__init__(self)
        self.target_surface = target
        self.image = None
        self.master_image = None
        self.rect = None
        self.topleft = 0, 0
        self.frame = 0
        self.old_frame = -1
        self.frame_width = 1
        self.frame_height = 1
        self.first_frame = 0
        self.last_frame = 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.frame_width = width
        self.frame_height = height
        self.rect = 0, 0, width, height
        self.columns = columns
        rect = self.master_image.get_rect()
        self.last_frame = (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_frame:
            self.frame = self.first_frame
            self.last_time = current_time
        if self.frame != self.old_frame:
            frame_x = (self.frame % self.columns) * self.frame_width
            frame_y = (self.frame // self.columns) * self.frame_height
            rect = (frame_x, frame_y, self.frame_width, self.frame_height)
            self.image = self.master_image.subsurface(rect)
            self.old_frame = self.frame
pygame.init()
screen = pygame.display.set_mode((800, 600), 0, 32)
pygame.display.set_caption("Elf Test")
font = pygame.font.Font(None, 18)
framerate = pygame.time.Clock()
cat = MySprite(screen)
cat.load("images\\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()

Execution results:

Source material:

Retro Snaker

Keyboard keys are used to control the movement of the snake to eat food. When the party snake touches the outside wall, the game ends.
The code is as follows:

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('snakey')
# Define some colors
redColor = pygame.Color(255, 0, 0)
blackColor = pygame.Color(0, 0, 0)
whiteColor = pygame.Color(255, 255, 255)
greyColor = pygame.Color(150, 150, 150)
# Initialized variables used in some programs
snakePosition = [100, 100]
snakeSegments = [[100, 100], [80, 100], [60, 100]]
raspberryPosition = [300, 300]    # Raspberry position
raspberrySpawned = 1              # Whether or not to eat raspberries, 1 is not eaten, 0 is eaten
direction = 'right'
changeDirection = direction

def gameOver():
    gameOverFont = pygame.font.Font('images\\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_DOWN 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

    # Add a section to the snake's body while placing it on the head
    snakeSegments.insert(0, list(snakePosition))
    # Check that the X and Y coordinates of the snake head are equal to the coordinates of the raspberry (the player's target point)
    if snakePosition[0] == raspberryPosition[0] and snakePosition[1] == raspberryPosition[1]:
        raspberrySpawned = 0
    else:
        snakeSegments.pop()
    # Add a new raspberry to the game interface:
    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)

Execution results:

Airplane Battle

The game starts, the music sounds, airplanes appear from above and move down. The player's task is to shoot bullets to destroy the enemy. For each enemy destroyed, the player accumulates 10 points.The game ends when the enemy is not destroyed by the player before it lands.
The code is as follows:

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

# Define Classes
SCREEN_WIDTH = 480
SCREEN_HEIGHT = 800

TYPE_SMALL = 1
TYPE_MIDDLE = 2
TYPE_BIG = 3

# ZiDan
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

# Player class
class Player(pygame.sprite.Sprite):
    def __init__(self, plane_img, player_rect, init_pos):
        pygame.sprite.Sprite.__init__(self)
        self.image = []                                 # List to store player 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 where the picture is located
        self.rect.topleft = init_pos                    # Initialize the upper left corner coordinates of the rectangle
        self.speed = 8                                  # Initialize player airplane speed, here is a fixed value
        self.bullets = pygame.sprite.Group()            # The collection of bullets fired by a player's aircraft
        self.img_index = 0                              # Player Wizard Picture Index
        self.is_hit = False                             # Is the player hit

    # Launch Bullet
    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 determine 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, you need to determine the boundary
    def moveLeft(self):
        if self.rect.left <= 0:
            self.rect.left = 0
        else:
            self.rect.left -= self.speed

    # Move right, you need to determine the 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

# Enemy class
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
        self.down_index = 0

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

# Initialize the game
pygame.init()
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
pygame.display.set_caption('Airplane Battle')

# Load Game Music
bullet_sound = pygame.mixer.Sound('images/resources/sound/bullet.wav')
enemy1_down_sound = pygame.mixer.Sound('images/resources/sound/enemy1_down.wav')
game_over_sound = pygame.mixer.Sound('images/resources/sound/game_over.wav')
bullet_sound.set_volume(0.3)
enemy1_down_sound.set_volume(0.3)
game_over_sound.set_volume(0.3)
pygame.mixer.music.load('images/resources/sound/game_music.wav')
pygame.mixer.music.play(-1, 0.0)
pygame.mixer.music.set_volume(0.25)

# Load Background Map
background = pygame.image.load('images/resources/image/background.png').convert()
game_over = pygame.image.load('images/resources/image/gameover.png')

filename = 'images/resources/image/shoot.png'  # It can also be loaded like this, with the same meaning as the previous sentence
plane_img = pygame.image.load(filename)

# Set player-related parameters
player_rect = []
player_rect.append(pygame.Rect(0, 99, 102, 126))        # Player elf picture area
player_rect.append(pygame.Rect(165, 360, 102, 126))
player_rect.append(pygame.Rect(165, 234, 102, 126))     # Player Explosion Elf Picture Area
player_rect.append(pygame.Rect(330, 624, 102, 126))
player_rect.append(pygame.Rect(330, 498, 102, 126))
player_rect.append(pygame.Rect(432, 624, 102, 126))
player_pos = [200, 600]
player = Player(plane_img, player_rect, player_pos)

# Define surface-related parameters used by bullet objects
bullet_rect = pygame.Rect(1004, 987, 9, 21)
bullet_img = plane_img.subsurface(bullet_rect)

# Define surface-related parameters used by enemy aircraft objects
enemy1_rect = pygame.Rect(534, 612, 57, 43)
enemy1_img = plane_img.subsurface(enemy1_rect)
enemy1_down_imgs = []
enemy1_down_imgs.append(plane_img.subsurface(pygame.Rect(267, 347, 57, 43)))
enemy1_down_imgs.append(plane_img.subsurface(pygame.Rect(873, 697, 57, 43)))
enemy1_down_imgs.append(plane_img.subsurface(pygame.Rect(267, 296, 57, 43)))
enemy1_down_imgs.append(plane_img.subsurface(pygame.Rect(930, 697, 57, 43)))

enemies1 = pygame.sprite.Group()

# Store destroyed planes to render destroyed elf animations
enemies_down = pygame.sprite.Group()

shoot_frequency = 0
enemy_frequency = 0

player_down_index = 16

score = 0

clock = pygame.time.Clock()

running = True

while running:
    # Control Game Maximum Frame Rate 60
    clock.tick(60)

    # Controls the frequency at which bullets are fired and fires them
    if not player.is_hit:
        if shoot_frequency % 15 == 0:
            bullet_sound.play()
            player.shoot(bullet_img)
        shoot_frequency += 1
        if shoot_frequency >= 15:
            shoot_frequency = 0

    # Generate enemy aircraft
    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

    # Move bullets, delete if out of window
    for bullet in player.bullets:
        bullet.move()
        if bullet.rect.bottom < 0:
            player.bullets.remove(bullet)

    # Move enemy aircraft, delete if out of window
    for enemy in enemies1:
        # Move enemy aircraft
        enemy.move()
        # Determine if a player is hit
        if pygame.sprite.collide_circle(enemy, player):
            enemies_down.add(enemy)
            enemies1.remove(enemy)
            player.is_hit = True
            game_over_sound.play()
            break
        # Remove enemies after moving out of the screen
        if enemy.rect.top > SCREEN_HEIGHT:
            enemies1.remove(enemy)

    # Add the hit enemy plane object to the destroy enemy plane Group to render the destroy animation
    enemies1_down = pygame.sprite.groupcollide(enemies1, player.bullets, 1, 1)
    for enemy_down in enemies1_down:
        enemies_down.add(enemy_down)

    # Draw Background
    screen.fill(0)
    screen.blit(background, (0, 0))

    # Draw player planes
    if not player.is_hit:
        screen.blit(player.image[player.img_index], player.rect)   # Draw a normal plane
        # Change the picture index to animate the plane
        player.img_index = shoot_frequency // 8
    else:
        # Effect handling after a player's plane is hit
        player.img_index = player_down_index // 8
        screen.blit(player.image[player.img_index], player.rect)    # Draw the exploding plane
        player_down_index += 1
        if player_down_index > 47:
            running = False

    # Draw destroy animation
    for enemy_down in enemies_down:
        if enemy_down.down_index == 0:
            enemy1_down_sound.play()
        if enemy_down.down_index > 7:
            enemies_down.remove(enemy_down)
            score += 10
            continue
        screen.blit(enemy_down.down_imgs[enemy_down.down_index // 2], enemy_down.rect) #Draw an exploding enemy plane
        enemy_down.down_index += 1

    # Draw bullets and enemy aircraft
    player.bullets.draw(screen)
    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)

    # Update Screen
    pygame.display.update()

    # Handle Game Exit
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            exit()

    # Listen for keyboard events
    key_pressed = pygame.key.get_pressed()

    # Invalid if the player is hit
    if not player.is_hit:
        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 GameOver
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 handle game exit
while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            exit()
    pygame.display.update()

Execution results:

Source material:

2048

The rules of the game are simple. You need to control all the squares moving in the same direction. Two squares with the same number collide and merge into their sum. After each operation, a random 2 or 4 is generated, and a "2048" square is won.
The code is as follows:

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

PIXEL = 150
SCORE_PIXEL = 100
SIZE = 4


# Classes of Maps
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, 1/4 probability produces 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 closes to the left and other directions can be rotated appropriately to return to 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 counterclockwise
    def rotate90(self):
        self.map = [[self.map[c][r] for c in range(self.size)] for r in reversed(range(self.size))]

    # Judging Game End
    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))
            # Numeric 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 Colors
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 as 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)

Execution results:

Tags: Python pip Pycharm network

Posted on Sun, 15 Mar 2020 13:32:53 -0400 by blackwidow