[SOLVED] Hover animation with 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.
Message
Author
User avatar
Black Cat 2412
Regular
Posts: 74
Joined: Wed Aug 16, 2017 10:10 am
Projects: Rapunzel: A classic retold
Deviantart: BlackCat2412
Location: Vietnam
Contact:

Re: Hover animation with imagebutton?

#16 Post by Black Cat 2412 »

I tried the code, and problem no 1 disappears (Yay): Now all three button play animation smoothly, at the first time hover.
Yet: problem no 2 still remains and a new problem no 3 appears (Noooo)!

Problem no 3: If I hover my mouse vertically through all of the buttons too fast, some or all of them will stuck at the last image of the animation:
Image
And (I haven't test this fully yet) when I do that, quite frequently (one of) the idle button(s) left will turn itself on, play the animation automatically and then get stuck as well-without being hovered. (Moment after the above picture taken, the start button do that and here is the result-I have not even touch it yet):
Image

I think that you would want to see this you self. So here is the game file (put into a flesh new project and retain all the problems), with all the images for the buttons and the script:
https://drive.google.com/file/d/0B2U5_y ... sp=sharing

P/S: Thank you so so much for helping me so far : ) I really appreciate it

User avatar
Divona
Miko-Class Veteran
Posts: 678
Joined: Sun Jun 05, 2016 8:29 pm
Completed: The Falconers: Moonlight
Organization: Bionic Penguin
itch: bionicpenguin
Contact:

Re: Hover animation with imagebutton?

#17 Post by Divona »

I'm at lost here. It could simply be the limitation of Ren'Py's screen where it doesn't take input fast enough for problem 3. It could also because "screen navigation" is reused for other screens that causing problem where other button animated when switching to others screen, yet some screen like "load" working fine. Might be the time to check with other who know internal of Ren'Py better than me. Pytom perhaps, if he is available.
Completed:
Image

User avatar
Black Cat 2412
Regular
Posts: 74
Joined: Wed Aug 16, 2017 10:10 am
Projects: Rapunzel: A classic retold
Deviantart: BlackCat2412
Location: Vietnam
Contact:

Re: Hover animation with imagebutton?

#18 Post by Black Cat 2412 »

BIG UPDATE: I got the problem solved, YAY!!!
There are two things I want to annouce:
1. I asked feathersnake about this issue, and they came up with a different code to help me with it (I really can't thank you enough, feathersnake!). With their permission here is the part of the code that make things work out perfectly, without any problem whatsoever (but please note that it can be a bit worrisome about potential CPU usage):

Code: Select all

init python:
   ######Xela's Displayable Switcher code###### 
   ######Found here -> https://lemmasoft.renai.us/forums/viewtopic.php?f=8&t=37312######
   ######Used here to make ATL animations on imagebuttons restart######
    from collections import OrderedDict

    class DisplayableSwitcher(renpy.Displayable, NoRollback):
        DEFAULT = {"d": Null(), "start_st": 0,}
       
        #"""This plainly switches displayable without reshowing the image/changing any variables by calling change method.
        #"""
       
        def __init__(self, start_displayable="default", displayable=None, conditions=None, always_reset=True, **kwargs):
         #   """Expects a dict of displayable={"string": something we can show in Ren'Py}
           
          #  Default is Null() unless specified otherwise.
           # """
            super(DisplayableSwitcher, self).__init__(**kwargs)
            if not isinstance(displayable, _dict):
                self.displayable = {"default": self.DEFAULT.copy()}
            else:
                self.displayable = {}
                for s, d in displayable.iteritems():
                    self.displayable[s] = self.DEFAULT.copy()
                    d = renpy.easy.displayable(d)
                    if isinstance(d, ImageReference):
                        d = renpy.display.image.images[(d.name)]
                    self.displayable[s]["d"] = d
                    if isinstance(d, renpy.atl.ATLTransformBase):
                        self.displayable[s]["atl"] = d.copy()
                       
                self.displayable["default"] = displayable.get("default", self.DEFAULT.copy())
                       
            if not isinstance(conditions, (tuple, list)):
                self.conditions = None
            else:
                self.conditions = OrderedDict()
                for c, a in conditions:
                    code = renpy.python.py_compile(c, 'eval')
                    self.conditions[c] = a
                   
            self.always_reset = always_reset
            self.d = self.displayable[start_displayable]
            self.animation_mode = "normal"
            self.last_st = 0
            self.last_condition = None
           
        def per_interact(self):
            if self.conditions:
                for c, v in self.conditions.iteritems():
                    if renpy.python.py_eval_bytecode(c):
                        s = v[0]
                        if len(v) > 1:
                            mode = v[1]
                        else:
                            mode = "normal"
                       
                        # We only want to change if we got a new condition:
                        if self.last_condition != c or (self.always_reset and "reset" in v):
                            self.last_condition = c
                            self.change(s, mode)
                        break
                   
        def change(self, s, mode="normal"):
            self.d = self.displayable[s]
           
            self.animation_mode = mode
            if mode == "reset":
                self.d["force_restart"] = 1
           
        def render(self, width, height, st, at):
            if not st:
                for d in self.displayable.itervalues():
                    d["start_st"] = 0
                   
            rp = store.renpy
           
            self.last_st = st
           
            if self.animation_mode == "reset":
                if self.d["force_restart"]:
                    self.d["force_restart"] = 0
                    if "atl" in self.d:
                        self.d["d"].take_execution_state(self.d["atl"])
                        self.d["d"].atl_st_offset = st
                    else:
                        self.d["start_st"] = st
                st = st - self.d["start_st"] if not "atl" in self.d else st
            
               
            d = self.d["d"]
            render = rp.Render(width, height)
            render.place(d, st=st)
            rp.redraw(self, 0)
            return render
    
        def visit(self):
            return [v["d"] for v in self.displayable.values()]
            
    
init offset = -1

###Define the animation for each button
image start_hover:
    "Button/start_h1.png"
    pause 0.1
    "Button/start_h2.png"
    pause 0.025 
    "Button/start_h3.png"
    pause 0.025
    "Button/start_h4.png"
    pause .1
 
image load_hover:
    "Button/load_h1.png"
    pause 0.1
    "Button/load_h2.png"
    pause 0.025 
    "Button/load_h3.png"
    pause 0.025
    "Button/load_h4.png"
    pause .1

image setting_hover:
    "Button/setting_h1.png"
    pause 0.1
    "Button/setting_h2.png"
    pause 0.025 
    "Button/setting_h3.png"
    pause 0.025
    "Button/setting_h4.png"
    pause .1
    
###Using the Displayable Switcher on the images above to prepare resetting the animations###
image start_anim = DisplayableSwitcher(displayable={"start_switch": "start_hover"}, conditions=(("switch == 0", ("start_switch", )),
     ("switch == 1", ("start_switch", "reset")),))

image load_anim = DisplayableSwitcher(displayable={"load_switch": "load_hover"}, conditions=(("switch == 0", ("load_switch", )),
     ("switch == 1", ("load_switch", "reset")),))

image setting_anim = DisplayableSwitcher(displayable={"setting_switch": "setting_hover"}, conditions=(("switch == 0", ("setting_switch", )),
     ("switch == 1", ("setting_switch", "reset")),))


###Putting it all together in the navigation screen
screen navigation():  
    if main_menu:
        #START button#
        ###Note: vbox made the Displayable Switcher act strangely, so positions were defined per imagebutton###
        imagebutton idle "Button/start_idle.png" hover "start_anim" selected_idle "Button/start_h4.png" selected_hover "Button/start_h4.png" xpos .04 ypos .3 focus_mask None action Start() hovered [SetVariable("switch", 1)]
        
    else:

        textbutton _("History") action ShowMenu("history")

        textbutton _("Save") action ShowMenu("save")

    #LOAD button#
    imagebutton idle "Button/load_idle.png" hover "load_anim" selected_idle "Button/load_si.png" selected_hover "Button/load_sh.png" xpos .04 ypos .38 focus_mask None action ShowMenu("load") hovered [SetVariable("switch", 1)] 
            
    #SETTING button#
    imagebutton idle "Button/setting_idle.png" hover "setting_anim" selected_idle "Button/setting_si.png" selected_hover "Button/setting_sh.png" xpos .04 ypos .46 focus_mask None action ShowMenu("preferences") hovered [SetVariable("switch", 1)]
        
    vbox:
        style_prefix "navigation"

        xpos gui.navigation_xpos
        yalign 0.65

        spacing gui.navigation_spacing
        if _in_replay:

            textbutton _("End Replay") action EndReplay(confirm=True)

        elif not main_menu:

            textbutton _("Main Menu") action MainMenu()

        textbutton _("About") action ShowMenu("about") 

        if renpy.variant("pc"):

            ## Help isn't necessary or relevant to mobile devices.
            textbutton _("Help") action ShowMenu("help")

            ## The quit button is banned on iOS and unnecessary on Android.
            textbutton _("Quit") action Quit(confirm=not main_menu)
2. I PM Tom Divona's code and he said that he has fixed the issue with the nested images. This mean that I should be able to use Dinova's code without any issue as well in the upcoming prerelease 6.99.13 (in about a week from now or so)

Thank all of you for following this thread!!

Post Reply

Who is online

Users browsing this forum: Ahrefs [Bot]