CarrotLib🥕是与pocketpy搭配使用的一套面向对象的游戏开发框架。
# main.py
import carrotlib as cl # 导入CarrotLib🥕
class MyGame(cl.Game):
def on_ready(self):
super().on_ready()
# TODO: 初始化你的游戏
@property
def design_size(self):
return (320, 180) # 返回游戏的设计分辨率
当脚本被加载后,CarrotLib🥕会自动搜索main.py
中,第一个继承自cl.Game
的类进行实例化。
CarrotLib🥕使用类似Unity和Godot的树形结构来管理所有游戏对象,这些游戏对象都继承自一个公共的父类Node
。
在游戏初始化时,根节点被自动创建出来,你将在MyGame.on_ready
函数中创建自己需要的节点。
你可以使用
cl.g.root
来访问根节点。cl.g
是一个特别的模块,里面包含了许多全局数据。
Node.__init__(self, name=None, parent=None)
Node
接受两个参数,name
为节点的名字,名字在同一层级下是唯一的,因此你可以通过.children
来用名字查找子节点。parent
可以设置节点的父节点,当它为None
时,父节点为根节点。
Node.destroy(self)
,立即销毁节点Node.destroy_later(self, delay: float)
,在若干秒后销毁节点
节点的销毁是将其从对象树中移除,它的数据仍将短暂存留在内存中,直到Python GC发生。
Node.on_ready(self)
,当节点即将进入第一帧的逻辑时,调用一次Node.on_update(self)
,每帧调用一次,重写此函数以实现游戏逻辑Node.on_render(self)
,每帧调用一次,重写此函数以渲染游戏场景中的对象(使用世界空间的变换矩阵)Node.on_render_ui(self)
,每帧调用一次,重写此函数以渲染UI对象(使用UI空间的变换矩阵)Node.on_destroy(self)
,当节点即将被销毁时,调用一次
每个Node
实例中都存储了位置、旋转和缩放的信息。
Node.position: vec2
,节点的本地坐标Node.rotation: float
,节点的本地旋转角度(顺时针、弧度制)Node.scale: vec2
,节点的缩放值Node.global_position: vec2
,节点的世界坐标
要获取节点在世界空间下的更详细数据,可以使用Node.transform(self) -> mat3x3
,该函数返回一个从世界空间到节点本地空间的变换矩阵。
Node.children: dict[str, Node]
,节点的子节点Node.parent: Node
,节点的父节点Node.get_node(self, path: str)
,以相对路径逐级查找子节点
控件Control
是Node
的子类,用于在UI上绘图和实现交互。
cl.controls.Image
,图片控件cl.controls.Label
,标签控件,用来绘制单行的短文本cl.controls.Text
,文本控件,用来绘制多行的长文本cl.controls.Container
,容器控件,为其他控件提供定位能力
CarrotLib🥕提供了类似Unity的协程支持。协程对象是一个标准的Python迭代器,通过一个节点来执行。
Node.start_coroutine(self, coro)
,启动一个协程Node.stop_coroutine(self, coro)
,停止一个协程Node.stop_all_coroutines(self)
,停止所有协程
以下是一个等待5秒后打印Hello, world
的协程。
def hello_coro():
yield from cl.WaitForSeconds(5.0)
print("Hello, world")
# 启动协程:node.start_coroutine(hello_coro())
cl.draw_texture(transform: mat3x3, tex: rl.Texture2D, src_rect: rl.Rectangle=None, flip_x=False, flip_y=False, color: rl.Color = None, origin: vec2 = None)
transform
,基础变换tex
,纹理src_rect
,源矩形flip_x
,翻转x轴flip_y
,翻转y轴color
,颜色origin
,锚点(默认为中心)
cl.draw_text(font: rl.Font, pos: vec2, text: str, font_size: int, color: rl.Color, spacing: int = 0, line_spacing: int = 0, origin: vec2 = None)
cl.draw_circle(center: vec2, radius: float, color: rl.Color, solid=True)
cl.draw_rect(rect: rl.Rectangle, color: rl.Color = None, origin: vec2 = None, solid=True)
cl.draw_line(begin: vec2, end: vec2, color: rl.Color)
游戏中会用到很多资源,比如纹理、声音、字体和源代码等,它们被存放在对应的项目文件夹中。
根据平台的差异,CarrotLib🥕提供了三套方案来打包资源,并提供一组平台无关接口来加载资源。
- 标准文件系统。在Windows/Linux/MacOS上,资源直接存放在文件系统中。此时,资源加载能力由C语言标准库函数所支持。
- Android资源数据库。在Android上,资源被复制到一个特殊的assets目录中,并使用AAAssetManager来加载资源。
- 硬编码资源数据库。若1和2的方案均不可用,资源将会被转换成字节数组,并硬编码到一个
.cpp
文件中,iOS和Web平台只能使用这种方法。
cl.load_asset(path: str) -> bytes
,从指定路径加载资源,返回资源本身的字节cl.list_assets(root: str) -> list[str]
,列出指定目录下的所有资源路径
你可以使用load_texture
函数从资源库中加载纹理(首次加载后缓存)。
tex = cl.load_texture("path/to/texture.png")
如果你不希望自动缓存纹理,可以使用更加底层的rl.LoadTexture
和rl.UnloadTexture
函数。
你可以使用load_font
函数从资源库中加载字体(首次加载后缓存)。
font: rl.Font = cl.load_font("path/to/font.ttf")
在CarrotLib🥕中,字体所包含的字符集是在加载时确定的。默认的load_font
函数只会构建ASCII字符集。
若字体中包含中文,你需要使用load_font_cjk
来加载,它会为字体额外构建4000个常用的汉字字符。
font: rl.Font = cl.load_font_cjk("path/to/font.ttf")
你可以使用load_sound
函数从资源库中加载声音(首次加载后缓存)。
sound: rl.Sound = cl.load_sound("path/to/sound.wav")
要播放一次性的声音,可使用
cl.play_sound
。
在构建之前,运行如下命令来预构建。
python scripts\prebuild.py projects\<your_project>
mkdir build
cd build
mkdir win32
cd win32
cmake ..\..
cmake --build .
Debug\Game.exe ..\..\projects\<your_project>
cd android
chmod +x ./gradlew
./gradlew --no-daemon assembleDebug
bash build_ios.h
bash build_web.h
python -m http.server -d build/web