from pygame.locals import * import pygame from pygame.math import Vector2 import math from math import sin, cos, pi, sqrt import time def screen2local(x, y): nx = x - WIDTH / 2 ny = HEIGHT / 2 - y return (nx, ny) def local2screen(x, y): nx = x + WIDTH / 2 ny = HEIGHT / 2 - y return (nx, ny) class Ellipse: def __init__(self, a, b): self.a = a self.b = b self.c = sqrt(self.a * self.a - self.b * self.b) # self.f1 = local2screen(self.c, 0) # self.f2 = local2screen(-self.c, 0) self.f1 = (self.c, 0) self.f2 = (-self.c, 0) def draw(self, deltatime, screen, cx, cy): cnt = 0 for i in range(0, int(2 * pi * 100) + 1): cnt += 1 t = i / 100 t1 = t + 1 / 100 # Координаты в локальном пространстве x = self.a * cos(t) y = self.b * sin(t) x1 = self.a * cos(t1) y1 = self.b * sin(t1) start = local2screen(x, y) end = local2screen(x1, y1) pygame.draw.line(screen, WHITE, start, end, 2) pygame.draw.circle(screen, WHITE, local2screen(*self.f1), 3) pygame.draw.circle(screen, WHITE, local2screen(*self.f2), 3) class NiceEllipse: def __init__(self, a, b): self.a = a self.b = b self.time = 0 self.timeout = 700 self.i = 0 self.lines = [] self.c = sqrt(self.a * self.a - self.b * self.b) self.f1 = local2screen(self.c, 0) self.f2 = local2screen(-self.c, 0) self.lastend = None def draw(self, deltatime, screen, cx, cy): print(deltatime) for start, end in self.lines: pygame.draw.line(screen, WHITE, start, end, 2) pygame.draw.circle(screen, WHITE, self.f1, 3) pygame.draw.circle(screen, WHITE, self.f2, 3) if self.lastend is not None: pygame.draw.line(screen, RED, self.f1, self.lastend, 2) pygame.draw.line(screen, GREEN, self.f2, self.lastend, 2) if self.i >= int(2 * pi * 100) + 1: self.lastend = None return if self.time > 0: self.time -= deltatime return self.time = self.timeout t = self.i / 100 t1 = t + 1 / 100 self.i += 1 # Координаты в локальном пространстве x = self.a * cos(t) y = self.b * sin(t) x1 = self.a * cos(t1) y1 = self.b * sin(t1) start = local2screen(x, y) end = local2screen(x1, y1) self.lastend = end self.lines.append((start, end)) pygame.draw.line(screen, WHITE, start, end, 2) class ScreenRay: def __init__(self, a: Vector2, b: Vector2, speed: float): # self.a = a # self.b = b self.pos = a self.dir = Vector2(b.x - a.x, b.y - a.y) self.dir.normalize_ip() self.speed = speed def update(self, deltatime): n_pos = self.pos + self.dir * (deltatime * self.speed) scr = Vector2(*local2screen(*tuple(self.pos))) scr_npos = Vector2(*local2screen(*tuple(n_pos))) if scr_npos.x < 0: self.dir = Vector2(-self.dir.x, self.dir.y) n_pos = Vector2(*screen2local(0, scr.y)) elif scr_npos.x > WIDTH: self.dir = Vector2(-self.dir.x, self.dir.y) n_pos = Vector2(*screen2local(WIDTH, scr.y)) elif scr_npos.y < 0: self.dir = Vector2(self.dir.x, -self.dir.y) n_pos = Vector2(*screen2local(scr.x, 0)) elif scr_npos.y > HEIGHT: self.dir = Vector2(self.dir.x, -self.dir.y) n_pos = Vector2(*screen2local(scr.x, HEIGHT)) self.pos = n_pos class EllipseRay: def __init__(self, s: Vector2, e: Vector2, speed: float, el): self.a = el.a self.b = el.b self.pos = e self.dir = Vector2(e.x - s.x, e.y - s.y) self.dir.normalize_ip() self.speed = speed def eps(self, x, y): a = self.a b = self.b tmp = (x * x) / (a * a) + (y * y) / (b * b) e = 0.05 return tmp < 1 + e and tmp > 1 - e def update(self, deltatime): npos = self.pos + self.dir * (deltatime * self.speed) scr = Vector2(*local2screen(*tuple(self.pos))) scr_npos = Vector2(*local2screen(*tuple(npos))) p0 = self.pos ######################## # Отражение от эллипса # ######################## if p0.y == 0: if p0.x < 0: self.dir.reflect_ip(Vector2(-1, 0)) else: self.dir.reflect_ip(Vector2(1, 0)) else: t = 1 m = 1 n = -(p0.x * self.b * self.b) / (p0.y * self.a * self.a) p1 = Vector2(p0.x + m * t, p0.y + n * t) kas = Vector2(p1.x - p0.x, p1.y - p0.y) kas.normalize_ip() # angle = kas.angle_to(self.dir) kas_p = Vector2(1, -kas.x / kas.y) kas_p.normalize_ip() if self.eps(npos.x, npos.y): self.dir.reflect_ip(kas_p) ######################## self.pos = npos def draw(self, screen): loc = tuple(self.pos) scr = local2screen(*loc) pygame.draw.circle(screen, RED, scr, 3) class Ray1Ellipse: def __init__(self, a, b): self.a = a self.b = b def draw(self, deltatime, screen, cx, cy): cnt = 0 for i in range(0, int(2 * pi * 100) + 1): cnt += 1 t = i / 100 t1 = t + 1 / 100 # Координаты в локальном пространстве x = self.a * cos(t) y = self.b * sin(t) x1 = self.a * cos(t1) y1 = self.b * sin(t1) start = local2screen(x, y) end = local2screen(x1, y1) pygame.draw.line(screen, WHITE, start, end, 2) c = sqrt(self.a * self.a - self.b * self.b) f1 = local2screen(c, 0) f2 = local2screen(-c, 0) pygame.draw.circle(screen, WHITE, f1, 3) pygame.draw.circle(screen, WHITE, f2, 3) pygame.init() WIDTH, HEIGHT = SIZE = 800, 600 screen = pygame.display.set_mode(SIZE) clock = pygame.time.Clock() running = True BLACK = Color("black") WHITE = Color("white") GREEN = Color("green") RED = Color("red") el = Ellipse(300, 200) rays = [] nn = 10 for i in range(1, nn + 1): x0, y0 = el.f2 xr = cos(2 * pi * i / nn) + x0 yr = sin(2 * pi * i / nn) + y0 r = EllipseRay(Vector2(x0, y0), Vector2(xr, yr), 70, el) rays.append(r) # deltatime = pygame.time.get_ticks() while running: screen.fill(BLACK) deltatime = clock.get_time() / 1000 for r in rays: r.update(deltatime) r.draw(screen) el.draw(deltatime, screen, 0, 0) # ... pygame.display.flip() for event in pygame.event.get(): if event.type == QUIT: pygame.quit() exit() elif event.type == KEYDOWN: if event.key == K_ESCAPE: pygame.quit() exit() clock.tick(60) # deltatime = pygame.time.get_ticks() - deltatime # print(clock.get_fps())