[SOLVED]How to change a variable in a animation using a imagebutton?

Discuss how to use the Ren'Py engine to create visual novels and story-based games. New releases are announced in this section.
Forum rules
This is the right place for Ren'Py help. Please ask one question per thread, use a descriptive subject like 'NotFound error in option.rpy' , and include all the relevant information - especially any relevant code and traceback messages. Use the code tag to format scripts.
Post Reply
Message
Author
VirtualPassion
Newbie
Posts: 10
Joined: Wed Feb 28, 2024 3:10 am
Deviantart: virdate
itch: virtual-passion
Contact:

[SOLVED]How to change a variable in a animation using a imagebutton?

#1 Post by VirtualPassion »

I have animation. I want to change the frame rate of the animation using buttons on the screen.
File 0animations.rpy

Code: Select all

init python:
     def Ani(img_name, frames, sspeed=0.1, loop=True, reverse=False, effect=None, start=0, ext="jpg", **properties):
        if img_name:
            args = []
            # loop through all the frames of the animation
            for i in range(start, start + frames):
                if ext is None:
                    args.append(renpy.easy.displayable(img_name + str(i)))
                else:
                    args.append(renpy.display.im.image(img_name + str(i) + "." + ext))
                if reverse or loop or (i < start + frames - 1):
                    args.append(sspeed)
                    # add a frame change effect
                    args.append(effect)
            return anim.TransitionAnimation(*args, **properties)
        return None

init:
    image 123mon097A = Ani("123mon097", 6, .06, True, True) #(How do I use the slidespeed variable here?)
File 0minigames.rpy

Code: Select all

init:
    $ slidespeed =.08
    
screen speed_buttons():
    hbox xalign 0.5: 
        imagebutton:
            idle ("images/buttons/gui/button_sf.png")
            hover ("images/buttons/gui/button_sf.png")
            action [SetVariable('slidespeed', slidespeed+0.02), Hide('speed_buttons'), Jump('twh123mon097')]
        imagebutton:
            idle ("images/buttons/gui/button_sr.png")
            hover ("images/buttons/gui/button_sr.png")
            action [SetVariable('slidespeed', slidespeed-0.02), Hide('speed_buttons'), Jump('twh123mon097')]
File script.rpy

Code: Select all

label twh123mon097:
    show screen speed_buttons
    scene 123mon097-0
    show 123mon097A
Please advise. How do I change the animation speed with a button?
Last edited by VirtualPassion on Sun Mar 03, 2024 3:03 am, edited 1 time in total.

jeffster
Veteran
Posts: 409
Joined: Wed Feb 03, 2021 9:55 pm
Contact:

Re: How to change a variable in a animation using a imagebutton?

#2 Post by jeffster »

If you don't mind to use Creator Defined Displayables
https://renpy.org/doc/html/cdd.html
it seems to be a pretty direct way to do that.

Basically you define there a class (a subclass of renpy.Displayable) with 3 main methods:

__init__(self) sets the data used in that displayable.

render(self, width, height, st, at) draws the picture.

event(self, ev, x, y, st) controls interactions and the speed of changes in the picture.
For example, using renpy.redraw() to cause "render()" to run (with new data) when you need to draw something new on the screen.

In parameters, see st and at to check "animation time" (since animation started), and at certain points in time you could change the picture to show in the displayable.

To control animation speed you can set the delay between redraws with renpy.redraw():
https://renpy.org/doc/html/cdd.html#renpy.redraw

Instead of Creator Defined Displayables, there may be also ways to use ATL with parameters to change animation speed.
E.g. see "Function Statement":
https://renpy.org/doc/html/atl.html#function-statement

PS. It seems that it's some old code that you are trying to change. If you are trying to do something new, then it makes sense to use newer methods. Otherwise I'm not sure that I can help much, as I didn't work with those old methods.

VirtualPassion
Newbie
Posts: 10
Joined: Wed Feb 28, 2024 3:10 am
Deviantart: virdate
itch: virtual-passion
Contact:

Re: How to change a variable in a animation using a imagebutton?

#3 Post by VirtualPassion »

Thanks for your help. I'll read up on the new method.
Yes, it's old code, I've been using it for years. I have over 450 animations in my game using this method.

VirtualPassion
Newbie
Posts: 10
Joined: Wed Feb 28, 2024 3:10 am
Deviantart: virdate
itch: virtual-passion
Contact:

Re: How to change a variable in a animation using a imagebutton?

#4 Post by VirtualPassion »

Still, maybe someone knows how to use a variable in my method?

User avatar
Ocelot
Lemma-Class Veteran
Posts: 2411
Joined: Tue Aug 23, 2016 10:35 am
Github: MiiNiPaa
Discord: MiiNiPaa#4384
Contact:

Re: How to change a variable in a animation using a imagebutton?

#5 Post by Ocelot »

In short, it isn't possible. TransitionAnimation oficially does not support changing its parameters once created. In addition, TransitionAnimation itself is not supported anymore and its entry in documentation is deleted.
< < insert Rick Cook quote here > >

jeffster
Veteran
Posts: 409
Joined: Wed Feb 03, 2021 9:55 pm
Contact:

Re: How to change a variable in a animation using a imagebutton?

#6 Post by jeffster »

Here is a script for animation with variable frame rate:

Code: Select all

init python:
    def get_frame(i=1, base="sample/ani", digits=2, extension="webp"):
        frameN = f"{i:09d}"[-digits:]
        return ''.join((base, frameN, '.', extension))

    class Anim(renpy.Displayable):
        def __init__(self, i=1, base="sample/ani", digits=2,
                        extension="webp", framerate=15, **kwargs):
            """ Shows image files like "sample/ani01.webp" (02, 03 etc)
                as animation frames, at frame rate "framerate"

                i = number of first frame (usually 1, maybe 0 etc)
                base = name of frame files, constant part
                digits = how many digits in frame name (2 for "ani01.webp", or 3 for "ani001.webp", etc.)
                extension = frame files' extension
                => frame names will be something like base##.extension, starting from f"base{i: 0<digits>d}.{extension}"
            """
            super(Anim, self).__init__(**kwargs)
            self.r = None               # render
            self.i = i                  # 1st frame number
            self.n = i                  # current frame number
            self.base = base            # image file name constant part
            self.digits = digits        # 2 for XX, 3 for XXX etc.
            self.extension = extension  # image file extension (webp, jpg, png...)
            self.f_length = 1.0 / framerate  # frame length in sec
            self.previous_at = 0.0      # animation time

        def render(self, width, height, st, at):
            try:
                self.r = renpy.load_image(get_frame(self.n,
                    base=self.base, digits=self.digits,
                    extension=self.extension))

            except:
                # If the next frame doesn't exist, go back to the 1st
                self.n = self.i
                self.r = renpy.load_image(get_frame(self.n,
                    base=self.base, digits=self.digits,
                    extension=self.extension))

            if at - self.previous_at > self.f_length:
                # Go to next image
                self.n += 1
                self.previous_at = at

            # Call redraw next frame (meaning monitor frequency frame)
            renpy.redraw(self, 0)

            # Return the render.
            return self.r

        def event(self, ev, x, y, st):
            # Put here events for displayable to react
            pass

default a = Anim()
default frate = 15

screen animated():
    add a align (0.5, 0.5)

label start:
    scene black
    show screen animated
label loop:
    $ frate = int(renpy.input(f"Frame rate ({frate}):"))
    $ a = Anim(framerate=frate)
    jump loop
To test it, put animation frames as files "images/sample/ani01.webp" (and so on: ani02.webp, ani03.webp...) or set different parameters in Anim().
(For Ren'Py before 8, change f-strings formatting to Python 2 formatting).

jeffster
Veteran
Posts: 409
Joined: Wed Feb 03, 2021 9:55 pm
Contact:

Re: How to change a variable in a animation using a imagebutton?

#7 Post by jeffster »

PS. If you want to change frame rate "on the fly":

Anim.event() runs every time a key is pressed, or the mouse is moved or its button clicked.

You can change some variable like "frate" by clicking buttons, pressing keys etc.

Anim.event() will run then, and you could just check "frate" value to adjust self.f_length:

Code: Select all

        def event(self, ev, x, y, st):
            self.f_length = 1.0 / store.frate
The displayable would change its frame rate immediately. (I think).

VirtualPassion
Newbie
Posts: 10
Joined: Wed Feb 28, 2024 3:10 am
Deviantart: virdate
itch: virtual-passion
Contact:

Re: How to change a variable in a animation using a imagebutton?

#8 Post by VirtualPassion »

It's so complicated. So much code... Thank you all, I'll think about it.

jeffster
Veteran
Posts: 409
Joined: Wed Feb 03, 2021 9:55 pm
Contact:

Re: How to change a variable in a animation using a imagebutton?

#9 Post by jeffster »

VirtualPassion wrote: Fri Mar 01, 2024 3:38 am It's so complicated. So much code... Thank you all, I'll think about it.
You can just copy-paste my code (everything in "init python" block), and then you would only need to set your displayable with proper parameters:

Code: Select all

$ a = Anim()
For example, if your animation is from "my-frames01.png" to "my-frames10.png", and the initial frame rate you want is 30 FPS:

Code: Select all

$ a = Anim(1, "my-frames", 2, "png", 30)

jeffster
Veteran
Posts: 409
Joined: Wed Feb 03, 2021 9:55 pm
Contact:

Re: How to change a variable in a animation using a imagebutton?

#10 Post by jeffster »

Here is a working game, changing animation speed with buttons and bar:
Image

Run it with Ren'Py 8
Attachments
anim-variable.zip
(656.02 KiB) Downloaded 15 times

VirtualPassion
Newbie
Posts: 10
Joined: Wed Feb 28, 2024 3:10 am
Deviantart: virdate
itch: virtual-passion
Contact:

Re: How to change a variable in a animation using a imagebutton?

#11 Post by VirtualPassion »

Thank you. I was able to paste the code and customize my animations.
I have animations that need reverse motion as well. For example:
"my-frames01.png", "my-frames02.png", "my-frames01.png"
How does this change the animation code?

VirtualPassion
Newbie
Posts: 10
Joined: Wed Feb 28, 2024 3:10 am
Deviantart: virdate
itch: virtual-passion
Contact:

Re: How to change a variable in a animation using a imagebutton?

#12 Post by VirtualPassion »

I did this code in the main game.

Code: Select all

label twh123mon043:
    stop music fadeout 1.0
    $ frate = 10
    $ a = Anim(0, "123mon043-", 2, "jpg", 20)
    scene black
    show screen animated
    pause
    you "Thank you. Call me whenever you need me again!"
    hide screen animated
And after that, I can't save the game

Code: Select all

I'm sorry, but an uncaught exception occurred.

While running game code:
  File "renpy/common/00action_file.rpy", line 414, in __call__
    renpy.save(fn, extra_info=save_name)
Exception: Can't pickle a Render. (perhaps store.a.r = <dead Render 10751630 of []>)

-- Full Traceback ------------------------------------------------------------

Full traceback:
  File "renpy/common/_layout/screen_load_save.rpym", line 35, in script
    $ ui.interact()
  File "C:\renpy-7.6.3-sdk\renpy\ast.py", line 823, in execute
    renpy.python.py_exec_bytecode(self.code.bytecode, self.hide, store=self.store)
  File "C:\renpy-7.6.3-sdk\renpy\python.py", line 1178, in py_exec_bytecode
    exec(bytecode, globals, locals)
  File "renpy/common/_layout/screen_load_save.rpym", line 35, in <module>
    $ ui.interact()
  File "C:\renpy-7.6.3-sdk\renpy\ui.py", line 301, in interact
    rv = renpy.game.interface.interact(roll_forward=roll_forward, **kwargs)
  File "C:\renpy-7.6.3-sdk\renpy\display\core.py", line 2165, in interact
    repeat, rv = self.interact_core(preloads=preloads, trans_pause=trans_pause, pause=pause, pause_start=pause_start, pause_modal=pause_modal, **kwargs) # type: ignore
  File "C:\renpy-7.6.3-sdk\renpy\display\core.py", line 3197, in interact_core
    rv = root_widget.event(ev, x, y, 0)
  File "C:\renpy-7.6.3-sdk\renpy\display\layout.py", line 1202, in event
    rv = i.event(ev, x - xo, y - yo, cst)
  File "C:\renpy-7.6.3-sdk\renpy\display\transition.py", line 53, in event
    return self.new_widget.event(ev, x, y, st) # E1101
  File "C:\renpy-7.6.3-sdk\renpy\display\layout.py", line 1202, in event
    rv = i.event(ev, x - xo, y - yo, cst)
  File "C:\renpy-7.6.3-sdk\renpy\display\layout.py", line 1202, in event
    rv = i.event(ev, x - xo, y - yo, cst)
  File "C:\renpy-7.6.3-sdk\renpy\display\screen.py", line 793, in event
    rv = self.child.event(ev, x, y, st)
  File "C:\renpy-7.6.3-sdk\renpy\display\layout.py", line 1202, in event
    rv = i.event(ev, x - xo, y - yo, cst)
  File "C:\renpy-7.6.3-sdk\renpy\display\layout.py", line 1426, in event
    rv = super(Window, self).event(ev, x, y, st)
  File "C:\renpy-7.6.3-sdk\renpy\display\layout.py", line 288, in event
    rv = d.event(ev, x - xo, y - yo, st)
  File "C:\renpy-7.6.3-sdk\renpy\display\layout.py", line 1202, in event
    rv = i.event(ev, x - xo, y - yo, cst)
  File "C:\renpy-7.6.3-sdk\renpy\display\layout.py", line 1202, in event
    rv = i.event(ev, x - xo, y - yo, cst)
  File "C:\renpy-7.6.3-sdk\renpy\display\behavior.py", line 1174, in event
    return handle_click(self.clicked)
  File "C:\renpy-7.6.3-sdk\renpy\display\behavior.py", line 1095, in handle_click
    rv = run(action)
  File "C:\renpy-7.6.3-sdk\renpy\display\behavior.py", line 388, in run
    new_rv = run(i, *args, **kwargs)
  File "C:\renpy-7.6.3-sdk\renpy\display\behavior.py", line 395, in run
    return action(*args, **kwargs)
  File "renpy/common/00action_file.rpy", line 414, in __call__
    renpy.save(fn, extra_info=save_name)
  File "C:\renpy-7.6.3-sdk\renpy\loadsave.py", line 436, in save
    reraise(t, e, tb)
  File "lib/python3.9/future/utils/__init__.py", line 444, in raise_
  File "C:\renpy-7.6.3-sdk\renpy\loadsave.py", line 417, in save
    dump((roots, renpy.game.log), logf)
  File "C:\renpy-7.6.3-sdk\renpy\compat\pickle.py", line 103, in dump
    pickle.dump(o, f, pickle.HIGHEST_PROTOCOL if highest else PROTOCOL)
  File "render.pyx", line 765, in renpy.display.render.Render.__getstate__
Exception: Can't pickle a Render. (perhaps store.a.r = <dead Render 10751630 of []>)

Windows-10-10.0.19045 AMD64
Ren'Py 8.2.0.24012702
Witcher Hunt 0.15
Sat Mar  2 11:17:03 2024

jeffster
Veteran
Posts: 409
Joined: Wed Feb 03, 2021 9:55 pm
Contact:

Re: How to change a variable in a animation using a imagebutton?

#13 Post by jeffster »

VirtualPassion wrote: Sat Mar 02, 2024 4:21 am And after that, I can't save the game
My bad. Render "r" shouldn't be saved, so it shouldn't be a part of the Anim object.

To correct the error,
(1) remove line

Code: Select all

            self.r = None               # render
in the function "__init__" of "class Anim" definition.

(2) Change all the three "self.r" to just "r" in "def render".
I have animations that need reverse motion as well. For example:
"my-frames01.png", "my-frames02.png", "my-frames01.png"
How does this change the animation code?
One possible way is to make a list of frames, and use that list as Anim() parameter.
Is it more convenient for you?
It's probably the most general and flexible way.
I didn't use this method just because it seemed to add more work (defining lists) when there are long animations with many frames. But maybe it's not your case. Then lists of files can be more convenient.

Otherwise it's possible to add a parameter like reverse and if it is set, then change the direction of frames iteration when we reach past the last one.

Then class Anim can be:

Code: Select all

    class Anim(renpy.Displayable):
        def __init__(self, i=1, base="sample/ani", digits=2,
                        extension="webp", framerate=15, reverse=False, **kwargs):
            super(Anim, self).__init__(**kwargs)
            self.i = i                  # 1st frame number
            self.n = i                  # current frame number
            self.base = base            # image file name constant part
            self.digits = digits        # 2 for XX, 3 for XXX etc.
            self.extension = extension  # image file extension (webp, jpg, png...)
            self.f_length = 1.0 / framerate  # frame length in sec
            self.reverse = reverse      # Should animation go forth and back
            self.add = 1                     # Add 1 (or -1 if in reverse) to get next frame file
            self.previous_at = 0.0      # animation time

        def render(self, width, height, st, at):
            filename = get_frame(self.n, base=self.base,
                        digits=self.digits, extension=self.extension)
            if not renpy.loadable(filename, directory="images"):
                if self.reverse:
                    self.add = -self.add
                    self.n += self.add
                else:
                    self.n = self.i
                filename = get_frame(self.n, base=self.base,
                        digits=self.digits, extension=self.extension)
            r = renpy.load_image(filename)

            if at - self.previous_at > self.f_length:
                # Go to next image
                self.n += self.add
                self.previous_at = at

            renpy.redraw(self, 0)
            return r

        def event(self, ev, x, y, st):
            # Put here events for displayable to react
            self.f_length = 1.0 / store.frate
and if the animation goes one way, you set it in the same manner as before;

Code: Select all

$ a = Anim(0, "123mon043-", 2, "jpg", 10)
and with reverse movement you add parameter True as the last one:

Code: Select all

$ a = Anim(0, "123mon043-", 2, "jpg", 10, True)

VirtualPassion
Newbie
Posts: 10
Joined: Wed Feb 28, 2024 3:10 am
Deviantart: virdate
itch: virtual-passion
Contact:

Re: How to change a variable in a animation using a imagebutton?

#14 Post by VirtualPassion »

It's all working now.
Thank you so much for your help. Success to you in all your projects!

jeffster
Veteran
Posts: 409
Joined: Wed Feb 03, 2021 9:55 pm
Contact:

Re: How to change a variable in a animation using a imagebutton?

#15 Post by jeffster »

Likewise. 👍

Post Reply

Who is online

Users browsing this forum: Semrush [Bot]