(solved) LiveComposite in class environments + Refreshing

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
GreatSam
Newbie
Posts: 22
Joined: Wed Aug 28, 2013 10:19 am
Contact:

(solved) LiveComposite in class environments + Refreshing

#1 Post by GreatSam » Sun Sep 01, 2013 12:09 pm

I'm trying to play around with LiveComposite objects and I ran into problems using classes. I do need classes as I don't want to hassle around with trivial functions...

I've got a code fragment like this which returns a LiveComposite object:

Code: Select all

def foo():
    return LiveComposite((10,100), (0, 0), 'base.png', (5, 50), 'some_pic.png')
(...)
image bar = foo()
show bar at Position(100,100)
Is getting the job done nicely.

But now I would like to call the same code as an instance method of an object...

Code: Select all

class Foo(object):
    def test(self):
        return LiveComposite((10,100), (0, 0), 'base.png', (5, 50), 'some_pic.png')
(...)
$ myobj = Foo()
$ bar = myobj.test()
(...)
show bar at Position(100,100)
...and I'm getting an Undefiend Images bar drawn on the screen. But if I look directly at the variable it tells me that it's storing <renpy.display.layout.MultiBox object at 0x224efd4>. Changing to bar = DynamicDisplayable(myobj.test()) doesn't help even though I'm getting an <renpy.display.layout.DynamicDisplayable object at 0x2d51de0>.

Does anybody have any idea how to use LiveComposite objects within a class properly? I've got no idea what I am doing wrong here...
Last edited by GreatSam on Mon Sep 02, 2013 11:20 am, edited 4 times in total.

Elmiwisa
Veteran
Posts: 476
Joined: Sun Jul 21, 2013 8:08 am
Contact:

Re: LiveComposite in objectoriented environments

#2 Post by Elmiwisa » Sun Sep 01, 2013 12:21 pm

Use renpy.image("bar",myobj.test())

GreatSam
Newbie
Posts: 22
Joined: Wed Aug 28, 2013 10:19 am
Contact:

Re: LiveComposite in objectoriented environments

#3 Post by GreatSam » Sun Sep 01, 2013 12:52 pm

Thanks - it's working :)

GreatSam
Newbie
Posts: 22
Joined: Wed Aug 28, 2013 10:19 am
Contact:

Re: (solved) LiveComposite in objectoriented environments

#4 Post by GreatSam » Mon Sep 02, 2013 8:37 am

I've got an additional question.

Is is possible to manually refresh an image as I don't like the default polling-system of Renpy. It's not necessary to call the function every x seconds as I know exactly when something changes and the refresh needs to be done so there is no need to keep polling all the time.

Some example code so make clear what I'd like to do:

Code: Select all

class Foo(object):
    refresh_interval = 0.5
    some_var = True

    # just flippin' a boolean
    def letsFlipSomeBools(self):
        self.some_var = self.some_bar if False else True

    def draw(self):
        if self.some_var:
            return LiveComposite((10,100), (0, 0), 'base.png', (5, 50), 'some_pic.png'), self.refresh_interval
        return LiveComposite((10,100), (0, 0), 'base.png', (5, 50), 'some_other_pic.png'), self.refresh_interval

(...)
init:
   $ foo = Foo()
   image test = DynamicDisplayable(foo.draw)
   (...)
label some_label:
    $ foo.letsFlipSomeBools()
     # and now I'd like to refresh manually without waiting for the polling as I'd like to do default polling times of minute ranges and not every second ;)
Is there a way so do this or am I bound to this polling stuff? I hope there is a method to invoke manually as well.

Elmiwisa
Veteran
Posts: 476
Joined: Sun Jul 21, 2013 8:08 am
Contact:

Re: LiveComposite in objectoriented environments + Refreshin

#5 Post by Elmiwisa » Mon Sep 02, 2013 11:06 am

The function will be automatically called to refresh before the time lapse if an interaction happen.
So if you want to do the refresh manually:
-Set the time lapse to None so that the function will not be called due to time, and only due to interaction.
-Whenever you want to refresh, force an interaction. For example, renpy.pause(0) is one way of doing it.

GreatSam
Newbie
Posts: 22
Joined: Wed Aug 28, 2013 10:19 am
Contact:

Re: LiveComposite in objectoriented environments + Refreshin

#6 Post by GreatSam » Mon Sep 02, 2013 11:15 am

Cool - that's exactly what I needed to know :)

Thanks a lot!! :D

GreatSam
Newbie
Posts: 22
Joined: Wed Aug 28, 2013 10:19 am
Contact:

Re: (solved) LiveComposite in class environments + Refreshin

#7 Post by GreatSam » Mon Sep 02, 2013 11:23 am

...is there a way to enforce an interaction without calling renpy.pause(0) as this causes the screen to fully render again (which results in a blinking in the quick_menu screen)

Elmiwisa
Veteran
Posts: 476
Joined: Sun Jul 21, 2013 8:08 am
Contact:

Re: (solved) LiveComposite in class environments + Refreshin

#8 Post by Elmiwisa » Mon Sep 02, 2013 12:15 pm

Oh sorry I guess renpy.pause(0) is not such a good idea. I also just realized that renpy.pause(0) would effectively block player from rollback after that point, since it is also a checkpoint.
I dig around the old wiki a bit, and there is a solution, sort of. Not a very good one I guess, but here it goes...

Code: Select all

$ImageReference("test").visit()[0].per_interact()
This code basically retrieve the displayable associated with the name "test", then use per_interact() to force it to assume that an interaction just occur, even if it does not.
Look here for more details: User-Defined Displayables

GreatSam
Newbie
Posts: 22
Joined: Wed Aug 28, 2013 10:19 am
Contact:

Re: (solved) LiveComposite in class environments + Refreshin

#9 Post by GreatSam » Mon Sep 02, 2013 4:42 pm

It get's quite tricky when it comes to advanced programming in RenPy I guess :D

The problem is that my class should not need to know which image refers to it. But due to the "always refresh when something changed"- feature it's okay to have a high refreshing time. The image will refreshed at every change anyway. Paired with a small cache within the class it's working properly and without too much calculations :)

Elmiwisa
Veteran
Posts: 476
Joined: Sun Jul 21, 2013 8:08 am
Contact:

Re: (solved) LiveComposite in class environments + Refreshin

#10 Post by Elmiwisa » Mon Sep 02, 2013 6:18 pm

First, is there a reason you need to force an interaction in the first place? Looking at your other post in the other thread, apparently you are going to make the boolean variable flip just before a say statement, which is already an interaction. That is probably why DynamicDisplayable update every interaction: interaction are so common.
Since the object cannot know which image it is for, then there is no choice but to update everything. How about you try using

Code: Select all

$ui.pausebehavior(0)
$ui.interact()
It seems to work for me. No flickering (but then again I did not get flickering problem with the renpy.pause(0) method either). The different between this method and that method is that it don't count as a checkpoint for rollback, so rollback will skip over it.
Otherwise, you could also maintain a list of all image that use that object, and manually update each of them using per_interact(). I have no clues on what are other consequence of each method though (including any potential issue with rollback and the like). This much technical details is beyond me. Perhaps at this point you can only hope that PyTom will come in and save the day.

GreatSam
Newbie
Posts: 22
Joined: Wed Aug 28, 2013 10:19 am
Contact:

Re: (solved) LiveComposite in class environments + Refreshin

#11 Post by GreatSam » Mon Sep 02, 2013 6:38 pm

Elmiwisa wrote:First, is there a reason you need to force an interaction in the first place?
No not really but I dislike polling as it's the most static variant of how to implement such a behavior. It may be fine for just a few objects or within microcontrollers as there is no need to have a look at resources, but there are plenty of better solutions for most cases in which polling is used.

The thing is: you can call the method a thousand times but nothing will change since a change is always triggered by the class itself (so no need for polling as the class could signalize RenPy "Hey wake up - I've changed something, so tell me when it's time to draw the new stuff"). This approach would be way less resource intensive and even though modern computers can handle such stuff but it may lead to problems on some weaker smartphones...it's basically like spamming into various pointers of the CPU without any need :D
But I don't know much about the internal code structure of RenPy - maybe there is a good reason for using polling. I just wanted to know if there is some way to get around it.

Elmiwisa wrote: Otherwise, you could also maintain a list of all image that use that object, and manually update each of them using per_interact(). I have no clues on what are other consequence of each method though (including any potential issue with rollback and the like). This much technical details is beyond me. Perhaps at this point you can only hope that PyTom will come in and save the day.
Yeah, well I guess it's okay now. My problem was that I had a really though calculation to figure out which images in which order I have to draw and my mind told me "Gosh, you don't want to let the system calculate all this stuff every time the user clicks" as I'd like to have multiple of such complex elements on the screen.

My solution (which keeps my mind from shouting at me :p):

Code: Select all

class Foo(object):
    changed = True

    def setSomeStuff(self, stuff):
       # configure the class/change attributes/ whatever
       self.changed = False

    def draw(self):
       if not self.changed: # return cached calcs
          return self.chached_stuff

       # calculate
       self.cached_stuff = calculated_stuff
        self.cached = True
       return calculated_stuff
This doesn't calculate all the complex stuff with lambda functions, filters and maps all the time but only when something changed internally within the class. It's basically just a small in-class cache...

Post Reply

Who is online

Users browsing this forum: Hojoo