[PYTHON] Balloon splitting game with pygame

Introduction

In Last post, I created a turn-based tic-tac-toe using tkinter, so this time the screen is constantly updated using pygame. I tried to make. I wrote it as a balloon splitting game in the title, but it is not so game-like. Lol However, can it be used when making games in the future? I wonder if I could learn the processing. .. .. I think. As usual, it's a chimeric code that has all the features you want, so readability is a future issue.

This finished product
balloon_game.gif

At the very end, the whole picture of this code is posted.

Display screen creation

First of all, it is the creation of the basic screen.

import pygame

pygame.init()
screen = pygame.display.set_mode((800, 600))
pygame.display.set_caption("Game")

Import pygame anyway. Initialize the pygame module with pygame.init (). When writing at the opening, it may be good to recognize the usual spell level. If you use a lot of modules, you should initialize the unused modules. Maybe the day will come in the middle of processing?

pygame.display.set_mode is the screen size, width and height. set_caption is the name that will appear in the title bar.

Screen update process

import time

FPSCLOCK = pygame.time.Clock()
FPS = 15

class CanonGame():
    def __init__(self):

        while True:
            pygame.display.update()
            FPSCLOCK.tick(FPS)

def main():
    CanonGame()

if __name__ == '__main__':
    main()

The leading role. After reflecting the screen drawing with pygame.display.update (), processing is executed at a speed that does not exceed (frames) per second with pygame.time.Clock.tick (frames). If you increase the number of frames, you can implement smooth movement, but the processing becomes heavy. Also, basically put things that keep updating in the range of while True :.

Get key event

from pygame.locals import *

pygame.key.set_repeat(5, 5)

class CanonGame():
        while True:
            for event in pygame.event.get():
                if event.type == QUIT:
                    pygame.quit()
                    sys.exit()
                elif event.type == KEYDOWN:
                    if event.key == K_SPACE:
                        self.bullet_shot = True
                    elif event.key == K_UP and self.cannon_radian < 89:
                        self.cannon_radian += 1
                    elif event.key == K_DOWN and self.cannon_radian > 0:
                        self.cannon_radian -= 1

When it comes to games, you still want to operate it, right? Gets the type of operation performed by event.get (). If event.type is QUIT (x button at the top right of the screen), exit everything. If it is KEYDOWN (keyboard press), then event.key is acquired and processing is assigned to each pressed key. This time, fire the ball with the space key. I adjusted the orientation with the up and down keys. By setting key.set_repeat, it will respond even if you hold down the key.

Image display, rotation


class CanonGame():
    def __init__(self):
        bullet_image = pygame.image.load("bullet.png ")
        self.cannon_image = pygame.image.load("cannon.png ")

            screen.fill((255, 255, 255))
            screen.blit(bullet_image, (self.bullet_x, self.bullet_y))

            rotate_cannon = pygame.transform.rotate(self.cannon_image, self.cannon_radian - 45)
            cannon_rect = rotate_cannon.get_rect()
            cannon_rect.center = (84, 536)
            screen.blit(rotate_cannon, cannon_rect)

Load the image with pygame.image.load (“image name”). The image is saved in the same place where the executable file is saved. screen.fill (Red, Green, Blue) is the background color. I haven't prepared a background image this time, so I repaint the background every time to erase the previous images. Without this, the previous processes will remain as they are. screen.blit (image, (x, y)): When arranging the image, you have to be careful that the upper left of the display screen is x: 0, y: 0. The x and y values increase toward the bottom right of the screen.

Various behaviors

Regarding the behavior in the game, I will pick up some and explain it.

from random import randint

self.balloon_x = randint(500, 700)

randint (minimum, maximum). This makes the x-coordinate where the balloon appears random. Since it is int, it is randomly selected from the integers in the set value.

import sys

sysfont = pygame.font.SysFont(None, 36)

        while True:
            score_image = sysfont.render("score : {}".format(self.score), True, (0, 0, 255))
            screen.blit(score_image, (10, 20))

Character output. You can change pygame.font.Sysfont (name, size, bold, italic) and 4 parameters. format () is included in {} of sysfont.render.

    def set_balloon(self):
        now_time = time.time()
        if self.is_collision:
            if now_time - self.balloon_break > 1:
                self.is_collision = False
        if self.is_collision is False:
            if self.is_balloon:
                self.balloon_y = self.balloon_y - 12
                self.balloon_alive = time.time()
                if self.balloon_alive - self.balloon_create > 4:
                    self.is_balloon = False
                else:
                    self.collision_check()
            else:
                self.balloon_image = pygame.image.load("balloon-red.png ")
                self.balloon_x = randint(500, 700)
                self.balloon_y = 600
                self.is_balloon = True
                self.balloon_create = time.time()

Also, the set_balloon function that I'm writing is using the time module here. When a balloon appears, the current time is acquired as balloon_create, and then the time called balloon_alive is continuously acquired so that the balloon will reappear when the difference is 4 seconds or more. By the way, I also measure now_time so that when the balloon breaks, it will appear 1 second later.

If you check to process after n seconds, sleep will appear, but please note that using that will stop the entire process.

import math

    def bullet(self):
        gravity = 9.8
        if self.bullet_shot:
            bullet_speed_x = self.bullet_speed * math.cos(math.radians(self.cannon_radian))
            bullet_speed_y = (self.bullet_speed * math.sin(math.radians(self.cannon_radian)))
            self.bullet_x = self.bullet_x + bullet_speed_x
            self.bullet_y = self.bullet_y - bullet_speed_y + gravity * self.time
            self.time += 0.2

            if self.bullet_x > 800 or self.bullet_y > 600:
                self.bullet_shot = False
                self.set_bullet()

The behavior of the launched ball will be like that with a sine cosine at the launch angle. I was wondering whether to use a proper physical formula, but it became a movement like that, so Yoshi!

The next ball will not be fired until the ball goes off the screen.

    def collision_check(self):
        distance_y = ((self.balloon_y + 15) - (self.bullet_y + 16))**2
        distance_x = ((self.balloon_x + 20) - (self.bullet_x + 16))**2
        distance = (distance_x + distance_y)**(1/2)
        if distance < 31:
            self.pang_image = pygame.image.load("pang.png ")
            self.pang_rect = self.pang_image.get_rect()
            self.pang_rect.center = (self.balloon_x + 20, self.balloon_y + 15)
            self.is_collision = True
            self.is_balloon = False
            self.total_score(100)
            self.balloon_break = time.time()

Collision detection. This time, the absolute value is calculated from the approximate center of the sphere and balloon. It's been a long time since I googled the three-square theorem. It's easy if the hit box is a circle! (In the case of a square, calculate the absolute value of the difference between the x-axis and the y-axis, and use and.) If you collide, you will get 100 points.

At the end

The best way to learn various behaviors is to touch them. If you combine the elements of this time, I feel like you can almost do a simple game. Also, I want to be able to draw illustrations ...

The whole code

import math
import sys
import pygame
from pygame.locals import *
from random import randint
import time

pygame.init()
screen = pygame.display.set_mode((800, 600))
pygame.display.set_caption("Game")
sysfont = pygame.font.SysFont(None, 36)
pygame.key.set_repeat(5, 5)
FPSCLOCK = pygame.time.Clock()
FPS = 15


class CanonGame():
    def __init__(self):
        bullet_image = pygame.image.load("bullet.png ")
        self.set_cannon()
        self.set_bullet()
        self.bullet_shot = False
        self.is_balloon = False
        self.is_collision = False
        self.score = 0

        while True:
            for event in pygame.event.get():
                if event.type == QUIT:
                    pygame.quit()
                    sys.exit()
                elif event.type == KEYDOWN:
                    if event.key == K_SPACE:
                        self.bullet_shot = True
                    elif event.key == K_UP and self.cannon_radian < 89:
                        self.cannon_radian += 1
                    elif event.key == K_DOWN and self.cannon_radian > 0:
                        self.cannon_radian -= 1

            self.set_balloon()
            self.bullet()

            screen.fill((255, 255, 255))
            screen.blit(bullet_image, (self.bullet_x, self.bullet_y))
            if not self.is_collision:
                screen.blit(self.balloon_image, (self.balloon_x, self.balloon_y))
            elif self.is_collision:
                screen.blit(self.pang_image, self.pang_rect)
            rotate_cannon = pygame.transform.rotate(self.cannon_image, self.cannon_radian - 45)
            cannon_rect = rotate_cannon.get_rect()
            cannon_rect.center = (84, 536)
            screen.blit(rotate_cannon, cannon_rect)
            score_image = sysfont.render("score : {}".format(self.score), True, (0, 0, 255))
            screen.blit(score_image, (10, 20))

            pygame.display.update()
            FPSCLOCK.tick(FPS)

    def set_bullet(self):
        self.bullet_x = 68
        self.bullet_y = 520
        self.bullet_speed = 50
        self.time = 0

    def set_cannon(self):
        self.cannon_image = pygame.image.load("cannon.png ")
        self.cannon_radian = 45

    def set_balloon(self):
        now_time = time.time()
        if self.is_collision:
            if now_time - self.balloon_break > 1:
                self.is_collision = False
        if self.is_collision is False:
            if self.is_balloon:
                self.balloon_y = self.balloon_y - 12
                self.balloon_alive = time.time()
                if self.balloon_alive - self.balloon_create > 4:
                    self.is_balloon = False
                else:
                    self.collision_check()
            else:
                self.balloon_image = pygame.image.load("balloon-red.png ")
                self.balloon_x = randint(500, 700)
                self.balloon_y = 600
                self.is_balloon = True
                self.balloon_create = time.time()

    def bullet(self):
        gravity = 9.8
        if self.bullet_shot:
            bullet_speed_x = self.bullet_speed * math.cos(math.radians(self.cannon_radian))
            bullet_speed_y = (self.bullet_speed * math.sin(math.radians(self.cannon_radian)))
            self.bullet_x = self.bullet_x + bullet_speed_x
            self.bullet_y = self.bullet_y - bullet_speed_y + gravity * self.time
            self.time += 0.2

            if self.bullet_x > 800 or self.bullet_y > 600:
                self.bullet_shot = False
                self.set_bullet()

    def collision_check(self):
        distance_y = ((self.balloon_y + 15) - (self.bullet_y + 16))**2
        distance_x = ((self.balloon_x + 20) - (self.bullet_x + 16))**2
        distance = (distance_x + distance_y)**(1/2)
        if distance < 31:
            self.pang_image = pygame.image.load("pang.png ")
            self.pang_rect = self.pang_image.get_rect()
            self.pang_rect.center = (self.balloon_x + 20, self.balloon_y + 15)
            self.is_collision = True
            self.is_balloon = False
            self.total_score(100)
            self.balloon_break = time.time()

    def total_score(self, score):
        self.score = self.score + score


def main():
    CanonGame()


if __name__ == '__main__':
    main()

Recommended Posts

Balloon splitting game with pygame
Create a game UI from scratch with pygame2!
Programming education game with SenseHAT
Simple typing game with DragonRuby
Othello game development made with Python
Life game with Python! (Conway's Game of Life)
Solving game theory with combinatorial optimization
Sugoroku game and addition game with python