赞
踩
接上篇文章继续解绍arcade游戏编程的基本知识。粒子系统
RGB = Union[Tuple[int, int, int], List[int]]
RGBA = Union[Tuple[int, int, int, int], List[int]]
Color = Union[RGB, RGBA]
Point = Union[Tuple[float, float], List[float]]
NamedPoint = namedtuple(“NamedPoint”, [“x”, “y”])
Vector = Point
def __init__(
self,
filename_or_texture: arcade.FilenameOrTexture,
change_xy: Vector,
SPARK_textures = [arcade.make_circle_texture(6, clr) for clr in Color_list]
def make_circle_texture(diameter: int, color: Color, name: str = None) -> Texture:
"""
返回具有给定直径和颜色的圆的纹理
"""
name = name or _build_cache_name("circle_texture", diameter, color[0], color[1], color[2])
bg_color = (0, 0, 0, 0) # fully transparent
img = PIL.Image.new("RGBA", (diameter, diameter), bg_color)
draw = PIL.ImageDraw.Draw(img)
draw.ellipse((0, 0, diameter - 1, diameter - 1), fill=color)
return Texture(name, img)
def make_soft_circle_texture(diameter: int, color: Color, center_alpha: int = 255, outer_alpha: int = 0,
name: str = None) -> Texture:
"""
Return a :class:`Texture` of a circle with the given diameter and color, fading out at its edges.
:param int diameter: Diameter of the circle and dimensions of the square :class:`Texture` returned.
:param Color color: Color of the circle.
:param int center_alpha: Alpha value of the circle at its center.
:param int outer_alpha: Alpha value of the circle at its edges.
:param str name: Custom or pre-chosen name for this texture
:returns: New :class:`Texture` object.
:rtype: arcade.Texture
"""
# TODO: create a rectangle and circle (and triangle? and arbitrary poly where client passes
# in list of points?) particle?
name = name or _build_cache_name("soft_circle_texture", diameter, color[0], color[1], color[2], center_alpha,
outer_alpha) # name must be unique for caching
bg_color = (0, 0, 0, 0) # fully transparent
img = PIL.Image.new("RGBA", (diameter, diameter), bg_color)
draw = PIL.ImageDraw.Draw(img)
max_radius = int(diameter // 2)
center = max_radius # for readability
for radius in range(max_radius, 0, -1):
alpha = int(lerp(center_alpha, outer_alpha, radius / max_radius))
clr = (color[0], color[1], color[2], alpha)
draw.ellipse((center - radius, center - radius, center + radius - 1, center + radius - 1), fill=clr)
return Texture(name, img)
Color_list = ( # rainbon 彩虹
arcade.color.ELECTRIC_CRIMSON,
arcade.color.FLUORESCENT_ORANGE,
arcade.color.ELECTRIC_YELLOW,
arcade.color.ELECTRIC_GREEN,
arcade.color.ELECTRIC_CYAN,
arcade.color.MEDIUM_ELECTRIC_BLUE,
arcade.color.ELECTRIC_INDIGO,
arcade.color.ELECTRIC_PURPLE,
)
SPARK_textures = [arcade.make_circle_texture(6, clr) for clr in Color_list]
# 火花_对
SPARK_list = [
[SPARK_textures[0], SPARK_textures[3]],
[SPARK_textures[1], SPARK_textures[5]],
[SPARK_textures[7], SPARK_textures[2]],
]
ROCKET_smoke_texture = arcade.make_soft_circle_texture(15, arcade.color.GRAY)
PUFF_texture = arcade.make_soft_circle_texture(80, (40, 40, 40))
FLASH_texture = arcade.make_soft_circle_texture(70, (128, 128, 90))
# 云 纹理
CLOUD_textures = [
arcade.make_soft_circle_texture(50, arcade.color.WHITE),
arcade.make_soft_circle_texture(50, arcade.color.LIGHT_GRAY),
arcade.make_soft_circle_texture(50, arcade.color.LIGHT_BLUE),
]
# 星星 纹理
STAR_textures = [
arcade.make_soft_circle_texture(8, arcade.color.WHITE),
arcade.make_soft_circle_texture(8, arcade.color.PASTEL_YELLOW),
]
粒子大小改大后
"""
粒子焰花
使用焰火展示演示发射器和粒子的“真实世界”用途
"""
import arcade
from arcade import Point, Vector
from arcade.utils import _Vec2 # bring in "private" class
import os
import random
import pyglet
SCREEN_width = 800
SCREEN_height = 600
Color_list = ( # rainbon 彩虹
arcade.color.ELECTRIC_CRIMSON,
arcade.color.FLUORESCENT_ORANGE,
arcade.color.ELECTRIC_YELLOW,
arcade.color.ELECTRIC_GREEN,
arcade.color.ELECTRIC_CYAN,
arcade.color.MEDIUM_ELECTRIC_BLUE,
arcade.color.ELECTRIC_INDIGO,
arcade.color.ELECTRIC_PURPLE,
)
SPARK_textures = [arcade.make_circle_texture(6, clr) for clr in Color_list]
# 火花_对
SPARK_list = [
[SPARK_textures[0], SPARK_textures[3]],
[SPARK_textures[1], SPARK_textures[5]],
[SPARK_textures[7], SPARK_textures[2]],
]
ROCKET_smoke_texture = arcade.make_soft_circle_texture(15, arcade.color.GRAY)
PUFF_texture = arcade.make_soft_circle_texture(80, (40, 40, 40))
FLASH_texture = arcade.make_soft_circle_texture(70, (128, 128, 90))
# 云 纹理
CLOUD_textures = [
arcade.make_soft_circle_texture(50, arcade.color.WHITE),
arcade.make_soft_circle_texture(50, arcade.color.LIGHT_GRAY),
arcade.make_soft_circle_texture(50, arcade.color.LIGHT_BLUE),
]
# 星星 纹理
STAR_textures = [
arcade.make_soft_circle_texture(8, arcade.color.WHITE),
arcade.make_soft_circle_texture(8, arcade.color.PASTEL_YELLOW),
]
# 旋转器 高
SPINNER_height = 75
# 旋转器 emitter 发射器
def make_spinner():
spinner = arcade.Emitter(
center_xy=(SCREEN_width / 2, SPINNER_height - 5),
emit_controller=arcade.EmitterIntervalWithTime(0.025, 2.0),
particle_factory=lambda emitter: arcade.FadeParticle(
filename_or_texture=random.choice(STAR_textures),
change_xy=(0, 6.0),
lifetime=0.2
)
)
spinner.change_angle = 16.28
return spinner
def make_rocket(emit_done_cb):
"""当烟花炮弹升入天空时显示烟雾轨迹的发射器"""
rocket = RocketEmitter(
center_xy=(random.uniform(100, SCREEN_width - 100), 25),
emit_controller=arcade.EmitterIntervalWithTime(0.04, 2.0),
particle_factory=lambda emitter: arcade.FadeParticle(
filename_or_texture=ROCKET_smoke_texture,
change_xy=arcade.rand_in_circle((0.0, 0.0), 0.08),
scale=0.5,
lifetime=random.uniform(1.0, 1.5),
start_alpha=100,
end_alpha=0,
mutation_callback=rocket_smoke_mutator
),
emit_done_cb=emit_done_cb
)
rocket.change_x = random.uniform(-1.0, 1.0) #
rocket.change_y = random.uniform(5.0, 7.25)
return rocket
def make_flash(prev_emitter):
"""当烟花炮弹爆炸时显示短暂闪光的返回发射器"""
return arcade.Emitter(
center_xy=prev_emitter.get_pos(),
emit_controller=arcade.EmitBurst(3),
particle_factory=lambda emitter: arcade.FadeParticle(
filename_or_texture=FLASH_texture,
change_xy=arcade.rand_in_circle((0.0, 0.0), 3.5),
lifetime=0.15
)
)
def make_puff(prev_emitter):
"""返回发射器,用于生成烟花炮弹爆炸后留下的细微烟雾云"""
return arcade.Emitter(
center_xy=prev_emitter.get_pos(),
emit_controller=arcade.EmitBurst(4),
particle_factory=lambda emitter: arcade.FadeParticle(
filename_or_texture=PUFF_texture,
change_xy=(_Vec2(arcade.rand_in_circle((0.0, 0.0), 0.4)) + _Vec2(0.3, 0.0)).as_tuple(),
lifetime=4.0
)
)
class AnimatedAlphaParticle(arcade.LifetimeParticle):
"""在三个不同的alpha级别之间设置动画的自定义粒子"""
def __init__(
self,
filename_or_texture: arcade.FilenameOrTexture,
change_xy: Vector,
start_alpha: int = 0,
duration1: float = 1.0,
mid_alpha: int = 255,
duration2: float = 1.0,
end_alpha: int = 0,
center_xy: Point = (0.0, 0.0),
angle: float = 0,
change_angle: float = 0,
scale: float = 1.0,
mutation_callback=None,
):
super().__init__(filename_or_texture,
change_xy,
duration1 + duration2,
center_xy,
angle,
change_angle,
scale,
start_alpha,
mutation_callback)
self.start_alpha = start_alpha
self.in_duration = duration1
self.mid_alpha = mid_alpha
self.out_duration = duration2
self.end_alpha = end_alpha
def update(self):
super().update()
if self.lifetime_elapsed <= self.in_duration:
u = self.lifetime_elapsed / self.in_duration
self.alpha = arcade.clamp(arcade.lerp(self.start_alpha, self.mid_alpha, u), 0, 255)
else:
u = (self.lifetime_elapsed - self.in_duration) / self.out_duration
self.alpha = arcade.clamp(arcade.lerp(self.mid_alpha, self.end_alpha, u), 0, 255)
class RocketEmitter(arcade.Emitter):
"""自定义发射器类,向发射器添加重力以表示烟花外壳上的重力"""
def update(self):
super().update()
# 重力
self.change_y += -0.05
class Game(arcade.Window):
def __init__(self):
super().__init__(SCREEN_width, SCREEN_height, '粒子焰火')
file_path = os.path.dirname(os.path.abspath(__file__))
os.chdir(file_path)
arcade.set_background_color(arcade.color.BLACK)
self.emitters = []
self.launch_firework(0)
arcade.schedule(self.launch_spinner, 4.0)
stars = arcade.Emitter(
center_xy=(0.0, 0.0),
emit_controller=arcade.EmitMaintainCount(20),
particle_factory=lambda emitter: AnimatedAlphaParticle(
filename_or_texture=random.choice(STAR_textures),
change_xy=(0.0, 0.0),
start_alpha=0,
duration1=random.uniform(2.0, 6.0),
mid_alpha=128,
duration2=random.uniform(2.0, 6.0),
end_alpha=0,
center_xy=arcade.rand_in_rect((0.0, 0.0), SCREEN_width, SCREEN_height)
)
)
self.emitters.append(stars)
self.cloud = arcade.Emitter(
center_xy=(50, 500),
change_xy=(0.15, 0),
emit_controller=arcade.EmitMaintainCount(60),
particle_factory=lambda emitter: AnimatedAlphaParticle(
filename_or_texture=random.choice(CLOUD_textures),
change_xy=(_Vec2(arcade.rand_in_circle((0.0, 0.0), 0.04)) + _Vec2(0.1, 0)).as_tuple(),
start_alpha=0,
duration1=random.uniform(5.0, 10.0),
mid_alpha=255,
duration2=random.uniform(5.0, 10.0),
end_alpha=0,
center_xy=arcade.rand_in_circle((0.0, 0.0), 50)
)
)
self.emitters.append(self.cloud)
def launch_firework(self, delta_time):
launchers = (
self.launch_random_firework,
self.launch_ringed_firework,
self.launch_sparkle_firework,
)
random.choice(launchers)(delta_time)
pyglet.clock.schedule_once(self.launch_firework, random.uniform(1.5, 2.5))
def launch_random_firework(self, _delta_time):
"""以随机颜色爆炸的简单烟花"""
rocket = make_rocket(self.explode_firework)
self.emitters.append(rocket)
def launch_ringed_firework(self, _delta_time):
""""具有基本爆炸和不同颜色圆环形烟花"""
rocket = make_rocket(self.explode_ringed_firework)
self.emitters.append(rocket)
def launch_sparkle_firework(self, _delta_time):
"""火花闪烁的烟花"""
rocket = make_rocket(self.explode_sparkle_firework)
self.emitters.append(rocket)
def launch_spinner(self, _delta_time):
"""启动喷射火花的旋转器"""
spinner1 = make_spinner()
spinner2 = make_spinner()
spinner2.angle = 180
self.emitters.append(spinner1)
self.emitters.append(spinner2)
def explode_firework(self, prev_emitter):
"""烟花炮弹爆炸时发生的动作,生成典型的烟花"""
self.emitters.append(make_puff(prev_emitter))
self.emitters.append(make_flash(prev_emitter))
spark_texture = random.choice(SPARK_textures)
sparks = arcade.Emitter(
center_xy=prev_emitter.get_pos(),
emit_controller=arcade.EmitBurst(random.randint(30, 40)),
particle_factory=lambda emitter: arcade.FadeParticle(
filename_or_texture=spark_texture,
change_xy=arcade.rand_in_circle((0.0, 0.0), 9.0),
lifetime=random.uniform(0.5, 1.2),
mutation_callback=firework_spark_mutator
)
)
self.emitters.append(sparks)
def explode_ringed_firework(self, prev_emitter):
"""当烟花炮弹爆炸时发生的动作,产生环形烟花"""
self.emitters.append(make_puff(prev_emitter))
self.emitters.append(make_flash(prev_emitter))
spark_texture, ring_texture = random.choice(SPARK_list)
sparks = arcade.Emitter(
center_xy=prev_emitter.get_pos(),
emit_controller=arcade.EmitBurst(25),
particle_factory=lambda emitter: arcade.FadeParticle(
filename_or_texture=spark_texture,
change_xy=arcade.rand_in_circle((0.0, 0.0), 8.0),
lifetime=random.uniform(0.55, 0.8),
mutation_callback=firework_spark_mutator
)
)
self.emitters.append(sparks)
ring = arcade.Emitter(
center_xy=prev_emitter.get_pos(),
emit_controller=arcade.EmitBurst(20),
particle_factory=lambda emitter: arcade.FadeParticle(
filename_or_texture=ring_texture,
change_xy=arcade.rand_on_circle((0.0, 0.0), 5.0) + arcade.rand_in_circle((0.0, 0.0), 0.25),
lifetime=random.uniform(1.0, 1.6),
mutation_callback=firework_spark_mutator
)
)
self.emitters.append(ring)
def explode_sparkle_firework(self, prev_emitter):
"""烟花炮弹爆炸时发生的动作,产生闪闪发光的烟花"""
self.emitters.append(make_puff(prev_emitter))
self.emitters.append(make_flash(prev_emitter))
spark_texture = random.choice(SPARK_textures)
sparks = arcade.Emitter(
center_xy=prev_emitter.get_pos(),
emit_controller=arcade.EmitBurst(random.randint(30, 40)),
particle_factory=lambda emitter: AnimatedAlphaParticle(
filename_or_texture=spark_texture,
change_xy=arcade.rand_in_circle((0.0, 0.0), 9.0),
start_alpha=255,
duration1=random.uniform(0.6, 1.0),
mid_alpha=0,
duration2=random.uniform(0.1, 0.2),
end_alpha=255,
mutation_callback=firework_spark_mutator
)
)
self.emitters.append(sparks)
def update(self, delta_time):
# 在遍历列表时,防止列表发生变化(通常是通过回调)
emitters_to_update = self.emitters.copy()
# 更新云
if self.cloud.center_x > SCREEN_width:
self.cloud.center_x = 0
# 更新
for e in emitters_to_update:
e.update()
# 清除
to_del = [e for e in emitters_to_update if e.can_reap()]
for e in to_del:
self.emitters.remove(e)
def on_draw(self):
self.clear()
for e in self.emitters:
e.draw()
# 画距形,left, right, top, and bottom
arcade.draw_lrtb_rectangle_filled(0, SCREEN_width, 25, 0, arcade.color.DARK_GREEN)
mid = SCREEN_width / 2
arcade.draw_lrtb_rectangle_filled(mid - 2, mid + 2, SPINNER_height, 10, arcade.color.DARK_BROWN)
def on_key_press(self, key, modifiers):
if key == arcade.key.ESCAPE:
arcade.close_window()
def firework_spark_mutator(particle: arcade.FadeParticle):
"""所有焰火火花共享的mutation_callback"""
# 重力
particle.change_y += -0.03
# drag
particle.change_x *= 0.92
particle.change_y *= 0.92
def rocket_smoke_mutator(particle: arcade.LifetimeParticle):
particle.scale = arcade.lerp(0.5, 3.0, particle.lifetime_elapsed / particle.lifetime_original)
if __name__ == "__main__":
app = Game()
arcade.run()
可关注博主后,私聊博主免费获取
需要技术指导,育娃新思考,企业软件合作等更多服务请联系博主
今天是以此模板持续更新此育儿专栏的第 33/50次。
可以关注我,点赞我、评论我、收藏我啦。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。