Skip to content

Instantly share code, notes, and snippets.

@rurubell
Created February 17, 2020 11:23
Show Gist options
  • Save rurubell/a30752048bbe20de546d737c2476916f to your computer and use it in GitHub Desktop.
Save rurubell/a30752048bbe20de546d737c2476916f to your computer and use it in GitHub Desktop.
init python:
#################################################################
# Здесь мы используем случайный модуль для некоторый произвольных материалов (так как мы
# не хотим, чтобы Ren'Py сохранял случайные числа, мы будем их генерировать).
import random
# инициализация случайных чисел
random.seed()
#################################################################
# Частицы снега
# ----------------
def Dust(image, max_particles=300, speed=10, wind=20, xborder=(0,0), yborder=(0,0), **kwargs):
"""
Это создает эффект снега. Следует использовать эту функцию вместо того, чтобы инстанцировать
DustFactory напрямую (Ну, на самом деле не имеет значения, но это сэкономит набор текста,
если вы используете значения по умолчанию =D)
@parm {image} image:
Это изображение используется в качестве снежинок. Это всегда должен быть файл изображения
или im объект, так как мы будем применять im трансформации на нем.
@parm {int} max_particles:
Максимально количество частиц на экране одновременно.
@parm {float} speed:
Основная скорость частиц по вертикали. Чем выше значение, тем быстрее частицы
будут падать.
Значения ниже 1 будут изменены на 1
@parm {float} wind:
Максимальная сила ветра, которая будет применена к частицам.
@parm {Tuple ({int} min, {int} max)} xborder:
Горизонтальная границы диапазона. Случайное значение между этими двумя будет применено
при создании частиц.
@parm {Tuple ({int} min, {int} max)} yborder:
Вертикальная границы диапазона. Случайное значение между этими двумя будет применено
при создании частиц.
Чем выше значения, тем дальше от экрана они будут создаваться.
"""
return Particles(DustFactory(image, max_particles, speed, wind, xborder, yborder, **kwargs))
# ---------------------------------------------------------------
class DustFactory(object):
"""
Фабрика, создающая частицы, используемые в эффекте снега.
"""
def __init__(self, image, max_particles, speed, wind, xborder, yborder, **kwargs):
"""
Инициализировать фабрику. Параметры такие же, как у Dust функции.
"""
# максимальное число частиц может быть одновременно на экране
self.max_particles = max_particles
# скорость частицы
self.speed = speed
# скорость ветра
self.wind = wind
# горизонтальный/вертикальный диапазон для создания частиц
self.xborder = xborder
self.yborder = yborder
# максимальная глубина экрана. Наибольшие значения приводит к большим имениям
# размера частиц, но они также используют больше памяти. 10 это значение по умолчанию
# и оно должно подходить для большинства игр,
# поскольку размеры частиц рассчитываются как процент от этого значения.
self.depth = kwargs.get("depth", 10)
# инициализация изображений
self.image = self.image_init(image)
def create(self, particles, st):
"""
Вызывается изнутри каждого фрейма объекта Particles для создания новых частиц.
Мы просто создадим новые частицы, если число частиц на экране меньше, чем
максимально число части, которое может быть.
"""
# Если мы создаем новую частицу...
if particles is None or len(particles) < self.max_particles:
# генерируем случайную глубину для частицы
depth = random.randint(1, self.depth)
# Мы предполагаем, что частицы падающие далеко от экрана будут двигаться медленнее,
# чем те, что падают вблизи экрана. Так мы изменим скорость падения частиц на основе
# их глубины =D
depth_speed = 1.5-depth/(self.depth+0.0)
return [ DustParticle(self.image[depth-1], # изображение, используемое частицей
random.uniform(-self.wind, self.wind)*depth_speed, # сила ветра
self.speed*depth_speed, # вертикальная скорость частицы
random.randint(self.xborder[0], self.xborder[1]), # горизонтальная граница
random.randint(self.yborder[0], self.yborder[1]), # вертикальная граница
) ]
def image_init(self, image):
"""
Это вызывают изнутри для инициализации изображений.
Создает список изображений с различными размерами, поэтому мы можем
предугадать их все и использовать кэшированные версии, чтобы сделать
их более эффективными для памяти.
"""
rv = [ ]
# создает массив изображений для каждого возможного значения глубины.
for depth in range(self.depth):
# Изменение размера и корректировка альфа значения на основе глубины изображения
p = 1.1 - depth/(self.depth+0.0)
if p > 1:
p = 1.0
rv.append( im.FactorScale( im.Alpha(image, p), p ) )
return rv
def predict(self):
"""
Это вызываемый изнутри объект Particles для прогнозирования используемых
изображений частиц. Предполагает возврат списка изображения для прогнозирования.
"""
return self.image
# ---------------------------------------------------------------
class DustParticle(object):
"""
Представляет каждую частицу на экране.
"""
def __init__(self, image, wind, speed, xborder, yborder):
"""
Инициализирует частицы снега. Вызывается автоматически при создании объекта.
"""
# Изображение, используемое этой частицей
self.image = image
# Для безопасности (и так как у нас нет снега, идущего от пола до неба o.o)
# если вертикальная скорость частиц ниже, чем 1, мы используем 1.
# Препятствует застреванию частиц на экране навсегда и не падению вообще.
if speed <= 0:
speed = 1
# скорость ветра
self.wind = wind
# скорость частицы
self.speed = speed
# Последний раз, когда частица была обновлена (используется для расчета непредвиденных
# задержек между обновлениями, иначе говоря лаг)
self.oldst = None
# горизонтальные/вертикальные положения частицы (0 - вниз, 1 - вверх)
self.xpos = random.uniform( 0, renpy.config.screen_width )
self.ypos = random.uniform( 0, renpy.config.screen_height )
self.direction = int( random.uniform( 0, 2 ) )
def update(self, st):
"""
Вызывается внутри каждого фрейма для обновления частицы.
"""
# вычисление лага
if self.oldst is None:
self.oldst = st
lag = st - self.oldst
self.oldst = st
# обновление положения
self.xpos += lag * self.wind
if( self.direction <= 0 ):
self.ypos += lag * self.speed
if( self.direction > 0 ):
self.ypos -= lag * self.speed
#Если частица вышла за педелы экрана по горизонтали, и летит направо
if( ( self.wind >= 0 ) and ( self.xpos >= renpy.config.screen_width ) ):
self.xpos = 0
#Если частица вышла за педелы экрана по горизонтали, и летит налево
if( ( self.wind < 0 ) and ( self.xpos <= 0 ) ):
self.xpos = renpy.config.screen_width
#Если частица летит вниз и вышла за пределы экрана
if( ( self.direction <= 0 ) and ( self.ypos > renpy.config.screen_height ) ):
self.ypos = 0
#Если частица летит вверх и вышла за пределы экрана
if( ( self.direction > 0 ) and ( self.ypos < 0 ) ):
self.ypos = renpy.config.screen_height
# возвращает частицу как кортеж (xpos, ypos, time, image)
# так как она предполагает, что горизонтальный и вертикальные положения - целые числа,
# мы должны преобразовать их (внутренней позиции используют float для плавных движений =D)
return int(self.xpos), int(self.ypos), st, self.image
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment