pygame6 pinball game

1. Events:

1. Mouse events:

pygame.mouse.get_pos(): Get the coordinates of the current point of the mouse

pygame.mouse.get_pressed()[0]: Get whether the left mouse button is clicked

2. Review the collision sprite

1. First, the most basic version of 3 balls moving on the window:

import pygame, sys
class MyBall(pygame.sprite.Sprite):
    def __init__(self, point, speed):
        self.image = pygame.image.load("beach_ball.png")
        self.rect = self.image.get_rect()
        self.rect.left = point[0]
        self.rect.top = point[1]
        self.speed = speed

    def move(self):
        self.rect = self.rect.move(self.speed)
        screen.blit(self.image, self.rect)

pygame.init()
size = width, height = 640, 480
screen = pygame.display.set_mode(size)
screen.fill([255, 255, 255])
balls = []
for i in range(3):
    ball = MyBall([180+i*180, 200], [8, 8])
    balls.append(ball)

while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            sys.exit()
    screen.fill([255, 255, 255])
    for i in range(len(balls)):
        balls[i].move()
    pygame.display.flip()
    pygame.time.delay(20)

These three balls have a disadvantage. Once they are moved out of the window, they cannot be moved back. Therefore, we need to judge the edge of the window when moving

2. Increase the judgment of the upper, lower, left, and right borders

In this way, when the ball tries to go beyond the boundary, the speed in the corresponding direction is reversed, so that it returns to the window:

    def move(self):
        self.rect = self.rect.move(self.speed)
        if self.rect.right > width:  # 新增右边框判断
            self.speed[0] = -abs(self.speed[0])
        if self.rect.left < 0:  # 新增左边框判断
            self.speed[0] = abs(self.speed[0])
        if self.rect.bottom > height:  # 新增下边框判断
            self.speed[1] = -abs(self.speed[1])
        if self.rect.top < 0:  # 新增上边框判断
            self.speed[1] = abs(self.speed[1])
        screen.blit(self.image, self.rect)

At this point, we found that there was no collision event when the balls collided together, that is, the balls that collided did not retreat from each other. At this time, collision detection is used:

Through pygame.sprite.spritecollide, we can detect whether the current ball collides with other balls. If there is a collision, the current speed of the ball is reversed.

3. Collision handling

1) Handling after collision

    def crash(self, balls): 
        balls.remove(self)  # 将自身从碰撞组中删除
        if pygame.sprite.spritecollide(self, balls, False): # 检测碰撞发生,将自身的速度取反
            self.speed[0] = -self.speed[0]
            self.speed[1] = -self.speed[1]

2) Collision processing for the pairwise combination of small balls:

    for i in range(len(balls)):
        for j in range(len(balls)):
            if i == j:
                continue
            balls[i].crash([balls[i], balls[j]])

In this way, the balls will bounce in opposite directions when they hit each other.

3. Draw the club and hit the ball

We can imagine that the action of hitting the ball can only be performed after the ball stops. Therefore, we can do a deceleration process for the ball

Then when the speed of the ball in the x and y directions is lower than 1, the ball is considered to be at rest

1. Deceleration logic

    def dec_speed(self):
        """减速"""
        self.speed[0] *= 0.995
        self.speed[1] *= 0.995

2. Draw the club

When the ball is static, we need to draw a club. The drawing method is to draw a line segment from the center point of the ball to the current mouse position:

    def wait_hit(self):
        if abs(self.speed[0]) > 1 or abs(self.speed[1]) > 1:  # 在运动状态,退出,注意需要用abs,原因是速度有正和负
            pass
        else:
            pos = pygame.mouse.get_pos()    # 获取鼠标坐标
            pygame.draw.line(screen, [255, 0, 0], self.rect.center, pos, 5) # 画出小球到鼠标的红线
            if pygame.mouse.get_pressed()[0]:   # 按下鼠标左键
                self.speed[0] = 0.1 * (self.rect.center[0] - pos[0])    # 给小球初始速度
                self.speed[1] = 0.1 * (self.rect.center[1] - pos[1])

Then add the call:

    for i in range(len(balls)):
        if i == 0:
            balls[i].wait_hit() # 只有0号小球静止时画出球杆
        balls[i].move()
        balls[i].dec_speed()    # 减速,使得小球最终静止下来

At this point, the three small balls will all move at the beginning, and they will collide and bounce when they touch each other during the movement. As time goes by, the small balls will become slower and slower, and finally stop, and then draw a red line at the No. 0 ball. Click the left button of the mouse, the ball will move in the opposite direction of the red line, but there is a problem, when the ball touches the stationary ball, the stationary ball will not move

3. After the collision, when you find that you have no speed, use the speed of the opponent

    def crash(self, groups):
        groups.remove(self)  # 将自身从碰撞组中删除
        if pygame.sprite.spritecollide(self, groups, False):  # 检测碰撞发生,将自身的速度取反
            if abs(self.speed[0]) > 1:  # 运动状态用自身的反速度
                self.speed[0] = -self.speed[0]
            else:
                self.speed[0] = -groups[0].speed[0] # 静止状态,用对方的反速度
                
            if abs(self.speed[1]) > 1:
                self.speed[1] = -self.speed[1]
            else:
                self.speed[1] = -groups[0].speed[1]

So far a simple pinball game is over

Attach the complete source code:

import pygame, sys


class MyBall(pygame.sprite.Sprite):
    def __init__(self, point, speed):
        self.image = pygame.image.load("beach_ball.png")
        self.rect = self.image.get_rect()
        self.rect.left = point[0]
        self.rect.top = point[1]
        self.speed = speed

    def move(self):
        self.rect = self.rect.move(self.speed)
        if self.rect.right > width:  # 新增右边框判断
            self.speed[0] = -abs(self.speed[0])
        if self.rect.left < 0:  # 新增左边框判断
            self.speed[0] = abs(self.speed[0])
        if self.rect.bottom > height:  # 新增下边框判断
            self.speed[1] = -abs(self.speed[1])
        if self.rect.top < 0:  # 新增上边框判断
            self.speed[1] = abs(self.speed[1])
        screen.blit(self.image, self.rect)

    def crash(self, groups):
        groups.remove(self)  # 将自身从碰撞组中删除
        if pygame.sprite.spritecollide(self, groups, False):  # 检测碰撞发生,将自身的速度取反
            if abs(self.speed[0]) > 1:  # 运动状态用自身的反速度
                self.speed[0] = -self.speed[0]
            else:
                self.speed[0] = -groups[0].speed[0] # 静止状态,用对方的反速度

            if abs(self.speed[1]) > 1:
                self.speed[1] = -self.speed[1]
            else:
                self.speed[1] = -groups[0].speed[1]

    def dec_speed(self):
        """减速"""
        self.speed[0] *= 0.995
        self.speed[1] *= 0.995

    def wait_hit(self):
        if abs(self.speed[0]) > 1 or abs(self.speed[1]) > 1:  # 在运动状态,退出,注意需要用abs,原因是速度有正和负
            pass
        else:
            pos = pygame.mouse.get_pos()    # 获取鼠标坐标
            pygame.draw.line(screen, [255, 0, 0], self.rect.center, pos, 5) # 画出小球到鼠标的红线
            if pygame.mouse.get_pressed()[0]:   # 按下鼠标左键
                self.speed[0] = 0.1 * (self.rect.center[0] - pos[0])    # 给小球初始速度
                self.speed[1] = 0.1 * (self.rect.center[1] - pos[1])


pygame.init()
size = width, height = 640, 480
screen = pygame.display.set_mode(size)
screen.fill([255, 255, 255])
balls = []
for i in range(3):
    ball = MyBall([180 + i * 180, 200], [8, 8])
    balls.append(ball)

while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            sys.exit()
    screen.fill([255, 255, 255])
    for i in range(len(balls)):
        if i == 0:
            balls[i].wait_hit() # 只有0号小球静止时画出球杆
        balls[i].move()
        balls[i].dec_speed()    # 减速,使得小球最终静止下来

    for i in range(len(balls)):
        for j in range(len(balls)):
            if i == j:
                continue
            balls[i].crash([balls[i], balls[j]])

    pygame.display.flip()
    pygame.time.delay(10)

Guess you like

Origin blog.csdn.net/luhouxiang/article/details/128686484
Recommended