Lev
3 years ago
1 changed files with 244 additions and 0 deletions
@ -0,0 +1,244 @@
|
||||
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() |
Loading…
Reference in new issue