class Galaxy(ParticleSystem): # total particles total_particles = 200 # duration duration = -1 # gravity gravity = Point2(0, 0) # angle angle = 90.0 angle_var = 360.0 # speed of particles speed = 60.0 speed_var = 10.0 # radial radial_accel = -80.0 radial_accel_var = 0 # tangential tangential_accel = 80.0 tangential_accel_var = 0.0 # emitter variable position pos_var = Point2(0, 0) # life of particles life = 4.0 life_var = 1.0 # size, in pixels size = 37.0 size_var = 10.0 # emits per frame emission_rate = total_particles / life # color of particles start_color = Color(0.12, 0.25, 0.76, 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) # blend additive blend_additive = True # color modulate color_modulate = True
class Spiral(ParticleSystem): # total paticles total_particles = 500 # duration duration = -1 # gravity gravity = Point2(0, 0) # angle angle = 90.0 angle_var = 0.0 # speed of particles speed = 150.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(0, 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(0.5, 0.5, 0.5, 1.0) start_color_var = Color(0.5, 0.5, 0.5, 0.0) end_color = Color(0.5, 0.5, 0.5, 1.0) end_color_var = Color(0.5, 0.5, 0.5, 0.0) # size, in pixels size = 20.0 size_var = 10.0 # blend additive blend_additive = True # color modulate color_modulate = True
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) # 粒子的结束颜色偏差
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
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 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
class Fire(ParticleSystem): # total particles total_particles = 250 # duration duration = -1 # gravity gravity = Point2(0, 0) # angle angle = 90.0 angle_var = 10.0 # radial radial_accel = 0 radial_accel_var = 0 # speed of particles speed = 60.0 speed_var = 20.0 # emitter variable position pos_var = Point2(40, 20) # life of particles life = 3.0 life_var = 0.25 # 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 = 100.0 size_var = 10.0 # blend additive blend_additive = True # color modulate color_modulate = True
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
def _load_background(self): background = Sprite( self.gallery.content["display"]["worldmap_quarters"]) self.optimal_scale = (self.config.window_width * self.display_pos_size[ "display_worldmap_quarters"]["W"]) / background.width background.image_anchor = 0, 0 background.scale = self.optimal_scale background.x = self.config.window_width * self.display_pos_size[ "display_worldmap_quarters"]["X"] background.y = self.config.window_height * self.display_pos_size[ "display_worldmap_quarters"]["Y"] self.left_margin = background.x self.bottom_margin = background.y self.optimal_width = background.width self.optimal_height = background.height self.add(background) self.ps_alarm = Sun() self.ps_alarm.total_particles = 20 self.ps_alarm.speed = 0.0 self.ps_alarm.speed_var = 0.0 self.ps_alarm.life_var = 0.0 self.ps_alarm.blend_additive = True self.ps_alarm.position = ( self.optimal_width * self.button_positions["ps_alarm"]["X"] + self.left_margin), ( self.optimal_height * self.button_positions["ps_alarm"]["Y"] + self.bottom_margin) self.ps_alarm.start_color = Color(1, 0.40, 0.40, 0.40) self.ps_alarm.size = 50.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
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 _load_background(self): background = Sprite(self.gallery.content["display"]["worldmap_engine"]) self.optimal_scale = (self.config.window_width * self.display_pos_size["display_worldmap_engine"] ["W"]) / background.width background.image_anchor = 0, 0 background.scale = self.optimal_scale background.x = self.config.window_width * self.display_pos_size[ "display_worldmap_engine"]["X"] background.y = self.config.window_height * self.display_pos_size[ "display_worldmap_engine"]["Y"] self.left_margin = background.x self.bottom_margin = background.y self.optimal_width = background.width self.optimal_height = background.height pic_fire = Sprite( self.gallery.content["display"]["worldmap_engine_fire"]) pic_fire.image_anchor = 0, 0 pic_fire.scale = self.optimal_scale pic_fire.x = self.optimal_width * self.button_positions["pic_fire"][ "X"] + self.left_margin pic_fire.y = self.optimal_height * self.button_positions["pic_fire"][ "Y"] + self.bottom_margin self.add(pic_fire, name="pic_fire") self.ps_fire = Fire() self.ps_fire.size = 120 self.ps_fire.position = ( self.optimal_width * self.button_positions["ps_fire"]["X"] + self.left_margin, self.optimal_height * self.button_positions["ps_fire"]["Y"] + self.bottom_margin) self.add(self.ps_fire, name="ps_fire") self.add(background) pic_anthracite = Sprite( self.gallery.content["display"]["worldmap_engine_anthracite"]) pic_anthracite.image_anchor = 0, 0 pic_anthracite.scale = self.optimal_scale pic_anthracite.x = self.optimal_width * self.button_positions[ "pic_anthracite"]["X"] + self.left_margin pic_anthracite.y = self.optimal_height * self.button_positions[ "pic_anthracite"]["Y"] + self.bottom_margin self.add(pic_anthracite, name="pic_anthracite") pic_lignite = Sprite( self.gallery.content["display"]["worldmap_engine_lignite"]) pic_lignite.image_anchor = 0, 0 pic_lignite.scale = self.optimal_scale pic_lignite.x = self.optimal_width * self.button_positions[ "pic_lignite"]["X"] + self.left_margin pic_lignite.y = self.optimal_height * self.button_positions[ "pic_lignite"]["Y"] + self.bottom_margin self.add(pic_lignite, name="pic_lignite") self.ps_alarm = Sun() self.ps_alarm.total_particles = 20 self.ps_alarm.speed = 0.0 self.ps_alarm.speed_var = 0.0 self.ps_alarm.life_var = 0.0 self.ps_alarm.blend_additive = True self.ps_alarm.position = ( self.optimal_width * self.button_positions["ps_alarm"]["X"] + self.left_margin), ( self.optimal_height * self.button_positions["ps_alarm"]["Y"] + self.bottom_margin) self.ps_alarm.start_color = Color(1, 0.40, 0.40, 0.40) self.ps_alarm.size = 50.0
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 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 __init__(self, map_manager): """initializer""" gallery = Gallery() self.rotation_vars = {} self.rotation_vars["NF"] = {} self.rotation_vars["SR"] = {} self.rotation_vars["BF"] = {} self.rotation_vars["DR"] = {} self.rotation_vars["EF"] = {} self.rotation_vars["WR"] = {} self.rotation_vars["CF"] = {} self.rotation_vars["AR"] = {} self.rotation_vars["SF"] = {} self.rotation_vars["NR"] = {} self.rotation_vars["DF"] = {} self.rotation_vars["BR"] = {} self.rotation_vars["WF"] = {} self.rotation_vars["ER"] = {} self.rotation_vars["AF"] = {} self.rotation_vars["CR"] = {} self.rotation_vars["BLANK"] = {} self.rotation_vars["NF"]["sprite"] = gallery.content["actor"][ "engine000"] self.rotation_vars["SR"]["sprite"] = gallery.content["actor"][ "engine000"] self.rotation_vars["BF"]["sprite"] = gallery.content["actor"][ "engine045"] self.rotation_vars["DR"]["sprite"] = gallery.content["actor"][ "engine045"] self.rotation_vars["EF"]["sprite"] = gallery.content["actor"][ "engine090"] self.rotation_vars["WR"]["sprite"] = gallery.content["actor"][ "engine090"] self.rotation_vars["CF"]["sprite"] = gallery.content["actor"][ "engine135"] self.rotation_vars["AR"]["sprite"] = gallery.content["actor"][ "engine135"] self.rotation_vars["SF"]["sprite"] = gallery.content["actor"][ "engine180"] self.rotation_vars["NR"]["sprite"] = gallery.content["actor"][ "engine180"] self.rotation_vars["DF"]["sprite"] = gallery.content["actor"][ "engine225"] self.rotation_vars["BR"]["sprite"] = gallery.content["actor"][ "engine225"] self.rotation_vars["WF"]["sprite"] = gallery.content["actor"][ "engine270"] self.rotation_vars["ER"]["sprite"] = gallery.content["actor"][ "engine270"] self.rotation_vars["AF"]["sprite"] = gallery.content["actor"][ "engine315"] self.rotation_vars["CR"]["sprite"] = gallery.content["actor"][ "engine315"] self.rotation_vars["BLANK"]["sprite"] = gallery.content["switch"][ "off"] self.rotation_vars["NF"]["smoke_angle"] = 270 self.rotation_vars["SR"]["smoke_angle"] = 90 self.rotation_vars["BF"]["smoke_angle"] = 225 self.rotation_vars["DR"]["smoke_angle"] = 45 self.rotation_vars["EF"]["smoke_angle"] = 180 self.rotation_vars["WR"]["smoke_angle"] = 0 self.rotation_vars["CF"]["smoke_angle"] = 135 self.rotation_vars["AR"]["smoke_angle"] = 315 self.rotation_vars["SF"]["smoke_angle"] = 90 self.rotation_vars["NR"]["smoke_angle"] = 270 self.rotation_vars["DF"]["smoke_angle"] = 45 self.rotation_vars["BR"]["smoke_angle"] = 225 self.rotation_vars["WF"]["smoke_angle"] = 0 self.rotation_vars["ER"]["smoke_angle"] = 180 self.rotation_vars["AF"]["smoke_angle"] = 315 self.rotation_vars["CR"]["smoke_angle"] = 135 self.rotation_vars["BLANK"]["smoke_angle"] = 0 self.rotation_vars["NF"]["smoke_pos"] = -2, 17 self.rotation_vars["SR"]["smoke_pos"] = -2, 17 self.rotation_vars["BF"]["smoke_pos"] = 1, 26 self.rotation_vars["DR"]["smoke_pos"] = 1, 26 self.rotation_vars["EF"]["smoke_pos"] = 18, 17 self.rotation_vars["WR"]["smoke_pos"] = 18, 17 self.rotation_vars["CF"]["smoke_pos"] = 25, -1 self.rotation_vars["AR"]["smoke_pos"] = 25, -1 self.rotation_vars["SF"]["smoke_pos"] = -2, -17 self.rotation_vars["NR"]["smoke_pos"] = -2, -17 self.rotation_vars["DF"]["smoke_pos"] = -26, -2 self.rotation_vars["BR"]["smoke_pos"] = -26, -2 self.rotation_vars["WF"]["smoke_pos"] = -18, 17 self.rotation_vars["ER"]["smoke_pos"] = -18, 17 self.rotation_vars["AF"]["smoke_pos"] = -5, 30 self.rotation_vars["CR"]["smoke_pos"] = -5, 30 self.rotation_vars["BLANK"]["smoke_pos"] = -18, 17 self.is_moving = False Sprite.__init__(self, self.rotation_vars["BLANK"]["sprite"]) self.counter = 0 self.map = map_manager self.transarctica = director.core.query_mover("Transarctica") self.transarctica.map = map_manager self.driver = TrainDriver() self.driver.target = self self.config = Config() self.break_sound_source = load('music/stop.wav') #, streaming=False) #self.break_sound.volume=0.5 * self.config.sound_switch self.anchor = self.config.tile_width / 2, self.config.tile_width / 2 #self.transarctica.current_position = self.config.start_position self.last_position = { "X": self.transarctica.current_position["X"], "Y": self.transarctica.current_position["Y"] } self.max_forward_speed = 450 / self.config.km_per_tile * self.config.tile_width / 3600 self.position = (-1, -1) self.last_break_status = self.transarctica.is_break_released self.last_reverse_status = self.transarctica.is_in_reverse self.last_direction = self.transarctica.direction self.arriving_from = "" self.leaving_toward = "" self.on_tile = "none" self.next_turn_at = (-1, -1) self.tile_entry_point = (-1, -1) self.smoke = Smoke() self.smoke.blend_additive = False self.smoke.position = self.rotation_vars["NF"]["smoke_pos"] self.smoke.life = 1 self.smoke.speed = 30 self.smoke.start_color = Color(0.20, 0.20, 0.20, 0.40) self.smoke.size = 15.0 self.smoke.total_particles = 60 self.add(self.smoke) self.prev_dirs = ""
def update_actor(self, dt): self.transarctica.proximity_alarm = 0 if self.last_break_status != self.transarctica.is_break_released: self.last_break_status = self.transarctica.is_break_released if self.transarctica.is_break_released: self.start() else: self.stop() if (self.last_position["X"] != self.transarctica.current_position["X"] or self.last_position["Y"] != self.transarctica.current_position["Y"] ) or (self.last_reverse_status != self.transarctica.is_in_reverse): cell = self.map.get("rails").cells[ self.transarctica.current_position["X"]][ self.transarctica.current_position["Y"]] if (self.last_reverse_status != self.transarctica.is_in_reverse): self.turn_back() if cell.tile: self.transarctica.Speed_Modifier = 1 if (("speedmod" in cell.properties) and ("tunneldir" not in cell.properties)) or ( ("tunneldir" in cell.properties) and (self.transarctica.direction in cell.properties["tunneldir"])): self.transarctica.Speed_Modifier = float( cell.properties["speedmod"]) if (self.last_position["X"] != self.transarctica.current_position["X"] or self.last_position["Y"] != self.transarctica.current_position["Y"]): self.tile_entry_point = self.position self.next_turn_at = (-1, -1) if "nodes" in cell.properties: self.arriving_from = self.opposites[ self.transarctica.direction] self.leaving_toward = cell.properties["directions"] if len(self.leaving_toward) == 1: self.on_tile = "bumper" self.leaving_toward = self.arriving_from elif len(self.leaving_toward) == 2: self.on_tile = "normal" self.leaving_toward = self.leaving_toward.replace( self.arriving_from, "") elif len(self.leaving_toward) == 3: if self.leaving_toward[0] != self.arriving_from: self.leaving_toward = self.leaving_toward[0] self.on_tile = "normal" else: self.leaving_toward = self.leaving_toward[1] self.on_tile = "switch" elif len(self.leaving_toward) == 5: self.on_tile = "cross" self.leaving_toward = self.opposites[ self.arriving_from] if (self.leaving_toward != self.opposites[self.arriving_from]) and ( self.next_turn_at == (-1, -1)): rails = self.map.get("hidden objects") self.next_turn_at = rails.cells[ self.transarctica.current_position["X"]][ self.transarctica.current_position["Y"]].center map_event = self.map.check_map_events( self.transarctica.current_position["X"], self.transarctica.current_position["Y"]) if map_event in ["tunnel_block", "bridge_monster"]: self.stop() self.start() events.emit_show_event("display_event_" + map_event) elif map_event in ["arrive_at_city"]: self.on_tile = "city_bumper" elif map_event in ["bridge_out"]: self.stop() self.start() events.emit_show_event("display_event_build_bridge") self.transarctica.current_position[ "X"] = self.last_position["X"] self.transarctica.current_position[ "Y"] = self.last_position["Y"] self.transarctica.is_in_reverse = not ( self.transarctica.is_in_reverse) self.transarctica.is_break_released = not ( self.transarctica.is_break_released) self.map.place_player() elif map_event in ["end_of_rail"]: self.stop() self.start() self.transarctica.current_position[ "X"] = self.last_position["X"] self.transarctica.current_position[ "Y"] = self.last_position["Y"] self.transarctica.is_in_reverse = not ( self.transarctica.is_in_reverse) self.transarctica.is_break_released = not ( self.transarctica.is_break_released) self.map.place_player() self.last_position["X"] = self.transarctica.current_position[ "X"] self.last_position["Y"] = self.transarctica.current_position[ "Y"] self.last_direction = self.transarctica.direction else: map_event = self.map.check_map_events( self.transarctica.current_position["X"], self.transarctica.current_position["Y"]) if map_event in ["arrive_at_city"]: self.service_bumper_hit() self.transarctica.current_position["X"] = self.last_position[ "X"] self.transarctica.current_position["Y"] = self.last_position[ "Y"] self.map.place_player() if self.transarctica.is_in_reverse: dirs = self.transarctica.direction + "R" else: dirs = self.transarctica.direction + "F" if self.prev_dirs != dirs: self.image = self.rotation_vars[dirs]["sprite"] self.smoke.position = self.rotation_vars[dirs]["smoke_pos"] self.prev_dirs = dirs if self.transarctica.speed == 0: self.smoke.angle = self.rotation_vars["SF"]["smoke_angle"] else: self.smoke.angle = self.rotation_vars[dirs]["smoke_angle"] self.smoke.speed = (self.transarctica.speed // 10) + 10 if (self.transarctica.Speed_Modifier > 1): self.smoke.total_particles = 0 self.counter = (self.counter + 1) % 30 if (self.counter == 15): self.image = self.rotation_vars["BLANK"]["sprite"] elif self.counter == 0: self.prev_dirs = "BLANK" else: self.smoke.total_particles = 60 self.smoke.start_color = Color( 0.10, 0.10, 0.10, max(min(1, self.transarctica.engine_temp / 600), 0.01)) if self.is_moving: self.move(dt)