找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 999|回复: 2

[原创] 《Ren'Py强化之旅:Windows下引擎潜力探索》02.Ren'Py特殊的包,模块机制

[复制链接]
发表于 2023-9-26 04:43:13 | 显示全部楼层 |阅读模式

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

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

×
本帖最后由 Furau 于 2023-10-1 15:11 编辑

《Ren'Py强化之旅:Windows下引擎潜力探索》
【转载需要署名Furau.com】
  02.Ren'Py特殊的包,模块机制

1.经过“阉割”的Python本体

有一些Python基础的朋友肯定会疑惑?为什么第一个帖子的hello world要写的如此复杂  使用标准库Python tkinter可以轻松实现上个帖子的功能,为何要调度底层DLL费时费力呢?
不错,有这个想法的朋友可以进行一些简单的测试,验证想法。首先编写一段标准Python TK代码:
Python:
[RenPy] 纯文本查看 复制代码
import tkinter.messagebox
result=tkinter.messagebox.showinfo("提示"," 你确定要关闭窗口吗? ")
# 返回布尔值参数
print(result)



Snipaste_2023-09-26_04-04-08.png


看起来非常简便,完美的语义化封装,并且函数齐全,可以当我们把它载入到Ren'Py引擎中,会发生什么?
新建一个Renpy项目在头部写入:
[RenPy] 纯文本查看 复制代码
init python:
    import tkinter.messagebox
    result=tkinter.messagebox.showinfo("提示"," 你确定要关闭窗口吗? ")
    # 返回布尔值参数
    print(result)


启动项目,大家可以看到答案了。


  1. I'm sorry, but an uncaught exception occurred.

  2. While running game code:
  3.   File "game/script.rpy", line 6, in script
  4.     init python:
  5.   File "game/script.rpy", line 7, in <module>
  6.     import tkinter.messagebox
  7. ModuleNotFoundError: No module named 'tkinter'

  8. -- Full Traceback ------------------------------------------------------------
  9. [mw_shl_code=renpy,true]
  10. Full traceback:
  11.   File "game/script.rpy", line 6, in script
  12.     init python:
  13.   File "C:\renpy\renpy-8.1.3-sdk\renpy\ast.py", line 1138, in execute
  14.     renpy.python.py_exec_bytecode(self.code.bytecode, self.hide, store=self.store)
  15.   File "C:\renpy\renpy-8.1.3-sdk\renpy\python.py", line 1122, in py_exec_bytecode
  16.     exec(bytecode, globals, locals)
  17.   File "game/script.rpy", line 7, in <module>
  18.     import tkinter.messagebox
  19. ModuleNotFoundError: No module named 'tkinter'

  20. Windows-10-10.0.19041 AMD64
  21. Ren'Py 8.1.3.23091805
  22. win32 1.0
  23. Tue Sep 26 04:10:34 2023
复制代码
在09行直观的一个提示



No module named 'tkinter'

出现这个错误并不是因为你没有安装对应库或者没有正确配置renpy,因为Ren'Py作者在设计Ren'Py的时候因为游戏规模的原因,就对Ren'Py使用的Python做了特殊的优化处理,使得Ren'Py所使用的的Python版本并非完全的兼容全部的标准包,一些第三方的包或者标准包就会因为标准包的不完整而失效
这点可以在官方github有所表达
https://github.com/renpy/renpy/issues/4457
作者在其中说:
Not every third party module works with Ren'Py. We ship a limited subset of Python, for game size reasons.
【注】笔者猜测是为了兼容三端所以对支持库做了特殊处理,再加上Ren'Py本身就是C和Python混合开发的产物,所以去做剥离处理也可以理解
现在,接受现实,我们的问题就变成了,如何使用现有的标准库(作者自定义后的Python),进行我们预期的开发呢?
很简单,首先检查余粮(先看看作者到底给我们剩了什么东西)
写入如下代码:
script.rpy
[RenPy] 纯文本查看 复制代码
import sys
# 获取当前被导入的包
imported_packages = list(sys.modules.keys())
# 将结果输出到文本文件
with open('E:\imported_modules.txt', 'w') as f:
    for package in imported_packages:
        f.write(package + '\n')


解释一下上面这段代码,这段代码使用sys包中的modules检查当前环境所有被导入的包
最后输出成一个txt文件,方便我们查看,这里注意OPEN路径最好是一个绝对路径,方便我们查找(如果你足够熟悉自己的安装路径可以忽略)
启动游戏,得到一个文件,打开就可以看到我们想要的文本。(下面很长 注意!!!)
sys
builtins
_frozen_importlib
_imp
_thread
_warnings
_weakref
_io
marshal
nt
winreg
_frozen_importlib_external
time
zipimport
_codecs
codecs
encodings.aliases
encodings
encodings.utf_8
_signal
encodings.latin_1
_abc
abc
io
__main__
_stat
stat
_collections_abc
genericpath
ntpath
os.path
os
_sitebuiltins
types
enum
_sre
sre_constants
sre_parse
sre_compile
_heapq
heapq
itertools
keyword
_operator
operator
reprlib
_collections
collections
_functools
functools
_locale
copyreg
re
locale
importlib._bootstrap
importlib._bootstrap_external
warnings
importlib
importlib.machinery
collections.abc
contextlib
typing.io
typing.re
typing
importlib.abc
importlib.util
token
tokenize
imp
sitecustomize
site
__future__
future
linecache
traceback
_weakrefset
weakref
_string
string
threading
atexit
logging
copy
numbers
_ast
ast
opcode
dis
inspect
future.utils
future.standard_library
cython_runtime
_cython_0_29_32
pygame_sdl2.error
binascii
_struct
struct
pygame_sdl2.color
pygame_sdl2.rect
pygame_sdl2.locals
pygame_sdl2.surface
pygame_sdl2.display
pygame_sdl2.event
pygame_sdl2.key
math
pygame_sdl2.pygame_time
pygame_sdl2.time
pygame_sdl2.version
pygame_sdl2.compat
pygame_sdl2.rwobject
pygame_sdl2.controller
pygame_sdl2.gfxdraw
pygame_sdl2.draw
pygame_sdl2.font
pygame_sdl2.image
pygame_sdl2.joystick
pygame_sdl2.mixer
pygame_sdl2.mouse
pygame_sdl2.power
pygame_sdl2.transform
pygame_sdl2.scrap
pygame_sdl2.sprite
posixpath
fnmatch
glob
pygame_sdl2.sysfont
pygame_sdl2
_renpy
future.builtins.iterators
future.builtins.misc
future.builtins
renpy.compat
_compat_pickle
_pickle
pickle
_datetime
datetime
renpy.compat.pickle
renpy.vc_version
errno
signal
msvcrt
_winapi
subprocess
platform
_bootlocale
_ctypes
ctypes._endian
ctypes
renpy
renpy.error
renpy.bootstrap
renpy.config
zlib
_compression
_bz2
bz2
_lzma
lzma
shutil
_bisect
bisect
_random
_sha512
random
tempfile
renpy.log
gettext
argparse
renpy.arguments
pygame.error
pygame.color
pygame.rect
pygame.locals
pygame.surface
pygame.display
pygame.event
pygame.key
pygame.pygame_time
pygame.time
pygame.version
pygame.compat
pygame.rwobject
pygame.controller
pygame.gfxdraw
pygame.draw
pygame.font
pygame.image
pygame.joystick
pygame.mixer
pygame.mouse
pygame.power
pygame.transform
pygame.scrap
pygame.sprite
pygame.sysfont
pygame
pygame.constants
renpy.display
renpy.display.presplash
renpy.compat.fixes
renpy.debug
renpy.object
renpy.game
renpy.preferences
unicodedata
renpy.webloader
renpy.loader
renpy.revertable
renpy.rollback
renpy.pydict
renpy.python
renpy.py3analysis
renpy.pyanalysis
_hashlib
_blake2
hashlib
renpy.ast
renpy.atl
renpy.curry
colorsys
renpy.color
renpy.easy
renpy.encryption
renpy.execution
renpy.lexersupport
renpy.lexer
zipfile
_json
json.scanner
json.decoder
json.encoder
json
renpy.loadsave
renpy.savelocation
base64
six
six.moves
ecdsa.numbertheory
ecdsa._compat
ecdsa.errors
ecdsa.der
ecdsa.util
ecdsa.ellipticcurve
ecdsa.ecdsa
ecdsa._sha3
ecdsa.eddsa
hmac
ecdsa.rfc6979
ecdsa.curves
ecdsa.keys
ecdsa.ecdh
ecdsa._version
ecdsa
renpy.savetoken
renpy.persistent
renpy.scriptedit
renpy.parser
renpy.performance
difflib
renpy.script
renpy.statements
renpy.util
renpy.versions
renpy.styledata
renpy.styledata.stylesets
renpy.style
style_functions
renpy.styledata.styleutil
renpy.styledata.style_functions
style_activate_functions
renpy.styledata.style_activate_functions
style_hover_functions
renpy.styledata.style_hover_functions
style_idle_functions
renpy.styledata.style_idle_functions
style_insensitive_functions
renpy.styledata.style_insensitive_functions
style_selected_functions
renpy.styledata.style_selected_functions
style_selected_activate_functions
renpy.styledata.style_selected_activate_functions
style_selected_hover_functions
renpy.styledata.style_selected_hover_functions
style_selected_idle_functions
renpy.styledata.style_selected_idle_functions
style_selected_insensitive_functions
renpy.styledata.style_selected_insensitive_functions
renpy.styledata.styleclass
renpy.styleclass
renpy.substitutions
renpy.translation
renpy.translation.scanstrings
renpy.translation.generation
renpy.translation.dialogue
renpy.translation.extract
renpy.translation.merge
renpy.display.pgrender
renpy.display.scale
renpy.display.module
renpy.display.matrix
gc
renpy.display.render
shlex
_socket
select
selectors
socket
jnius.env
renpy.display.core
renpy.display.swdraw
renpy.text
renpy.text.textsupport
renpy.text.ftfont
xml
xml.etree
xml.etree.ElementPath
pyexpat.errors
pyexpat.model
pyexpat
_elementtree
xml.etree.ElementTree
renpy.text.font
renpy.text.texwrap
renpy.text.extras
_renpybidi
renpy.text.text
renpy.display.text
renpy.gl
renpy.gl2
renpy.display.layout
renpy.display.viewport
renpy.display.accelerator
renpy.display.transform
renpy.display.motion
renpy.display.behavior
renpy.display.transition
renpy.display.movetransition
renpy.display.im
renpy.display.imagelike
renpy.display.image
renpy.display.video
renpy.display.focus
renpy.display.anim
renpy.display.particle
renpy.display.joystick
renpy.display.controller
renpy.display.minigame
renpy.display.screen
renpy.display.dragdrop
renpy.display.imagemap
renpy.display.predict
renpy.display.emulator
renpy.display.tts
renpy.display.gesture
renpy.display.model
renpy.display.quaternion
renpy.display.error
renpy.audio
renpy.audio.renpysound
renpy.audio.audio
renpy.audio.music
renpy.audio.sound
renpy.ui
renpy.screenlang
renpy.sl2
renpy.sl2.slast
renpy.sl2.slparser
renpy.sl2.slproperties
renpy.sl2.sldisplayables
textwrap
renpy.lint
renpy.warp
renpy.editor
renpy.memory
renpy.character
renpy.gl2.gl2shadercache
renpy.gl2.live2dmotion
renpy.gl2.gl2polygon
renpy.gl2.gl2mesh
renpy.gl2.gl2mesh2
renpy.uguu.gl
renpy.uguu.uguu
renpy.uguu
renpy.gl2.live2dmodel
renpy.gl2.live2d
renpy.exports
renpy.add_from
renpy.dump
renpy.gl2.gl2texture
renpy.gl2.gl2model
renpy.gl2.gl2shader
renpy.gl2.gl2mesh3
renpy.gl2.gl2functions
array
renpy.gl2.gl2draw
renpy.minstore
renpy.defaultstore
renpy.test
renpy.test.testmouse
renpy.test.testfocus
renpy.test.testkey
renpy.test.testast
renpy.test.testparser
renpy.test.testexecution
renpy.main
renpy.six
store
renpy.store
renpy.subprocess
store.gui
store._errorhandling
store._warper
store.audio
store.achievement
store.build
store._console
store.director
store._gamepad
store.iap
store.icon
store.layeredimage
store.bubble
store._renpysteam
store._sync
store.updater
encodings.cp437
pkgutil
sysconfig
urllib
urllib.parse
pydoc
tarfile
rsa._compat
rsa.common
rsa.transform
rsa.randnum
rsa.prime
rsa.pem
rsa.core
rsa.key
rsa.pkcs1
rsa

这是笔者版本所产生的产物,我们可以使用这些现存的库完善,拓展renpy功能,看到这里的朋友 应该理解第一个问题了。
我向chatgpt 询问了一些库的介绍可以作为一个中文参考
[RenPy] 纯文本查看 复制代码
sys:提供对Python解释器的访问和控制。
builtins:提供Python内置函数和异常的访问。
_thread:提供多线程编程的支持。
warnings:提供警告处理的功能。
_io:提供对I/O操作的支持。
marshal:提供对Python对象的序列化和反序列化。
time:提供时间相关的功能。
codecs:提供对字符编码和解码的支持。
os:提供与操作系统交互的功能。
types:提供对Python类型操作的支持。
math:提供数学计算相关的功能。
random:提供生成随机数的功能。
subprocess:提供执行外部命令和子进程管理的功能。
platform:提供访问操作系统平台信息的功能。
re:提供正则表达式匹配和操作的功能。
json:提供对JSON数据的编码和解码的功能。
pickle:提供对Python对象的序列化和反序列化。
datetime:提供对日期和时间的处理功能。
hashlib:提供多种哈希算法的功能。
base64:提供对Base64编码和解码的功能。
shutil:提供文件和目录操作的功能。
zipfile:提供对ZIP文件的读取和写入的功能。
xml:提供对XML数据的解析和操作的功能。
array:提供对数组操作的功能。
tarfile:提供对tar文件的读取和写入的功能。
urllib:提供对URL的访问和处理的功能。
pydoc:提供生成文档的功能。
pkgutil:提供对Python包的操作的功能。
sysconfig:提供访问Python配置信息的功能。
rsa:提供RSA加密和解密的功能。


2.game下的包路径引入
在官方文档中,作者给包或者模块做了分类,主要是两点:
1.游戏本体就需要使用的第一方的包和模块可以直接在gane目录下调用
2.第三方下载的包可以存储到game/python-packages
下面我们给01的程序进行调优,把开发的模块和和主程序分离。
game下建立一个py文件,在其中写入对应的函数体:
msgbox.py
[RenPy] 纯文本查看 复制代码
import ctypes
def messagebox(title, message):
    MB_OK = 0x00000000
    user32 = ctypes.WinDLL('user32')
    user32.MessageBoxW.argtypes = (ctypes.c_void_p, ctypes.c_wchar_p, ctypes.c_wchar_p, ctypes.c_uint)
    title = ctypes.c_wchar_p(title)
    message = ctypes.c_wchar_p(message)
    user32.MessageBoxW(None, message, title, MB_OK)


主程序中写入对应的调用代码和调用语句:
script.rpy
[RenPy] 纯文本查看 复制代码
# 游戏的脚本可置于此文件中。

# 声明此游戏使用的角色。颜色参数可使角色姓名着色。

define e = Character("艾琳")
init python:
    import msgbox

label start:

    # 显示一个背景。此处默认显示占位图,但您也可以在图片目录添加一个文件
    # (命名为 bg room.png 或 bg room.jpg)来显示。

    scene bg room
    python:
        msgbox.messagebox("title","Hello Windows!")
    # 显示角色立绘。此处使用了占位图,但您也可以在图片目录添加命名为
    # eileen happy.png 的文件来将其替换掉。
    show eileen happy

    # 此处显示各行对话。

    e "您已创建一个新的 Ren'Py 游戏。"

    e "当您完善了故事、图片和音乐之后,您就可以向全世界发布了!"

    # 此处为游戏结尾。

    return

可以看到与01一致的效果,但是已经按照作者的设计,模块化处理了


评分

参与人数 1活力 +300 干货 +3 收起 理由
被诅咒的章鱼 + 300 + 3 感谢分享!

查看全部评分

本帖被以下淘专辑推荐:

发表于 2023-9-26 10:10:32 | 显示全部楼层
写得挺棒。要不要给楼主整个置顶合集呢?
回复 支持 抱歉

使用道具 举报

 楼主| 发表于 2023-9-26 10:35:17 | 显示全部楼层
被诅咒的章鱼 发表于 2023-9-26 10:10
写得挺棒。要不要给楼主整个置顶合集呢?

感谢支持
回复 支持 抱歉

使用道具 举报

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

本版积分规则

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

GMT+8, 2024-12-22 19:13 , Processed in 0.153934 second(s), 34 queries .

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

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