PythonIDE Docs
中文
简体中文

scene

2D 场景、精灵节点、触摸、Action 动画、物理与 Classic 绘图。

Pythonista 风格的 2D 场景运行时:精灵节点、触摸、逐帧 update()、Classic 绘图、动作动画与 SpriteKit 物理。

边界scene 适合小游戏、画布动画和物理交互。普通表单、设置页、列表导航请用 appui;教材式海龟绘图用 turtle;主屏小组件用 widget。坐标原点在左下角(与 Pythonista 一致)。

#模块概览

说明
导入import scene
适合做什么触摸游戏、精灵动画、粒子、碰撞、Classic 画布、手柄输入
入口定义 Scene 子类,脚本末尾只调用一次 scene.run(MyScene())
生命周期setup() 建节点;update() 每帧逻辑;draw() Classic 绘图;触摸走 touch_*
关闭方式scene.run() 会阻塞直到场景关闭(界面上的关闭按钮或系统下滑 dismiss)
MiniAppScene 类型 MiniApp 入口同样是 scene.run(...),不是 appui.run()
文档示例代码块标记 previewScene,点「预览」直接打开全屏场景,不弹控制台 sheet

#快速开始

点击运行后会打开全屏 2D 场景;触摸屏幕可看到坐标更新。

python
import scene


class TapDemo(scene.Scene):
    def setup(self):
        self.background_color = (0.08, 0.09, 0.12)
        self.label = scene.LabelNode(
            "Tap anywhere",
            font=("Helvetica", 22),
            position=(self.size.w / 2, self.size.h / 2),
            parent=self,
        )

    def touch_began(self, touch):
        self.label.text = f"{touch.location.x:.0f}, {touch.location.y:.0f}"


scene.run(TapDemo(), show_fps=True)

#可运行示例

#精灵与 Action 动画

SpriteNode 的第一个位置参数是纹理名;纯色块请用关键字 color=。动画用 node.run_action(...) 启动。

python
import scene


class SpriteDemo(scene.Scene):
    def setup(self):
        self.background_color = "black"
        self.box = scene.SpriteNode(
            color="cyan",
            size=(80, 80),
            position=(self.size.w / 2, self.size.h / 2),
            parent=self,
        )
        pulse = scene.Action.sequence([
            scene.Action.scale_to(1.2, 0.5),
            scene.Action.scale_to(0.8, 0.5),
        ])
        self.box.run_action(scene.Action.repeat_forever(pulse))


scene.run(SpriteDemo(), show_fps=True)

#Classic 绘制(draw()

fillrectlinetext只能在 draw() 里调用。

python
import scene


class DrawDemo(scene.Scene):
    def draw(self):
        scene.background(0.05, 0.06, 0.08)
        scene.fill(0.2, 0.6, 1.0)
        scene.rect(40, 80, 120, 80, corner_radius=12)
        scene.stroke(1.0, 1.0, 1.0, 0.8)
        scene.stroke_weight(3)
        scene.line(40, 40, 180, 120)
        scene.fill(1, 1, 1)
        scene.text("Draw", x=100, y=130, font_size=20)


scene.run(DrawDemo())

#物理与碰撞

给节点设置 physics_body;静态地面设 dynamic = False。需要碰撞回调时重写 contact_began(contact)

python
import scene


class PhysicsDemo(scene.Scene):
    def setup(self):
        self.background_color = "#101820"
        w, h = self.size.w, self.size.h

        floor = scene.SpriteNode(
            color="#444",
            size=(w, 120),
            position=(w / 2, 60),
            parent=self,
        )
        floor_body = scene.PhysicsBody.rectangle(w=w, h=120)
        floor_body.dynamic = False
        floor.physics_body = floor_body

        self.ball = scene.SpriteNode(
            color="#ff8c42",
            size=(44, 44),
            position=(w / 2, h - 100),
            parent=self,
        )
        ball_body = scene.PhysicsBody.circle(r=22)
        ball_body.restitution = 0.65
        self.ball.physics_body = ball_body

    def touch_began(self, touch):
        self.ball.position = (touch.location.x, touch.location.y)


scene.run(PhysicsDemo(), show_fps=True)

#模态子场景

主场景 present_modal_scene,子场景 dismiss_modal_scene 关闭。

python
import scene


class SubScene(scene.Scene):
    def setup(self):
        self.background_color = (0.1, 0.1, 0.15, 0.92)
        self.label = scene.LabelNode(
            "子场景 — 点一下关闭",
            font=("Helvetica", 20),
            position=(self.size.w / 2, self.size.h / 2),
            parent=self,
        )

    def touch_began(self, touch):
        self.dismiss_modal_scene()


class MainScene(scene.Scene):
    def setup(self):
        self.label = scene.LabelNode(
            "主场景 — 点一下打开子场景",
            font=("Helvetica", 20),
            position=(self.size.w / 2, self.size.h / 2),
            parent=self,
        )

    def touch_began(self, touch):
        self.present_modal_scene(SubScene())


scene.run(MainScene())

#心智模型

  1. 入口scene.run(SceneSubclass(), ...) 阻塞当前脚本,直到用户关闭场景视图。
  2. 初始化:在 setup() 创建节点、纹理、物理体;此时 self.size 已由运行时注入。
  3. 持续逻辑:轻量状态推进放 update();节点位移/缩放优先 Action,避免每帧新建节点。
  4. 自绘:Classic API(scene.rect 等)只放在 draw();保留式 UI 用 SpriteNode / LabelNode
  5. 触摸:实现 touch_began / touch_moved / touch_ended,用 touch.location.x/y
  6. 资源:图片、音效、控制器状态在 setup() 缓存,不要在每帧重复加载。

#与 appui / turtle 怎么选

需求首选原因
小游戏、Sprite、粒子、碰撞、触摸循环scene帧循环、节点树、Action、Physics
设置页、列表、图表、导航appui原生控件与状态管理
Pythonista 命令式 UIKit 控件ui迁移旧 ui 脚本
教材海龟、几何作图turtleAPI 更简单,无节点/物理
主屏/锁屏展示widgetWidgetKit 时间线模型

#API 参考

#速查

API作用
run(scene, *, orientation=0, frame_interval=1, ...)全屏运行场景(阻塞至关闭)
Scene场景基类:setup / update / draw / touch_*
SpriteNode / LabelNode / ShapeNode精灵、文字、矢量形状
Action.move_to / sequence / repeat_forever节点动画
PhysicsBody / PhysicsWorld碰撞与重力
background / fill / rect / textClassic 绘图(仅 draw()
get_screen_size() / get_safe_area_insets()屏幕与安全区
PORTRAIT / LANDSCAPErun() 的方向常量

#scene.run()

python
scene.run(
    MyScene(),
    orientation=scene.PORTRAIT,   # DEFAULT_ORIENTATION=0, PORTRAIT=1, LANDSCAPE=2
    frame_interval=1,             # 1≈60fps,2≈30fps
    anti_alias=True,
    show_fps=True,
    multi_touch=True,
)

IDE / MiniApp 的 Scene 模式 会在内部使用主线程回调(_mode='main');文档里直接运行上述示例即可。

#常用节点构造

python
# 纹理精灵(texture 为资源名或 Texture)
scene.SpriteNode("Player", position=(100, 200), parent=self)

# 纯色块 — 必须用 color= 关键字,不要把颜色当第一个位置参数
scene.SpriteNode(color="cyan", size=(60, 60), position=(x, y), parent=self)

# 文字
scene.LabelNode("Hello", font=("Helvetica", 24), position=(x, y), parent=self)

# 形状
scene.ShapeNode(fill_color="yellow", stroke_color="white", parent=self)

#Action Timing

Action.move_to(x, y, duration, timing_mode=scene.TIMING_LINEAR) 常用 timing:TIMING_EASE_IN_OUTTIMING_BOUNCE_OUT 等(见 API 参考)。

#Classic 绘图要点

API说明
scene.text(txt, x=0, y=0, font_name='Helvetica', font_size=16)draw() 中绘制文字
scene.rect(x, y, w, h, corner_radius=0)矩形;先 fill / stroke 再画
scene.image(name, x, y, w, h)绘制已加载图片

image_quadtriangle_strip 在兼容层中尚未实现,调用会抛 NotImplementedError

#场景属性(运行时)

属性说明
self.size / self.size.w / self.size.h场景尺寸(Size,支持 / 2 等向量运算)
self.dt / self.t帧间隔 / 累计时间(秒)
self.frame_count帧计数
self.physics_world物理世界,可改 gravity
self.safe_area_insets刘海/底栏安全区

完整签名见 scene API 索引scene API 参考


#常见错误

错误写法后果修正
SpriteNode("cyan", ...)"cyan" 被当成纹理名使用 SpriteNode(color="cyan", ...)
setup() 里调用 scene.rect()不显示或行为异常绘图放进 draw()
只创建 Action.move_to(...)run_action节点不动node.run_action(action)
脚本里没有 scene.run(...)场景不出现末尾调用一次 scene.run(MyScene())
update() 里做网络/大文件 I/O掉帧、卡顿放后台线程,主线程只改状态
appui.Button 做场景 HUDAPI 不存在LabelNode + 触摸,或改用 appui
表单/设置页整页用 scene难维护改用 appuiForm / List

#失败路径

情况处理
场景不显示确认调用了 scene.run(SceneSubclass()),且 setup() 未抛错
触摸无反应实现 touch_began 等,坐标用 touch.location
节点在 (0,0)检查 position= 是否在 setup() 里用 self.size.w/h 居中
物理不碰撞设置 physics_body,静态体 dynamic=False
关闭后文档里再运行提示忙等上一次 scene.run 完全结束,或先停止当前 Python 运行

#相关文档

文档用途
scene API 索引按类族快速查名称
scene API 参考生命周期、节点、Action、Physics 签名
turtle海龟教学绘图
appui原生表单与导航 UI
uiPythonista 风格 ui 控件
motion加速度计/陀螺仪(可与 scene 配合)

#先选写法

目标写法
精灵 / 物理游戏Scene 子类 + 节点树
即时画布draw() + Classic API
教程海龟turtle

#写 scene 的心智模型

  1. setup() 建节点;update() 做帧逻辑;draw() 只负责即时绘制。
  2. 动画优先 Action + run_action,不要阻塞循环。
  3. 脚本末尾只调用一次 scene.run(...)

#发布前检查

  • 触摸、暂停、关闭路径可验证
  • 精灵颜色使用 color= 关键字参数
  • 未使用 AppUI 布局 API

#预期效果

运行示例后,界面应出现文档描述的目标结果;若与预期不符,先看「失败路径」并按返回值或日志排查。