[RenPy] 纯文本查看 复制代码
#移除原生相应的快捷键
init python:
config.keymap["director"].remove("noshift_K_d")
config.keymap["screenshot"].remove("noshift_K_s")
config.keymap["toggle_fullscreen"].remove("noshift_K_f")
# 初始化Python代码块(在Ren'Py初始化阶段执行)
init python:
import math
import pygame
class VirtualJoystick(renpy.Displayable):
# 将字符串按键映射到pygame常量
DEFAULT_KEYMAP = {
"w": pygame.K_w,
"a": pygame.K_a,
"s": pygame.K_s,
"d": pygame.K_d,
"q": pygame.K_q,
"f": pygame.K_f,
}
def __init__(self,joy_bg=None,joy_fg=None,q_button_img=None,f_button_img=None,joypos=(100,700),qpos=(1500,800),fpos=(1600,800),keymap=None,**kwargs):
super(VirtualJoystick, self).__init__(**kwargs)
# 摇杆外观
self.joy_bg = joy_bg or Solid("#66666666", xysize=(200,200))
self.joy_fg = joy_fg or Solid("#ffffffcc", xysize=(50,50))
self.q_button_normal = q_button_img or Solid("#666666cc", xysize=(70,70))
self.f_button_normal = f_button_img or Solid("#666666cc", xysize=(70,70))
self.q_button_pressed = Transform(self.q_button_normal,matrixcolor=BrightnessMatrix(-0.1))
self.f_button_pressed = Transform(self.f_button_normal,matrixcolor=BrightnessMatrix(-0.1))
# 尺寸设置
self.joy_bg_size = 200
self.joy_fg_size = 50
self.joy_pos = joypos
self.q_button_size = 70
self.f_button_size = 70
self.q_button_pos = qpos
self.f_button_pos = fpos
self.radius = (self.joy_bg_size - self.joy_fg_size) // 2
self.deadzone_radius = self.radius * 0.2
# 状态变量
self.dragging = False
self.position = (0, 0)
self.offset = (0, 0)
# 键位配置
self.keymap = keymap or self.DEFAULT_KEYMAP.copy()
# 初始化按键状态(使用逻辑键名)
self.j_keys = {k: 0 for k in self.DEFAULT_KEYMAP.keys()}
self.q_button = False
self.f_button = False
#自适应渲染检查
self.sss_joy_check = False
# 动态获取素材尺寸,没有则使用默认尺寸
def get_displayable_size(self, displayable, default_size):
if displayable is None:
return default_size
try:
render = renpy.render(displayable, 0, 0, 0, 0)
size = render.get_size()
return size if size[0] > 0 and size[1] > 0 else default_size
except:
return (getattr(displayable, 'width', default_size[0]), getattr(displayable, 'height', default_size[1]))
def render(self, width, height, st, at):
# 首次渲染时检查尺寸
if not self.sss_joy_check:
# 重新获取尺寸
self.joy_bg_size = self.get_displayable_size(self.joy_bg, (200, 200))[0]
self.joy_fg_size = self.get_displayable_size(self.joy_fg, (50, 50))[0]
self.q_button_size = self.get_displayable_size(self.q_button_normal, (70, 70))[0]
self.f_button_size = self.get_displayable_size(self.f_button_normal, (70, 70))[0]
# 更新相关计算
self.radius = (self.joy_bg_size - self.joy_fg_size) // 2
self.deadzone_radius = self.radius * 0.2
self.sss_joy_check = True
render = renpy.Render(width, height)
joy_bg_render = self.joy_bg.render(self.joy_bg_size, self.joy_bg_size, st, at)
render.blit(joy_bg_render, (self.joy_pos[0], self.joy_pos[1]))
joy_fg_x = self.joy_pos[0] + (self.joy_bg_size - self.joy_fg_size) // 2 + self.position[0]
joy_fg_y = self.joy_pos[1] + (self.joy_bg_size - self.joy_fg_size) // 2 + self.position[1]
joy_fg_render = self.joy_fg.render(self.joy_fg_size, self.joy_fg_size, st, at)
render.blit(joy_fg_render, (joy_fg_x, joy_fg_y))
# 渲染Q按钮
q_button = self.q_button_pressed if self.q_button else self.q_button_normal
q_render = q_button.render(self.q_button_size, self.q_button_size, st, at)
render.blit(q_render, (self.q_button_pos[0], self.q_button_pos[1]))
# 渲染F按钮
f_button = self.f_button_pressed if self.f_button else self.f_button_normal
f_render = f_button.render(self.f_button_size, self.f_button_size, st, at)
render.blit(f_render, (self.f_button_pos[0], self.f_button_pos[1]))
#调试说明
if config.developer:
debug = Text("W: [joy.j_keys['w']] A: [joy.j_keys['a']] S: [joy.j_keys['s']] D: [joy.j_keys['d']] Q: [joy.j_keys['q']] F: [joy.j_keys['f']]")
debug_render = renpy.render(debug, width, height, st, at)
render.blit(debug_render, (0, 0))
renpy.redraw(self, 0)
return render
def event(self, ev, x, y, st):
# 按钮位置
q_button_rect = (self.q_button_pos[0], self.q_button_pos[1], self.q_button_size, self.q_button_size)
f_button_rect = (self.f_button_pos[0], self.f_button_pos[1], self.f_button_size, self.f_button_size)
center_x = self.joy_pos[0] + self.joy_bg_size // 2
center_y = self.joy_pos[1] + self.joy_bg_size // 2
distance = ((x - center_x)**2 + (y - center_y)**2) ** 0.5
# 处理鼠标事件
if ev.type == pygame.MOUSEBUTTONDOWN and ev.button == 1:
# 点击Q按钮
if (self.q_button_pos[0] <= x < self.q_button_pos[0] + self.q_button_size and
self.q_button_pos[1] <= y < self.q_button_pos[1] + self.q_button_size):
self.q_button = True
self.j_keys["q"] = 1
# 点击F按钮
if (self.f_button_pos[0] <= x < self.f_button_pos[0] + self.f_button_size and
self.f_button_pos[1] <= y < self.f_button_pos[1] + self.f_button_size):
self.f_button = True
self.j_keys["f"] = 1
# 点击摇杆
if distance <= self.radius + self.joy_fg_size//2:
self.dragging = True
self.offset = (x - center_x, y - center_y)
return None
elif ev.type == pygame.MOUSEBUTTONUP and ev.button == 1:
# 释放Q按钮
if self.q_button:
self.q_button = False
self.j_keys["q"] = 0
# 释放F按钮
if self.f_button:
self.f_button = False
self.j_keys["f"] = 0
# 释放摇杆
if self.dragging:
self.dragging = False
self.position = (0, 0)
self.offset = (0, 0)
# 重置方向键状态(使用字符串键名)
for key in ["w", "a", "s", "d"]:
self.j_keys[key] = 0
return None
# 拖拽摇杆
elif ev.type == pygame.MOUSEMOTION and self.dragging:
rel_x = x - center_x - self.offset[0]
rel_y = y - center_y - self.offset[1]
distance = (rel_x**2 + rel_y**2) ** 0.5
if distance > self.radius:
rel_x = rel_x * self.radius / distance
rel_y = rel_y * self.radius / distance
self.position = (rel_x, rel_y)
# 先重置所有方向键状态
for key in ["w", "a", "s", "d"]:
self.j_keys[key] = 0
# 角度计算
if distance > self.deadzone_radius:
angle = math.degrees(math.atan2(-rel_y, rel_x))
angle = (angle + 360) % 360
# 根据角度设置方向键
if 22.5 <= angle < 67.5: # 右上
self.j_keys["w"] = 1
self.j_keys["d"] = 1
elif 67.5 <= angle < 112.5: # 上
self.j_keys["w"] = 1
elif 112.5 <= angle < 157.5: # 左上
self.j_keys["w"] = 1
self.j_keys["a"] = 1
elif 157.5 <= angle < 202.5: # 左
self.j_keys["a"] = 1
elif 202.5 <= angle < 247.5: # 左下
self.j_keys["a"] = 1
self.j_keys["s"] = 1
elif 247.5 <= angle < 292.5: # 下
self.j_keys["s"] = 1
elif 292.5 <= angle < 337.5: # 右下
self.j_keys["d"] = 1
self.j_keys["s"] = 1
else: # 右
self.j_keys["d"] = 1
# 当摇杆没有被拖拽时才检查键盘,避免数据过快刷新且重复覆盖
if not self.dragging:
# 键盘事件处理(统一使用键名字符串)
keys = pygame.key.get_pressed()
for logic_key, pygame_key in self.keymap.items():
self.j_keys[logic_key] = 1 if keys[pygame_key] else 0
return None
def get_joy_input(self):
return self.j_keys
default joy = VirtualJoystick()
#一共7个参数,摇杆区域背景图片,摇杆图片,Q按键图片,F按键图片,摇杆整体坐标(左上角),Q按钮坐标(左上角),F按钮坐标(左上角)
#示例,图片得传入renpy.displayable("xxx")
#default joy = VirtualJoystick(
# renpy.displayable("xxx"),
# renpy.displayable("xxx"),
# renpy.displayable("xxx"),
# renpy.displayable("xxx"),
# (x,y),
# (x,y),
# (x,y)
#)
#
# 返回的值是一个字典,我声明的摇杆是joy,所以返回的就是joy.j_keys = {"w":0,"a":0,"s":0,"d":0,"q":0,"f":0,},0是未被按下,1是被按下了
# 在屏幕上显示摇杆
screen virtual_joystick():
# 添加摇杆到界面
add joy
label start2:
call screen virtual_joystick
jump start2