catalogue
1, Game development using Pygame
1, Game development using Pygame
Pygame is an open source Python module, which is specially used for the development of multimedia applications (such as video games), including support for images, sounds, videos, events, collisions, etc. Pygame is built on SDL SDL is a cross platform multimedia development library, which is implemented in C language. It is widely used in the development of games, simulators, players and so on. Pygame makes game developers no longer bound by the underlying language and can pay more attention to the functions and logic of the game.
Now let's finish a simple game. The name of the game is "big ball eats small ball"
1. Make game window
import pygame def main(): # Initialize the modules in the imported pygame pygame.init() # Initializes the window for display and sets the window size screen = pygame.display.set_mode((800, 600)) # Sets the title of the current window pygame.display.set_caption('Big balls eat small balls') running = True # Start an event loop to handle the events that occur while running: # Get events from the message queue and process them for event in pygame.event.get(): if event.type == pygame.QUIT: running = False if __name__ == '__main__': main()
2. Drawing in a window
You can draw on the window through the function of the draw module in pygame. The graphics you can draw include lines, rectangles, polygons, circles, ellipses, arcs, etc. It should be noted that the screen coordinate system sets the upper left corner of the screen as the coordinate origin (0, 0), the right is the positive direction of the x axis, and the down is the positive direction of the y axis. When indicating the position or setting the size, our default unit is pixel . The so-called pixel is a point on the screen. You can use the image browsing software to try to enlarge a picture several times, and you can see these points. pygame uses color light to represent color Three primary colors Representation, that is, the RGB values of colors are specified through a tuple or list, and each value is between 0 and 255, because each primary color is represented by an 8-bit value. The three colors are equivalent to a total of 24 bits, which is often referred to as "24 bit color representation".
import pygame def main(): # Initialize the modules in the imported pygame pygame.init() # Initializes the window for display and sets the window size screen = pygame.display.set_mode((800, 600)) # Sets the title of the current window pygame.display.set_caption('Big balls eat small balls') # Set the background color of the window (the color is a tuple composed of red, green and blue primary colors) screen.fill((242, 242, 242)) # Draw a circle (parameters are: screen, color, center position, radius, 0 indicates filling circle) pygame.draw.circle(screen, (255, 0, 0,), (100, 100), 30, 0) # Refresh the current window (the rendering window renders the drawn image) pygame.display.flip() running = True # Start an event loop to handle the events that occur while running: # Get events from the message queue and process them for event in pygame.event.get(): if event.type == pygame.QUIT: running = False if __name__ == '__main__': main()
3. Load image
If you need to load the image directly into the window, you can use the function of the image module in pygame to load the image, and then render the image through the blit method of the previously obtained window object. The code is as follows.
import pygame def main(): # Initialize the modules in the imported pygame pygame.init() # Initializes the window for display and sets the window size screen = pygame.display.set_mode((800, 600)) # Sets the title of the current window pygame.display.set_caption('Big balls eat small balls') # Set the background color of the window (the color is a tuple composed of red, green and blue primary colors) screen.fill((255, 255, 255)) # Loads the image with the specified file name ball_image = pygame.image.load('./res/ball.png') # Rendering an image on a window screen.blit(ball_image, (50, 50)) # Refresh the current window (the rendering window renders the drawn image) pygame.display.flip() running = True # Start an event loop to handle the events that occur while running: # Get events from the message queue and process them for event in pygame.event.get(): if event.type == pygame.QUIT: running = False if __name__ == '__main__': main()
4. Achieve animation effect
Speaking of animation This word is not unfamiliar to everyone. In fact, to achieve animation effect, the principle itself is very simple, that is, play discontinuous pictures continuously. As long as a certain number of frames per second is reached, you can make a relatively smooth animation effect. If you want to move the small ball in the above code, you can use variables to represent the position of the small ball, modify the position of the small ball in the loop, and then refresh the whole window.
import pygame def main(): # Initialize the modules in the imported pygame pygame.init() # Initializes the window for display and sets the window size screen = pygame.display.set_mode((800, 600)) # Sets the title of the current window pygame.display.set_caption('Big balls eat small balls') # Define variables to represent the position of the ball on the screen x, y = 50, 50 running = True # Start an event loop to handle the events that occur while running: # Get events from the message queue and process them for event in pygame.event.get(): if event.type == pygame.QUIT: running = False screen.fill((255, 255, 255)) pygame.draw.circle(screen, (255, 0, 0,), (x, y), 30, 0) pygame.display.flip() # Change the position of the ball every 50 milliseconds and refresh the window pygame.time.delay(50) x, y = x + 5, y + 5 if __name__ == '__main__': main()
5. Collision detection
Usually, many objects appear in a game, and the "collision" between these objects is inevitable, such as shells hitting aircraft, boxes hitting the ground, etc. Collision detection is a crucial problem that must be handled in most games. The sprite module of pygame provides support for collision detection. Here we will not introduce the functions provided by the sprite module for the time being, because it is very simple to detect whether two balls collide, Just check whether the distance between the center of the ball is less than the sum of the radii of the two balls. In order to create more small balls, we can create small balls with random color, size and moving speed at the click of the mouse through the processing of mouse events. Of course, to do this, we can apply the object-oriented knowledge we learned before.
from enum import Enum, unique from math import sqrt from random import randint import pygame @unique class Color(Enum): """colour""" RED = (255, 0, 0) GREEN = (0, 255, 0) BLUE = (0, 0, 255) BLACK = (0, 0, 0) WHITE = (255, 255, 255) GRAY = (242, 242, 242) @staticmethod def random_color(): """Get random colors""" r = randint(0, 255) g = randint(0, 255) b = randint(0, 255) return (r, g, b) class Ball(object): """ball""" def __init__(self, x, y, radius, sx, sy, color=Color.RED): """Initialization method""" self.x = x self.y = y self.radius = radius self.sx = sx self.sy = sy self.color = color self.alive = True def move(self, screen): """move""" self.x += self.sx self.y += self.sy if self.x - self.radius <= 0 or \ self.x + self.radius >= screen.get_width(): self.sx = -self.sx if self.y - self.radius <= 0 or \ self.y + self.radius >= screen.get_height(): self.sy = -self.sy def eat(self, other): """Eat other balls""" if self.alive and other.alive and self != other: dx, dy = self.x - other.x, self.y - other.y distance = sqrt(dx ** 2 + dy ** 2) if distance < self.radius + other.radius \ and self.radius > other.radius: other.alive = False self.radius = self.radius + int(other.radius * 0.146) def draw(self, screen): """Draw the ball on the window""" pygame.draw.circle(screen, self.color, (self.x, self.y), self.radius, 0)
6. Event handling
The mouse event can be processed in the event loop. The event type can be determined through the type attribute of the event object, and then the position of the mouse click can be obtained through the pos attribute. If you want to handle keyboard events, it is also in this place, which is similar to handling mouse events.
def main(): # Defines the container used to hold all balls balls = [] # Initialize the modules in the imported pygame pygame.init() # Initializes the window for display and sets the window size screen = pygame.display.set_mode((800, 600)) # Sets the title of the current window pygame.display.set_caption('Big balls eat small balls') running = True # Start an event loop to handle the events that occur while running: # Get events from the message queue and process them for event in pygame.event.get(): if event.type == pygame.QUIT: running = False # Code for handling mouse events if event.type == pygame.MOUSEBUTTONDOWN and event.button == 1: # Get the mouse click position x, y = event.pos radius = randint(10, 100) sx, sy = randint(-10, 10), randint(-10, 10) color = Color.random_color() # Create a ball at the click of the mouse (random size, speed and color) ball = Ball(x, y, radius, sx, sy, color) # Add ball to list container balls.append(ball) screen.fill((255, 255, 255)) # Take out the ball in the container, draw it if it is not eaten, and remove it if it is eaten for ball in balls: if ball.alive: ball.draw(screen) else: balls.remove(ball) pygame.display.flip() # Change the position of the ball every 50 milliseconds and refresh the window pygame.time.delay(50) for ball in balls: ball.move(screen) # Check if the ball eats any other balls for other in balls: ball.eat(other) if __name__ == '__main__': main()
2, Gobang
The game program is as follows
import pygame EMPTY = 0 BLACK = 1 WHITE = 2 black_color = [0, 0, 0] white_color = [255, 255, 255] class RenjuBoard(object): def __init__(self): self._board = [[]] * 15 self.reset() def reset(self): for row in range(len(self._board)): self._board[row] = [EMPTY] * 15 def move(self, row, col, is_black): if self._board[row][col] == EMPTY: self._board[row][col] = BLACK if is_black else WHITE return True return False def draw(self, screen): for index in range(1, 16): pygame.draw.line(screen, black_color, [40, 40 * index], [600, 40 * index], 1) pygame.draw.line(screen, black_color, [40 * index, 40], [40 * index, 600], 1) pygame.draw.rect(screen, black_color, [36, 36, 568, 568], 4) pygame.draw.circle(screen, black_color, [320, 320], 5, 0) pygame.draw.circle(screen, black_color, [160, 160], 5, 0) pygame.draw.circle(screen, black_color, [480, 480], 5, 0) pygame.draw.circle(screen, black_color, [480, 160], 5, 0) pygame.draw.circle(screen, black_color, [160, 480], 5, 0) for row in range(len(self._board)): for col in range(len(self._board[row])): if self._board[row][col] != EMPTY: ccolor = black_color \ if self._board[row][col] == BLACK else white_color pos = [40 * (col + 1), 40 * (row + 1)] pygame.draw.circle(screen, ccolor, pos, 20, 0) def main(): board = RenjuBoard() is_black = True pygame.init() pygame.display.set_caption('Gobang') screen = pygame.display.set_mode([640, 640]) screen.fill([255, 255, 0]) board.draw(screen) pygame.display.flip() running = True while running: for event in pygame.event.get(): if event.type == pygame.QUIT: running = False elif event.type == pygame.KEYUP: pass elif event.type == pygame.MOUSEBUTTONDOWN\ and event.button == 1: x, y = event.pos row = round((y - 40) / 40) col = round((x - 40) / 40) if board.move(row, col, is_black): is_black = not is_black screen.fill([255, 255, 0]) board.draw(screen) pygame.display.flip() pygame.quit() if __name__ == '__main__': main()
3, Snake game
The code is as follows
from abc import ABCMeta, abstractmethod from enum import Enum, unique from random import randrange from threading import Thread import pygame class Color(object): """colour""" GRAY = (242, 242, 242) BLACK = (0, 0, 0) GREEN = (0, 255, 0) PINK = (255, 20, 147) @unique class Direction(Enum): """direction""" UP = 0 RIGHT = 1 DOWN = 2 LEFT = 3 class GameObject(object, metaclass=ABCMeta): """Objects in the game""" def __init__(self, x=0, y=0, color=Color.BLACK): """ Initialization method :param x: Abscissa :param y: Ordinate :param color: colour """ self._x = x self._y = y self._color = color @property def x(self): return self._x @property def y(self): return self._y @abstractmethod def draw(self, screen): """ draw :param screen: screen """ pass class Wall(GameObject): """enclosing wall""" def __init__(self, x, y, width, height, color=Color.BLACK): """ Initialization method :param x: Abscissa :param y: Ordinate :param width: width :param height: height :param color: colour """ super().__init__(x, y, color) self._width = width self._height = height @property def width(self): return self._width @property def height(self): return self._height def draw(self, screen): pygame.draw.rect(screen, self._color, (self._x, self._y, self._width, self._height), 4) class Food(GameObject): """food""" def __init__(self, x, y, size, color=Color.PINK): """ Initialization method :param x: Abscissa :param y: Ordinate :param size: size :param color: colour """ super().__init__(x, y, color) self._size = size self._hidden = False def draw(self, screen): if not self._hidden: pygame.draw.circle(screen, self._color, (self._x + self._size // 2, self._y + self._size // 2), self._size // 2, 0) self._hidden = not self._hidden class SnakeNode(GameObject): """Node on Snake""" def __init__(self, x, y, size, color=Color.GREEN): """ Initialization method :param x: Abscissa :param y: Ordinate :param size: size :param color: colour """ super().__init__(x, y, color) self._size = size @property def size(self): return self._size def draw(self, screen): pygame.draw.rect(screen, self._color, (self._x, self._y, self._size, self._size), 0) pygame.draw.rect(screen, Color.BLACK, (self._x, self._y, self._size, self._size), 1) class Snake(GameObject): """snake""" def __init__(self, x, y, size=20, length=5): """ Initialization method :param x: Abscissa :param y: Ordinate :param size: size :param length: Initial length """ super().__init__() self._dir = Direction.LEFT self._nodes = [] self._alive = True self._new_dir = None for index in range(length): node = SnakeNode(x + index * size, y, size) self._nodes.append(node) @property def dir(self): return self._dir @property def alive(self): return self._alive @property def head(self): return self._nodes[0] def change_dir(self, new_dir): """ Change direction :param new_dir: New direction """ if new_dir != self._dir and \ (self._dir.value + new_dir.value) % 2 != 0: self._new_dir = new_dir def move(self): """move""" if self._new_dir: self._dir, self._new_dir = self._new_dir, None snake_dir = self._dir x, y, size = self.head.x, self.head.y, self.head.size if snake_dir == Direction.UP: y -= size elif snake_dir == Direction.RIGHT: x += size elif snake_dir == Direction.DOWN: y += size else: x -= size new_head = SnakeNode(x, y, size) self._nodes.insert(0, new_head) self._nodes.pop() def collide(self, wall): """ Hit the wall :param wall: enclosing wall """ head = self.head if head.x < wall.x or head.x + head.size > wall.x + wall.width \ or head.y < wall.y or head.y + head.size > wall.y + wall.height: self._alive = False def eat_food(self, food): """ Eat food :param food: food :return: Eat food and return True Otherwise return False """ if self.head.x == food.x and self.head.y == food.y: tail = self._nodes[-1] self._nodes.append(tail) return True return False def eat_self(self): """Bite yourself""" for index in range(4, len(self._nodes)): node = self._nodes[index] if node.x == self.head.x and node.y == self.head.y: self._alive = False def draw(self, screen): for node in self._nodes: node.draw(screen) def main(): def refresh(): """Refresh game window""" screen.fill(Color.GRAY) wall.draw(screen) food.draw(screen) snake.draw(screen) pygame.display.flip() def handle_key_event(key_event): """Handle key events""" key = key_event.key if key == pygame.K_F2: reset_game() elif key in (pygame.K_a, pygame.K_w, pygame.K_d, pygame.K_s): if snake.alive: if key == pygame.K_w: new_dir = Direction.UP elif key == pygame.K_d: new_dir = Direction.RIGHT elif key == pygame.K_s: new_dir = Direction.DOWN else: new_dir = Direction.LEFT snake.change_dir(new_dir) def create_food(): """Create food""" unit_size = snake.head.size max_row = wall.height // unit_size max_col = wall.width // unit_size row = randrange(0, max_row) col = randrange(0, max_col) return Food(wall.x + unit_size * col, wall.y + unit_size * row, unit_size) def reset_game(): """Reset game""" nonlocal food, snake food = create_food() snake = Snake(250, 290) def background_task(): nonlocal running, food while running: if snake.alive: refresh() clock.tick(10) if snake.alive: snake.move() snake.collide(wall) if snake.eat_food(food): food = create_food() snake.eat_self() """ class BackgroundTask(Thread): def run(self): nonlocal running, food while running: if snake.alive: refresh() clock.tick(10) if snake.alive: snake.move() snake.collide(wall) if snake.eat_food(food): food = create_food() snake.eat_self() """ wall = Wall(10, 10, 600, 600) snake = Snake(250, 290) food = create_food() pygame.init() screen = pygame.display.set_mode((620, 620)) pygame.display.set_caption('Greedy snake') # Create a clock that controls the number of frames per second of the game clock = pygame.time.Clock() running = True # Start the background thread, which is responsible for refreshing the window and moving the snake # BackgroundTask().start() Thread(target=background_task).start() # Message loop for handling events while running: for event in pygame.event.get(): if event.type == pygame.QUIT: running = False elif event.type == pygame.KEYDOWN: handle_key_event(event) pygame.quit() if __name__ == '__main__': main()
https://github.com/jackfrued/Python-100-Dayshttps://github.com/jackfrued/Python-100-Days