diff --git a/game/examples/glitch.rpy b/game/examples/glitch.rpy new file mode 100644 index 0000000..823c866 --- /dev/null +++ b/game/examples/glitch.rpy @@ -0,0 +1,250 @@ +# https://github.com/Gouvernathor/renpy-ChromaGlitch +init python: + class glitch(renpy.Displayable): + """ + `randomkey` + Follows the rules of the random modume's seed function. + If not set, a random seed is generated when the transform is applied, + and stays the same afterwards. + If you want the effect to be random for each render operation, set to None. + + `chroma` + Boolean, whether to apply the chromatic aberration effect. + + `minbandheight` + Minimum height of each slice. + + `offset` + The offset of each slice will be between -offset and offset pixels. + + `nslices` + Number of slicings to do (the number of slices will be nslices + 1). + Setting this to 0 is not supported. + None (the default) makes it random. + """ + + NotSet = object() + + def __init__(self, child, *, randomkey=NotSet, chroma=True, minbandheight=1, offset=30, nslices=None, **properties): + super().__init__(**properties) + self.child = renpy.displayable(child) + if randomkey is self.NotSet: + randomkey = renpy.random.random() + self.randomkey = randomkey + self.chroma = chroma + self.minbandheight = minbandheight + self.offset = offset + self.nslices = nslices + + def render(self, width, height, st, at): + child = self.child + child_render = renpy.render(child, width, height, st, at) + cwidth, cheight = child_render.get_size() + if not (cwidth and cheight): + return child_render + render = renpy.Render(cwidth, cheight) + randomobj = renpy.random.Random(self.randomkey) + chroma = self.chroma and renpy.display.render.models + offset = self.offset + minbandheight = self.minbandheight + nslices = self.nslices + if nslices is None: + nslices = min(int(cheight/minbandheight), randomobj.randrange(10, 21)) + + theights = sorted(randomobj.randrange(cheight+1) for k in range(nslices)) # y coordinates demarcating all the strips + offt = 0 # next strip's lateral offset + fheight = 0 # sum of the size of all the strips added this far + while fheight= self.timeout: + randomkey = self.randomkey + randomobj = renpy.random.Random(randomkey) + self.randomkey = randomobj.random() + + # determine whether to show vanilla or not + if vanilla or (self.timeout_vanilla is False): + # if we were showing it or if showing it is disabled + vanilla = False + else: + vanilla = (randomobj.random() < .3) + + self.set_timeout(vanilla, st) + + renpy.redraw(self, st-self.timeout) + + if vanilla: + return renpy.render(self.child, width, height, st, at) + else: + return super().render(width, height, st, at) + + class squares_glitch(renpy.Displayable): + """ + `squareside` + The size, in pixels, of the side of the squares the child image will be cut to. This will + be adjusted so that all the "squares" (rectangles, really) have the same width and the + same height, and that none is cut at the borders of the image. Defaults to 20 pixels. + + `chroma` + The probability for each square to get a chromatic effect. Defaults to .25. + + `permutes` + The percentage of squares which will be moved to another square's place. If not passed, + defaults to a random value between .1 and .4. + """ + + NotSet = object() + + def __init__(self, child, *args, randomkey=NotSet, **kwargs): + super().__init__() + self.child = renpy.displayable(child) + self.args = args + if randomkey is self.NotSet: + randomkey = renpy.random.random() + self.randomkey = randomkey + self.kwargs = kwargs + + def render(self, width, height, st, at): + cwidth, cheight = renpy.render(self.child, width, height, st, at).get_size() + return renpy.render(self.glitch(self.child, + cwidth, cheight, renpy.random.Random(self.randomkey), + *self.args, **self.kwargs), + width, height, + st, at) + + @staticmethod + def glitch(child, cwidth, cheight, randomobj, squareside=20, chroma=.25, permutes=None): + if not renpy.display.render.models: + chroma = False + if not (cwidth and cheight): + return child + + ncols = round(cwidth/squareside) + nrows = round(cheight/squareside) + square_width = absolute(cwidth/ncols) + square_height = absolute(cheight/nrows) + + lizt = [] + for y in range(nrows): + for x in range(ncols): + lizt.append(Transform(child, + crop=(absolute(x*square_width), absolute(y*square_height), square_width, square_height), + subpixel=True, + )) + + if permutes is None: + permutes = randomobj.randrange(10, 40)/100 # between 10% and 40% + permutes = round(permutes*ncols*nrows) + permute_a = randomobj.sample(range(ncols*nrows), permutes) + permute_b = randomobj.sample(range(ncols*nrows), permutes) + + for a, b in zip(permute_a, permute_b): + lizt[a], lizt[b] = lizt[b], lizt[a] + + for k, el in enumerate(lizt): + if randomobj.random() < chroma: + lizt[k] = Transform(el, + gl_color_mask=(randomobj.random()<.33, randomobj.random()<.33, randomobj.random()<.33, True), + # matrixcolor=HueMatrix(randomobj.random()*360), + ) + + return Grid(ncols, nrows, *lizt) + + def __eq__(self, other): + return (type(self) == type(other)) and (self.args == other.args) and (self.kwargs == other.kwargs) + +label glitch_example: + + show expression glitch("eileen happy") + + e "I'm glitched and happy!" + + show eileen concerned at glitch + + e "I'm glitched and concerned..." + + # Use the randomkey parameter if you want to make the animation periodic + image eileen glitched: + glitch("eileen vhappy") + pause 1.0 + glitch("eileen happy", offset=60, randomkey=None) + pause 0.1 + repeat + + show eileen glitched + + e "I'm glitched and animated." + + jump start diff --git a/game/examples/start.rpy b/game/examples/start.rpy index 1a1e022..c71bd9a 100644 --- a/game/examples/start.rpy +++ b/game/examples/start.rpy @@ -9,8 +9,6 @@ label start: scene bg club menu: - "Which example do you want to see?" - "Creator-Defined Statements (CDS)": jump creator_defined_statements @@ -20,6 +18,9 @@ label start: "Drag and Drop": jump drag_and_drop + "Glitch": + jump glitch_example + "Image": jump image_example