Portrait System

A place for Ren'Py tutorials and reusable Ren'Py code.
Forum rules
Do not post questions here!

This forum is for example code you want to show other people. Ren'Py questions should be asked in the Ren'Py Questions and Announcements forum.
User avatar
Posts: 117
Joined: Sat Jul 05, 2014 7:57 pm

Re: Portrait System

#16 Post by Tayruu » Sun Aug 18, 2019 3:04 am

I'm actually working on an improved version of this where you can pair different expressions with the same base portrait. It's technically done but I probably need to test it some more.
What it results in though, is that it re-splits body/eyes/mouth into separate files, hahah. But it keeps the code itself simple, so you still only need to specify a single line for each (Renpy) image.

As for the other stuff - like different closed frames used outside of closed/mid/open cycles - I'll have to look about implementing them.
If you want to show closed eyes specifically, it would probably require showing the base sprite + a slice of the closed eyes.

Only thing I'm not sure about is if I should update this thread or create a separate thread, as I kinda changed the design approach while having the same end-goal.

User avatar
Posts: 5
Joined: Wed Mar 26, 2014 7:13 pm
Location: Mexico

Re: Portrait System

#17 Post by ChocoKeki » Wed Aug 21, 2019 11:26 am

That was an unexpectedly fast response, I didn't think that you'd still be working on this but it's awesome that you are. Thank you for your hard work, I can't wait to try the new version.

I'm not really sure, since I haven't seen how different the new system is, but I think the best option would be to keep it in this thread, at least for now.

User avatar
Posts: 117
Joined: Sat Jul 05, 2014 7:57 pm

Re: Portrait System

#18 Post by Tayruu » Thu Nov 21, 2019 12:41 am

Release of Portrait System v2.0! (... beta 0.9)

So as I mentioned, I was working on an improved version of this script. I sent a message to ChocoKeki but as I have not heard back, I have decided to go ahead and release it to the public anyway.

There are some major design direction changes from v1.X - most notably, images are no longer single files, but separate ones for the base, eyes, and mouth. I originally grouped them as one as I felt it would be more convenient, but it immediately became a problem when I wanted to make subtle expression changes. Thus an important difference with v2.0 is it separates portraits into separate files for base, eyes, and mouth. This version also does away with the restraints caused by height limitations and simplifies some arguments.

You can read more about it and download it here, but the following is any extra useful information.

Code: Select all

image tamati neutral = Portrait("tamati", "neutral", (298, 209), (339, 277))
This is a basic example for defining a character portrait. You have your image name, the Portrait() object, and its arguments - directory, body expression, eyes, and mouth. Naturally, the eyes and mouth are specifying the co-ordinates for the eyes and mouth animation.
You can also add a third argument to the eyes and mouth to define a different expression for them:

Code: Select all

image tamati scowl = Portrait("tamati", "neutral", (298, 209, "scowl"), (339, 277))
In this example, the eyes argument has been appended with scowl, thus it'll use a scowl expression for the eyes, while retaining neutral files for the base and mouth.

This is a fairly drastic rejigging compared to v1.X I feel, but I will keep it in the same thread, as was suggested, eheh.

* * *

So this release is "v2.0 b0.9". The reason I call it that is there's one bug I ran into that, while solved, doesn't feel a graceful solution. I had to create a DynamicDisplayable for a static frame. In the portrait script, underneath the eyes_idle argument, you will see renpy.render(DynamicDisplayable(self.static, self.eyes_idle), width, height, 0, 0). This calls def static() further down that'll render self.eyes_idle with 0.05sec of redraw timing.

The thing I found is that if I just straight specified, say, renpy.render(Image(self.eyes_idle), width, height, 0, 0), the portrait would stop animating if it had certain static frames displayed, after a message pause. I could replicate this behaviour with the DynamicDisplayable if the redraw was None.

I don't feel this solution is particularly correct, nor does it make much sense when the base portrait doesn't have redraw timing either, but it's the current fix for now. If anyone can provide a fix or explanation, that would be swell.

Post Reply

Who is online

Users browsing this forum: No registered users