class Sun(ParticleSystem): # total particles total_particles = 350 # duration duration = -1 # gravity gravity = Point2(0, 0) # angle angle = 90.0 angle_var = 360.0 # speed of particles speed = 20.0 speed_var = 5.0 # radial radial_accel = 0 radial_accel_var = 0 # tangential tangential_accel = 0.0 tangential_accel_var = 0.0 # emitter variable position pos_var = Point2(0, 0) # life of particles life = 1.0 life_var = 0.5 # emits per frame emission_rate = total_particles / life # color of particles start_color = Color(0.75, 0.25, 0.12, 1.0) start_color_var = Color(0.0, 0.0, 0.0, 0.0) end_color = Color(0.0, 0.0, 0.0, 0.0) end_color_var = Color(0.0, 0.0, 0.0, 0.0) # size, in pixels size = 40.0 size_var = 00.0 # blend additive blend_additive = True # color modulate color_modulate = True
class Death(ParticleSystem): pic = resources.particleTexture texture = pic.get_texture() # total particles total_particles = 1000 # duration duration = 0.12 # gravity gravity = Point2(0, 0) # angle angle = 90 angle_var = 360 # radial radial_accel = -1000 radial_accel_var = 100 # speed of particles speed = 400 speed_var = 50 # emitter variable position pos_var = Point2(5, 5) # life of particles life = 0.3 life_var = 0.1 # emits per frame # emission_rate = total_particles / life emission_rate = 1000 start_color = Color(1, 0.53, 0, 1.0) start_color_var = Color(0.0, 0.0, 0.0, 0.0) end_color = Color(1, 1, 1, 0) end_color_var = Color(0.0, 0.0, 0.0, 0.0) # size, in pixels size = 15 size_var = 3 # blend additive blend_additive = True # color modulate color_modulate = True
class Smoke(ParticleSystem): # total particles total_particles = 80 # duration duration = -1 # gravity gravity = Point2(0, 0) # angle angle = 90.0 angle_var = 10.0 # speed of particles speed = 25.0 speed_var = 10.0 # radial radial_accel = 5 radial_accel_var = 0 # tangential tangential_accel = 0.0 tangential_accel_var = 0.0 # emitter variable position pos_var = Point2(0.1, 0) # life of particles life = 4.0 life_var = 1.0 # size, in pixels size = 40.0 size_var = 10.0 # emits per frame emission_rate = total_particles / life start_color = Color(0.5, 0.5, 0.5, 0.1) start_color_var = Color(0, 0, 0, 0.1) end_color = Color(0.5, 0.5, 0.5, 0.1) end_color_var = Color(0, 0, 0, 0.1) # blend additive blend_additive = True # color modulate color_modulate = False
def _calculate_vertex_points(self): w = float(self.texture.width) h = float(self.texture.height) index_points = [] vertex_points_idx = [] texture_points_idx = [] for x in range(0, self.grid.x + 1): for y in range(0, self.grid.y + 1): vertex_points_idx += [-1, -1, -1] texture_points_idx += [-1, -1] for x in range(0, self.grid.x): for y in range(0, self.grid.y): x1 = x * self.x_step x2 = x1 + self.x_step y1 = y * self.y_step y2 = y1 + self.y_step # d <-- c # ^ # | # a --> b a = x * (self.grid.y + 1) + y b = (x + 1) * (self.grid.y + 1) + y c = (x + 1) * (self.grid.y + 1) + (y + 1) d = x * (self.grid.y + 1) + (y + 1) # 2 triangles: a-b-d, b-c-d index_points += [a, b, d, b, c, d] # triangles l1 = (a * 3, b * 3, c * 3, d * 3) l2 = (Point3(x1, y1, 0), Point3(x2, y1, 0), Point3(x2, y2, 0), Point3(x1, y2, 0)) # building the vertex for i in range(len(l1)): vertex_points_idx[l1[i]] = l2[i].x vertex_points_idx[l1[i] + 1] = l2[i].y vertex_points_idx[l1[i] + 2] = l2[i].z # building the texels tex1 = (a * 2, b * 2, c * 2, d * 2) tex2 = (Point2(x1, y1), Point2(x2, y1), Point2(x2, y2), Point2(x1, y2)) for i in range(len(tex1)): texture_points_idx[tex1[i]] = tex2[i].x / w texture_points_idx[tex1[i] + 1] = tex2[i].y / h return index_points, vertex_points_idx, texture_points_idx
class Explosion(ParticleSystem): # total particle total_particles = 700 # duration duration = 0.1 # gravity gravity = Point2(0, -90) # angle angle = 90.0 angle_var = 360.0 # radial radial_accel = 0 radial_accel_var = 0 # speed of particles speed = 70.0 speed_var = 40.0 # emitter variable position pos_var = Point2(0, 0) # life of particles life = 5.0 life_var = 2.0 # emits per frame emission_rate = total_particles / duration # color of particles start_color = Color(0.7, 0.2, 0.1, 1.0) start_color_var = Color(0.5, 0.5, 0.5, 0.0) end_color = Color(0.5, 0.5, 0.5, 0.0) end_color_var = Color(0.5, 0.5, 0.5, 0.0) # size, in pixels size = 15.0 size_var = 10.0 # blend additive blend_additive = False # color modulate color_modulate = True
class Fireworks(ParticleSystem): # total particles total_particles = 3000 # duration duration = -1 # gravity gravity = Point2(0, -90) # angle angle = 90 angle_var = 20 # radial radial_accel = 0 radial_accel_var = 0 # speed of particles speed = 180 speed_var = 50 # emitter variable position pos_var = Point2(0, 0) # life of particles life = 3.5 life_var = 1 # emits per frame emission_rate = total_particles / life # color of particles start_color = Color(0.5, 0.5, 0.5, 1.0) start_color_var = Color(0.5, 0.5, 0.5, 1.0) end_color = Color(0.1, 0.1, 0.1, 0.2) end_color_var = Color(0.1, 0.1, 0.1, 0.2) # size, in pixels size = 8.0 size_var = 2.0 # blend additive blend_additive = False # color modulate color_modulate = True
def spawnStompCloud(self, reverse): # show cloud particles from stomps stomp_cloud = Meteor() stomp_cloud.start_color = cocos.particle.Color(0.3, 0.3, 0.3, 1.0) stomp_cloud.end_color = cocos.particle.Color(0.5, 0.5, 0.5, 0.2) stomp_cloud.duration = 0.1 stomp_cloud.blend_additive = False stomp_cloud.size = 10 + (10 * self.battle_mech.getSize() / 4) stomp_cloud.speed = 20 stomp_cloud.gravity = Point2(0, 0) # TODO: offer decreased particle emission rate to improve performance stomp_cloud.emission_rate = 100 stomp_cloud.life = 0.5 stomp_cloud.life_var = 0.1 if not reverse: stomp_cloud.position = self.indicator.position[0] + (self.img_static.width // 4), \ self.indicator.position[1] - self.indicator.height // 5 else: stomp_cloud.position = self.indicator.position[0] - (self.img_static.width // 4), \ self.indicator.position[1] - self.indicator.height // 5 self.add(stomp_cloud, z=1) stomp_action = Delay(stomp_cloud.duration + stomp_cloud.life + stomp_cloud.life_var) \ + CallFunc(stomp_cloud.kill) self.do(stomp_action)
def __init__(self): self.rot = 0 # left-bottom corner position corresponding to board array self.pos = Point2((Settings.COLUMN - self.n) // 2, Settings.ROW - 2) self.color_shape()
def update_grid(self): win_size = director.get_window_size() grid_size = (win_size[0] / g_grid_size), (win_size[1] / g_grid_size) for x in xrange(grid_size[0] + 1): for y in xrange(grid_size[1] + 1): world_grid_pos = x, y world_pos = grid_to_world(world_grid_pos) aligned_world_pos = align_pos_to_grid(self.game_world.point_to_local(world_pos)) # Visible if anything is visible within a radius fog_grid_pos = world_to_grid(aligned_world_pos) fog_visible = self.grid_pos_is_active(fog_grid_pos) if fog_visible: radius = g_fog_neighbour_radius for radius_x in xrange(-radius, radius + 1): if not fog_visible: break for radius_y in xrange(-radius, radius + 1): new_fog_grid_pos = tuple(fog_grid_pos + Point2(radius_x, radius_y)) fog_visible = self.grid_pos_is_active(new_fog_grid_pos) if not fog_visible: break self.squares_screen_space[world_grid_pos] = fog_visible for square in self.grid_canvases: if square.needs_update(): square.free()
class Rain(ParticleSystem): def __init__(self, w, h): ParticleSystem.__init__(self, False) self.pos_var = Point2(w, 0) self.speed = h * 3.5 self.speed_var = h * 2.5 texture = pyglet.resource.image('res/particles/rain2.png').texture # def load_texture(self): # return pyglet.image.load('res/particles/rain.png').texture # total paticles total_particles = 2000 # duration duration = -1 # gravity gravity = Point2(0, -100) # angle angle = -105.0 angle_var = 0 # speed of particles # speed = 300.0 # speed_var = 0.0 # radial # radial_accel = -380 # radial_accel_var = 0 # tangential # tangential_accel = 45.0 # tangential_accel_var = 0.0 # emitter variable position # pos_var = Point2(100, 0) # life of particles life = 12.0 life_var = 0.0 # emits per frame emission_rate = total_particles / life # color of particles start_color = Color(1, 1, 1, 0.5) # start_color_var = Color(0, 0, 0, 0.0) end_color = Color(1, 1, 1, 0) # end_color_var = Color(0, 0, 0, 0, 0.0) # size, in pixels size = 20.0 size_var = 10.0 # blend additive blend_additive = True
def __init__(self): # load the image script_dir = os.path.dirname('.') path = os.path.join(script_dir, 'datas/cooling_map.png') self.image = pyglet.image.load(path) # get the texture self.texture = self.image.get_texture() # get image size x, y = self.image.width, self.image.height # size of the grid: 20 x 20 # The image will be slipted in 20 squares x 20 tiles self.grid_size = Point2(10, 12) # size of each tile self.x_step = x // self.grid_size.x self.y_step = y // self.grid_size.y # calculate vertex, textures depending on image size idx_pts, ver_pts_idx, tex_pts_idx = self._calculate_vertex_points() # Generates an indexed vertex array with texture, vertex and color # http://www.glprogramming.com/red/chapter02.html#name6 nb_vertex = (self.grid_size.x + 1) * (self.grid_size.y + 1) self.vertex_list = pyglet.graphics.vertex_list_indexed( nb_vertex, idx_pts, "t2f", "v3f/stream", "c4B") self.vertex_list.vertices = ver_pts_idx # vertex points self.vertex_list.tex_coords = tex_pts_idx # texels self.vertex_list.colors = (255, 255, 255, 255) * self.vertex_list.count # call the "step" method every frame when the layer is active self.elapsed = 0
class Explosion0(ParticleSystem): # total particles total_particles = 500 # duration duration = 0.05 # gravity gravity = Point2(0, 0) # angle angle = 90.0 angle_var = 360 # radial radial_accel = -200 radial_accel_var = 40 # speed of particles speed = 100 speed_var = 80 # emitter variable position pos_var = Point2(5, 5) # life of particles life = 0.18 life_var = 0.1 # emits per frame emission_rate = total_particles / life # color of particles start_color = Color(0.76, 0.25, 0.12, 1.0) start_color_var = Color(0.0, 0.0, 0.0, 0.0) end_color = Color(0.0, 0.0, 0.0, 1.0) end_color_var = Color(0.0, 0.0, 0.0, 0.0) # size, in pixels size = 70.0 size_var = 10.0 # blend additive blend_additive = True # color modulate color_modulate = True
def moveToCell(self, col, row, reverse=False, func=None): num_steps = 1 + int(math.ceil(Point2(col, row).distance(Point2(self.battle_mech.col, self.battle_mech.row)))) time = self.timeBySize() * (num_steps * 2) self.battle_mech.col = col self.battle_mech.row = row shadow_rect = self.shadow.get_rect() shadow_rect.bottomleft = (col * 32), (row * 32) rect = self.img_static.get_rect() rect.bottomleft = (col * Board.TILE_SIZE) - (self.img_static.width // 2 - self.shadow.width // 2), \ (row * Board.TILE_SIZE) actions = MoveTo(rect.center, duration=time) if func is not None: actions += CallFunc(func) self.do(actions) shadow_action = MoveTo(shadow_rect.center, duration=time) self.shadow.do(shadow_action) # play movement sounds sound_index = self.battle_mech.getSize() - 1 stomp_sound = Resources.stomp_sounds[sound_index] stomp_action = Delay(0) for i in range(num_steps): # use channel 0 and 1 for alternating steps stomp_channel = pygame.mixer.Channel(i % 2) stomp_reverse = True if i % 2 == (1 if reverse else 0): stomp_reverse = False stomp_action += CallFunc(stomp_channel.play, stomp_sound) + Delay(time / num_steps) \ + CallFunc(self.spawnStompCloud, stomp_reverse) self.do(stomp_action) return time
def __init__(self): super( Character, self ).__init__() self.pos = Point2( COLUMNS//2-1, ROWS ) self.status = 'STAY' s0 = pyglet.resource.image('fez.png') sprites = [s0] anim = pyglet.image.Animation.from_image_sequence(sprites, 0.5, True) self.sprite = pyglet.sprite.Sprite(anim)
class BigExplosion(cocos.particle_systems.Explosion): """玩家或敌人爆炸粒子系统""" speed = 100.0 # 粒子移动速度 life = 0.5 # 粒子生命期 life_var = 0.2 size = 5.0 # 粒子大小 size_var = 1.0 # 粒子大小偏差 gravity = Point2(0, 0) # 粒子的重力, (0, 0)不受重力影响 start_color = Color(0.7, 0.2, 0.5, 1.0) # 粒子的开始颜色 start_color_var = Color(0.5, 0.5, 0.7, 0.0) # 粒子开始颜色偏差 end_color = Color(0.5, 0.5, 0.5, 0.3) # 粒子的结束颜色 end_color_var = Color(0.5, 0.5, 0.5, 0.0) # 粒子的结束颜色偏差
def __init__(self): super(Block, self).__init__() self.pos = Point2(COLUMNS // 2 - 1, ROWS) self.rot = 0 for x in range(len(self._shape)): for y in range(len(self._shape[x])): if self._shape[x][y]: r = random.random() if r < status.level.prob: color = random.choice(status.level.blocks) else: color = self.color self._shape[x][y] = color
class BrokenBrick(ParticleSystem): total_particles = 4 duration = 0.1 gravity = Point2(0, -600) angle = 90 angle_var = 90.0 speed = 100.0 life = 3.0 size = 8.0 start_color = Color(255, 255, 255, 255) end_color = Color(255, 255, 255, 255) emission_rate = total_particles / duration def __init__(self, pos): super().__init__() self.position = pos self.auto_remove_on_finish = True def load_texture(self): self.__class__.texture = Image.normal_brick2.get_texture()
def __init__(self): super(Flag3D, self).__init__() # load the image self.image = pyglet.resource.image('flag.png') # get the texture self.texture = self.image.get_texture() # get image size x, y = self.image.width, self.image.height # size of the grid: 20 x 20 # The image will be slipted in 20 squares x 20 tiles self.grid_size = Point2(20, 20) # size of each tile self.x_step = x // self.grid_size.x self.y_step = y // self.grid_size.y # calculate vertex, textures depending on image size idx_pts, ver_pts_idx, tex_pts_idx = self._calculate_vertex_points() # Generates an indexed vertex array with texture, vertex and color # http://www.glprogramming.com/red/chapter02.html#name6 self.vertex_list = pyglet.graphics.vertex_list_indexed( (self.grid_size.x + 1) * (self.grid_size.y + 1), idx_pts, "t2f", "v3f/stream", "c4B") self.vertex_list.vertices = ver_pts_idx # vertex points self.vertex_list.tex_coords = tex_pts_idx # texels self.vertex_list.colors = (255, 255, 255, 255) * ( self.grid_size.x + 1) * (self.grid_size.y + 1) # colors # call the "step" method every frame when the layer is active self.schedule(self.step)
def __init__(self): super(GameLayer, self).__init__() # 获得窗口的宽度和高度 s_width, s_height = director.get_window_size() # 创建背景精灵 background = Sprite('images/zippo.jpg') background.position = s_width // 2, s_height // 2 # 添加背景精灵 self.add(background, 0) ps = Fire() ps.gravity = Point2(45, 600) # x,y轴重力加速度 x正值为右边 y正值为上 ps.radial_accel = 60 ps.size = 220 ps.size_var = 50 ps.tangential_accel = 20 ps.tangential_accel_var = 10 ps.life = 0.99 ps.life_var = 0.45 ps.emission_rate = 200 ps.position = 270, 580 self.add(ps)
def init_particle(self): # position # p=self.particles[idx] a = self.particle_life < 0 idxs = a.nonzero() idx = -1 if len(idxs[0]) > 0: idx = idxs[0][0] else: raise ExceptionNoEmptyParticle() # position self.particle_pos[idx][0] = self.pos_var.x * rand() self.particle_pos[idx][1] = self.pos_var.y * rand() # start position self.start_pos[idx][0] = self.x self.start_pos[idx][1] = self.y a = math.radians(self.angle + self.angle_var * rand()) v = Point2(math.cos(a), math.sin(a)) s = self.speed + self.speed_var * rand() dir = v * s # direction self.particle_dir[idx][0] = dir.x self.particle_dir[idx][1] = dir.y # radial accel self.particle_rad[idx] = self.radial_accel + self.radial_accel_var * rand() # tangential accel self.particle_tan[idx] = self.tangential_accel + self.tangential_accel_var * rand() # life life = self.particle_life[idx] = self.life + self.life_var * rand() # Color # start sr = self.start_color.r + self.start_color_var.r * rand() sg = self.start_color.g + self.start_color_var.g * rand() sb = self.start_color.b + self.start_color_var.b * rand() sa = self.start_color.a + self.start_color_var.a * rand() self.particle_color[idx][0] = sr self.particle_color[idx][1] = sg self.particle_color[idx][2] = sb self.particle_color[idx][3] = sa # end er = self.end_color.r + self.end_color_var.r * rand() eg = self.end_color.g + self.end_color_var.g * rand() eb = self.end_color.b + self.end_color_var.b * rand() ea = self.end_color.a + self.end_color_var.a * rand() delta_color_r = (er - sr) / life delta_color_g = (eg - sg) / life delta_color_b = (eb - sb) / life delta_color_a = (ea - sa) / life self.particle_delta_color[idx][0] = delta_color_r self.particle_delta_color[idx][1] = delta_color_g self.particle_delta_color[idx][2] = delta_color_b self.particle_delta_color[idx][3] = delta_color_a # size self.particle_size[idx] = self.size + self.size_var * rand() self._scale_particle_size() # gravity self.particle_grav[idx][0] = self.gravity.x self.particle_grav[idx][1] = self.gravity.y
class ParticleSystem(CocosNode): """ Base class for many flawors of cocos particle systems The most easy way to customize is subclass and redefine some class members; see particle_systems by example. If you want to use a custom texture remember it should hold only one image, so don't use texture = pyglet.resource.image(...) (it would produce an atlas, ie multiple images in a texture); using texture = pyglet.image.load(...) is fine """ # type of particle POSITION_FREE, POSITION_GROUPED = range(2) #: is the particle system active ? active = True #: duration in seconds of the system. -1 is infinity duration = 0 #: time elapsed since the start of the system (in seconds) elapsed = 0 #: Gravity of the particles gravity = Point2(0.0, 0.0) #: position is from "superclass" CocosNode #: Position variance pos_var = Point2(0.0, 0.0) #: The angle (direction) of the particles measured in degrees angle = 0.0 #: Angle variance measured in degrees; angle_var = 0.0 #: The speed the particles will have. speed = 0.0 #: The speed variance speed_var = 0.0 #: Tangential acceleration tangential_accel = 0.0 #: Tangential acceleration variance tangential_accel_var = 0.0 #: Radial acceleration radial_accel = 0.0 #: Radial acceleration variance radial_accel_var = 0.0 #: Size of the particles size = 0.0 #: Size variance size_var = 0.0 #: How many seconds will the particle live life = 0 #: Life variance life_var = 0 #: Start color of the particles start_color = Color(0.0, 0.0, 0.0, 0.0) #: Start color variance start_color_var = Color(0.0, 0.0, 0.0, 0.0) #: End color of the particles end_color = Color(0.0, 0.0, 0.0, 0.0) #: End color variance end_color_var = Color(0.0, 0.0, 0.0, 0.0) #: Maximum particles total_particles = 0 #: texture for the particles. Lazy loaded because Intel weakness, #235 texture = None #: blend additive blend_additive = False #: color modulate color_modulate = True # position type position_type = POSITION_GROUPED def __init__(self, fallback=None): """ fallback can be None, True, False; default is None False: use point sprites, faster, not always availabel True: use quads, slower but always available) None: autodetect, use the faster available """ super(ParticleSystem, self).__init__() # particles # position x 2 self.particle_pos = numpy.zeros((self.total_particles, 2), numpy.float32) # direction x 2 self.particle_dir = numpy.zeros((self.total_particles, 2), numpy.float32) # rad accel x 1 self.particle_rad = numpy.zeros((self.total_particles, 1), numpy.float32) # tan accel x 1 self.particle_tan = numpy.zeros((self.total_particles, 1), numpy.float32) # gravity x 2 self.particle_grav = numpy.zeros((self.total_particles, 2), numpy.float32) # colors x 4 self.particle_color = numpy.zeros((self.total_particles, 4), numpy.float32) # delta colors x 4 self.particle_delta_color = numpy.zeros((self.total_particles, 4), numpy.float32) # life x 1 self.particle_life = numpy.zeros((self.total_particles, 1), numpy.float32) self.particle_life.fill(-1.0) # size x 1 self.particle_size = numpy.zeros((self.total_particles, 1), numpy.float32) # particle size in respect to node scaling and window resizing self.particle_size_scaled = self.particle_size # start position self.start_pos = numpy.zeros((self.total_particles, 2), numpy.float32) #: How many particles can be emitted per second self.emit_counter = 0 #: Count of particles self.particle_count = 0 #: auto remove when particle finishes self.auto_remove_on_finish = False self.load_texture() #: rendering mode; True is quads, False is point_sprites, None is auto fallback if fallback is None: fallback = not point_sprites_available() self.fallback = fallback if fallback: self._fallback_init() self.draw = self.draw_fallback else: self._init_shader() self.schedule(self.step) def _init_shader(self): vertex_code = """ #version 120 attribute float particle_size; void main() { gl_PointSize = particle_size; gl_Position = ftransform(); gl_FrontColor = gl_Color; } """ frag_code = """ #version 120 uniform sampler2D sprite_texture; void main() { gl_FragColor = gl_Color * texture2D(sprite_texture, gl_PointCoord); } """ self.sprite_shader = ShaderProgram.simple_program('sprite', vertex_code, frag_code) self.particle_size_idx = gl.glGetAttribLocation(self.sprite_shader.program, b'particle_size') def load_texture(self): if self.texture is None: pic = pyglet.image.load('fire.png', file=pyglet.resource.file('fire.png')) self.__class__.texture = pic.get_texture() def on_enter(self): super(ParticleSystem, self).on_enter() director.push_handlers(self) # self.add_particle() def on_exit(self): super(ParticleSystem, self).on_exit() director.remove_handlers(self) def on_cocos_resize(self, usable_width, usable_height): self._scale_particle_size() @CocosNode.scale.setter def scale(self, s): # Extend CocosNode scale setter property # The use of super(CocosNode, CocosNode).name.__set__(self, s) in the setter function is no mistake. # To delegate to the previous implementation of the setter, control needs to pass # through the __set__() method of the previously defined name property. However, the # only way to get to this method is to access it as a class variable instead of an instance # variable. This is what happens with the super(CocosNode, CocosNode) operation. super(ParticleSystem, ParticleSystem).scale.__set__(self, s) self._scale_particle_size() def _scale_particle_size(self): """Resize the particles in respect to node scaling and window resize; only used when rendering with shaders. """ node = self scale = 1.0 while node.parent: scale *= node.scale node = node.parent if director.autoscale: scale *= 1.0 * director._usable_width / director._window_virtual_width self.particle_size_scaled = self.particle_size * scale def draw(self): gl.glPushMatrix() self.transform() # color preserve - at least nvidia 6150SE needs that gl.glPushAttrib(gl.GL_CURRENT_BIT) # glPointSize(self.get_scaled_particle_size()) gl.glEnable(gl.GL_TEXTURE_2D) gl.glEnable(gl.GL_PROGRAM_POINT_SIZE) # glBindTexture(GL_TEXTURE_2D, self.texture.id) gl.glEnable(gl.GL_POINT_SPRITE) gl.glTexEnvi(gl.GL_POINT_SPRITE, gl.GL_COORD_REPLACE, gl.GL_TRUE) gl.glEnableClientState(gl.GL_VERTEX_ARRAY) vertex_ptr = PointerToNumpy(self.particle_pos) gl.glVertexPointer(2, gl.GL_FLOAT, 0, vertex_ptr) gl.glEnableClientState(gl.GL_COLOR_ARRAY) color_ptr = PointerToNumpy(self.particle_color) gl.glColorPointer(4, gl.GL_FLOAT, 0, color_ptr) gl.glEnableVertexAttribArray(self.particle_size_idx) size_ptr = PointerToNumpy(self.particle_size_scaled) gl.glVertexAttribPointer(self.particle_size_idx, 1, gl.GL_FLOAT, False, 0, size_ptr) gl.glPushAttrib(gl.GL_COLOR_BUFFER_BIT) gl.glEnable(gl.GL_BLEND) if self.blend_additive: gl.glBlendFunc(gl.GL_SRC_ALPHA, gl.GL_ONE) else: gl.glBlendFunc(gl.GL_SRC_ALPHA, gl.GL_ONE_MINUS_SRC_ALPHA) # mode = GLint() # glTexEnviv( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, mode ) # # if self.color_modulate: # glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE ) # else: # glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE ) self.sprite_shader.install() self.sprite_shader.usetTex('sprite_texture', 0, gl.GL_TEXTURE_2D, self.texture.id) gl.glDrawArrays(gl.GL_POINTS, 0, self.total_particles) self.sprite_shader.uninstall() # un -blend gl.glPopAttrib() # color restore gl.glPopAttrib() # restore env mode # glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, mode) # disable states gl.glDisableVertexAttribArray(self.particle_size_idx) gl.glDisableClientState(gl.GL_COLOR_ARRAY) gl.glDisableClientState(gl.GL_VERTEX_ARRAY) gl.glDisable(gl.GL_POINT_SPRITE) gl.glDisable(gl.GL_PROGRAM_POINT_SIZE) gl.glDisable(gl.GL_TEXTURE_2D) gl.glPopMatrix() def step(self, delta): # update particle count self.particle_count = numpy.sum(self.particle_life >= 0) if self.active: rate = 1.0 / self.emission_rate self.emit_counter += delta # if random.random() < 0.01: # delta += 0.5 while self.particle_count < self.total_particles and self.emit_counter > rate: self.add_particle() self.emit_counter -= rate self.elapsed += delta if self.duration != -1 and self.duration < self.elapsed: self.stop_system() self.update_particles(delta) if (not self.active and self.particle_count == 0 and self.auto_remove_on_finish is True): self.unschedule(self.step) self.parent.remove(self) def add_particle(self): """ Code calling add_particle must be either: be sure there is room for the particle or be prepared to catch the exception ExceptionNoEmptyParticle It is acceptable to try: ... except...: pass """ self.init_particle() self.particle_count += 1 def stop_system(self): self.active = False self.elapsed = self.duration self.emit_counter = 0 def reset_system(self): self.elapsed = self.duration self.emit_counter = 0 def update_particles(self, delta): # radial: posx + posy norm = numpy.sqrt(self.particle_pos[:, 0] ** 2 + self.particle_pos[:, 1] ** 2) # XXX prevent div by 0 norm = numpy.select([norm == 0], [0.0000001], default=norm) posx = self.particle_pos[:, 0] / norm posy = self.particle_pos[:, 1] / norm radial = numpy.array([posx, posy]) tangential = numpy.array([-posy, posx]) # update dir radial = numpy.swapaxes(radial, 0, 1) radial *= self.particle_rad tangential = numpy.swapaxes(tangential, 0, 1) tangential *= self.particle_tan self.particle_dir += (tangential + radial + self.particle_grav) * delta # update pos with updated dir self.particle_pos += self.particle_dir * delta # life self.particle_life -= delta # position: free or grouped if self.position_type == self.POSITION_FREE: tuple = numpy.array([self.x, self.y]) tmp = tuple - self.start_pos self.particle_pos -= tmp # color self.particle_color += self.particle_delta_color * delta # if life < 0, set alpha in 0 self.particle_color[:, 3] = numpy.select([self.particle_life[:, 0] < 0], [0], default=self.particle_color[:, 3]) # print self.particles[0] # print self.pas[0,0:4] def init_particle(self): # position # p=self.particles[idx] a = self.particle_life < 0 idxs = a.nonzero() idx = -1 if len(idxs[0]) > 0: idx = idxs[0][0] else: raise ExceptionNoEmptyParticle() # position self.particle_pos[idx][0] = self.pos_var.x * rand() self.particle_pos[idx][1] = self.pos_var.y * rand() # start position self.start_pos[idx][0] = self.x self.start_pos[idx][1] = self.y a = math.radians(self.angle + self.angle_var * rand()) v = Point2(math.cos(a), math.sin(a)) s = self.speed + self.speed_var * rand() dir = v * s # direction self.particle_dir[idx][0] = dir.x self.particle_dir[idx][1] = dir.y # radial accel self.particle_rad[idx] = self.radial_accel + self.radial_accel_var * rand() # tangential accel self.particle_tan[idx] = self.tangential_accel + self.tangential_accel_var * rand() # life life = self.particle_life[idx] = self.life + self.life_var * rand() # Color # start sr = self.start_color.r + self.start_color_var.r * rand() sg = self.start_color.g + self.start_color_var.g * rand() sb = self.start_color.b + self.start_color_var.b * rand() sa = self.start_color.a + self.start_color_var.a * rand() self.particle_color[idx][0] = sr self.particle_color[idx][1] = sg self.particle_color[idx][2] = sb self.particle_color[idx][3] = sa # end er = self.end_color.r + self.end_color_var.r * rand() eg = self.end_color.g + self.end_color_var.g * rand() eb = self.end_color.b + self.end_color_var.b * rand() ea = self.end_color.a + self.end_color_var.a * rand() delta_color_r = (er - sr) / life delta_color_g = (eg - sg) / life delta_color_b = (eb - sb) / life delta_color_a = (ea - sa) / life self.particle_delta_color[idx][0] = delta_color_r self.particle_delta_color[idx][1] = delta_color_g self.particle_delta_color[idx][2] = delta_color_b self.particle_delta_color[idx][3] = delta_color_a # size self.particle_size[idx] = self.size + self.size_var * rand() self._scale_particle_size() # gravity self.particle_grav[idx][0] = self.gravity.x self.particle_grav[idx][1] = self.gravity.y # Below only fallback functionality. # It uses quads instehad of point sprites, doing a transformation # point sprites buffers -> quads buffer, so any change in point sprite mode # is automatically reflects in the fallback mode (except for changes in the # draw method which should be manually adapted def _fallback_init(self): self.vertexs = numpy.zeros((self.total_particles, 4, 2), numpy.float32) tex_coords_for_quad = numpy.array([[0.0, 1.0], [0.0, 0.0], [1.0, 0.0], [1.0, 1.0]], numpy.float32) self.tex_coords = numpy.zeros((self.total_particles, 4, 2), numpy.float32) self.tex_coords[:] = tex_coords_for_quad[numpy.newaxis, :, :] self.per_vertex_colors = numpy.zeros((self.total_particles, 4, 4), numpy.float32) self.delta_pos_to_vertex = numpy.zeros((self.total_particles, 4, 2), numpy.float32) def draw_fallback(self): self.make_delta_pos_to_vertex() self.update_vertexs_from_pos() self.update_per_vertex_colors() gl.glPushMatrix() self.transform() # color preserve - at least intel 945G needs that gl.glPushAttrib(gl.GL_CURRENT_BIT) gl.glEnable(gl.GL_TEXTURE_2D) gl.glBindTexture(gl.GL_TEXTURE_2D, self.texture.id) gl.glEnableClientState(gl.GL_VERTEX_ARRAY) vertexs_ptr = PointerToNumpy(self.vertexs) gl.glVertexPointer(2, gl.GL_FLOAT, 0, vertexs_ptr) gl.glEnableClientState(gl.GL_COLOR_ARRAY) color_ptr = PointerToNumpy(self.per_vertex_colors) # gl.glColorPointer(4, gl.GL_UNSIGNED_BYTE, 0, color_ptr) gl.glColorPointer(4, gl.GL_FLOAT, 0, color_ptr) gl.glEnableClientState(gl.GL_TEXTURE_COORD_ARRAY) tex_coord_ptr = PointerToNumpy(self.tex_coords) gl.glTexCoordPointer(2, gl.GL_FLOAT, 0, tex_coord_ptr) gl.glPushAttrib(gl.GL_COLOR_BUFFER_BIT) gl.glEnable(gl.GL_BLEND) if self.blend_additive: gl.glBlendFunc(gl.GL_SRC_ALPHA, gl.GL_ONE) else: gl.glBlendFunc(gl.GL_SRC_ALPHA, gl.GL_ONE_MINUS_SRC_ALPHA) gl.glDrawArrays(gl.GL_QUADS, 0, len(self.vertexs) * 4) # un -blend gl.glPopAttrib() # color restore gl.glPopAttrib() # disable states gl.glDisableClientState(gl.GL_TEXTURE_COORD_ARRAY) gl.glDisableClientState(gl.GL_COLOR_ARRAY) gl.glDisableClientState(gl.GL_VERTEX_ARRAY) gl.glDisable(gl.GL_TEXTURE_2D) gl.glPopMatrix() def update_vertexs_from_pos(self): vertexs = self.vertexs delta = self.delta_pos_to_vertex pos = self.particle_pos vertexs[:] = delta + pos[:, numpy.newaxis, :] def update_per_vertex_colors(self): colors = self.particle_color per_vertex_colors = self.per_vertex_colors per_vertex_colors[:] = colors[:, numpy.newaxis, :] def make_delta_pos_to_vertex(self): size2 = self.particle_size / 2.0 # counter-clockwise self.delta_pos_to_vertex[:,0] = numpy.array([-size2, +size2]).T # NW self.delta_pos_to_vertex[:,1] = numpy.array([-size2, -size2]).T # SW self.delta_pos_to_vertex[:,2] = numpy.array([+size2, -size2]).T # SE self.delta_pos_to_vertex[:,3] = numpy.array([+size2, +size2]).T # NE
def __init__(self, w, h): ParticleSystem.__init__(self, False) self.pos_var = Point2(w, 0) self.speed = h * 3.5 self.speed_var = h * 2.5
def performAttackOnUnit(battle, target_unit): # perform an attack on the given target BattleUnit turn_unit = battle.getTurnUnit() if turn_unit is None or target_unit is None\ or turn_unit.isDestroyed() or target_unit.isDestroyed(): # TODO: make sure it is a player unit's turn return 0 src_cell = turn_unit.col, turn_unit.row dest_cell = target_unit.col, target_unit.row # minimum travel time to target used to determine when to show the damage floater min_travel_time = 0 # maximum travel time to target used to determine when all animations are finished max_travel_time = 0 # cell distance used to determine which range of weapons will fire cell_distance = Battle.getCellDistance(src_cell, dest_cell) target_range = Battle.getDistanceRange(cell_distance) print(target_range + ": " + str(src_cell) + " -> " + str(dest_cell) + " = " + str(cell_distance)) # TODO: introduce dynamic damage (optional?) attack_damage = int(getattr(turn_unit, target_range)) # apply damage to model before animating attack_remainder = target_unit.applyDamage(attack_damage) # determine actual target point based on the target unit sprite size target_sprite = target_unit.getSprite() real_x = (dest_cell[0] * Board.TILE_SIZE) + Board.TILE_SIZE // 2 real_y = (dest_cell[1] * Board.TILE_SIZE) + (2 * target_sprite.get_height() // 3) for weaponMap in turn_unit.mech.weapons: for weapon in weaponMap.iterkeys(): if not weapon.inRange(cell_distance): continue weapon_data = weaponMap[weapon] # get sound channel to use just for this weapon weapon_channel = pygame.mixer.find_channel() if weapon_channel is None: weapon_channel = pygame.mixer.Channel(0) weapon_offset = weapon_data.get('offset', [0, 0]) weapon_x = turn_unit.sprite.position[0] + weapon_offset[0] weapon_y = turn_unit.sprite.position[1] + weapon_offset[1] weapon_color = weapon.get_color() if weapon.isPPC(): # fire test ppcs ppc = Meteor() ppc.size = 10 ppc.speed = 20 ppc.gravity = Point2(0, 0) # TODO: offer decreased particle emission rate to improve performance ppc.emission_rate = 100 ppc.life = 0.5 ppc.life_var = 0.1 ppc.position = weapon_x, weapon_y battle.board.add(ppc, z=1000) target_x = real_x + random_offset() target_y = real_y + random_offset() target_pos = target_x, target_y # figure out the duration based on speed and distance ppc_speed = weapon.get_speed() # pixels per second distance = Point2(ppc.x, ppc.y).distance(Point2(target_x, target_y)) ppc_t = distance / ppc_speed ppc_sound = Resources.ppc_sound weapon_channel.play(ppc_sound) action = Delay(0.5) + MoveTo((target_x, target_y), duration=ppc_t) \ + CallFunc(impact_ppc, ppc) \ + Delay(0.5) + CallFunc(ppc.kill) \ + Delay(ppc_sound.get_length()) \ + CallFunc(weapon_channel.stop) ppc.do(action) travel_time = 0.5 + ppc_t if min_travel_time == 0 or min_travel_time > travel_time: min_travel_time = travel_time if travel_time > max_travel_time: max_travel_time = travel_time elif weapon.isFlamer(): # fire test flamer flamer = Fire() flamer.size = 25 flamer.speed = 300 flamer.gravity = Point2(0, 0) # TODO: offer decreased particle emission rate to improve performance flamer.emission_rate = 100 dx = real_x - weapon_x dy = real_y - weapon_y rads = atan2(-dy, dx) rads %= 2 * pi angle = degrees(rads) + 90 flamer.rotation = angle flamer.angle_var = 5 flamer.pos_var = Point2(5, 5) flamer.position = weapon_x, weapon_y battle.board.add(flamer, z=1000) target_x = real_x + random_offset() target_y = real_y + random_offset() target_pos = target_x, target_y # figure out the duration based on speed and distance flamer_speed = weapon.get_speed() # pixels per second distance = Point2(flamer.x, flamer.y).distance( Point2(target_x, target_y)) flamer_t = 1 flamer.life = distance / flamer_speed flamer.life_var = 0 flamer_sound = Resources.flamer_sound weapon_channel.play(flamer_sound) action = Delay(flamer_t) \ + CallFunc(impact_flamer, flamer) \ + CallFunc(weapon_channel.fadeout, 750) \ + Delay(flamer_t) + CallFunc(flamer.kill) \ + CallFunc(weapon_channel.stop) flamer.do(action) travel_time = flamer_t if min_travel_time == 0 or min_travel_time > travel_time: min_travel_time = travel_time if travel_time > max_travel_time: max_travel_time = travel_time elif weapon.isLaser(): # fire test laser las_life = 1.0 las_size = (1, 1, 1) if weapon.isShort(): las_size = (2, 1, 0.5) las_life = 0.5 elif weapon.isMedium(): las_size = (3, 2, 1) las_life = 0.75 elif weapon.isLong(): las_size = (6, 4, 2) las_life = 1.0 target_x = real_x + random_offset() target_y = real_y + random_offset() target_pos = target_x, target_y las_outer = gl.SingleLine( (weapon_x, weapon_y), (target_x, target_y), width=las_size[0], color=(weapon_color[0], weapon_color[1], weapon_color[2], 50)) las_middle = gl.SingleLine( (weapon_x, weapon_y), (target_x, target_y), width=las_size[1], color=(weapon_color[0], weapon_color[1], weapon_color[2], 125)) las_inner = gl.SingleLine( (weapon_x, weapon_y), (target_x, target_y), width=las_size[2], color=(weapon_color[0], weapon_color[1], weapon_color[2], 200)) las_outer.visible = False las_middle.visible = False las_inner.visible = False node = cocos.layer.Layer() node.add(las_outer, z=1) node.add(las_middle, z=2) node.add(las_inner, z=3) battle.board.add(node, z=1000) # give lasers a small particle pre-fire effect laser_charge = Galaxy() laser_charge.angle = 270 laser_charge.angle_var = 180 laser_charge.position = weapon_x, weapon_y laser_charge.size = 10 laser_charge.size_var = 5 laser_charge.emission_rate = 15 laser_charge.life = 0.5 laser_charge.speed = 0 laser_charge.speed_var = 0 laser_charge.start_color = Color(weapon_color[0] / 255, weapon_color[1] / 255, weapon_color[2] / 255, 1.0) laser_charge.end_color = Color(weapon_color[0] / 255, weapon_color[1] / 255, weapon_color[2] / 255, 1.0) node.add(laser_charge, z=0) laser_drift = random.uniform(-15.0, 15.0), random.uniform( -15.0, 15.0) las_action = Delay(0.5) + ToggleVisibility() \ + CallFunc(create_laser_impact, battle.board, target_pos, laser_drift, las_life) \ + gl.LineDriftBy(laser_drift, las_life) \ + CallFunc(laser_charge.stop_system) + CallFunc(node.kill) las_outer.do(las_action) las_middle.do(las_action) las_inner.do(las_action) las_sound = Resources.las_sound weapon_channel.play(las_sound) las_duration_ms = int(las_action.duration * 1000) weapon_channel.fadeout(las_duration_ms) travel_time = 0.5 if min_travel_time == 0 or min_travel_time > travel_time: min_travel_time = travel_time if travel_time > max_travel_time: max_travel_time = travel_time elif weapon.isBallistic(): # fire test ballistic projectile num_ballistic = weapon.get_projectiles() if weapon.isGauss(): ballistic_img = Resources.gauss_img elif weapon.isLBX(): # LBX fires only one projectile, but will appear to have multiple random impacts num_ballistic = 1 ballistic_img = Resources.buckshot_img else: ballistic_img = Resources.ballistic_img # machine gun sound only plays once instead of per projectile cannon_sound = None if weapon.isMG(): cannon_sound = Resources.machinegun_sound elif weapon.isGauss(): cannon_sound = Resources.gauss_sound for i in range(num_ballistic): ballistic = Sprite(ballistic_img) ballistic.visible = False ballistic.position = weapon_x, weapon_y ballistic.scale = weapon.get_scale() ballistic.anchor = 0, 0 dx = real_x - weapon_x dy = real_y - weapon_y rads = atan2(-dy, dx) rads %= 2 * pi angle = degrees(rads) ballistic.rotation = angle target_x = real_x + random_offset() target_y = real_y + random_offset() target_pos = target_x, target_y # figure out the duration based on speed and distance ballistic_speed = weapon.get_speed() # pixels per second distance = Point2(weapon_x, weapon_y).distance( Point2(target_x, target_y)) ballistic_t = distance / ballistic_speed # setup the firing sound if cannon_sound is None: cannon_sound = Resources.cannon_sound impact_func = create_ballistic_impact if weapon.isLBX(): impact_func = create_lbx_impact action = Delay(i * 0.1) + ToggleVisibility() \ + CallFunc(weapon_channel.play, cannon_sound) \ + MoveTo((target_x, target_y), ballistic_t) \ + CallFunc(impact_func, weapon, battle.board, target_pos) \ + CallFunc(ballistic.kill) if weapon.isGauss(): # give gauss sound a bit more time to stop action += Delay(cannon_sound.get_length()) if i == num_ballistic - 1: # stop the sound channel after the last projectile only action += CallFunc(weapon_channel.stop) ballistic.do(action) battle.board.add(ballistic, z=1000 + i) travel_time = (i * 0.1) + ballistic_t if min_travel_time == 0 or min_travel_time > travel_time: min_travel_time = travel_time if travel_time > max_travel_time: max_travel_time = travel_time elif weapon.isMissile(): # get another sound channel to use just for the explosions explosion_channel = pygame.mixer.find_channel() if explosion_channel is None: explosion_channel = pygame.mixer.Channel(1) # fire test missile projectile missile_img = Resources.missile_img num_missile = weapon_data.get('count', 1) num_per_row = 1 if weapon.isLRM(): num_per_row = 5 elif weapon.isSRM(): num_per_row = 2 for i in range(num_missile): tube_x = i % num_per_row tube_y = i // num_per_row missile = Sprite(missile_img) missile.visible = False missile.position = weapon_x + tube_x, weapon_y + tube_y missile.scale = weapon.get_scale() missile.anchor = 0, 0 dx = real_x - weapon_x dy = real_y - weapon_y rads = atan2(-dy, dx) rads %= 2 * pi angle = degrees(rads) missile.rotation = angle target_x = real_x + random_offset() target_y = real_y + random_offset() target_pos = target_x, target_y # figure out the duration based on speed and distance missile_speed = weapon.get_speed() # pixels per second distance = Point2(weapon_x, weapon_y).distance( Point2(target_x, target_y)) missile_t = distance / missile_speed rand_missile_sound = random.randint(0, 7) missile_sound = Resources.missile_sounds[ rand_missile_sound] explosion_sound = Resources.explosion_sound action = Delay(i * 0.05) + ToggleVisibility() \ + CallFunc(weapon_channel.play, missile_sound) \ + MoveTo((target_x, target_y), missile_t) \ + CallFunc(create_missile_impact, battle.board, target_pos) \ + CallFunc(missile.kill) \ + CallFunc(explosion_channel.play, explosion_sound) \ + Delay(0.5) if i == num_missile - 1: # stop the sound channels after the last missile only action += CallFunc(weapon_channel.stop) + CallFunc( explosion_channel.stop) missile.do(action) battle.board.add(missile, z=1000 + i) travel_time = (i * 0.05) + missile_t if min_travel_time == 0 or min_travel_time > travel_time: min_travel_time = travel_time if travel_time > max_travel_time: max_travel_time = travel_time # scroll focus over to the target area halfway through the travel time target_area = Board.board_to_layer(target_unit.col, target_unit.row) # show damage floater after the travel time of the first projectile to hit floater = floaters.TextFloater("%i" % attack_damage) floater.visible = False floater.position = real_x, real_y + target_sprite.get_height() // 3 battle.board.add(floater, z=2000) action = Delay(min_travel_time / 2) + CallFunc(battle.scroller.set_focus, *target_area) \ + Delay(min_travel_time / 2) + ToggleVisibility() \ + Delay(0.25) + MoveBy((0, Board.TILE_SIZE), 1.0) \ + FadeOut(1.0) + CallFunc(floater.kill) floater.do(action) if action.duration > max_travel_time: max_travel_time = action.duration stats_action = Delay(min_travel_time) + CallFunc(target_sprite.updateStatsIndicators) \ + CallFunc(Interface.UI.updateTargetUnitStats, target_unit) target_sprite.do(stats_action) if attack_remainder > 0: print("Overkill by %i!" % attack_remainder) if target_unit.structure > 0: print("Remaining %i/%i" % (target_unit.armor, target_unit.structure)) else: print("Target destroyed!") # show destroyed floater after the travel time of the first projectile to hit destroyed = floaters.TextFloater("DESTROYED") destroyed.visible = False destroyed.position = real_x, real_y + target_sprite.get_height() // 3 battle.board.add(destroyed, z=5000) # get another sound channel to use just for the explosions explosion_channel = pygame.mixer.find_channel() if explosion_channel is None: explosion_channel = pygame.mixer.Channel(1) explosion_sound = Resources.explosion_multiple_sound action = Delay(max_travel_time) + ToggleVisibility() \ + CallFunc(explosion_channel.play, explosion_sound) \ + (MoveBy((0, Board.TILE_SIZE), 1.0) | CallFunc(create_destruction_explosions, battle.board, target_unit)) \ + Delay(0.5) + CallFunc(target_sprite.destroy) + FadeOut(2.0) + CallFunc(destroyed.kill) destroyed.do(action) # give a bit of extra time to explode max_travel_time = action.duration return max_travel_time
def on_key_release(self, key, modifiers): self.keys_pressed.remove(key) move_key_map = { ord('w'): Point2(0, 1), ord('a'): Point2(-1, 0), ord('s'): Point2(0, -1), ord('d'): Point2(1, 0), } if key in move_key_map: grid_pos = world_to_grid(self.player.position) new_pos = Point2(grid_pos[0], grid_pos[1]) + move_key_map[key] if self.is_valid_player_grid_pos(new_pos): self.game_world.current_turn += 1 self.player.position = grid_to_world(new_pos) # Do circle around player radius = g_player_view_radius square_radius = radius * radius for x in xrange(-radius, radius + 1): for y in xrange(-radius, radius + 1): if (x * x + y * y) <= square_radius: target_pos = new_pos + (x, y) hit, hit_pos = self.raytrace(new_pos, target_pos, ignore_half_cover=True) if hit: self.fow.set_grid_pos_visible( hit_pos, True, self.game_world.current_turn + g_steps_fog_stays_around) self.fow_visited.set_grid_pos_visible( hit_pos, True, self.game_world.current_turn + g_steps_half_fog_stays_around) # Check from around the player if we can't see. if hit and g_check_around_player: moves = [ Point2(1, 0), Point2(-1, 0), Point2(0, 1), Point2(0, -1), Point2(1, 1), Point2(1, -1), Point2(-1, 1), Point2(-1, -1), ] for move in moves: if self.is_valid_player_grid_pos(new_pos + move): hit, hit_pos = self.raytrace(new_pos + move, target_pos, ignore_half_cover=True) if hit: self.fow.set_grid_pos_visible( hit_pos, True, self.game_world.current_turn + g_steps_fog_stays_around) self.fow_visited.set_grid_pos_visible( hit_pos, True, self.game_world.current_turn + g_steps_half_fog_stays_around) elif not hit: break if not hit: self.fow.set_grid_pos_visible( new_pos + (x, y), True, self.game_world.current_turn + g_steps_fog_stays_around) self.fow_visited.set_grid_pos_visible( new_pos + (x, y), True, self.game_world.current_turn + g_steps_half_fog_stays_around) self.update_camera()
class PyFenseProjectileSlow(ParticleSystem, pyglet.event.EventDispatcher): """ Projectile in the form of particles for the slow tower. Class variables have to be used because of ParticleSystem. """ # total particles total_particles = 2000 # duration duration = 0.1 # gravity gravity = Point2(0, 0) # angle angle = 0 angle_var = 5 # radial radial_accel = 1000 radial_accel_var = 0 # speed of particles, fallback value speed = 800 speed_var = 50 # emitter variable position pos_var = Point2(12, 0) # distance that particles fly, fallback value distance = 200 # life of particles, fallback value life = 5 life_var = 0.005 # emits per frame emission_rate = 500 # color of particles start_color = Color(0.58, 0.98, 0.98, 1.0) start_color_var = Color(0.0, 0.0, 0.0, 0.6) end_color = Color(0.53, 0.96, 0.95, 1.0) end_color_var = Color(0.0, 0.0, 0.0, 0.2) # size, in pixels size = 40 size_var = 2.0 # blend additive blend_additive = True # color modulate color_modulate = True def __init__(self, towerParent, target, towerNumber, rotation, speed, damage, effect, effectDuration, effectFactor): """ Create a projectile and schedule event. :Parameters: `towerParent`: tower object Tower that launched the projectile. `target` : enemy object Enemy that is targeted. `towerNumber` : int Number of the parent tower. `rotation` : int Rotation of the parent tower. `speed` : int Speed of the particles. `damage` : int Damage the projectile causes. `effect` : string Effect that is caused by projectile (here: slow) `effectDuration` : int Duration that the effect is active. `effectFactor` : int How strong the effect is. """ super().__init__() self.position = towerParent.position self.rotation = rotation - 90 __class__.speed = speed __class__.distance = self._distance(target.position, self.position) __class__.life = __class__.distance / __class__.speed self.damage = damage self.schedule_interval(self._dispatch_hit_event, __class__.life, target, towerNumber, effect, effectDuration, effectFactor) def _dispatch_hit_event(self, dt, target, towerNumber, effect, effectDuration, effectFactor): """ Dispatch event when enemy is hit. The event is then handled by the enitites class in order to subtract health points from the enemy and to handle the different effects. """ self.unschedule(self._dispatch_hit_event) self.dispatch_event('on_target_hit', self, target, towerNumber, effect, effectDuration, effectFactor) def _distance(self, a, b): """ Compute distance between two tupels (= position). """ dis = math.sqrt((b[0] - a[0])**2 + (b[1] - a[1])**2) return dis
def _calculate_vertex_points(self): # generate the vertex array with the correct values # size of the texture (power of 2) w = float(self.image.width) // self.texture.tex_coords[3] h = float(self.image.height) // self.texture.tex_coords[7] index_points = [] vertex_points_idx = [] texture_points_idx = [] # generate 2 empty lists: # vertex_list: # texex_list: for x in range(0, self.grid_size.x + 1): for y in range(0, self.grid_size.y + 1): vertex_points_idx += [-1, -1, -1] texture_points_idx += [-1, -1] # since we are using vertex_list_indexed we must calculate # the index points for x in range(0, self.grid_size.x): for y in range(0, self.grid_size.y): x1 = x * self.x_step x2 = x1 + self.x_step y1 = y * self.y_step y2 = y1 + self.y_step # d <-- c # ^ # | # a --> b a = x * (self.grid_size.y + 1) + y b = (x + 1) * (self.grid_size.y + 1) + y c = (x + 1) * (self.grid_size.y + 1) + (y + 1) d = x * (self.grid_size.y + 1) + (y + 1) # we are generating 2 triangles: a-b-d, b-c-d # (and not 1 quad, to prevent concave quads # although this example can work OK with quads) index_points += [a, b, d, b, c, d] l1 = (a * 3, b * 3, c * 3, d * 3) l2 = (Point3(x1, y1, 0), Point3(x2, y1, 0), Point3(x2, y2, 0), Point3(x1, y2, 0)) # populate the vertex list for i in range(len(l1)): vertex_points_idx[l1[i]] = l2[i].x vertex_points_idx[l1[i] + 1] = l2[i].y vertex_points_idx[l1[i] + 2] = l2[i].z tex1 = (a * 2, b * 2, c * 2, d * 2) tex2 = (Point2(x1, y1), Point2(x2, y1), Point2(x2, y2), Point2(x1, y2)) # populate the texel list for i in range(len(l1)): texture_points_idx[tex1[i]] = tex2[i].x / w texture_points_idx[tex1[i] + 1] = tex2[i].y / h return (index_points, vertex_points_idx, texture_points_idx)
def getCellDistance(cell_1, cell_2): point_1 = Point2(cell_1[0], cell_1[1]) point_2 = Point2(cell_2[0], cell_2[1]) return point_1.distance(point_2)