[Solved]Questions about function(in button action)

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
GoodmanLove
Newbie
Posts: 18
Joined: Thu Jun 24, 2021 4:12 am
Contact:

[Solved]Questions about function(in button action)

#1 Post by GoodmanLove »

I want to use function to complete some simple calculation, such as clicking a button to increase or decrease some values or bar animation.

But there are two questions.
First of all, I want to figure out how SetVariable() works,however I can't find those code from renpy.
So,I changed my mind,I used Function() to complete the calculation I want.
But how can the value of Function() be fed back to screen?
There is my code(I'm a new fish, don't laugh at me :( )

Code: Select all

default flag001 = 0
default flag002 = 0

init -1 python:
    import requests
    import random

    def plus_var_fun():
        global flag001
        flag001 = flag001 + random.randint(5,8)
        if flag001 >= 50:
            flag001 = 50

    def red_var_fun():
        global flag001
        flag001 = flag001 - random.randint(5,8)
        if flag001 <= 0:
            flag001 = 0



label start:

    $ flag001 = 21
    $ flag002 = 5
    scene black
    call screen stats


    return


screen stats():
    use attack_fun(flag001,0.25)
    use attack_fun(flag002,0.75)


screen attack_fun(hp, xalign):

    frame:
        xalign xalign
        ycenter 0.25
        xsize 180
        ysize 320
        vbox:
            bar:
                value AnimatedValue(value=hp, range=50, delay=0.3, old_value=None)
                xsize 170
                xcenter 0.5

            if hp < 50:
                textbutton "heal":
                    text_size 40
                    text_outlines[(absolute(2), "#effdff", absolute(0), absolute(0))]
                    text_color "#ed54de"
                    text_selected_color "#32e0fc"
                    action Function(plus_var_fun)
            elif hp >= 50:
                textbutton "backZero":
                    text_size 40
                    text_outlines[(absolute(2), "#effdff", absolute(0), absolute(0))]
                    text_color "#ed54de"
                    text_selected_color "#32e0fc"
                    action SetVariable("hp", 0)

            if hp > 0:
                textbutton "damage":
                    text_size 40
                    text_outlines[(absolute(2), "#effdff", absolute(0), absolute(0))]
                    text_color "#ed54de"
                    text_selected_color "#32e0fc"
                    action Function(red_var_fun)
            elif hp <= 0:
                textbutton "backFull":
                    text_size 40
                    text_outlines[(absolute(2), "#effdff", absolute(0), absolute(0))]
                    text_color "#ed54de"
                    text_selected_color "#32e0fc"
                    action SetVariable("hp", 50)

            text "hp:[hp]"
The first question is how to make the return value of the function return to "hp" correctly.
I should design a function which have a parameter, but it's back to the beginning,how can the value of Function() be fed back correctly.

The second question is whether the code can be reused through such a design, but after the above code runs, an error will eventually be generate.
Renpy warns me : "The variable hp does not exist."
Do I need to define parameters like hp? I am confused.

Code: Select all

def plus_var_fun(x):
        x = x + random.randint(5,8)
        if x >= 50:
            x = 50
def red_var_fun(x):
        x = x - random.randint(5,8)
        if x <= 0:
            x = 0
Because "x" is not a global variable, it cannot be passed back to "hp"
besides, is it right on grammar "action Function(plus_var_fun, x=hp)"?

Godman please help me.
Last edited by GoodmanLove on Thu Jul 15, 2021 8:59 pm, edited 1 time in total.

User avatar
hell_oh_world
Miko-Class Veteran
Posts: 777
Joined: Fri Jul 12, 2019 5:21 am
Contact:

Re: Questions about function(in button action)

#2 Post by hell_oh_world »

SetVariable("hp", 0)
this one throws an error because the SetVariable action is meant for global variables not local variables, in your screen you're passing the hp as a local variable.
Use SetLocalVariable instead, its also documented in Renpy Actions section.

GoodmanLove
Newbie
Posts: 18
Joined: Thu Jun 24, 2021 4:12 am
Contact:

Re: Questions about function(in button action)

#3 Post by GoodmanLove »

hell_oh_world wrote: Thu Jul 15, 2021 6:45 am SetVariable("hp", 0)
this one throws an error because the SetVariable action is meant for global variables not local variables, in your screen you're passing the hp as a local variable.
Use SetLocalVariable instead, its also documented in Renpy Actions section.
Thank very much!

GoodmanLove
Newbie
Posts: 18
Joined: Thu Jun 24, 2021 4:12 am
Contact:

Re: Questions about function(in button action)

#4 Post by GoodmanLove »

hell_oh_world wrote: Thu Jul 15, 2021 6:45 am SetVariable("hp", 0)
this one throws an error because the SetVariable action is meant for global variables not local variables, in your screen you're passing the hp as a local variable.
Use SetLocalVariable instead, its also documented in Renpy Actions section.
If I want to use a custom function of Function(), select incoming and outgoing parameters, what kind of syntax I should write?
For example
def plus_var_fun():
global flag001
flag001 = flag001 + random.randint(5,8)
if flag001 >= 50:
flag001 = 50
The flag001 is a global variable
If I change
def plus_var_fun(x):
x = x + random.randint(5,8)
if x >= 50:
x = 50

textbutton "治疗":
action Function(plus_var_fun,x = hp)
What do I need to let x return to Function, and connect x with hp?

User avatar
hell_oh_world
Miko-Class Veteran
Posts: 777
Joined: Fri Jul 12, 2019 5:21 am
Contact:

Re: Questions about function(in button action)

#5 Post by hell_oh_world »

if you're planning to return something from the function then the interaction will end (the called screen will hide and continue to your current script in labels).
https://www.renpy.org/doc/html/screen_a ... l#Function
If the function returns a non-None value, the interaction stops and returns that value. (When called using the call screen statement, the result is placed in the _return variable.)
Basically, the return value will be stored in the _return variable you can then access the _return variable in your labels, etc since it's a global variable.
So yeah, don't return anything from a function if you're using it as an action unless you know what you're doing.

The problem with your code is you're trying to pass around the variables like it's a reference when it's a literal you're passing.
Your best bet is to just use global variables, and don't overcomplicate things by passing them as arguments.
Another way maybe is to resort to OOP so you can pass them as references. Might be overkill though since this is just a health bar. It really depends on your preference.

Code: Select all

init python:
  class Health(object):
    @property
    def value(self): return self._value
    
    @value.setter
    def value(self, value): self._value = max(min(value, self.max), self.min) # clamp the health value
    
    def __init__(self, value=0, min=0, max=50):
      object.__init__(self)
      
      self.min = min
      self.max = max
      self.value = value
   
    def heal(self, amount):
      self.value += amount
   
    # A helper method that can act as an Action to eliminate Function(...)
    def Heal(self, amount):
      return Function(self.heal, amount)
     
default health1 = Health()
default health2 = Health()

screen stat(health):
  if health.value < health.max:
    textbutton "Heal" action health.Heal(renpy.random.randint(5, 8)) # You can also just do `action SetField(health, "value", health.value + renpy.random.randint(5, 8))`, so you wont be needing to create those health methods...
    
label start:
  call screen stat(health1)
If you want to continue your code, you can try using renpy.run(SetLocalVariable(<var_name>, <value>)) at the end of your function, <var_name> should be the name of your local variable passed as a string.

Code: Select all

def your_function(var_name):
  ...
  x = ...
  renpy.run(SetLocalVariable(var_name, x))

Code: Select all

screen stat(health):
  textbutton "Your Function" action Function(your_function, "health")
Don't know if it's fully correct, been rusty...

GoodmanLove
Newbie
Posts: 18
Joined: Thu Jun 24, 2021 4:12 am
Contact:

Re: Questions about function(in button action)

#6 Post by GoodmanLove »

hell_oh_world wrote: Thu Jul 15, 2021 10:54 am if you're planning to return something from the function then the interaction will end (the called screen will hide and continue to your current script in labels).
https://www.renpy.org/doc/html/screen_a ... l#Function
If the function returns a non-None value, the interaction stops and returns that value. (When called using the call screen statement, the result is placed in the _return variable.)
Basically, the return value will be stored in the _return variable you can then access the _return variable in your labels, etc since it's a global variable.
So yeah, don't return anything from a function if you're using it as an action unless you know what you're doing.

The problem with your code is you're trying to pass around the variables like it's a reference when it's a literal you're passing.
Your best bet is to just use global variables, and don't overcomplicate things by passing them as arguments.
Another way maybe is to resort to OOP so you can pass them as references. Might be overkill though since this is just a health bar. It really depends on your preference.

Code: Select all

init python:
  class Health(object):
    @property
    def value(self): return self._value
    
    @value.setter
    def value(self, value): self._value = max(min(value, self.max), self.min) # clamp the health value
    
    def __init__(self, value=0, min=0, max=50):
      object.__init__(self)
      
      self.min = min
      self.max = max
      self.value = value
   
    def heal(self, amount):
      self.value += amount
   
    # A helper method that can act as an Action to eliminate Function(...)
    def Heal(self, amount):
      return Function(self.heal, amount)
     
default health1 = Health()
default health2 = Health()

screen stat(health):
  if health.value < health.max:
    textbutton "Heal" action health.Heal(renpy.random.randint(5, 8)) # You can also just do `action SetField(health, "value", health.value + renpy.random.randint(5, 8))`, so you wont be needing to create those health methods...
    
label start:
  call screen stat(health1)
If you want to continue your code, you can try using renpy.run(SetLocalVariable(<var_name>, <value>)) at the end of your function, <var_name> should be the name of your local variable passed as a string.

Code: Select all

def your_function(var_name):
  ...
  x = ...
  renpy.run(SetLocalVariable(var_name, x))

Code: Select all

screen stat(health):
  textbutton "Your Function" action Function(your_function, "health")
Don't know if it's fully correct, been rusty...
You are a genius, this is a very good idea which I haven't think about.
I thought about it for a long time,I have no idea about how to use the Class,
Compared with Functions, Class attributes seem to be able to directly bypass the local and act on the global.
I will try to use your method to try to solve this problem, this is also a good opportunity to learn Renpy.
Thank you for your help.

Post Reply

Who is online

Users browsing this forum: No registered users