/
Vibek
/
First_Game
Обзор
Документация
Войти
/
Vibek
/
First_Game
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
models/thrown_sword.py
114 строк
4 KB
Vibek
Добавлен сюжет
21 июн 2026, 20:20
21 июн 2026, 20:20
422c0e0
Код
Авторство
О чём код?
import math from pygame.math import Vector2 from models.entity import Entity from core.events import EventBus from models.hitbox import HitboxDef from utils.collision import check_polygon_overlap, get_obb_corners from enum import Enum class ThrowState(Enum): OUTWARD = "OUTWARD" RETURNING = "RETURNING" class ThrownSword(Entity): """ Брошенный меч: две фазы с разной геометрией коллизий. OUTWARD — круглый хитбокс + вращение; RETURNING — OBB по размеру, рукоять к игроку. """ def __init__( self, x: float, y: float, direction: Vector2, owner_id: int, bus: EventBus, hitbox: HitboxDef, outward_hit_radius: float, spin_speed: float, return_angle_offset_deg: float = 180.0, return_art_angle_offset: float = 0.0, outward_art_angle_offset: float = 0.0, ) -> None: super().__init__( x, y, speed=0, size=hitbox.size, bus=bus, hp=1, hitbox=hitbox, art_angle_offset=outward_art_angle_offset, ) self.owner_id = owner_id self.state = ThrowState.OUTWARD self.direction = direction.normalize() self.start_pos = self.collision_center.copy() self.outward_hit_radius = outward_hit_radius self.spin_speed = spin_speed self.return_angle_offset_deg = return_angle_offset_deg self.return_art_angle_offset = return_art_angle_offset self.max_range = 400.0 self.speed_outward = 600.0 self.speed_return = 800.0 self.catch_radius = 40.0 self.spin_angle = 0.0 self.hit_enemies: set[int] = set() @property def collision_center(self) -> Vector2: return self.hitbox_center @property def facing_angle(self) -> float: if self.state == ThrowState.OUTWARD: return self.spin_angle + self.art_angle_offset # return_art_angle_offset и art_angle_offset — только спрайт; self.angle — только OBB return self.angle + self.return_art_angle_offset + self.art_angle_offset @property def visual_angle(self) -> float: return self.facing_angle def get_obb_corners(self) -> list[Vector2]: if self.state != ThrowState.RETURNING: return [] return get_obb_corners(self.hitbox_center, self.hitbox.size, self.angle) def overlaps_enemy(self, enemy: Entity) -> bool: if self.state == ThrowState.OUTWARD: return self.collision_center.distance_to(enemy.hitbox_center) <= self.outward_hit_radius enemy_corners = enemy.get_obb_corners() if not enemy_corners: return self.collision_center.distance_to(enemy.hitbox_center) <= self.outward_hit_radius return check_polygon_overlap(self.get_obb_corners(), enemy_corners) def update(self, dt: float, player_pos: Vector2) -> None: if not self.is_alive: return if self.state == ThrowState.OUTWARD: self.pos += self.direction * self.speed_outward * dt self.spin_angle = (self.spin_angle + self.spin_speed * dt) % 360.0 if self.collision_center.distance_to(self.start_pos) >= self.max_range: self.state = ThrowState.RETURNING elif self.state == ThrowState.RETURNING: to_player = player_pos - self.collision_center if to_player.length() <= self.catch_radius: self.is_alive = False self.bus.emit("ability:sword_caught", {"owner_id": self.owner_id}) return return_dir = to_player.normalize() self.pos += return_dir * self.speed_return * dt flight_angle = math.degrees(math.atan2(return_dir.y, return_dir.x)) self.angle = flight_angle + self.return_angle_offset_deg self._sync_rect() def take_damage(self, amount: int) -> None: pass