-
Notifications
You must be signed in to change notification settings - Fork 0
/
collision_detection.py
executable file
·99 lines (78 loc) · 3.2 KB
/
collision_detection.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
import pygame, constants
def tank_collides_with_tank(tank1, tank2):
if not pygame.sprite.collide_rect(tank1, tank2):
return False
tank1_sides = tank1.get_sides()
tank2_sides = tank2.get_sides()
for tank1_side in tank1_sides:
for tank2_side in tank2_sides:
p = tank1_side.intersect_segments(tank2_side)
if p is not None:
return True
return False
def bullet_collides_with_bullet(bullet1, bullet2):
return pygame.sprite.collide_rect(bullet1, bullet2)
def bullet_collides_with_shield(bullet, shield):
if bullet.owner is shield.tank and bullet.total_distance < constants.SHIELD_RADIUS_RATIO and not bullet.has_bounced():
return False
return sprite_collide(bullet, shield)
def bullet_collides_with_tank(bullet, tank):
# if this is the owner and we haven't yet travelled past the
# end of the tank, this can't be a hit!
if tank is bullet.owner and bullet.total_distance < constants.TANK_SIZE_RATIO / 2 and not bullet.has_bounced():
return False
pos = bullet.position.scale(constants.TILE_SIZE)
# if the bullet is not in the tank's rect, then a collision
# could not have occurred.
if not tank.rect.collidepoint(pos):
return False
# now check the pixel of the tank's image where the bullet is.
# if it's not transparent it's a collision.
pixel = (
max(0, min(tank.rect.width - 1, int(round(pos[0] - tank.rect.x)))),
max(0, min(tank.rect.height - 1, int(round(pos[1] - tank.rect.y))))
)
color = tank.image.get_at(pixel)
return color[3] != 0
def tank_collides_with_tile(tank, tiles):
for tile in tiles:
# if the rects don't even collide, then they don't collide
if not pygame.sprite.collide_rect(tank, tile):
continue
# otherwise, have to verify collision in case of turned tank
intersects = []
for side in tank.get_sides():
for tile_side in tile.get_sides():
p = side.intersect_segments(tile_side)
if not p is None:
intersects.append((side, tile_side, p))
if intersects:
return intersects
return []
def is_transparent(color):
return color[3] == 0
def sprite_collide_exact(sprite1, sprite2):
x_offset = sprite1.rect.x - sprite2.rect.x
y_offset = sprite1.rect.y - sprite2.rect.y
for x in range(0, sprite1.image.get_width()):
sprite2_x = x + x_offset
if sprite2_x < 0 or sprite2_x >= sprite2.image.get_width():
continue
for y in range(0, sprite1.image.get_height()):
sprite2_y = y + y_offset
if sprite2_y < 0 or sprite2_y >= sprite2.image.get_height():
continue
if not is_transparent(sprite1.image.get_at((x, y))) and \
not is_transparent(sprite2.image.get_at((sprite2_x, sprite2_y))):
return True
return False
def sprite_collide(sprite1, sprite2):
return pygame.sprite.collide_rect(sprite1, sprite2) and \
sprite_collide_exact(sprite1, sprite2)
def sprite_contains_exact(sprite, point):
x_offset = int(round(point.x - sprite.rect.x))
y_offset = int(round(point.y - sprite.rect.y))
return not is_transparent(sprite.image.get_at((x_offset, y_offset)))
def sprite_contains(sprite, point):
return sprite.rect.collidepoint(point) and \
sprite_contains_exact(sprite, point)