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 VERTICALLY = 1 NORMAL = 2 def get_sign(num: float) -> int: if (num == 0): return 0 if (num > 0): return 1 if (num < 0): return -1 def simplify_angle(angle: float): return (angle + 2 * math.pi) % (2 * math.pi) def get_derive(segment: Segment) -> float: if (segment.start.x == segment.stop.x): return None return (segment.stop.y - segment.start.y) / (segment.stop.x - segment.start.x) def get_intercept(derive: float, point: Point) -> float: if (derive is None): return None return point.y - (point.x * derive) def get_constant(segment: Segment) -> float: return segment.start.x def identify(segment: Segment) -> str: if (segment.start.x == segment.stop.x): return VERTICALLY return NORMAL def get_interception(segment1: Segment, segment2: Segment): if (identify(segment1) == VERTICALLY and identify(segment2) == VERTICALLY): return None if (identify(segment1) == NORMAL and identify(segment2) == NORMAL): # representation m * x + p m1 = get_derive(segment1) m2 = get_derive(segment2) p1 = get_intercept(m1, segment1.start) p2 = get_intercept(m2, segment2.start) # m1 * x + p1 = m2 * x + p2 # m1 * x = m2 * x + p2 -p1 # m1 * x - m2 * x = p1 - p2 # x * (m1 - m2) = p1 - p2 # x = (p1 - p2) / (m1 - m2) if (m1 == m2): return None else: x: float = (p1 - p2) / (m1 - m2) y: float = m1 * x + p1 else: if (identify(segment1) == VERTICALLY): constant: float = get_constant(segment1) m: float = get_derive(segment2) p: float = get_intercept(m, segment2.start) else: constant: float = get_constant(segment2) m: float = get_derive(segment1) p: float = get_intercept(m, segment1.start) x: float = constant y: float = m * x + p impact: Point = Point(x,y) return impact def get_impact_point(segments: list[Segment], ball: Ball): cos: float = round(math.cos(ball.angle), 6) sin: float = round(math.sin(ball.angle), 6) print("cos:", cos) print("sin:", sin) point: Point = Point(ball.position.x + cos, ball.position.y + sin) ball_segment = Segment(ball.position, point) closest: Point = None for segment in segments: impact: Point = get_interception(segment, ball_segment) if (impact is None): continue diff_x: float = ball.position.x - impact.x print("x:", diff_x) if (get_sign(diff_x) == get_sign(cos) and cos != 0): continue print("OK: X") diff_y: float = ball.position.y - impact.y print("y:", diff_y) if (get_sign(diff_y) == get_sign(sin) and sin != 0): continue print("OK: Y") print("OK: PARFAIT") impact.x += (ball.size / 2) * get_sign(cos) * (-1) impact.y += (ball.size / 2) * get_sign(sin) * (-1) if (closest is None or impact.distance(ball.position) < closest.distance(ball.position)): closest = impact return closest async def update_ball(game: Game, impact: Point): distance: float = impact.distance(game.ball.position) print("distance:", distance) time_before_impact: float = distance / game.ball.speed print("time:", time_before_impact) await asyncio.sleep(time_before_impact) game.ball.angle = game.ball.angle + math.pi 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) print("bozo") 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)