马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
×
本帖最后由 法海叔叔 于 2018-3-27 22:38 编辑
特征
通过指定即使只有一行,您可以定义一个角色人像,根据需要进行动画制作,而不是为每个姿势/图像复制20多行。
包含可在不同字符之间变化的文字嘟嘟音效果。
启用“介绍性”动画和类似的短序列,在角色进入姿势时播放。
将肖像,眼睛和嘴巴存储在每个姿势的一个文件中。
原文地址:http://taylor.revasser.net/misc/renpy-portraitsys/
下载地址:http://taylor.revasser.net/misc/renpy-portraitsys/talktest13.7z
文件加图片太大,就不发上来了。代码如下
[RenPy] 纯文本查看 复制代码 ##############################################################################
# You don't need the character template to use the Portrait engine,
# that's below the next divider.
# However, this code does make it easier to keep dialogue formatted
# consistently between speakers.
# If you copy the way I format my Characters in the third section of this
# file though, you *will* need this section.
init python:
# Character template
def CharTemplate(name=None, quote=True, mode=None, file=None, speaker=None, **args):
if quote:
return Character(name, what_prefix=u"“", what_suffix="”", who_prefix=u"【", who_suffix="】", ctc="continimg", ctc_pause="continimg", ctc_timedpause=Null(), kind=mode, callback=text_effect(file, speaker), **args)
else:
return Character(name, ctc="continimg", ctc_pause="continimg", ctc_timedpause=Null(), kind=mode, **args)
# Text blip and speaker set
def text_effect(file, speaker, event, **args):
if event == "show_done":
pass
if file and _preferences.text_cps != 0:
renpy.music.play(file, channel="text")
elif event == "slow_done" or event == "end":
speaking = None
renpy.music.stop(channel="text")
renpy.invoke_in_new_context(speaker_curry(speaker, event))
text_effect = renpy.curry(text_effect)
# This is set to the name of the character that is speaking, or
# None if no character is currently speaking.
speaking = None
# This callback maintains the speaking variable.
def speaker_callback(name, event, **kwargs):
global speaking
if event == "show":
speaking = name
elif event == "slow_done":
speaking = None
elif event == "end":
speaking = None
# Curried form of the same.
speaker_curry = renpy.curry(speaker_callback)
##############################################################################
# This is the Portrait System! You copy this into your own game in wherever
# you think it's best suited.
init python:
import random
import math
class Portrait(renpy.Displayable):
def __init__(self, image, width=416, eyepos=(0,0), moupos=(0,0), eyesize=(128, 64), mousize=(128, 64), speaker=None, **kwargs):
super(Portrait, self).__init__(**kwargs)
self.image = ("graphics/char/%s" % image)
self.portrait_width = width
self.eyes = eyepos + eyesize
self.mouth = moupos + mousize
self.speaker = speaker
self.bt()
def bt(self, **kwargs):
self.blink_time = random.choice([3, 4, 4, 4, 5, 5, 5, 6])
def render(self, width, height, st, at):
# This is the base portrait displayable
portrait = im.Crop(self.image, (0, 0, self.portrait_width, 640))
# This is the render of the base portrait displayable.
portrait_render = renpy.render(portrait, self.portrait_width, 640, st, at)
# Now we're going to render the eyes
# The reason why we're using a DynamicDisplayable here is that it forces us to rerender the eyes later.
eye_render = renpy.render(DynamicDisplayable(self.redraw_eyes), self.eyes[2], self.eyes[3], st, at)
portrait_render.blit(eye_render, (self.eyes[0], self.eyes[1]))
# This is a render of the mouth, and it follows the same pattern as the eyes
global speaking
if speaking == self.speaker and self.speaker != None:
mouth_render = renpy.render(DynamicDisplayable(self.redraw_mouth), self.mouth[2], self.mouth[3], st, at)
portrait_render.blit(mouth_render, (self.mouth[0], self.mouth[1]))
# Return the render.
flatten_portrait = renpy.render(Flatten(portrait), self.portrait_width, 640, st, at)
return flatten_portrait
def redraw_eyes(self, st, at):
# Set frames
half_opened = im.Crop(self.image, (self.portrait_width, 0, self.eyes[2], self.eyes[3]))
closed = im.Crop(self.image, (self.portrait_width, self.eyes[3], self.eyes[2], self.eyes[3]))
# Draw frames as per this timing
p = self.blink_time
time = st % (p + .4)
if p < time < (p + .1):
return half_opened, 0.05
elif (p + .1) < time < (p + .2):
return closed, 0.05
elif (p + .2) < time < (p + .3):
return half_opened, 0.05
elif (p + .3) < time < (p + .4):
self.bt()
return Null(), 0.05
else:
return Null(), 0.05
def redraw_mouth(self, st, at):
# Set frames
mouth_y_orign = self.eyes[3]*2 + 32
half_opened = im.Crop(self.image, (self.portrait_width, mouth_y_orign, self.mouth[2], self.mouth[3]))
opened = im.Crop(self.image, (self.portrait_width, mouth_y_orign+self.mouth[3], self.mouth[2], self.mouth[3]))
# Draw frames as per this timing
time = st % .4
if time < .1:
return half_opened, 0.1
elif time < .2:
return opened, 0.1
elif time < .3:
return half_opened, 0.1
else:
return Null(), 0.1
def PortraitStrip(st, at, image, width, frames):
f = min([frames, math.trunc(st * 10)])
frame = im.Crop("graphics/char/%s" % image, (f * width, 0, width, 640))
return frame, .1
##############################################################################
# The following code is only for the demo. You don't need to include this,
# however you can use it to learn from.
# Characters
june = CharTemplate("June", file="vb_high2.ogg", speaker="june")
clover = CharTemplate("Clover", file="vb_high3.ogg", speaker="clover")
lotus = CharTemplate("Lotus", file="vb_high1.ogg", speaker="lotus")
nv = CharTemplate(quote=False, mode=nvl)
init:
# Portraits
# June
image june idle = Portrait("june/idle.png", eyepos=(144, 192), moupos=(144,256), speaker="june")
image june concern = Portrait("june/concern.png", eyepos=(144, 208), moupos=(144,272), speaker="june")
# Clover
image clover concern = Portrait("clover/concern.png", eyepos=(160, 240), moupos=(144,304), speaker="clover")
image clover shock = Portrait("clover/shock.png", eyepos=(144, 224), moupos=(144,288), speaker="clover")
image clover anger = Portrait("clover/anger.png", eyepos=(128, 240), moupos=(128,304), speaker="clover")
image clover point:
DynamicDisplayable(PortraitStrip, "clover/point_start.png", 480, 7)
pause 0.8
Portrait("clover/point.png", moupos=(128,320), speaker="clover")
image clover point2 = Portrait("clover/point.png", moupos=(128,320), speaker="clover")
# Lotus
image lotus thought = Portrait("lotus/thought.png", eyepos=(144, 192), moupos=(144,256), speaker="lotus")
image lotus handwave = Flatten(LiveComposite((416, 640),
(0, 0), Portrait("lotus/handwave.png", eyepos=(128,192), moupos=(128,256), speaker="lotus"),
(0, 0), "lotus hw_hand",))
image lotus hw_hand:
DynamicDisplayable(PortraitStrip, "lotus/handwave_hand.png", 416, 7)
pause 3.8
repeat
[RenPy] 纯文本查看 复制代码 ##############################################################################
init:
image bg ruin = "graphics/bg/ruin.png"
image bg none = "#000"
image code set1 = "graphics/code1.png"
image code set2 = "graphics/code2.png"
image code set3 = "graphics/code3.png"
image code set4 = "graphics/code4.png"
image code set5 = "graphics/code5.png"
image code set6 = "graphics/code6.png"
$ renpy.music.set_volume(0.2, channel="music")
##############################################################################
label start:
scene bg ruin
play music "ee.ogg" fadein 3.0
show june idle at char_fade, center
pause(0.3)
window show
june "Hello there!{w} Welcome to the demonstration for--"
clover "Hey, June!"
show june idle at char_fade, right
show clover point at char_fade, left
clover "Tell me what the hell's going on here -- why are we in this weird ruin?"
show june concern
june "... well, that's..."
window hide
nvl show dissolve
nv "What am I supposed to tell her?"
nv "I'm not sure Clover would understand that we're here to demonstrate the Portrait System.{w} It was created to make it easy to display character art and animate it without having massive amounts of similar code."
nvl clear
nvl hide dissolve
window show
show june idle
june "We're not going into the ruins, I can explain that much."
show clover anger
clover "Why not?"
june "Well, there's nothing in there.{w} We're incapable of going in there, because nothing else exists in this demo."
show clover point
clover "Screw that, I don't believe you!"
window hide
hide clover
pause(2)
show june concern
pause(1)
show clover concern at char_fade, left
window show
clover "... okay, so we can't go in there."
june "Can we move on?"
show june idle
june "Ahem, we're here to show off our animation capabilities.{w} This system lets us have blinking and speaking,{w=0.2} and it's simple to set up dozens of portraits in the same fashion."
june "With normal image setups in Ren'py we would have to copy large amounts of code for {i}every{/i} pose, which would result in the script being 100 times larger than it needs to be."
show clover shock
clover "Oh!"
show clover concern
clover "Uh... wait, huh?"
june "See, your poses just then were created by single lines!"
june "It's a lot more efficient."
show clover anger
clover "You know,{w=0.2} I don't really like how you're treating me like a computer program."
june "You're barely that,{w=0.4} you're lines in a script."
clover "I remember when you used to be young and innocent, June..."
clover "Can I just,{w=0.2} go?{w=0.4} I know you said I can't, but...{w} hey,{w=0.4} get Lotus here instead. She's the computer whiz."
show june concern
june "... maybe that would be a good idea after all,{w=0.4} her sprites demonstrate something else worth exploring."
hide clover
window hide
pause(1)
show lotus handwave at char_fade, left
window show
lotus "Okay...{w} lets put the meta existential talk aside for once,{w=0.4} and get down to business here."
window hide
stop music fadeout 2.0
pause(2)
play music "dr.ogg" fadein 2.0
window show
show june idle
show lotus thought
lotus "The most obvious feature the Portrait() function allows is the basic setup of portrait graphics."
lotus "They can't do anything fancy on their own,{w=0.4} but they can be combined with ATL functions,{w=0.4} or used within an image block for a complex setup."
hide june
lotus "There are three different types of portrait graphics being shown off in this demo, and I'll explain each one for you."
window hide
show clover concern behind code at char_fade, right
pause(1)
window show
lotus "The first one of course, is a basic Portrait()."
show code set1 at char_fade:
pos(2.0, 0.6)
anchor(0.5, 0.5)
linear 0.2 xpos 0.5
lotus "The avaliable arguments include the width of the portrait body, position of the eyes and mouth sprite, and the Character() callback."
show code set2
lotus "The eyes and mouth both default to a position of (0, 0)."
show code set3
lotus "You {i}can{/i} exclude the width and callback if you wish.{w} The width has a default value to cover a common portrait size, and the callback is used for lip-flap."
lotus "Given the purpose of this engine, I'm not really sure why you'd create a portrait that doesn't take advantage of the character callback, except in specific situations."
show code set3:
linear 0.2 xpos 2.0
pause(0.4)
window hide
show clover point
pause(2)
window show
lotus "The next type of portrait is one preceded by an animation, as Clover has already demonstrated."
show code set4:
pos(2.0, 0.6)
anchor(0.5, 0.5)
linear 0.2 xpos 0.5
lotus "The animation was created by a second function called PortraitStrip.{w} This was called through DynamicDisplayable."
lotus "It takes a strip of images and animates them as specified."
lotus "The arguments allowed are:{w=0.4} the frame width,{w=0.2} and the number of frames."
lotus "This is followed by a pause that is the same length as the animation, then by the Portrait function."
lotus "If the pause is too long, the animation will stop on the last frame as a fallback."
lotus "You might also have noticed that this portrait does not specify \nthe eye sprite.{w} This... is because this particular pose does not, as it happens, blink."
hide clover
hide code
lotus "You might already know that there exists a function in Renpy that performs a similar function, called Filmstrip."
lotus "However Filmstrip was found to conflict with ATL, this is why a different system had to be created to produce the animation."
lotus "It's not known whether the unreliability of Filmstrip is because of deprecation or an unintended bug."
window hide
pause(1.5)
window show
lotus "...{w=0.4} there is one last style of portrait I'd like to demonstrate, and this one is created in a similar manner to the others."
show lotus handwave
lotus "That would be this."
lotus "This animation is also created through the use of the PortraitStrip function.{w} However this time, the function contains a slice of an image, instead of an whole bust for a pre-pose animation."
lotus "The setup is also a little more complicated, because of how the ATL language works."
show code set5 at char_fade:
pos(2.0, 0.6)
anchor(0.5, 0.5)
linear 0.2 xpos 0.5
lotus "As can be seen, the use of LiveComposite had to be made.{w} This allows the display of several elements in one image, which is the original Ren'py-language method of the Portrait system."
lotus "Because the graphics are pre-sized and aligned, the only extrenous variables specified are the width and height of the overall portrait."
show code set6
lotus "The hand element isn't that much different to the way Clover's pointing animation worked.{w} The difference is the larger pause, and the repeat function."
lotus "You could make more varied animations leading off of this."
lotus "The purpose of this sort of setup is to show that you can have a portrait perform a continuous little animation, so as to add some character to your...{w} characters."
show code set6:
linear 0.2 xpos 2.0
show lotus thought
lotus "And that's it for the Portrait System's features."
lotus "As you were then, June."
window hide
hide lotus
stop music fadeout 2.0
pause(2)
window show
show june concern at char_fade, center
june "Oh, it's my turn again?"
show june idle
june "Ahem..."
june "Thank you for viewing this demo!"
show june concern
june "Er,{w=0.2} uh..."
show june idle
june "Should you decide to take advantage of this engine, I hope that it makes things easier for you."
june "And of course, credit to Taylor and Bryan Tsang/@bvtsang is greatly appreciated!"
june "The characters and music featured in this demonstration are owned by Chunsoft and Kotaro Uchikoshi."
june "If anything new is added or improved with this system, we hope to see you again."
window hide
hide june
pause(1)
scene bg none with Dissolve(0.5)
pause(0.2)
return
|