42_ft_transcendence/games/routine.py

107 lines
2.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
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)