PyIgnition

https://github.com/animatinator/PyIgnition update for Python 3
Clone: git clone https://git.frombelow.net/PyIgnition.git
Log | Files | Refs | README

particles.py (10898B)


      1 ### EXESOFT PYIGNITION ###
      2 # Copyright David Barker 2010
      3 #
      4 # Particle and ParticleSource objects
      5 
      6 
      7 import keyframes, interpolate, random, math, pygame
      8 from constants import *
      9 
     10 
     11 class Particle:
     12 	def __init__(self, parent, initpos, velocity, life, drawtype = DRAWTYPE_POINT, colour = (0, 0, 0), radius = 0.0, length = 0.0, image = None, keyframes = []):
     13 		self.parent = parent
     14 		self.pos = initpos
     15 		self.velocity = velocity
     16 		self.life = life
     17 		self.drawtype = drawtype
     18 		self.colour = colour
     19 		self.radius = radius
     20 		self.length = length
     21 		self.image = image
     22 		
     23 		self.keyframes = []
     24 		self.keyframes.extend(keyframes[:])
     25 		self.curframe = 0
     26 		
     27 		self.alive = True
     28 	
     29 	def Update(self):
     30 		self.pos = [self.pos[0] + self.velocity[0], self.pos[1] + self.velocity[1]]
     31 		
     32 		if self.life != -1 and self.curframe > self.life:
     33 			self.alive = False
     34 		else:
     35 			if self.life == -1 and self.curframe >= len(self.parent.particlecache):  # If the particle has infinite life and has passed the last cached frame
     36 				self.colour = (self.parent.particlecache[len(self.parent.particlecache) - 1]['colour_r'], self.parent.particlecache[len(self.parent.particlecache) - 1]['colour_g'], self.parent.particlecache[len(self.parent.particlecache) - 1]['colour_b'])
     37 				self.radius = self.parent.particlecache[len(self.parent.particlecache) - 1]['radius']
     38 				self.length = self.parent.particlecache[len(self.parent.particlecache) - 1]['length']
     39 			else:  # Otherwise, get the values for the current frame
     40 				self.colour = (self.parent.particlecache[self.curframe]['colour_r'], self.parent.particlecache[self.curframe]['colour_g'], self.parent.particlecache[self.curframe]['colour_b'])
     41 				self.radius = self.parent.particlecache[self.curframe]['radius']
     42 				self.length = self.parent.particlecache[self.curframe]['length']
     43 			
     44 			self.curframe = self.curframe + 1
     45 	
     46 	def Draw(self, display):
     47 		offset = self.parent.parenteffect.pos
     48 		
     49 		if (self.pos[0] > 10000) or (self.pos[1] > 10000) or (self.pos[0] < -10000) or (self.pos[1] < -10000):
     50 			return
     51 		
     52 		if self.drawtype == DRAWTYPE_POINT:  # Point
     53 			pygame.draw.circle(display, self.colour, (offset[0] + int(self.pos[0]), offset[1] + int(self.pos[1])), 0)
     54 			
     55 		elif self.drawtype == DRAWTYPE_CIRCLE:  # Circle
     56 			pygame.draw.circle(display, self.colour, (offset[0] + int(self.pos[0]), offset[1] + int(self.pos[1])), int(self.radius))
     57 		
     58 		elif self.drawtype == DRAWTYPE_LINE:
     59 			if self.length == 0.0:
     60 				pygame.draw.circle(display, self.colour, (offset[0] + int(self.pos[0]), offset[1] + int(self.pos[1])), 0)
     61 			
     62 			else:
     63 				# Vector = (velocity / mag(velocity)) * length (a line of magnitude 'length' in
     64 				# direction of velocity); this is calculated as velocity / (mag(velocity) / length)
     65 				# so that parts consistent for both components in the final calculation are only calculated once
     66 				velocitymagoverlength = math.sqrt(self.velocity[0]**2 + self.velocity[1]**2) / self.length
     67 				
     68 				if velocitymagoverlength > 0.0:  # Avoid division-by-zero errors by handling lines with zero velocity separately
     69 					linevec = [(self.velocity[0] / velocitymagoverlength), (self.velocity[1] / velocitymagoverlength)]
     70 				else:
     71 					linevec = [self.length, 0.0]  # Draw a line pointing to the right
     72 				
     73 				endpoint = [offset[0] + int(self.pos[0] + linevec[0]), offset[1] + int(self.pos[1] + linevec[1])]
     74 				pygame.draw.aaline(display, self.colour, (offset[0] + int(self.pos[0]), offset[1] + int(self.pos[1])), endpoint)
     75 			
     76 		elif self.drawtype == DRAWTYPE_SCALELINE:  # Scaling line (scales with velocity)
     77 			endpoint = [offset[0] + int(self.pos[0] + self.velocity[0]), offset[1] + int(self.pos[1] + self.velocity[1])]
     78 			pygame.draw.aaline(display, self.colour, (offset[0] + int(self.pos[0]), offset[1] + int(self.pos[1])), endpoint)
     79 			
     80 		elif self.drawtype == DRAWTYPE_BUBBLE:  # Bubble
     81 			if self.radius >= 1.0:
     82 				pygame.draw.circle(display, self.colour, (offset[0] + int(self.pos[0]), offset[1] + int(self.pos[1])), int(self.radius), 1)
     83 			else:  # Pygame won't draw circles with thickness < radius, so if radius is smaller than one don't bother trying to set thickness
     84 				pygame.draw.circle(display, self.colour, (offset[0] + int(self.pos[0]), offset[1] + int(self.pos[1])), int(self.radius))
     85 		
     86 		elif self.drawtype == DRAWTYPE_IMAGE:  # Image
     87 			if self.image != None:
     88 				size = self.image.get_size()
     89 				display.blit(self.image, (offset[0] + int(self.pos[0] - (size[1]* 0.5)), offset[1] + int(self.pos[1] - (size[1] * 0.5))))
     90 
     91 	def CreateKeyframe(self, frame, colour = (None, None, None), radius = None, length = None):
     92 		keyframes.CreateKeyframe(self.keyframes, frame, {'colour_r':colour[0], 'colour_g':colour[1], 'colour_b':colour[2], 'radius':radius, 'length':length})
     93 
     94 
     95 class ParticleSource:
     96 	def __init__(self, parenteffect, pos, initspeed, initdirection, initspeedrandrange, initdirectionrandrange, particlesperframe, particlelife, genspacing, drawtype = 0, colour = (0, 0, 0), radius = 0.0, length = 0.0, imagepath = None):
     97 		self.selected = False
     98 		self.parenteffect = parenteffect
     99 		self.pos = pos
    100 		self.initspeed = initspeed
    101 		self.initdirection = initdirection
    102 		self.initspeedrandrange = initspeedrandrange
    103 		self.initdirectionrandrange = initdirectionrandrange
    104 		self.particlesperframe = particlesperframe
    105 		self.particlelife = particlelife
    106 		self.genspacing = genspacing
    107 		self.colour = colour
    108 		self.drawtype = drawtype
    109 		self.radius = radius
    110 		self.length = length
    111 		self.imagepath = imagepath
    112 		if self.imagepath == None:
    113 			self.image = None
    114 		else:
    115 			self.image = pygame.image.load(self.imagepath).convert_alpha()
    116 		self.drawtype = drawtype
    117 		
    118 		self.keyframes = []
    119 		self.CreateKeyframe(0, self.pos, self.initspeed, self.initdirection, self.initspeedrandrange, self.initdirectionrandrange, self.particlesperframe, self.genspacing)
    120 		self.particlekeyframes = []
    121 		self.particlecache = []
    122 		self.CreateParticleKeyframe(0, colour = self.colour, radius = self.radius, length = self.length)
    123 		self.curframe = 0
    124 	
    125 	def Update(self):
    126 		newvars = interpolate.InterpolateKeyframes(self.curframe, {'pos_x':self.pos[0], 'pos_y':self.pos[1], 'initspeed':self.initspeed, 'initdirection':self.initdirection, 'initspeedrandrange':self.initspeedrandrange, 'initdirectionrandrange':self.initdirectionrandrange, 'particlesperframe':self.particlesperframe, 'genspacing':self.genspacing}, self.keyframes)
    127 		self.pos = (newvars['pos_x'], newvars['pos_y'])
    128 		self.initspeed = newvars['initspeed']
    129 		self.initdirection = newvars['initdirection']
    130 		self.initspeedrandrange = newvars['initspeedrandrange']
    131 		self.initdirectionrandrange = newvars['initdirectionrandrange']
    132 		self.particlesperframe = newvars['particlesperframe']
    133 		self.genspacing = newvars['genspacing']
    134 		
    135 		particlesperframe = self.particlesperframe
    136 		
    137 		if (self.genspacing == 0) or ((self.curframe % self.genspacing) == 0):
    138 			for i in range(0, int(particlesperframe)):
    139 				self.CreateParticle()
    140 		
    141 		self.curframe = self.curframe + 1
    142 	
    143 	def CreateParticle(self):
    144 		if self.initspeedrandrange != 0.0:
    145 			speed = self.initspeed + (float(random.randrange(int(-self.initspeedrandrange * 100.0), int(self.initspeedrandrange * 100.0))) / 100.0)
    146 		else:
    147 			speed = self.initspeed
    148 		if self.initdirectionrandrange != 0.0:
    149 			direction = self.initdirection + (float(random.randrange(int(-self.initdirectionrandrange * 100.0), int(self.initdirectionrandrange * 100.0))) / 100.0)
    150 		else:
    151 			direction = self.initdirection
    152 		velocity = [speed * math.sin(direction), -speed * math.cos(direction)]
    153 		newparticle = Particle(self, initpos = self.pos, velocity = velocity, life = self.particlelife, drawtype = self.drawtype, colour = self.colour, radius = self.radius, length = self.length, image = self.image, keyframes = self.particlekeyframes)
    154 		self.parenteffect.AddParticle(newparticle)
    155 
    156 	def CreateKeyframe(self, frame, pos = (None, None), initspeed = None, initdirection = None, initspeedrandrange = None, initdirectionrandrange = None, particlesperframe = None, genspacing = None, interpolationtype = INTERPOLATIONTYPE_LINEAR):
    157 		return keyframes.CreateKeyframe(self.keyframes, frame, {'pos_x':pos[0], 'pos_y':pos[1], 'initspeed':initspeed, 'initdirection':initdirection, 'initspeedrandrange':initspeedrandrange, 'initdirectionrandrange':initdirectionrandrange, 'particlesperframe':particlesperframe, 'genspacing':genspacing, 'interpolationtype':interpolationtype})
    158 	
    159 	def CreateParticleKeyframe(self, frame, colour = (None, None, None), radius = None, length = None, interpolationtype = INTERPOLATIONTYPE_LINEAR):
    160 		newframe = keyframes.CreateKeyframe(self.particlekeyframes, frame, {'colour_r':colour[0], 'colour_g':colour[1], 'colour_b':colour[2], 'radius':radius, 'length':length, 'interpolationtype':interpolationtype})
    161 		self.PreCalculateParticles()
    162 		return newframe
    163 	
    164 	def GetKeyframeValue(self, keyframe):
    165 		return keyframe.frame
    166 	
    167 	def PreCalculateParticles(self):
    168 		self.particlecache = []  # Clear the cache
    169 		
    170 		# If the particle has infinite life, interpolate for each frame up until its last keyframe
    171 		if self.particlelife == -1:
    172 			particlelife = max(self.particlekeyframes, key = self.GetKeyframeValue).frame
    173 		else:  # Otherwise, interpolate the particle variables for each frame of its life
    174 			particlelife = self.particlelife
    175 		
    176 		for i in range(0, particlelife + 1):
    177 			vars = interpolate.InterpolateKeyframes(i, {'colour_r':0, 'colour_g':0, 'colour_b':0, 'radius':0, 'length':0}, self.particlekeyframes)
    178 			self.particlecache.append(vars)
    179 	
    180 	def ConsolidateKeyframes(self):
    181 		keyframes.ConsolidateKeyframes(self.keyframes, self.curframe, {'pos_x':self.pos[0], 'pos_y':self.pos[1], 'initspeed':self.initspeed, 'initdirection':self.initdirection, 'initspeedrandrange':self.initspeedrandrange, 'initdirectionrandrange':self.initdirectionrandrange, 'particlesperframe':self.particlesperframe, 'genspacing':self.genspacing})
    182 	
    183 	def SetPos(self, newpos):
    184 		self.CreateKeyframe(self.curframe, pos = newpos)
    185 	
    186 	def SetInitSpeed(self, newinitspeed):
    187 		self.CreateKeyframe(self.curframe, initspeed = newinitspeed)
    188 	
    189 	def SetInitDirection(self, newinitdirection):
    190 		self.CreateKeyframe(self.curframe, initdirection = newinitdirection)
    191 	
    192 	def SetInitSpeedRandRange(self, newinitspeedrandrange):
    193 		self.CreateKeyframe(self.curframe, initspeedrandrange = newinitspeedrandrange)
    194 	
    195 	def SetInitDirectionRandRange(self, newinitdirectionrandrange):
    196 		self.CreateKeyframe(self.curframe, initdirectionrandrange = newinitdirectionrandrange)
    197 	
    198 	def SetParticlesPerFrame(self, newparticlesperframe):
    199 		self.CreateKeyframe(self.curframe, particlesperframe = newparticlesperframe)
    200 	
    201 	def SetGenSpacing(self, newgenspacing):
    202 		self.CreateKeyframe(self.curframe, genspacing = newgenspacing)