-
Notifications
You must be signed in to change notification settings - Fork 0
/
PhysicsEntity.py
162 lines (115 loc) · 5.31 KB
/
PhysicsEntity.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
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
'''
Created on Jun 24, 2012
@author: Jami
'''
from Vec2 import Vec2
import consts
import math
import pygame
class PhysicsEntity(pygame.sprite.Sprite):
velocity = (0,0) # current velocity of the entity
max_vel_sq = 1024 # maximum velocity squared (for speed)
accel = (0,0) # current acceleration
max_accel_sq = 4 # max accel squared
mass = 0 # TODO implement momentum in collisions
rotation = 0 # important for acceleration stuff
position = (0.0, 0.0) # important for floating point physics
future_positions = None # will be used for collision prediction
x, y, bounding_radius, bounding_radius_squared = 0, 0, 0, 0
left, right, top, bottom = 0, 0, 0, 0
removeSelf = False
parent = None
engine_points = None
engine_color = None
target = None
collider = None
active = True
def __init__(self):
super(PhysicsEntity, self).__init__() # for now, we just call the super constructor
self.image = None
self.rect = None
self.original = None
def accelerate(self, mag = 0):
self.accelerate_r(mag, self.rotation)
def accelerate_r(self, mag = 0, r = 0):
# basically, we add the vector (mag, rotation) to the current accel value
jerk = Vec2(mag, r)
accel = Vec2(0,0)
accel.setXY(self.accel[0], self.accel[1])
new_accel = accel.add(jerk)
if new_accel.magnitude * new_accel.magnitude > self.max_accel_sq:
new_accel.magnitude = math.sqrt(self.max_accel_sq)
self.accel = new_accel.getXY()
def brake(self, brake = 0):
# to brake, we are going to subtract mag from the velocity vector until it becomes 0
mag = math.sqrt(self.get_vel_sq())
if mag == 0: return
vec = Vec2(0,0)#Vec2(mag, math.degrees(math.asin(self.velocity[1] / mag)))
vec.setXY(self.velocity[0],self.velocity[1])
vec.magnitude -= brake
if vec.magnitude < 0:
self.velocity = (0,0)
else:
self.velocity = vec.getXY()
def set_rotation(self, r=0):
self.rotation = float(r) % 360.0
self.image = pygame.transform.rotate(self.original, int(r))
cp = self.rect.copy()
self.rect = self.image.get_rect(center = self.rect.center)
self.position = (self.position[0] - cp.left + self.rect.left, self.position[1] - cp.top + self.rect.top)
def get_rotation(self):
return self.rotation
def get_vel_sq(self): return (self.velocity[0] * self.velocity[0]) + (self.velocity[1] * self.velocity[1])
def get_accel_sq(self): return (self.accel[0] * self.accel[0]) + (self.accel[1] * self.accel[1])
'''
' update(context)
' @param context is the main game manager that exposes variables that may be needed by the update function
'''
def update(self, context = None, timestep = 1):
self.rect.topleft = self.position
self.x, self.y = self.rect.center
if self.rect.width < self.rect.height:
self.bounding_radius = self.rect.height * 0.5
else:
self.bounding_radius = self.rect.width * 0.5
self.bounding_radius_squared = self.bounding_radius ** 2
self.left, self.top = self.rect.topleft
self.right, self.bottom = self.rect.bottomright
self.predict_positions(consts.COLLIDE_TICKS, consts.COLLIDE_INTERVAL)
if not self.active:
return
def distance_to_sq(self, targetRect = None):
if targetRect:
dx = self.rect.center[0] - targetRect.center[0]
dy = self.rect.center[1] - targetRect.center[1]
return dx*dx + dy*dy
return -1
def consider_target(self, target):
pass
def remove(self):
pass
def collide(self, physicsEntity = None, context = None):
pass
def can_collide(self, physicsEntity):
return not self is physicsEntity.parent
def will_collide(self, physicsEntity):
'''determine if this entity will collide with physicsEntity within the given number of ticks'''
if not self.future_positions or not physicsEntity.future_positions:
return False
# determine if we may collide
for i in range(0, len(self.future_positions)):
if i >= len(physicsEntity.future_positions):
return False
if self.future_positions[i].colliderect(physicsEntity.future_positions[i]):
return True
return False
def predict_positions(self, ticks = consts.COLLIDE_TICKS, interval = consts.COLLIDE_INTERVAL):
'''predict the future positions of this entity'''
n = 0
self.future_positions = []
n_rect = self.rect.copy()
while n <= ticks:
n_rect.left += self.velocity[0]
n_rect.top += self.velocity[1]
self.future_positions.append(n_rect.copy())
n += interval