1393 lines
36 KiB
Python
1393 lines
36 KiB
Python
# from __future__ import annotations
|
|
import math
|
|
import pygame
|
|
from pgzero.actor import Actor, POS_TOPLEFT, ANCHOR_CENTER, transform_anchor
|
|
from pgzero import game, loaders
|
|
import sys
|
|
import time
|
|
from typing import Sequence, Tuple, Union
|
|
from pygame import Vector2
|
|
|
|
_Coordinate = Union[Tuple[float, float], Sequence[float], Vector2]
|
|
_fullscreen = False
|
|
|
|
def set_fullscreen():
|
|
global _fullscreen
|
|
mod = sys.modules['__main__']
|
|
mod.screen.surface = pygame.display.set_mode((mod.WIDTH, mod.HEIGHT), pygame.FULLSCREEN)
|
|
_fullscreen = True
|
|
|
|
def set_windowed():
|
|
global _fullscreen
|
|
mod = sys.modules['__main__']
|
|
mod.screen.surface = pygame.display.set_mode((mod.WIDTH, mod.HEIGHT))
|
|
_fullscreen = False
|
|
|
|
def toggle_fullscreen():
|
|
if _fullscreen:
|
|
set_windowed()
|
|
else:
|
|
set_fullscreen()
|
|
|
|
def hide_mouse():
|
|
pygame.mouse.set_visible(False)
|
|
|
|
def show_mouse():
|
|
pygame.mouse.set_visible(True)
|
|
|
|
def distance_to(from_x, from_y, to_x, to_y):
|
|
dx = to_x - from_x
|
|
dy = to_y - from_y
|
|
return math.sqrt(dx**2 + dy**2)
|
|
|
|
def distance_to_squared(from_x, from_y, to_x, to_y):
|
|
dx = to_x - from_x
|
|
dy = to_y - from_y
|
|
return dx**2 + dy**2
|
|
|
|
def direction_to(from_x, from_y, to_x, to_y):
|
|
dx = to_x - from_x
|
|
dy = from_y - to_y
|
|
|
|
angle = math.degrees(math.atan2(dy, dx))
|
|
if angle > 0:
|
|
return angle
|
|
|
|
return 360 + angle
|
|
|
|
def get_move(direction, distance):
|
|
angle = math.radians(direction)
|
|
dx = distance * math.cos(angle)
|
|
dy = -distance * math.sin(angle)
|
|
return (dx, dy)
|
|
|
|
def move(x, y, direction, distance):
|
|
dx, dy = get_move(direction, distance)
|
|
return (x + dx, y + dy)
|
|
|
|
class Collide():
|
|
@staticmethod
|
|
def line_line(l1x1, l1y1, l1x2, l1y2, l2x1, l2y1, l2x2, l2y2):
|
|
l1x2_l1x1 = l1x2-l1x1
|
|
l1y2_l1y1 = l1y2-l1y1
|
|
|
|
determinant = (l2y2-l2y1)*l1x2_l1x1 - (l2x2-l2x1)*l1y2_l1y1
|
|
|
|
# Simplify: Parallel lines are never considered to be intersecting
|
|
if determinant == 0:
|
|
return False
|
|
|
|
uA = ((l2x2-l2x1)*(l1y1-l2y1) - (l2y2-l2y1)*(l1x1-l2x1)) / determinant
|
|
if uA < 0 or uA > 1:
|
|
return False
|
|
|
|
uB = (l1x2_l1x1*(l1y1-l2y1) - l1y2_l1y1*(l1x1-l2x1)) / determinant
|
|
if uB < 0 or uB > 1:
|
|
return False
|
|
|
|
return True
|
|
|
|
@staticmethod
|
|
def line_lines(l1x1, l1y1, l1x2, l1y2, l2):
|
|
l1x2_l1x1 = l1x2-l1x1
|
|
l1y2_l1y1 = l1y2-l1y1
|
|
|
|
i = 0
|
|
for l in l2:
|
|
determinant = (l[3]-l[1])*l1x2_l1x1 - (l[2]-l[0])*l1y2_l1y1
|
|
|
|
# Simplify: Parallel lines are never considered to be intersecting
|
|
if determinant == 0:
|
|
i += 1
|
|
continue
|
|
|
|
uA = ((l[2]-l[0])*(l1y1-l[1]) - (l[3]-l[1])*(l1x1-l[0])) / determinant
|
|
uB = (l1x2_l1x1*(l1y1-l[1]) - l1y2_l1y1*(l1x1-l[0])) / determinant
|
|
if 0 <= uA <= 1 and 0 <= uB <= 1:
|
|
return i
|
|
|
|
i += 1
|
|
|
|
return -1
|
|
|
|
@staticmethod
|
|
def line_line_XY(l1x1, l1y1, l1x2, l1y2, l2x1, l2y1, l2x2, l2y2):
|
|
determinant = (l2y2-l2y1)*(l1x2-l1x1) - (l2x2-l2x1)*(l1y2-l1y1)
|
|
|
|
# Simplify: Parallel lines are never considered to be intersecting
|
|
if determinant == 0:
|
|
return (None, None)
|
|
|
|
uA = ((l2x2-l2x1)*(l1y1-l2y1) - (l2y2-l2y1)*(l1x1-l2x1)) / determinant
|
|
uB = ((l1x2-l1x1)*(l1y1-l2y1) - (l1y2-l1y1)*(l1x1-l2x1)) / determinant
|
|
|
|
if 0 <= uA <= 1 and 0 <= uB <= 1:
|
|
ix = l1x1 + uA * (l1x2 - l1x1)
|
|
iy = l1y1 + uA * (l1y2 - l1y1)
|
|
return (ix, iy)
|
|
|
|
return (None, None)
|
|
|
|
@staticmethod
|
|
def line_line_dist(l1x1, l1y1, l1x2, l1y2, l2x1, l2y1, l2x2, l2y2):
|
|
ix, iy = Collide.line_line_XY(l1x1, l1y1, l1x2, l1y2, l2x1, l2y1, l2x2, l2y2)
|
|
if ix is not None:
|
|
return distance_to(l1x1, l1y1, ix, iy)
|
|
return None
|
|
|
|
@staticmethod
|
|
def line_line_dist_squared(l1x1, l1y1, l1x2, l1y2, l2x1, l2y1, l2x2, l2y2):
|
|
ix, iy = Collide.line_line_XY(l1x1, l1y1, l1x2, l1y2, l2x1, l2y1, l2x2, l2y2)
|
|
if ix is not None:
|
|
return distance_to_squared(l1x1, l1y1, ix, iy)
|
|
return None
|
|
|
|
@staticmethod
|
|
def line_circle(x1, y1, x2, y2, cx, cy, radius):
|
|
r_sq = radius ** 2
|
|
|
|
dist_sq = (x1 - cx) ** 2 + (y1 - cy) ** 2
|
|
if dist_sq <= r_sq:
|
|
return True
|
|
|
|
dist_sq = (x2 - cx) ** 2 + (y2 - cy) ** 2
|
|
if dist_sq <= r_sq:
|
|
return True
|
|
|
|
dx = x2 - x1
|
|
dy = y2 - y1
|
|
l_sq = dx ** 2 + dy ** 2
|
|
dot = (((cx - x1) * dx) + ((cy - y1) * dy)) / l_sq
|
|
|
|
ix = x1 + dot * dx
|
|
if (dx!=0) and (ix < x1) == (ix < x2):
|
|
return False
|
|
|
|
iy = y1 + dot * dy
|
|
if (dy!=0) and (iy < y1) == (iy < y2):
|
|
return False
|
|
|
|
dist_sq = (ix - cx) ** 2 + (iy - cy) ** 2
|
|
if dist_sq <= r_sq:
|
|
return True
|
|
|
|
return False
|
|
|
|
@staticmethod
|
|
def line_circle_XY(x1, y1, x2, y2, cx, cy, radius):
|
|
if Collide.circle_point(cx, cy, radius, x1, y1):
|
|
return (x1, y1)
|
|
|
|
x1 -= cx
|
|
y1 -= cy
|
|
x2 -= cx
|
|
y2 -= cy
|
|
|
|
if x2 < x1:
|
|
x_min, x_max = x2, x1
|
|
else:
|
|
x_min, x_max = x1, x2
|
|
|
|
if y2 < y1:
|
|
y_min, y_max = y2, y1
|
|
else:
|
|
y_min, y_max = y1, y2
|
|
|
|
# Coefficients of circle
|
|
c_r2 = radius ** 2
|
|
|
|
# Simplify if dx == 0: Vertical line
|
|
dx = x2 - x1
|
|
if dx == 0:
|
|
d = c_r2 - x1**2
|
|
if d < 0:
|
|
return (None, None)
|
|
elif d == 0:
|
|
i = 0
|
|
else:
|
|
i = math.sqrt(d)
|
|
|
|
iy = None
|
|
if y_min <= i <= y_max:
|
|
iy = i
|
|
|
|
if y_min <= -i <= y_max:
|
|
if iy is None or abs(i - y1) > abs(-i - y1):
|
|
iy = -i
|
|
|
|
if iy:
|
|
return (x1 + cx, iy + cy)
|
|
return (None, None)
|
|
|
|
# Gradient of line
|
|
l_m = (y2 - y1) / dx
|
|
|
|
# Simplify if l_m == 0: Horizontal line
|
|
if l_m == 0:
|
|
d = c_r2 - y1**2
|
|
if d < 0:
|
|
return (None, None)
|
|
elif d == 0:
|
|
i = 0
|
|
else:
|
|
i = math.sqrt(d)
|
|
ix = None
|
|
if x_min <= i <= x_max:
|
|
ix = i
|
|
|
|
if x_min <= -i <= x_max:
|
|
if ix is None or abs(i - x1) > abs(-i - x1):
|
|
ix = -i
|
|
|
|
if ix:
|
|
return (ix + cx, y1 + cy)
|
|
return (None, None)
|
|
|
|
# y intercept
|
|
l_c = y1 - l_m * x1
|
|
|
|
# Coefficients of quadratic
|
|
a = 1 + l_m**2
|
|
b = 2 * l_c * l_m
|
|
c = l_c**2 - c_r2
|
|
|
|
# Calculate discriminant and solve quadratic
|
|
discriminant = b**2 - 4 * a * c
|
|
if discriminant < 0:
|
|
return (None, None)
|
|
|
|
if discriminant == 0:
|
|
d_root = 0
|
|
else:
|
|
d_root = math.sqrt(discriminant)
|
|
|
|
ix = None
|
|
i1 = (-b + d_root) / (2 * a)
|
|
if x_min <= i1 <= x_max:
|
|
ix = i1
|
|
|
|
|
|
i2 = (-b - d_root) / (2 * a)
|
|
if x_min <= i2 <= x_max:
|
|
if ix is None or abs(i1 - x1) > abs(i2 - x1):
|
|
ix = i2
|
|
|
|
if ix:
|
|
return (ix + cx, l_m * ix + l_c + cy)
|
|
|
|
return (None, None)
|
|
|
|
@staticmethod
|
|
def line_circle_dist(x1, y1, x2, y2, cx, cy, radius):
|
|
ix, iy = Collide.line_circle_XY(x1, y1, x2, y2, cx, cy, radius)
|
|
if ix is not None:
|
|
return distance_to(x1, y1, ix, iy)
|
|
return None
|
|
|
|
@staticmethod
|
|
def line_circle_dist_squared(x1, y1, x2, y2, cx, cy, radius):
|
|
ix, iy = Collide.line_circle_XY(x1, y1, x2, y2, cx, cy, radius)
|
|
if ix is not None:
|
|
return distance_to_squared(x1, y1, ix, iy)
|
|
return None
|
|
|
|
@staticmethod
|
|
def line_rect(x1, y1, x2, y2, rx, ry, w, h):
|
|
if Collide.rect_points(rx, ry, w, h, [(x1, y1), (x2, y2)]) != -1:
|
|
return True
|
|
|
|
half_w = w / 2
|
|
half_h = h / 2
|
|
rect_lines = [
|
|
[rx - half_w, ry - half_h, rx - half_w, ry + half_h],
|
|
[rx - half_w, ry - half_h, rx + half_w, ry - half_h],
|
|
[rx + half_w, ry + half_h, rx - half_w, ry + half_h],
|
|
[rx + half_w, ry + half_h, rx + half_w, ry - half_h],
|
|
]
|
|
if Collide.line_lines(x1, y1, x2, y2, rect_lines) != -1:
|
|
return True
|
|
|
|
return False
|
|
|
|
@staticmethod
|
|
def line_rect_XY(x1, y1, x2, y2, rx, ry, w, h):
|
|
if Collide.rect_point(rx, ry, w, h, x1, y1):
|
|
return (x1, y1)
|
|
|
|
half_w = w / 2
|
|
half_h = h / 2
|
|
rect_lines = [
|
|
[rx - half_w, ry - half_h, rx - half_w, ry + half_h],
|
|
[rx - half_w, ry - half_h, rx + half_w, ry - half_h],
|
|
[rx + half_w, ry + half_h, rx - half_w, ry + half_h],
|
|
[rx + half_w, ry + half_h, rx + half_w, ry - half_h],
|
|
]
|
|
XYs = []
|
|
for l in rect_lines:
|
|
ix, iy = Collide.line_line_XY(x1, y1, x2, y2, l[0], l[1], l[2], l[3])
|
|
if ix is not None:
|
|
XYs.append((ix, iy))
|
|
|
|
length = len(XYs)
|
|
if length == 0:
|
|
return (None, None)
|
|
elif length == 1:
|
|
return XYs[0]
|
|
|
|
ix, iy = XYs[0]
|
|
shortest_dist = (ix - x1) ** 2 + (iy - y1) ** 2
|
|
for XY in XYs:
|
|
dist = (XY[0] - x1) ** 2 + (XY[1] - y1) ** 2
|
|
if dist < shortest_dist:
|
|
ix, iy = XY
|
|
shortest_dist = dist
|
|
|
|
return (ix, iy)
|
|
|
|
@staticmethod
|
|
def line_rect_dist(x1, y1, x2, y2, rx, ry, w, h):
|
|
ix, iy = Collide.line_rect_XY(x1, y1, x2, y2, rx, ry, w, h)
|
|
if ix is not None:
|
|
return distance_to(x1, y1, ix, iy)
|
|
return None
|
|
|
|
@staticmethod
|
|
def line_rect_dist_squared(x1, y1, x2, y2, rx, ry, w, h):
|
|
ix, iy = Collide.line_rect_XY(x1, y1, x2, y2, rx, ry, w, h)
|
|
if ix is not None:
|
|
return distance_to_squared(x1, y1, ix, iy)
|
|
return None
|
|
|
|
@staticmethod
|
|
def line_obb_XY(x1, y1, x2, y2, ox, oy, w, h, angle):
|
|
half_width = w / 2
|
|
half_height = h / 2
|
|
r_angle = math.radians(angle)
|
|
costheta = math.cos(r_angle)
|
|
sintheta = math.sin(r_angle)
|
|
|
|
tx = x1 - ox
|
|
ty = y1 - oy
|
|
rx = tx * costheta - ty * sintheta
|
|
ry = ty * costheta + tx * sintheta
|
|
|
|
if rx > -half_width and rx < half_width and ry > -half_height and ry < half_height:
|
|
return (x1, y1)
|
|
|
|
wc = half_width * costheta
|
|
hs = half_height * sintheta
|
|
hc = half_height * costheta
|
|
ws = half_width * sintheta
|
|
p = [
|
|
[ox + wc + hs, oy + hc - ws],
|
|
[ox - wc + hs, oy + hc + ws],
|
|
[ox + wc - hs, oy - hc - ws],
|
|
[ox - wc - hs, oy - hc + ws],
|
|
]
|
|
obb_lines = [
|
|
[p[0][0], p[0][1], p[1][0], p[1][1]],
|
|
[p[1][0], p[1][1], p[3][0], p[3][1]],
|
|
[p[3][0], p[3][1], p[2][0], p[2][1]],
|
|
[p[2][0], p[2][1], p[0][0], p[0][1]]
|
|
]
|
|
|
|
XYs = []
|
|
for l in obb_lines:
|
|
ix, iy = Collide.line_line_XY(x1, y1, x2, y2, l[0], l[1], l[2], l[3])
|
|
if ix is not None:
|
|
XYs.append((ix, iy))
|
|
|
|
length = len(XYs)
|
|
if length == 0:
|
|
return (None, None)
|
|
elif length == 1:
|
|
return XYs[0]
|
|
|
|
ix, iy = XYs[0]
|
|
shortest_dist = (ix - x1) ** 2 + (iy - y1) ** 2
|
|
for XY in XYs:
|
|
dist = (XY[0] - x1) ** 2 + (XY[1] - y1) ** 2
|
|
if dist < shortest_dist:
|
|
ix, iy = XY
|
|
shortest_dist = dist
|
|
|
|
return (ix, iy)
|
|
|
|
@staticmethod
|
|
def line_obb_dist(x1, y1, x2, y2, ox, oy, w, h, angle):
|
|
ix, iy = Collide.line_obb_XY(x1, y1, x2, y2, ox, oy, w, h, angle)
|
|
if ix is not None:
|
|
return distance_to(x1, y1, ix, iy)
|
|
return None
|
|
|
|
@staticmethod
|
|
def line_obb_dist_squared(x1, y1, x2, y2, ox, oy, w, h, angle):
|
|
ix, iy = Collide.obb_line_XY(x1, y1, x2, y2, ox, oy, w, h, angle)
|
|
if ix is not None:
|
|
return distance_to_squared(x1, y1, ix, iy)
|
|
return None
|
|
|
|
@staticmethod
|
|
def circle_point(x1, y1, radius, x2, y2):
|
|
rSquare = radius ** 2
|
|
dSquare = (x2 - x1)**2 + (y2 - y1)**2
|
|
|
|
if dSquare < rSquare:
|
|
return True
|
|
|
|
return False
|
|
|
|
@staticmethod
|
|
def circle_points(x, y, radius, points):
|
|
rSquare = radius ** 2
|
|
|
|
i = 0
|
|
for point in points:
|
|
try:
|
|
px = point[0]
|
|
py = point[1]
|
|
except (KeyError, TypeError):
|
|
px = point.x
|
|
py = point.y
|
|
dSquare = (px - x)**2 + (py - y)**2
|
|
|
|
if dSquare < rSquare:
|
|
return i
|
|
i += 1
|
|
|
|
return -1
|
|
|
|
@staticmethod
|
|
def circle_line(cx, cy, radius, x1, y1, x2, y2):
|
|
return Collide.line_circle(x1, y1, x2, y2, cx, cy, radius)
|
|
|
|
@staticmethod
|
|
def circle_circle(x1, y1, r1, x2, y2, r2):
|
|
rSquare = (r1 + r2) ** 2
|
|
dSquare = (x2 - x1)**2 + (y2 - y1)**2
|
|
|
|
if dSquare < rSquare:
|
|
return True
|
|
|
|
return False
|
|
|
|
@staticmethod
|
|
def circle_rect(cx, cy, cr, rx, ry, rw, rh):
|
|
h_w = rw / 2
|
|
h_h = rh / 2
|
|
rect_l = rx - h_w
|
|
rect_t = ry - h_h
|
|
|
|
if cx < rect_l:
|
|
dx2 = (cx - rect_l) ** 2
|
|
elif cx > (rect_l + rw):
|
|
dx2 = (cx - rect_l - rw) ** 2
|
|
else:
|
|
dx2 = 0
|
|
|
|
if cy < rect_t:
|
|
dy2 = (cy - rect_t) ** 2
|
|
elif cy > (rect_t + rh):
|
|
dy2 = (cy - rect_t - rh) ** 2
|
|
else:
|
|
dy2 = 0
|
|
|
|
dist2 = dx2 + dy2
|
|
|
|
if dist2 < (cr ** 2):
|
|
return True
|
|
|
|
return False
|
|
|
|
@staticmethod
|
|
def rect_point(x, y, w, h, px, py):
|
|
half_w = w / 2
|
|
half_h = h / 2
|
|
|
|
if (
|
|
px < x - half_w
|
|
or px > x + half_w
|
|
or py < y - half_h
|
|
or py > y + half_h
|
|
):
|
|
return False
|
|
|
|
return True
|
|
|
|
@staticmethod
|
|
def rect_points(x, y, w, h, points):
|
|
half_w = w / 2
|
|
half_h = h / 2
|
|
min_x = x - half_w
|
|
max_x = x + half_w
|
|
min_y = y - half_h
|
|
max_y = y + half_h
|
|
|
|
i = 0
|
|
for point in points:
|
|
try:
|
|
px = point[0]
|
|
py = point[1]
|
|
except (KeyError, TypeError):
|
|
px = point.x
|
|
py = point.y
|
|
if (
|
|
px >= min_x
|
|
and px <= max_x
|
|
and py >= min_y
|
|
and py <= max_y
|
|
):
|
|
return i
|
|
i += 1
|
|
|
|
return -1
|
|
|
|
@staticmethod
|
|
def rect_line(x, y, w, h, lx1, ly1, lx2, ly2):
|
|
return Collide.line_rect(lx1, ly1, lx2, ly2, x, y, w, h)
|
|
|
|
@staticmethod
|
|
def rect_circle(rx, ry, rw, rh, cx, cy, cr):
|
|
return Collide.circle_rect(cx, cy, cr, rx, ry, rw, rh)
|
|
|
|
@staticmethod
|
|
def rect_rect(x1, y1, w1, h1, x2, y2, w2, h2):
|
|
h_w1 = w1 / 2
|
|
h_h1 = h1 / 2
|
|
h_w2 = w2 / 2
|
|
h_h2 = h2 / 2
|
|
|
|
if (
|
|
x2 - h_w2 > x1 + h_w1
|
|
or x2 + h_w2 < x1 - h_w1
|
|
or y2 - h_h2 > y1 + h_h1
|
|
or y2 + h_h2 < y1 - h_h1
|
|
):
|
|
return False
|
|
|
|
return True
|
|
|
|
@staticmethod
|
|
def obb_point(x, y, w, h, angle, px, py):
|
|
half_width = w / 2
|
|
half_height = h / 2
|
|
b_radius_sq = half_width ** 2 + half_height ** 2
|
|
tx = px - x
|
|
ty = py - y
|
|
|
|
if tx ** 2 + ty ** 2 > b_radius_sq:
|
|
return False
|
|
|
|
r_angle = math.radians(angle)
|
|
costheta = math.cos(r_angle)
|
|
sintheta = math.sin(r_angle)
|
|
|
|
rx = tx * costheta - ty * sintheta
|
|
ry = ty * costheta + tx * sintheta
|
|
|
|
if rx > -half_width and rx < half_width and ry > -half_height and ry < half_height:
|
|
return True
|
|
|
|
return False
|
|
|
|
@staticmethod
|
|
def obb_points(x, y, w, h, angle, points):
|
|
half_width = w / 2
|
|
half_height = h / 2
|
|
r_angle = math.radians(angle)
|
|
costheta = math.cos(r_angle)
|
|
sintheta = math.sin(r_angle)
|
|
|
|
i = 0
|
|
for point in points:
|
|
try:
|
|
px = point[0]
|
|
py = point[1]
|
|
except (KeyError, TypeError):
|
|
px = point.x
|
|
py = point.y
|
|
|
|
tx = px - x
|
|
ty = py - y
|
|
rx = tx * costheta - ty * sintheta
|
|
ry = ty * costheta + tx * sintheta
|
|
|
|
if rx > -half_width and rx < half_width and ry > -half_height and ry < half_height:
|
|
return i
|
|
i += 1
|
|
|
|
return -1
|
|
|
|
@staticmethod
|
|
def obb_line(x, y, w, h, angle, lx1, ly1, lx2, ly2):
|
|
half_width = w / 2
|
|
half_height = h / 2
|
|
r_angle = math.radians(angle)
|
|
costheta = math.cos(r_angle)
|
|
sintheta = math.sin(r_angle)
|
|
|
|
tx = lx1 - x
|
|
ty = ly1 - y
|
|
rx = tx * costheta - ty * sintheta
|
|
ry = ty * costheta + tx * sintheta
|
|
|
|
if rx > -half_width and rx < half_width and ry > -half_height and ry < half_height:
|
|
return True
|
|
|
|
tx = lx2 - x
|
|
ty = ly2 - y
|
|
rx = tx * costheta - ty * sintheta
|
|
ry = ty * costheta + tx * sintheta
|
|
|
|
if rx > -half_width and rx < half_width and ry > -half_height and ry < half_height:
|
|
return True
|
|
|
|
wc = half_width * costheta
|
|
hs = half_height * sintheta
|
|
hc = half_height * costheta
|
|
ws = half_width * sintheta
|
|
p = [
|
|
[x + wc + hs, y + hc - ws],
|
|
[x - wc + hs, y + hc + ws],
|
|
[x + wc - hs, y - hc - ws],
|
|
[x - wc - hs, y - hc + ws],
|
|
]
|
|
obb_lines = [
|
|
[p[0][0], p[0][1], p[1][0], p[1][1]],
|
|
[p[1][0], p[1][1], p[3][0], p[3][1]],
|
|
[p[3][0], p[3][1], p[2][0], p[2][1]],
|
|
[p[2][0], p[2][1], p[0][0], p[0][1]]
|
|
]
|
|
|
|
if Collide.line_lines(lx1, ly1, lx2, ly2, obb_lines) != -1:
|
|
return True
|
|
|
|
return False
|
|
|
|
@staticmethod
|
|
def obb_lines(x, y, w, h, angle, lines):
|
|
half_width = w / 2
|
|
half_height = h / 2
|
|
r_angle = math.radians(angle)
|
|
costheta = math.cos(r_angle)
|
|
sintheta = math.sin(r_angle)
|
|
|
|
wc = half_width * costheta
|
|
hs = half_height * sintheta
|
|
hc = half_height * costheta
|
|
ws = half_width * sintheta
|
|
p = [
|
|
[x + wc + hs, y + hc - ws],
|
|
[x - wc + hs, y + hc + ws],
|
|
[x + wc - hs, y - hc - ws],
|
|
[x - wc - hs, y - hc + ws],
|
|
]
|
|
obb_lines = [
|
|
[p[0][0], p[0][1], p[1][0], p[1][1]],
|
|
[p[1][0], p[1][1], p[3][0], p[3][1]],
|
|
[p[3][0], p[3][1], p[2][0], p[2][1]],
|
|
[p[2][0], p[2][1], p[0][0], p[0][1]]
|
|
]
|
|
|
|
i = 0
|
|
for l in lines:
|
|
tx = l[0] - x
|
|
ty = l[1] - y
|
|
rx = tx * costheta - ty * sintheta
|
|
ry = ty * costheta + tx * sintheta
|
|
|
|
if rx > -half_width and rx < half_width and ry > -half_height and ry < half_height:
|
|
return i
|
|
|
|
tx = l[2] - x
|
|
ty = l[3] - y
|
|
rx = tx * costheta - ty * sintheta
|
|
ry = ty * costheta + tx * sintheta
|
|
|
|
if rx > -half_width and rx < half_width and ry > -half_height and ry < half_height:
|
|
return i
|
|
|
|
if Collide.line_lines(l[0], l[1], l[2], l[3], obb_lines) != -1:
|
|
return i
|
|
|
|
i += 1
|
|
|
|
return -1
|
|
|
|
@staticmethod
|
|
def obb_circle(x, y, w, h, angle, cx, cy, radius):
|
|
half_width = w / 2
|
|
half_height = h / 2
|
|
tx = cx - x
|
|
ty = cy - y
|
|
|
|
if tx ** 2 + ty ** 2 > (half_height + half_width + radius) ** 2:
|
|
return False
|
|
|
|
r_angle = math.radians(angle)
|
|
costheta = math.cos(r_angle)
|
|
sintheta = math.sin(r_angle)
|
|
|
|
rx = tx * costheta - ty * sintheta
|
|
ry = ty * costheta + tx * sintheta
|
|
|
|
if (rx < -half_width - radius
|
|
or rx > half_width + radius
|
|
or ry < -half_height - radius
|
|
or ry > half_height + radius
|
|
):
|
|
return False
|
|
|
|
if (rx <= half_width and rx >= -half_width) or (ry <= half_height and ry >= -half_height):
|
|
return True
|
|
|
|
dx = abs(rx) - half_width
|
|
dy = abs(ry) - half_height
|
|
dist_squared = dx ** 2 + dy ** 2
|
|
if dist_squared > radius ** 2:
|
|
return False
|
|
|
|
return True
|
|
|
|
@staticmethod
|
|
def obb_circles(x, y, w, h, angle, circles):
|
|
half_width = w / 2
|
|
half_height = h / 2
|
|
r_angle = math.radians(angle)
|
|
costheta = math.cos(r_angle)
|
|
sintheta = math.sin(r_angle)
|
|
|
|
i = 0
|
|
for circle in circles:
|
|
tx = circle[0] - x
|
|
ty = circle[1] - y
|
|
|
|
rx = tx * costheta - ty * sintheta
|
|
ry = ty * costheta + tx * sintheta
|
|
|
|
if (rx < -half_width - circle[2]
|
|
or rx > half_width + circle[2]
|
|
or ry < -half_height - circle[2]
|
|
or ry > half_height + circle[2]
|
|
):
|
|
i += 1
|
|
continue
|
|
|
|
if (rx <= half_width and rx >= -half_width) or (ry <= half_height and ry >= -half_height):
|
|
return i
|
|
|
|
dx = abs(rx) - half_width
|
|
dy = abs(ry) - half_height
|
|
dist_squared = dx ** 2 + dy ** 2
|
|
if dist_squared > circle[2] ** 2:
|
|
i += 1
|
|
continue
|
|
|
|
return i
|
|
|
|
return -1
|
|
|
|
@staticmethod
|
|
def obb_rect(x, y, w, h, angle, rx, ry, rw, rh):
|
|
half_width = w / 2
|
|
half_height = h / 2
|
|
tx = rx - x
|
|
ty = ry - y
|
|
|
|
if tx ** 2 + ty ** 2 > (half_height + half_width + rw + rh) ** 2:
|
|
return False
|
|
|
|
r_angle = math.radians(angle)
|
|
costheta = math.cos(r_angle)
|
|
sintheta = math.sin(r_angle)
|
|
|
|
tx2 = tx * costheta - ty * sintheta
|
|
ty2 = ty * costheta + tx * sintheta
|
|
|
|
if tx2 > -half_width and tx2 < half_width and ty2 > -half_height and ty2 < half_height:
|
|
return True
|
|
|
|
wc = half_width * costheta
|
|
hs = half_height * sintheta
|
|
hc = half_height * costheta
|
|
ws = half_width * sintheta
|
|
p = [
|
|
[wc + hs, hc - ws],
|
|
[-wc + hs, hc + ws],
|
|
[wc - hs, -hc - ws],
|
|
[-wc - hs, -hc + ws],
|
|
]
|
|
obb_lines = [
|
|
[p[0][0], p[0][1], p[1][0], p[1][1]],
|
|
[p[1][0], p[1][1], p[3][0], p[3][1]],
|
|
[p[3][0], p[3][1], p[2][0], p[2][1]],
|
|
[p[2][0], p[2][1], p[0][0], p[0][1]]
|
|
]
|
|
h_rw = rw / 2
|
|
h_rh = rh / 2
|
|
rect_lines = [
|
|
[tx - h_rw, ty - h_rh, tx - h_rw, ty + h_rh],
|
|
[tx + h_rw, ty - h_rh, tx + h_rw, ty + h_rh],
|
|
[tx - h_rw, ty - h_rh, tx + h_rw, ty - h_rh],
|
|
[tx - h_rw, ty + h_rh, tx + h_rw, ty + h_rh]
|
|
]
|
|
|
|
for obb_p in p:
|
|
if obb_p[0] > tx - h_rw and obb_p[0] < tx + h_rw and obb_p[1] > ty - h_rh and obb_p[1] < ty + h_rh:
|
|
return True
|
|
|
|
for obb_line in obb_lines:
|
|
l1x1 = obb_line[0]
|
|
l1y1 = obb_line[1]
|
|
l1x2 = obb_line[2]
|
|
l1y2 = obb_line[3]
|
|
l1x2_l1x1 = l1x2-l1x1
|
|
l1y2_l1y1 = l1y2-l1y1
|
|
|
|
for rect_line in rect_lines:
|
|
l2x1 = rect_line[0]
|
|
l2y1 = rect_line[1]
|
|
l2x2 = rect_line[2]
|
|
l2y2 = rect_line[3]
|
|
|
|
determinant = (l2y2-l2y1)*l1x2_l1x1 - (l2x2-l2x1)*l1y2_l1y1
|
|
|
|
# Simplify: Parallel lines are never considered to be intersecting
|
|
if determinant == 0:
|
|
continue
|
|
|
|
uA = ((l2x2-l2x1)*(l1y1-l2y1) - (l2y2-l2y1)*(l1x1-l2x1)) / determinant
|
|
if uA < 0 or uA > 1:
|
|
continue
|
|
|
|
uB = (l1x2_l1x1*(l1y1-l2y1) - l1y2_l1y1*(l1x1-l2x1)) / determinant
|
|
if uB < 0 or uB > 1:
|
|
continue
|
|
|
|
return True
|
|
|
|
return False
|
|
|
|
@staticmethod
|
|
def obb_rects(x, y, w, h, angle, rects):
|
|
half_width = w / 2
|
|
half_height = h / 2
|
|
r_angle = math.radians(angle)
|
|
costheta = math.cos(r_angle)
|
|
sintheta = math.sin(r_angle)
|
|
|
|
i = 0
|
|
for rect in rects:
|
|
rx = rect[0]
|
|
ry = rect[1]
|
|
rw = rect[2]
|
|
rh = rect[3]
|
|
|
|
tx = rx - x
|
|
ty = ry - y
|
|
|
|
if tx ** 2 + ty ** 2 > (half_height + half_width + rw + rh) ** 2:
|
|
i += 1
|
|
continue
|
|
|
|
tx2 = tx * costheta - ty * sintheta
|
|
ty2 = ty * costheta + tx * sintheta
|
|
|
|
if tx2 > -half_width and tx2 < half_width and ty2 > -half_height and ty2 < half_height:
|
|
return i
|
|
|
|
wc = half_width * costheta
|
|
hs = half_height * sintheta
|
|
hc = half_height * costheta
|
|
ws = half_width * sintheta
|
|
p = [
|
|
[wc + hs, hc - ws],
|
|
[-wc + hs, hc + ws],
|
|
[wc - hs, -hc - ws],
|
|
[-wc - hs, -hc + ws],
|
|
]
|
|
obb_lines = [
|
|
[p[0][0], p[0][1], p[1][0], p[1][1]],
|
|
[p[1][0], p[1][1], p[3][0], p[3][1]],
|
|
[p[3][0], p[3][1], p[2][0], p[2][1]],
|
|
[p[2][0], p[2][1], p[0][0], p[0][1]]
|
|
]
|
|
h_rw = rw / 2
|
|
h_rh = rh / 2
|
|
rect_lines = [
|
|
[tx - h_rw, ty - h_rh, tx - h_rw, ty + h_rh],
|
|
[tx + h_rw, ty - h_rh, tx + h_rw, ty + h_rh],
|
|
[tx - h_rw, ty - h_rh, tx + h_rw, ty - h_rh],
|
|
[tx - h_rw, ty + h_rh, tx + h_rw, ty + h_rh]
|
|
]
|
|
|
|
for obb_p in p:
|
|
if obb_p[0] > tx - h_rw and obb_p[0] < tx + h_rw and obb_p[1] > ty - h_rh and obb_p[1] < ty + h_rh:
|
|
return i
|
|
|
|
for obb_line in obb_lines:
|
|
l1x1 = obb_line[0]
|
|
l1y1 = obb_line[1]
|
|
l1x2 = obb_line[2]
|
|
l1y2 = obb_line[3]
|
|
l1x2_l1x1 = l1x2-l1x1
|
|
l1y2_l1y1 = l1y2-l1y1
|
|
|
|
for rect_line in rect_lines:
|
|
l2x1 = rect_line[0]
|
|
l2y1 = rect_line[1]
|
|
l2x2 = rect_line[2]
|
|
l2y2 = rect_line[3]
|
|
|
|
determinant = (l2y2-l2y1)*l1x2_l1x1 - (l2x2-l2x1)*l1y2_l1y1
|
|
|
|
# Simplify: Parallel lines are never considered to be intersecting
|
|
if determinant == 0:
|
|
continue
|
|
|
|
uA = ((l2x2-l2x1)*(l1y1-l2y1) - (l2y2-l2y1)*(l1x1-l2x1)) / determinant
|
|
if uA < 0 or uA > 1:
|
|
continue
|
|
|
|
uB = (l1x2_l1x1*(l1y1-l2y1) - l1y2_l1y1*(l1x1-l2x1)) / determinant
|
|
if uB < 0 or uB > 1:
|
|
continue
|
|
|
|
return i
|
|
|
|
i += 1
|
|
|
|
return -1
|
|
|
|
def obb_obb(x, y, w, h, angle, x2, y2, w2, h2, angle2):
|
|
r_angle = math.radians(angle)
|
|
costheta = math.cos(r_angle)
|
|
sintheta = math.sin(r_angle)
|
|
|
|
tx2 = x2 - x
|
|
ty2 = y2 - y
|
|
rx2 = tx2 * costheta - ty2 * sintheta
|
|
ry2 = ty2 * costheta + tx2 * sintheta
|
|
return Collide.obb_rect(rx2, ry2, w2, h2, angle2-angle, 0, 0, w, h)
|
|
|
|
def obb_obbs(x, y, w, h, angle, obbs):
|
|
r_angle = math.radians(angle)
|
|
costheta = math.cos(r_angle)
|
|
sintheta = math.sin(r_angle)
|
|
for obb in obbs:
|
|
x2, y2, w2, h2, angle2 = obb
|
|
tx2 = x2 - x
|
|
ty2 = y2 - y
|
|
rx2 = tx2 * costheta - ty2 * sintheta
|
|
ry2 = ty2 * costheta + tx2 * sintheta
|
|
return Collide.obb_rect(rx2, ry2, w2, h2, angle2-angle, 0, 0, w, h)
|
|
|
|
|
|
class Actor(Actor):
|
|
def __init__(self, image:Union[str, pygame.Surface], pos=POS_TOPLEFT, anchor=ANCHOR_CENTER, **kwargs):
|
|
self._flip_x = False
|
|
self._flip_y = False
|
|
self._scale = 1
|
|
self._mask = None
|
|
self._images = None
|
|
self._image_idx = 0
|
|
self._subrects = None
|
|
self._transform_cnt = 0
|
|
self._orig_surfs = {}
|
|
self._surfs = {}
|
|
self._animate_counter = 0
|
|
self._animate_run = False
|
|
self._radius = None
|
|
self._collision_width = None
|
|
self._collision_height = None
|
|
self.fps = 5
|
|
self.direction = 0
|
|
subrect=kwargs.pop('subrect',None)
|
|
image_str = None
|
|
if isinstance(image,str):
|
|
image_str = image
|
|
super().__init__(image_str, pos, anchor, **kwargs)
|
|
if isinstance(image,pygame.Surface):
|
|
self._orig_surf = image
|
|
self._update_pos()
|
|
self._subrect=None
|
|
if subrect is not None:
|
|
self.subrect=subrect
|
|
|
|
def distance_to(self, target):
|
|
if isinstance(target, Actor):
|
|
x, y = target.pos
|
|
else:
|
|
x, y = target
|
|
return distance_to(self.x, self.y, x, y)
|
|
|
|
def distance_toXY(self, x, y):
|
|
return distance_to(self.x, self.y, x, y)
|
|
|
|
def direction_to(self, target):
|
|
if isinstance(target, Actor):
|
|
x, y = target.pos
|
|
else:
|
|
x, y = target
|
|
return direction_to(self.x, self.y, x, y)
|
|
|
|
def direction_toXY(self, x, y):
|
|
return direction_to(self.x, self.y, x, y)
|
|
|
|
|
|
def move_towards(self, target:Union[int, float, Actor, _Coordinate], dist, stop_on_target=True):
|
|
if isinstance(target, (int,float)):
|
|
direction = target
|
|
else:
|
|
direction = self.direction_to(target)
|
|
if stop_on_target:
|
|
target_distance = self.distance_to(target)
|
|
if (target_distance < dist) and dist>0:
|
|
dist = target_distance
|
|
self.x, self.y = move(self.x, self.y, direction, dist)
|
|
|
|
def move_towardsXY(self, x, y, dist):
|
|
direction = self.direction_toXY(x, y)
|
|
self.x, self.y = move(self.x, self.y, direction, dist)
|
|
|
|
def point_towards(self, actor, y=None):
|
|
self.angle = self.direction_to(actor)
|
|
|
|
def point_towardsXY(self, x, y):
|
|
self.angle = direction_to(self.x, self.y, x, y)
|
|
|
|
def move_in_direction(self, dist):
|
|
self.x, self.y = move(self.x, self.y, self.direction, dist)
|
|
|
|
def move_forward(self, dist):
|
|
self.x, self.y = move(self.x, self.y, self.angle, dist)
|
|
|
|
def move_left(self, dist):
|
|
self.x, self.y = move(self.x, self.y, self.angle + 90, dist)
|
|
|
|
def move_right(self, dist):
|
|
self.x, self.y = move(self.x, self.y, self.angle - 90, dist)
|
|
|
|
def move_back(self, dist):
|
|
self.x, self.y = move(self.x, self.y, self.angle, -dist)
|
|
|
|
@property
|
|
def images(self):
|
|
return self._images
|
|
|
|
@images.setter
|
|
def images(self, images):
|
|
self._subrects = None
|
|
self._images = images
|
|
if len(self._images) != 0:
|
|
self.image = self._images[0]
|
|
|
|
def load_images(self, sheet_name:str, cols:int, rows:int, cnt:int=0, subrect:pygame.Rect=None):
|
|
self._subrects=[None]*cols*rows
|
|
self._image_idx=0
|
|
sheet:pygame.Surface = loaders.images.load(sheet_name)
|
|
if subrect is not None:
|
|
sheet = sheet.subsurface(subrect)
|
|
for col in range(0,cols):
|
|
for row in range(0,rows):
|
|
width=sheet.get_width()/cols
|
|
height=sheet.get_height()/rows
|
|
self._subrects[col+row*cols]=(int(col*width),int(row*height),int(width),int(height))
|
|
if len(self._subrects) != 0:
|
|
self.image = sheet_name
|
|
self.subrect = self._subrects[0]
|
|
|
|
def sel_image(self, newimage:Union[str, int])-> bool:
|
|
try:
|
|
if isinstance(newimage, int):
|
|
if self._subrects is None and self._images is None:
|
|
return False
|
|
if self._subrects is not None:
|
|
self.subrect = self._subrects[newimage]
|
|
else:
|
|
self.image = self._images[newimage]
|
|
self._image_idx = newimage
|
|
return True
|
|
else:
|
|
self._image_idx = self._images.index(newimage)
|
|
self.image = newimage
|
|
except:
|
|
return False
|
|
|
|
def next_image(self)-> int:
|
|
if self._subrects is not None:
|
|
next_image_idx = (self._image_idx+1) % len(self._subrects)
|
|
self._image_idx = next_image_idx
|
|
self.subrect = self._subrects[self._image_idx]
|
|
elif (self._images is not None) :
|
|
if (self.image in self._images):
|
|
next_image_idx = (self._images.index(self.image)+1) % len(self._images)
|
|
self._image_idx = next_image_idx
|
|
self.image = self._images[self._image_idx]
|
|
else:
|
|
self._image_idx = 0
|
|
self.image = self._images[0]
|
|
else:
|
|
self._image_idx = 0
|
|
return self._image_idx
|
|
|
|
def animate(self)-> int:
|
|
now = int(time.time() * self.fps)
|
|
if self._animate_counter == 0:
|
|
self._animate_counter=now
|
|
frames_elapsed = now-self._animate_counter
|
|
|
|
if frames_elapsed!=0:
|
|
self._animate_counter = now
|
|
idx=self.next_image()
|
|
return idx
|
|
else:
|
|
return -1
|
|
|
|
@property
|
|
def angle(self):
|
|
return self._angle
|
|
|
|
@angle.setter
|
|
def angle(self, angle):
|
|
self._angle = angle
|
|
self._transform_surf()
|
|
self._transform_cnt+=1
|
|
|
|
@property
|
|
def scale(self):
|
|
return self._scale
|
|
|
|
@scale.setter
|
|
def scale(self, scale):
|
|
self._scale = scale
|
|
self._transform_surf()
|
|
self._transform_cnt+=1
|
|
|
|
@property
|
|
def flip_x(self):
|
|
return self._flip_x
|
|
|
|
@flip_x.setter
|
|
def flip_x(self, flip_x):
|
|
self._flip_x = flip_x
|
|
self._transform_surf()
|
|
self._transform_cnt+=1
|
|
|
|
@property
|
|
def flip_y(self):
|
|
return self._flip_y
|
|
|
|
@flip_y.setter
|
|
def flip_y(self, flip_y):
|
|
self._flip_y = flip_y
|
|
self._transform_surf()
|
|
self._transform_cnt+=1
|
|
|
|
@property
|
|
def image(self):
|
|
return self._image_name
|
|
|
|
@image.setter
|
|
def image(self, image):
|
|
if image is not None:
|
|
self._orig_surf = self._surf = loaders.images.load(image)
|
|
self._image_name = image
|
|
self._orig_surfs[image]=self._orig_surf
|
|
else:
|
|
self._orig_surf = self._surf = pygame.Surface((1,1),pygame.SRCALPHA)
|
|
self._image_name = ''
|
|
self._update_pos()
|
|
if image is not None:
|
|
if (image not in self._surfs) or (self._surfs[image][1]!=self._transform_cnt):
|
|
self._transform_surf()
|
|
self._surfs[image]=(self._surf,self._transform_cnt)
|
|
|
|
@property
|
|
def subrect(self):
|
|
return self._subrect
|
|
@subrect.setter
|
|
def subrect(self, subrect:pygame.Rect):
|
|
subr = subrect
|
|
if subrect is not None:
|
|
subr=pygame.Rect(subrect)
|
|
if subr != self._subrect:
|
|
self._subrect = subr
|
|
if self._subrect is not None:
|
|
hashv=hash((subr.x, subr.y,subr.width,subr.height))
|
|
surf_name=self._image_name+str(hashv)
|
|
if surf_name not in self._orig_surfs:
|
|
self._orig_surfs[surf_name] = loaders.images.load(self.image).subsurface(subr)
|
|
self._orig_surf=self._orig_surfs[surf_name]
|
|
self._update_pos()
|
|
if (surf_name not in self._surfs) or (self._surfs[surf_name][1]!=self._transform_cnt):
|
|
self._transform_surf()
|
|
self._surfs[surf_name]=(self._surf,self._transform_cnt)
|
|
self._surf=self._surfs[surf_name][0]
|
|
else:
|
|
self._orig_surf = self._surf = loaders.images.load(self.image)
|
|
self._update_pos()
|
|
self._transform_surf()
|
|
|
|
@property
|
|
def orig_surf(self):
|
|
return self._orig_surf
|
|
|
|
@orig_surf.setter
|
|
def orig_surf(self, surf:pygame.Surface):
|
|
self._orig_surf = self._surf =surf
|
|
self._update_pos()
|
|
self._transform_surf()
|
|
|
|
def recalc(self):
|
|
self._surf = self._orig_surf
|
|
self._update_pos()
|
|
self._transform_surf()
|
|
|
|
def _transform_surf(self):
|
|
self._surf = self._orig_surf
|
|
p = self.pos
|
|
|
|
if self._scale != 1:
|
|
size = self._orig_surf.get_size()
|
|
self._surf = pygame.transform.scale(self._surf, (int(size[0] * self.scale), int(size[1] * self.scale)))
|
|
if self._flip_x:
|
|
self._surf = pygame.transform.flip(self._surf, True, False)
|
|
if self._flip_y:
|
|
self._surf = pygame.transform.flip(self._surf, False, True)
|
|
|
|
self._surf = pygame.transform.rotate(self._surf, self._angle)
|
|
|
|
self.width, self.height = self._surf.get_size()
|
|
w, h = self._orig_surf.get_size()
|
|
ax, ay = self._untransformed_anchor
|
|
anchor = transform_anchor(ax, ay, w, h, self._angle)
|
|
self._anchor = (anchor[0] * self.scale, anchor[1] * self.scale)
|
|
|
|
self.pos = p
|
|
self._mask = None
|
|
|
|
def collidepoint_pixel(self, x, y=0):
|
|
if isinstance(x, tuple):
|
|
y = x[1]
|
|
x = x[0]
|
|
if self._mask == None:
|
|
self._mask = pygame.mask.from_surface(self._surf)
|
|
|
|
xoffset = int(x - self.left)
|
|
yoffset = int(y - self.top)
|
|
if xoffset < 0 or yoffset < 0:
|
|
return 0
|
|
|
|
width, height = self._mask.get_size()
|
|
if xoffset >= width or yoffset >= height:
|
|
return 0
|
|
|
|
return self._mask.get_at((xoffset, yoffset))
|
|
|
|
def collide_pixel(self, actor):
|
|
for a in [self, actor]:
|
|
if a._mask == None:
|
|
a._mask = pygame.mask.from_surface(a._surf)
|
|
|
|
xoffset = int(actor.left - self.left)
|
|
yoffset = int(actor.top - self.top)
|
|
|
|
return self._mask.overlap(actor._mask, (xoffset, yoffset))
|
|
|
|
def collidelist_pixel(self, actors):
|
|
for i in range(len(actors)):
|
|
if self.collide_pixel(actors[i]):
|
|
return i
|
|
return -1
|
|
|
|
def collidelistall_pixel(self, actors):
|
|
collided = []
|
|
for i in range(len(actors)):
|
|
if self.collide_pixel(actors[i]):
|
|
collided.append(i)
|
|
return collided
|
|
|
|
def _unrotated_size(self):
|
|
w = self._orig_surf.get_width()*self.scale
|
|
h = self._orig_surf.get_height()*self.scale
|
|
return w, h
|
|
|
|
@property
|
|
def collision_width(self):
|
|
if self._collision_width is None:
|
|
w,_ = self._unrotated_size()
|
|
return w
|
|
return self._collision_width
|
|
|
|
@collision_width.setter
|
|
def collision_width(self, collision_width):
|
|
self._collision_width = collision_width
|
|
|
|
@property
|
|
def collision_height(self):
|
|
if self._collision_height is None:
|
|
_,h = self._unrotated_size()
|
|
return h
|
|
return self._collision_height
|
|
|
|
@collision_height.setter
|
|
def collision_height(self, collision_height):
|
|
self._collision_height = collision_height
|
|
|
|
def obb_collidepoint(self, x, y):
|
|
w,h = self._unrotated_size()
|
|
return Collide.obb_point(self.centerx, self.centery, w, h, self._angle, x, y)
|
|
|
|
def obb_collidepoints(self, points):
|
|
w,h = self._unrotated_size()
|
|
return Collide.obb_points(self.centerx, self.centery, w, h, self._angle, points)
|
|
|
|
def obb_collideobb(self, actor):
|
|
if self._collision_width is None and self._collision_height is None:
|
|
x,y = self.centerx, self.centery
|
|
else:
|
|
x,y = self.x, self.y
|
|
|
|
if actor._collision_width is None and actor._collision_height is None:
|
|
x2,y2 = actor.centerx, actor.centery
|
|
else:
|
|
x2,y2 = actor.x, actor.y
|
|
|
|
return Collide.obb_obb(x, y, self.collision_width, self.collision_height, self._angle,
|
|
x2, y2, actor.collision_width, actor.collision_height, actor._angle)
|
|
|
|
@property
|
|
def radius(self):
|
|
if self._radius is None:
|
|
w,h = self._unrotated_size()
|
|
self._radius = min(w, h) * .5
|
|
return self._radius
|
|
|
|
@radius.setter
|
|
def radius(self, radius):
|
|
self._radius = radius
|
|
|
|
def circle_collidepoints(self, points):
|
|
return Collide.circle_points(self.centerx, self.centery, self._radius, points)
|
|
|
|
def circle_collidepoint(self, x, y):
|
|
return Collide.circle_point(self.centerx, self.centery, self._radius, x, y)
|
|
|
|
def circle_collidecircle(self, actor):
|
|
return Collide.circle_circle(self.centerx, self.centery, self._radius, actor.centerx, actor.centery, actor._radius)
|
|
|
|
def circle_colliderect(self, actor):
|
|
return Collide.circle_rect(self.centerx, self.centery, self._radius, actor.centerx, actor.centery, actor.width, actor.height)
|
|
|
|
def circle_collideobb(self, actor):
|
|
w2, h2 = actor._unrotated_size()
|
|
return Collide.obb_circle(actor.centerx, actor.centery, w2, h2, actor.angle,
|
|
self.centerx, self.centery, self._radius)
|
|
|
|
def draw(self):
|
|
game.screen.blit(self._surf, self.topleft)
|
|
|
|
def get_rect(self):
|
|
return self._rect
|