from __future__ import annotations from typing import TYPE_CHECKING if TYPE_CHECKING: from .objects.Spectator import Spectator from .objects.Player import Player from .objects.Game import Game from .objects.Ball import Ball from .objects.Point import Point from .objects.Vector import Point from .objects.Segment import Segment from .objects.Vector import Vector from . import config import math import asyncio from asgiref.sync import SyncToAsync from time import sleep def get_sign(num: float): return 1 if num >= 0 else -1 def get_impact_point(segments: list[Segment], ball: Ball): angle_radian: float = ball.angle * math.pi / 180 direction_vector: Vector = Vector(math.cos(angle_radian), math.sin(angle_radian)) x: float = ball.position.x if (direction_vector.x > 0): x = x + ball.size / 2 elif (direction_vector.x < 0): x = x - ball.size / 2 y: float = ball.position.y if (direction_vector.y > 0): y = y + ball.size / 2 elif (direction_vector.y < 0): y = y - ball.size / 2 position: Point = Point(x, y) for segment in segments: segment_vector: Vector = Vector(segment.start.x - segment.stop.x, segment.start.y - segment.stop.y) segment_vector_unit = segment_vector / segment_vector.norm scalar: float = segment_vector_unit.scalar(direction_vector) if (scalar < 0.01): continue print(segment_vector, segment_vector_unit, direction_vector) distance: float = scalar * segment_vector.norm / 2 impact_x: float = position.x + distance * direction_vector.x impact_y: float = position.y + distance * direction_vector.y impact: Point = Point(impact_x, impact_y) print("impact", impact) return impact async def update_ball(game: Game, impact: Point): distance: float = impact.distance(game.ball.position) - game.ball.size / 2 time_before_impact: float = distance / game.ball.speed await asyncio.sleep(time_before_impact) game.ball.angle = game.ball.angle + 180 game.ball.position = impact await SyncToAsync(game.broadcast)("update_ball", game.ball.to_dict()) async def render(game: Game): while True: segments: list[Segment] = [player.rail for player in game.players] + [wall.rail for wall in game.walls] impact = get_impact_point(segments, game.ball) await update_ball(game, impact) def routine(game: Game): asyncio.run(render(game)) while True: for player in game._updated_players: game.broadcast("update_paddle", player.to_dict(), [player]) game._updated_players.clear() sleep(1 / config.SERVER_TPS)