找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 11|回复: 0

[原创] 勉强能用的【手柄】兼容包

[复制链接]
发表于 昨天 16:39 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
本帖最后由 birctreel 于 2025-4-4 17:45 编辑

为了STEAM商店上那个“本游支持手柄”功能做的手柄模块,主要功能是在手柄插拔时提示,以及检测手柄是否插上和手柄型号等等。

【【【【【注意,本代码仍然存在一定问题,如果有大佬知道或愿意讨论如何改进就太好了!!!问题我会列在最后面】】】】】

使用方法:在你的游戏工程下新建一个joystick.rpy(或别的什么名字这个无所谓),把以下代码丢进去即可:
[RenPy] 纯文本查看 复制代码
init -85 python:

    import pygame
    import time as pytime 

    class ControllerHandler:#定义手柄插拔功能
        def __init__(self):
            self.joystick = None
            self.right_shoulder_pressed = False
            self.press_start_time = 0
            self.last_joystick_count = 0
            self.check_interval = 0.1
            self.last_check_time = 0

        def update(self):# 功能:定期检查手柄连接状态
            current_time = pytime.time()
            if current_time - self.last_check_time >= self.check_interval:
                self.last_check_time = current_time
                self._check_joystick_connection()
                
            if self.joystick is None:
                return
                


        def _check_joystick_connection(self):
            joystick_count = pygame.joystick.get_count()
            
            if joystick_count != self.last_joystick_count:
                self.last_joystick_count = joystick_count
                
                if joystick_count > 0:
                    if self.joystick is None:
                        try:
                            self.joystick = pygame.joystick.Joystick(0)
                            self.joystick.init()
                            renpy.notify(f"手柄已连接: {self.joystick.get_name()}")
                        except Exception as e:
                            self.joystick = None
                            renpy.notify(f"手柄连接失败: {e}")
                else:
                    if self.joystick is not None:
                        self.joystick = None
                        renpy.notify("手柄已断开")


    # 创建一个用来调用以上代码块的功能
    controller_handler = ControllerHandler()
    # 每帧更新
    def controller_update():
        controller_handler.update()
    #让update功能时时被检测
    config.periodic_callback = controller_update





在以上代码定义了之后,你可以用以下功能来检测手柄数据:


controller_handler.joystick.get_name() #输出连接的手柄名字,比如PS5手柄会返回"PS5 Controller",Xbox手柄会返回含有Xbox的名字,方便进行不同类型手柄的按键兼容
controller_handler.joystick #判断手柄连接状态,如果没有连接手柄就会返回None


剩下来定义按键操作参考文档就行了:https://doc.renpy.cn/zh-CN/keymap.html

===============================================================
根据我的测试结果,不同手柄的按键识别对应的编号是不一样的。我另外写了一个手柄测试界面,大家可以使用这个界面,来测试自己想要调用的按键对应的参数是什么:

[RenPy] 纯文本查看 复制代码
screen joystick_test():
default show_advanced = False
add Solid('#FFF')
timer 0.1 repeat True action Function(controller_handler.update) # 实时更新按键情况
frame:
xalign 0.5
yalign 0.5
xpadding 30
ypadding 30

vbox:
spacing 20

label "手柄测试面板" xalign 0.5

if controller_handler.joystick:
text "手柄: [controller_handler.joystick.get_name()]" xalign 0.5

hbox:
spacing 40


vbox:
label "按钮状态" xalign 0.5

# 普通按键
grid 4 5:
spacing 10

for i in range(min(20, len(controller_handler.buttons))):
frame:
xsize 100
ysize 60

if controller_handler.buttons[i]:
background "#333"
else:
background "#111"

vbox:
xalign 0.5
yalign 0.5
spacing 2

text str(i):
size 16
xalign 0.5
color "#fff"

if controller_handler.buttons[i]:
text "按下":
size 14
xalign 0.5
color "#0f0"
else:
text "未按":
size 14
xalign 0.5
color "#f00"

# 有关轴的按钮(摇杆+扳机)
label "轴按钮" xalign 0.5
grid 2 4:
spacing 10
for i in range(min(8, len(controller_handler.axes))):
frame:
xsize 150
ysize 80

if controller_handler.axis_buttons[i]:
background "#336"
else:
background "#114"

vbox:
xalign 0.5
yalign 0.5
spacing 5

text "轴 {}:".format(i):
size 16
xalign 0.5
color "#fff"

# 用来显示按下轴按钮后的状态和对应编号
text "{:.2f}".format(controller_handler.axes[i]):
size 18
xalign 0.5
if controller_handler.axis_buttons[i]:
color "#0f0"
else:
color "#aaa"

if controller_handler.axis_buttons[i]:
text "激活":
size 14
xalign 0.5
color "#0f0"
else:
text "未激活":
size 14
xalign 0.5
color "#f00"

# 高级信息
vbox:
label "高级信息" xalign 0.5

textbutton "显示/隐藏高级信息" action ToggleScreenVariable("show_advanced") xalign 0.5

if show_advanced:
vbox:
spacing 10

label "摇杆状态:"
for i, axis in enumerate(controller_handler.axes):
hbox:
spacing 10
text "轴 {}:".format(i)
bar:
value axis
range 2.0
xmaximum 200
left_bar "#0f0"
right_bar "#888"
text "{:.2f}".format(axis) xalign 1.0

label "方向键状态:"
for i, hat in enumerate(controller_handler.hats):
text "方向键 {}: {}".format(i, hat)
else:
text "未检测到手柄" xalign 0.5
textbutton "重新检测" action Function(controller_handler.update) xalign 0.5



将以上代码copy到joystick.rpy后,使用
call screen joystick_test
就可以开始测试手柄了


===============================================================
目前存在的问题:
使用了以上功能之后,在存档时(尤其是你使用了renpy.save之类的强制存档功能),会报
TypeError: no default __reduce__ due to non-trivial __cinit__ (perhaps renpy.game.log.log[110].objects[7][0].joystick = <pygame_sdl2.joystick.Joystick object at 0x00000000166c2d20>)

查了一圈似乎时因为pygame中不能储存joystick的数据,所以我还尝试过在renpy.save之前把controller_handler改为None,但反而导致了更大的问题……
*顺便提,如果不用renpy.save的话似乎就不会报错,只要不使用这个功能,在游戏中autosave是没有问题的,可以放心使用。

不知道有没有大佬知道这个问题要怎么解决……!



您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|RenPy中文空间 ( 苏ICP备17067825号|苏公网安备 32092302000068号 )

GMT+8, 2025-4-5 09:48 , Processed in 0.043665 second(s), 24 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

快速回复 返回顶部 返回列表