42_ft_transcendence/games/routine.py

155 lines
4.1 KiB
Python

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) -> int:
if (num == 0):
return 1
if (num > 0):
return 1
if (num < 0):
return -1
def simplify_angle(angle: float):
return (angle + 2 * math.pi) % (2 * math.pi)
def exclude_invalid_segments(segments: list[Segment], ball: Ball):
cos: float = math.cos(ball.angle)
sin: float = math.sin(ball.angle)
valid_segments = []
print(ball.angle)
angle: float = ball.angle
for segment in segments:
diff_x: float = segment.start.x - ball.position.x
diff_y: float = segment.start.y - ball.position.y
start_angle: float = math.atan2(diff_y, diff_x)
diff_x: float = segment.stop.x - ball.position.x
diff_y: float = segment.stop.y - ball.position.y
stop_angle: float = math.atan2(diff_y, diff_x)
min_angle: float = min(start_angle, stop_angle)
max_angle: float = max(start_angle, stop_angle)
print(min_angle, max_angle)
if not (min_angle <= angle <= max_angle):
continue
start_cos: float = math.cos(start_angle)
start_sin: float = math.sin(start_angle)
stop_cos: float = math.cos(stop_angle)
stop_sin: float = math.sin(stop_angle)
if (get_sign(start_cos) != get_sign(cos) and get_sign(cos) != get_sign(stop_cos)):
continue
if (get_sign(start_sin) != get_sign(sin) and get_sign(sin) != get_sign(stop_sin)):
continue
valid_segments.append(segment)
return valid_segments
def get_derive(segment: Segment):
if (segment.start.x == segment.stop.x):
return None
return (segment.stop.y - segment.start.y) / (segment.stop.x - segment.stop.y)
def get_intercept(derive: float, point: Point):
if (derive is None):
return None
return point.y - (point.x * derive)
def get_interception(segment1: Segment, segment2: Segment):
#TODO https://chat.openai.com/c/3fd8b80f-86cc-4fb9-8ff1-44c108f5ccae
pass
def get_impact_point(segments: list[Segment], ball: Ball):
valid_segments: list[Segment] = exclude_invalid_segments(segments, ball)
point: Point = Point(ball.position.x + math.cos(ball.angle), ball.position.y + math.sin(ball.angle))
closest: Point = None
distance: float = None
for segment in valid_segments:
impact: Point = get_interception(Segment(ball.position, point), segment)
distance2: float = impact.distance(ball.position)
if (closest is None or distance2 < distance):
closest = impact
distance = distance2
return closest
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)