-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathbullet.py
executable file
·122 lines (101 loc) · 4.15 KB
/
bullet.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
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
import pygame, math
import constants
from geometry import Vector, Point, Line
from explosion import BigExplosion, Explosion, Shockwave
BOUNCED = 1
EXPLODED = 2
class Bullet(pygame.sprite.Sprite):
# position holds xy coordinates of the bullet as a Point
# direction contains an angle in radians from the positive
# x axis.
def __init__(self, p, direction, owner, splash=False):
super(Bullet, self).__init__()
self.position = p
self.direction = direction
self.owner = owner
self.splash = splash
if not self.splash:
self.original = pygame.Surface([constants.TILE_SIZE * constants.BULLET_WIDTH_RATIO, constants.TILE_SIZE * constants.BULLET_HEIGHT_RATIO], flags=pygame.SRCALPHA)
self.original.fill(constants.BULLET_COLOR)
else:
size = int(round(constants.BULLET_WIDTH_RATIO * constants.TILE_SIZE))
self.original = pygame.Surface([size, size], flags=pygame.SRCALPHA)
self.original.fill(constants.COLOR_TRANSPARENT)
image_center = (self.original.get_width() / 2, self.original.get_height() / 2)
pygame.draw.circle(self.original, constants.BULLET_COLOR, image_center, int(round(self.original.get_width() / 2)))
self.old_position = self.position
self.reset_vec()
self.bounces = 0
self.total_distance = 0.0
self.dead = False
self.travelled = Line(self.position, self.position)
self.update_graphics()
def get_explosion(self):
if self.splash:
return BigExplosion(self.position, True)
else:
return Explosion(self.position)
def expired(self):
return self.dead
def die(self):
self.owner.bullets -= 1
self.dead = True
def has_bounces(self):
return self.bounces < 1
def has_bounced(self):
return self.bounces > 0
def reset_vec(self):
self.vec = Vector(math.cos(self.direction), math.sin(self.direction)).normalize()
# bounce off wall (which is a line segment).
# traces movement of bullet backwards
def bounce(self, tiles):
results = []
while True:
if self.travelled.as_vector().length2() == 0:
return results
max_dist2 = -1.0
reflectors = []
for tile in tiles:
# if the distance between the bullet and the center of the tile is
# greater than the distance travelled by the bullet plus the
# size of the tile, then no collision could have occurred
if self.travelled.length() + math.sqrt(2) / 2 < (self.position - tile.position).length():
continue
for tile_side in tile.get_sides():
# first check that we're coming from the right direction
if self.travelled.as_vector().normalize().dot(tile_side.normal()) > 0:
continue
p = self.travelled.intersect_segments(tile_side)
if not p is None:
if reflectors is None or (p - self.position).length2() > max_dist2:
reflectors = [(p, tile_side)]
elif max_dist2 < (p - self.position).length2() <= max_dist2:
reflectors.append((p, tile_side))
if len(reflectors) == 1:
if self.has_bounces() and not self.splash:
(p, wall) = reflectors[0]
self.position = wall.reflect(self.position)
self.direction = (self.position - p).angle()
self.travelled = Line(p, self.position)
self.reset_vec()
self.bounces += 1
self.update_graphics()
results.append((BOUNCED, self.position))
else:
results.append((EXPLODED, self.position))
break
elif reflectors:
print("multiple reflectors!")
else:
break
return results
def update(self, delta):
self.old_position = self.position
displacement = (constants.BULLET_SPEED * delta / 1000.0) * self.vec
self.total_distance += displacement.length()
self.position = self.position.translate(displacement)
self.travelled = Line(self.old_position, self.position)
self.update_graphics()
def update_graphics(self):
self.image = pygame.transform.rotate(self.original, -self.direction * 180.0 / math.pi)
self.rect = self.image.get_rect(center=(constants.TILE_SIZE * self.position.x, constants.TILE_SIZE * self.position.y))