42_ft_transcendence/games/routine.py

193 lines
4.8 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
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.stop.y)
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)):
continue
print("OK: X")
diff_y: float = ball.position.y - impact.y
print("y:", diff_y)
if (get_sign(diff_y) == get_sign(sin)):
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)