Лабораторные работы по Python, ЛФИ, 1 семестр
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

244 lines
7.5 KiB

import math
from random import choice, randrange as rnd
import pygame
import typing
FPS = 30
RED = 0xFF0000
BLUE = 0x0000FF
YELLOW = 0xFFC91F
GREEN = 0x00FF00
MAGENTA = 0xFF03B8
CYAN = 0x00FFCC
BLACK = (0, 0, 0)
WHITE = 0xFFFFFF
GREY = 0x7D7D7D
GAME_COLORS = [RED, BLUE, YELLOW, GREEN, MAGENTA, CYAN]
WIDTH = 800
HEIGHT = 600
global balls, bullet
balls, bullet = [], 0
class Ball:
def __init__(self, screen: pygame.Surface, x: int = 40, y: int = 450):
""" Конструктор класса ball
Args:
x - начальное положение мяча по горизонтали
y - начальное положение мяча по вертикали
"""
self.screen = screen
self.x = x
self.y = y
self.r = 10
self.vx = 0
self.vy = 0
self.color = choice(GAME_COLORS)
self.live = 30
def move(self):
"""Переместить мяч по прошествии единицы времени.
Метод описывает перемещение мяча за один кадр перерисовки. То есть, обновляет значения
self.x и self.y с учетом скоростей self.vx и self.vy, силы гравитации, действующей на мяч,
и стен по краям окна (размер окна 800х600).
"""
if self.y <= 500:
self.vy -= 1.2
self.y -= self.vy
self.x += self.vx
self.vx *= 0.99
else:
if self.vx ** 2 + self.vy ** 2 > 10:
self.vy =- self.vy / 2
self.vx = self.vx / 2
self.y = 499
if self.live < 0:
balls.pop(balls.index(self))
else:
self.live -= 1
if self.x > 780:
self.vx =- self.vx / 2
self.x = 779
def draw(self):
pygame.draw.circle(
self.screen,
self.color,
(self.x, self.y),
self.r
)
def hittest(self, obj):
"""Функция проверяет сталкивалкивается ли данный обьект с целью, описываемой в обьекте obj.
Args:
obj: Обьект, с которым проверяется столкновение.
Returns:
Возвращает True в случае столкновения мяча и цели. В противном случае возвращает False.
"""
if abs(obj.x - self.x) <= (self.r + obj.r) and abs(obj.y - self.y) <= (self.r + obj.r):
return True
else:
return False
class Gun:
def __init__(self, screen):
global bullet
bullet = 0
self.screen = screen
self.f2_power = 10
self.f2_on = 0
self.an = 1
self.color = GREY
self.x0 = 40
self.y0 = 450
def fire2_start(self, event):
self.f2_on = 1
def fire2_end(self, event):
"""Выстрел мячом.
Происходит при отпускании кнопки мыши.
Начальные значения компонент скорости мяча vx и vy зависят от положения мыши.
"""
global bullet
bullet += 1
new_ball = Ball(self.screen, x=self.x0 + self.deltas()[0], y=self.y0 + self.deltas()[1])
new_ball.r += 5
self.an = math.atan2((event.pos[1] - new_ball.y), (event.pos[0] - new_ball.x))
new_ball.vx = self.f2_power * math.cos(self.an)
new_ball.vy = - self.f2_power * math.sin(self.an)
balls.append(new_ball)
self.f2_on = 0
self.f2_power = 10
def targetting(self, event):
"""Прицеливание. Зависит от положения мыши."""
if event and event.pos[0] != 20:
self.an = math.atan((event.pos[1] - 450) / (event.pos[0] - 20))
if self.f2_on:
self.color = RED
else:
self.color = GREY
def deltas(self) -> typing.Union[float, float]:
length = 50 + self.f2_power
return length * math.cos(self.an), length * math.sin(self.an)
def draw(self):
r, length = 10, 50 + self.f2_power
dx, dy = r * math.sin(self.an), -r * math.cos(self.an)
delta_x, delta_y = self.deltas()
points = [
(self.x0 + dx, self.y0 + dy), (self.x0 - dx, self.y0 - dy),
(self.x0 + delta_x - dx, self.y0 + delta_y - dy), (self.x0 + delta_x + dx, self.y0 + delta_y + dy)]
pygame.draw.polygon(self.screen, self.color, points)
def power_up(self):
if self.f2_on:
if self.f2_power < 100:
self.f2_power += 1
self.color = RED
else:
self.color = GREY
class Target:
def __init__(self, screen):
"""Инициализация новой цели. """
x = self.x = rnd(600, 780)
y = self.y = rnd(300, 550)
r = self.r = rnd(2, 50)
self.vx = rnd(2, 6)
self.vy = rnd(2, 6)
color = self.color = RED
self.screen = screen
self.points = 0
self.live = 1
def hit(self, points=1):
"""Попадание шарика в цель."""
self.points += points
def draw(self):
pygame.draw.circle(
self.screen,
self.color,
(self.x, self.y),
self.r
)
def move(self):
"""Переместить мяч по прошествии единицы времени.
Метод описывает перемещение мяча за один кадр перерисовки. То есть, обновляет значения
self.x и self.y с учетом скоростей self.vx и self.vy, силы гравитации, действующей на мяч,
и стен по краям окна (размер окна 800х600).
"""
if self.y < 0:
self.vy = -abs(self.vy)
if self.y <= 500:
self.y -= self.vy
self.x += self.vx
self.vx *= 0.99
else:
if self.vx ** 2 + self.vy ** 2 > 10:
self.vy =- self.vy / 2
self.vx = self.vx / 2
self.y = 499
if self.x > 780:
self.vx =- self.vx / 2
self.x = 779
pygame.init()
screen = pygame.display.set_mode((WIDTH, HEIGHT))
bullet = 0
balls = []
clock = pygame.time.Clock()
gun = Gun(screen)
targets = [Target(screen), Target(screen)]
finished = False
while not finished:
screen.fill(WHITE)
gun.draw()
for target in targets:
target.draw()
target.move()
for b in balls:
b.draw()
pygame.display.update()
clock.tick(FPS)
for event in pygame.event.get():
if event.type == pygame.QUIT:
finished = True
elif event.type == pygame.MOUSEBUTTONDOWN:
gun.fire2_start(event)
elif event.type == pygame.MOUSEBUTTONUP:
gun.fire2_end(event)
elif event.type == pygame.MOUSEMOTION:
gun.targetting(event)
for b in balls:
b.move()
for target in targets:
if b.hittest(target) and target.live:
target.live = 0
target.hit()
targets.remove(target)
targets.append(Target(screen))
gun.power_up()
pygame.quit()