gravity.py (8991B)
1 ### EXESOFT PYIGNITION ### 2 # Copyright David Barker 2010 3 # 4 # Gravity objects 5 6 7 from math import sqrt 8 import keyframes, interpolate, random 9 from constants import * 10 11 12 def RandomiseStrength(base, range): 13 return base + (float(random.randrange(int(-range * 100), int(range * 100))) / 100.0) 14 15 16 class DirectedGravity: 17 def __init__(self, strength = 0.0, strengthrandrange = 0.0, direction = [0, 1]): 18 self.selected = False 19 self.type = "directed" 20 self.initstrength = strength 21 self.strength = strength 22 self.strengthrandrange = strengthrandrange 23 directionmag = sqrt(direction[0]**2 + direction[1]**2) 24 self.direction = [direction[0] / directionmag, direction[1] / directionmag] 25 26 self.keyframes = [] 27 self.CreateKeyframe(0, self.strength, self.strengthrandrange, self.direction) 28 self.curframe = 0 29 30 def Update(self): 31 newvars = interpolate.InterpolateKeyframes(self.curframe, {'strength':self.initstrength, 'strengthrandrange':self.strengthrandrange, 'direction_x':self.direction[0], 'direction_y':self.direction[1]}, self.keyframes) 32 self.initstrength = newvars['strength'] 33 self.strengthrandrange = newvars['strengthrandrange'] 34 self.direction = [newvars['direction_x'], newvars['direction_y']] 35 36 if self.strengthrandrange != 0.0: 37 self.strength = RandomiseStrength(self.initstrength, self.strengthrandrange) 38 39 self.curframe = self.curframe + 1 40 41 def GetForce(self, pos): 42 force = [self.strength * self.direction[0], self.strength * self.direction[1]] 43 44 return force 45 46 def GetForceOnParticle(self, particle): 47 return self.GetForce(particle.pos) 48 49 def CreateKeyframe(self, frame, strength = None, strengthrandrange = None, direction = [None, None], interpolationtype = INTERPOLATIONTYPE_LINEAR): 50 return keyframes.CreateKeyframe(self.keyframes, frame, {'strength':strength, 'strengthrandrange':strengthrandrange, 'direction_x':direction[0], 'direction_y':direction[1], 'interpolationtype':interpolationtype}) 51 52 def ConsolidateKeyframes(self): 53 keyframes.ConsolidateKeyframes(self.keyframes, self.curframe, {'strength':self.initstrength, 'strengthrandrange':self.strengthrandrange, 'direction_x':self.direction[0], 'direction_y':self.direction[1]}) 54 55 def SetStrength(self, newstrength): 56 self.CreateKeyframe(self.curframe, strength = newstrength) 57 58 def SetStrengthRandRange(self, newstrengthrandrange): 59 self.CreateKeyframe(self.curframe, strengthrandrange = newstrengthrandrange) 60 61 def SetDirection(self, newdirection): 62 self.CreateKeyframe(self.curframe, direction = newdirection) 63 64 65 class PointGravity: 66 def __init__(self, strength = 0.0, strengthrandrange = 0.0, pos = (0, 0)): 67 self.selected = False 68 self.type = "point" 69 self.initstrength = strength 70 self.strength = strength 71 self.strengthrandrange = strengthrandrange 72 self.pos = pos 73 74 self.keyframes = [] 75 self.CreateKeyframe(0, self.strength, self.strengthrandrange, self.pos) 76 self.curframe = 0 77 78 def Update(self): 79 newvars = interpolate.InterpolateKeyframes(self.curframe, {'strength':self.initstrength, 'strengthrandrange':self.strengthrandrange, 'pos_x':self.pos[0], 'pos_y':self.pos[1]}, self.keyframes) 80 self.initstrength = newvars['strength'] 81 self.strengthrandrange = newvars['strengthrandrange'] 82 self.pos = (newvars['pos_x'], newvars['pos_y']) 83 84 if self.strengthrandrange != 0.0: 85 self.strength = RandomiseStrength(self.initstrength, self.strengthrandrange) 86 else: 87 self.strength = self.initstrength 88 89 self.curframe = self.curframe + 1 90 91 def GetForce(self, pos): 92 distsquared = (pow(float(pos[0] - self.pos[0]), 2.0) + pow(float(pos[1] - self.pos[1]), 2.0)) 93 if distsquared == 0.0: 94 return [0.0, 0.0] 95 96 forcemag = (self.strength * UNIVERSAL_CONSTANT_OF_MAKE_GRAVITY_LESS_STUPIDLY_SMALL) / (distsquared) 97 98 # Calculate normal vector from pos to the gravity point and multiply by force magnitude to find force vector 99 dist = sqrt(distsquared) 100 dx = float(self.pos[0] - pos[0]) / dist 101 dy = float(self.pos[1] - pos[1]) / dist 102 103 force = [forcemag * dx, forcemag * dy] 104 105 return force 106 107 def GetForceOnParticle(self, particle): 108 return self.GetForce(particle.pos) 109 110 def GetMaxForce(self): 111 return self.strength * UNIVERSAL_CONSTANT_OF_MAKE_GRAVITY_LESS_STUPIDLY_SMALL 112 113 def CreateKeyframe(self, frame, strength = None, strengthrandrange = None, pos = (None, None), interpolationtype = INTERPOLATIONTYPE_LINEAR): 114 return keyframes.CreateKeyframe(self.keyframes, frame, {'strength':strength, 'strengthrandrange':strengthrandrange, 'pos_x':pos[0], 'pos_y':pos[1], 'interpolationtype':interpolationtype}) 115 116 def ConsolidateKeyframes(self): 117 keyframes.ConsolidateKeyframes(self.keyframes, self.curframe, {'strength':self.initstrength, 'strengthrandrange':self.strengthrandrange, 'pos_x':self.pos[0], 'pos_y':self.pos[1]}) 118 119 def SetStrength(self, newstrength): 120 self.CreateKeyframe(self.curframe, strength = newstrength) 121 122 def SetStrengthRandRange(self, newstrengthrandrange): 123 self.CreateKeyframe(self.curframe, strengthrandrange = newstrengthrandrange) 124 125 def SetPos(self, newpos): 126 self.CreateKeyframe(self.curframe, pos = newpos) 127 128 129 class VortexGravity(PointGravity): 130 def __init__(self, strength = 0.0, strengthrandrange = 0.0, pos = (0, 0)): 131 PointGravity.__init__(self, strength, strengthrandrange, pos) 132 self.type = "vortex" 133 134 self.CreateKeyframe(0, self.strength, self.strengthrandrange, self.pos) 135 136 def Update(self): 137 newvars = interpolate.InterpolateKeyframes(self.curframe, {'strength':self.initstrength, 'strengthrandrange':self.strengthrandrange, 'pos_x':self.pos[0], 'pos_y':self.pos[1]}, self.keyframes) 138 self.initstrength = newvars['strength'] 139 self.strengthrandrange = newvars['strengthrandrange'] 140 self.pos = (newvars['pos_x'], newvars['pos_y']) 141 142 if self.strengthrandrange != 0.0: 143 self.strength = RandomiseStrength(self.initstrength, self.strengthrandrange) 144 else: 145 self.strength = self.initstrength 146 147 self.curframe = self.curframe + 1 148 149 def GetForce(self, pos): 150 try: 151 self.alreadyshownerror 152 except: 153 print ("WARNING: VortexGravity relies upon particle velocities as well as positions, and so its \ 154 force can only be obtained using GetForceOnParticle([PyIgnition particle object]).".replace("\t", "")) 155 self.alreadyshownerror = True 156 157 return [0.0, 0.0] 158 159 def GetForceOnParticle(self, particle): 160 # This uses F = m(v^2 / r) (the formula for centripetal force on an object moving in a circle) 161 # to determine what force should be applied to keep an object circling the gravity. A small extra 162 # force (self.strength * VORTEX_ACCELERATION) is added in order to accelerate objects inward as 163 # well, thus creating a spiralling effect. Note that unit mass is assumed throughout. 164 165 distvector = [self.pos[0] - particle.pos[0], self.pos[1] - particle.pos[1]] # Vector from the particle to this gravity 166 try: 167 distmag = sqrt(float(distvector[0] ** 2) + float(distvector[1] ** 2)) # Distance from the particle to this gravity 168 except: 169 return [0.0, 0.0] # This prevents OverflowErrors 170 171 if distmag == 0.0: 172 return [0.0, 0.0] 173 174 if distmag <= VORTEX_SWALLOWDIST: 175 particle.alive = False 176 177 normal = [float(distvector[0]) / distmag, float(distvector[1]) / distmag] # Normal from particle to this gravity 178 179 velocitymagsquared = (particle.velocity[0] ** 2) + (particle.velocity[1] ** 2) # Velocity magnitude squared 180 forcemag = (velocitymagsquared / distmag) + (self.strength * VORTEX_ACCELERATION) # Force magnitude = (v^2 / r) + radial acceleration 181 182 #velparmag = (particle.velocity[0] * normal[0]) + (particle.velocity[1] * normal[1]) # Magnitude of velocity parallel to normal 183 #velpar = [normal[0] * velparmag, normal[1] * velparmag] # Vector of velocity parallel to normal 184 #velperp = [particle.velocity[0] - velpar[0], particle.velocity[1] - velpar[1]] # Vector of velocity perpendicular to normal 185 # 186 #fnpar = [-velperp[1], velperp[0]] # Force normal parallel to normal 187 #fnperp = [velpar[1], -velpar[0]] # Force normal perpendicular to normal 188 # 189 #force = [(fnpar[0] + fnperp[0]) * forcemag, (fnpar[1] + fnperp[1]) * forcemag] 190 191 force = [normal[0] * forcemag, normal[1] * forcemag] # Works, but sometimes goes straight to the gravity w/ little spiraling 192 193 return force 194 195 def CreateKeyframe(self, frame, strength = None, strengthrandrange = None, pos = (None, None), interpolationtype = INTERPOLATIONTYPE_LINEAR): 196 return keyframes.CreateKeyframe(self.keyframes, frame, {'strength':strength, 'strengthrandrange':strengthrandrange, 'pos_x':pos[0], 'pos_y':pos[1], 'interpolationtype':interpolationtype}) 197 198 def ConsolidateKeyframes(self): 199 keyframes.ConsolidateKeyframes(self.keyframes, self.curframe, {'strength':self.initstrength, 'strengthrandrange':self.strengthrandrange, 'pos_x':self.pos[0], 'pos_y':self.pos[1]})