Ren’Py含有一些拖放组件,这些组件允许使用鼠标在界面上任意移动。关于拖拽功能的使用有以下要点:
拖放组件提供不仅限于自身的拖放功能。这里主要涉及两个类。Drag类提供让一些东西能够在界面上拖动的功能,让其他可拖动组件掉落在自己上面的功能,或者两者兼有。DragGroup类提供了Drag的群组功能——当拖放发生时,作为同一个DragGroup内的一部分,组内所有Drag对象都需要做出响应。
拖放系统可以通过 Screen Language 使用,或者直接用作可视组件。当你创建Drag对象后不再需要引用这些对象,最好使用界面语言。典型的情况是,可拖拽组件显示了一个用于放置在界面里的窗口。如果你在创建Drag对象后还需要引用,通常更好的做法是直接创建Darg对象并把它们添加到一个DragGroup对象中。
Drag(d=None, drag_name=None, draggable=True, droppable=True, drag_raise=True, dragged=None, dropped=None, drag_handle=(0.0, 0.0, 1.0, 1.0), drag_joined=..., clicked=None, hovered=None, unhovered=None, mouse_drop=False, **properties) link一个可视组件,提供了一个对象,可以在其有效区域内使用鼠标拖拽。一个Drag对象还有供其他Drag对象可以掉落在上面的区域。
一个Drag对象可以在父对象(parent)内部随意移动。通常,Drag的父对象是一个 Fixed() 或 DragGroup 。
一个Drag对象有一个子组件。子组件的状态反映出拖放操作的状态:
selected_hover - 当其被拖拽时。selected_idle - 当其被放下时。hover - 鼠标已点击而拖拽未发生时。idle - 其他情况。拖拽句柄(handle)是一个子组件内的矩形。当鼠标进到拖拽句柄里的非透明像素上方时,就允许发生拖拽或点击。
一个新创建的可拖拽组件会被添加到默认的DragGroup中。一个可拖拽组件只能在一个DragGroup里。一旦被添加到另一个组中,就会自动被上一个组移除。
当某个Drag对象首次渲染时,如果从其所在的DragGroup中无法获得坐标,就使用标准布局算法计算出它的左上角坐标。
一个回调函数(或回调函数列表),当Drag对象落下时被调用。调用时使用两个入参。第一个参数表示掉落在哪个Drag对象上。第二个参数是一个被拖拽的Drag对象列表。如果回调函数返回一个非None,这个值也会作为此次交互行为的返回结果。
当dragged和dropped回调函数被同一个事件消息触发,那么仅在dragged回调函数返回None的情况dropped回调函数才会被调用。
除了 d ,所有的参数都在Drag对象的字段(field)中。除此之外,在Drag对象被渲染后,下列域里的值也变成可用状态:
bottom(self) link降低该可视组件的高度,降到其所在drag_group的底层。
set_child(d) link将该Drag对象的子组件设为d。
snap(x, y, delay=0) link修改Drag对象的坐标。如果Drag对象没有显示,坐标的改变瞬时完成。否则,坐标的改变会耗时 dalay 秒,生成线性移动的动画。
top(self) link升高该可视组件的高度,升到其所在drag_group的顶层。
DragGroup(*children, **properties) link表示一个Drag对象组。某个Drag对象受限于整个DragGroup。掉落只在同一个组内的Drag对象间发生。组内的Drag对象可以会被抬升高度。
DragGroup的布局类似 Fixed() 。
DragGroup构造函数的所有固定位置参数都是需要添加到DragGroup的Drag对象。
add(child) link添加Drag对象作为DragGroup的子组件(child)。
get_child_by_name(name) link返回该DragGroup中名为 name 的第一个子组件。
remove(child) link移除该DragGroup中的子组件child。
这个样例中,在say界面允许用户拖拽窗口并选择放在界面的任意位置。
screen say:
drag:
drag_name "say"
yalign 1.0
drag_handle (0, 0, 1.0, 30)
xalign 0.5
window id "window":
# 确保窗口尺寸小于整个界面。
xmaximum 600
has vbox
if who:
text who id "who"
text what id "what"
这是一个稍微复杂的样例,展示了如何拖拽功能如何用在游戏流程中,还有如何使用拖拽功能将一个角色移动到某个位置:
init python:
def detective_dragged(drags, drop):
if not drop:
return
store.detective = drags[0].drag_name
store.city = drop.drag_name
return True
screen send_detective_screen:
# 作为背景的地图。
add "europe.jpg"
# DragGroup确保每个侦探可以拖拽到每个城市。
draggroup:
# 侦探们
drag:
drag_name "Ivy"
child "ivy.png"
droppable False
dragged detective_dragged
xpos 100 ypos 100
drag:
drag_name "Zack"
child "zack.png"
droppable False
dragged detective_dragged
xpos 150 ypos 100
# 可选的城市。
drag:
drag_name "London"
child "london.png"
draggable False
xpos 450 ypos 140
drag:
drag_name "Paris"
draggable False
child "paris.png"
xpos 500 ypos 280
label send_detective:
"我们需要调查!应该派谁去哪里?"
call screen send_detective_screen
"好的,我们派 [detective] 去 [city]。"
更复杂的系统需要使用更重要的编程技巧才能搞定。 Ren’Py cardgame framework 是一个在复杂系统如何使用拖放功能和制作卡牌游戏两方面都很有用的例子。
使用 as 分句可以将一个拖拽组件绑定到变量,这样就可以直接调用组件的各类方法。
screen snap():
drag:
as carmen
draggable True
xpos 100 ypos 100
frame:
style "empty"
background "carmen.png"
xysize (100, 100)
vbox:
textbutton "London" action Function(carmen.snap, 450, 140, 1.0)
textbutton "Paris" action Function(carmen.snap, 500, 280, 1.0)