You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

能否在Kivy的atlas文件中添加变量以动态修改y坐标?

提问

是否可以在Kivy的atlas文件中添加变量?我现在有一张包含角色四个方向动画帧的精灵图,atlas文件里已经列出了所有帧,我希望把帧的y坐标换成变量,这样就能在py文件的类里修改这个变量,根据按下的方向键切换对应行的动画。

理想的atlas文件结构如下:

{
    "frames/player.png": {
        "f0_1": [0, var, 64, 50],
        "f0_2": [64, var, 64, 50],
        "f0_3": [128, var, 64, 50],
        "f0_4": [192, var, 64, 50],
        "f0_5": [256, var, 64, 50],
        "f0_6": [320, var, 64, 50],
        "f0_7": [384, var, 64, 50],
        "f0_8": [448, var, 64, 50],
        "f0_9": [512, var, 64, 50]
    }
}

这样我就能在py文件里根据方向键修改var的值,切换不同方向的动画帧。

我当前的atlas文件内容是:

{
    "frames/player.png": {
        "f0_1": [0, 0, 64, 50],
        "f0_2": [64, 0, 64, 50],
        "f0_3": [128, 0, 64, 50],
        "f0_4": [192, 0, 64, 50],
        "f0_5": [256, 0, 64, 50],
        "f0_6": [320, 0, 64, 50],
        "f0_7": [384, 0, 64, 50],
        "f0_8": [448, 0, 64, 50],
        "f0_9": [512, 0, 64, 50],

        "f1_1": [0, 50, 64, 50],
        "f1_2": [64, 50, 64, 50],
        "f1_3": [128, 50, 64, 50],
        "f1_4": [192, 50, 64, 50],
        "f1_5": [256, 50, 64, 50],
        "f1_6": [320, 50, 64, 50],
        "f1_7": [384, 50, 64, 50],
        "f1_8": [448, 50, 64, 50],
        "f1_9": [512, 50, 64, 50],

        "f2_1": [0, 101, 64, 50],
        "f2_2": [64, 101, 64, 50],
        "f2_3": [128, 101, 64, 50],
        "f2_4": [192, 101, 64, 50],
        "f2_5": [256, 101, 64, 50],
        "f2_6": [320, 101, 64, 50],
        "f2_7": [384, 101, 64, 50],
        "f2_8": [448, 101, 64, 50],
        "f2_9": [512, 101, 64, 50],

        "f3_1": [0, 150, 64, 50],
        "f3_2": [64, 150, 64, 50],
        "f3_3": [128, 150, 64, 50],
        "f3_4": [192, 150, 64, 50],
        "f3_5": [256, 150, 64, 50],
        "f3_6": [320, 150, 64, 50],
        "f3_7": [384, 150, 64, 50],
        "f3_8": [448, 150, 64, 50],
        "f3_9": [512, 150, 64, 50]
    }
}

回答

Kivy的atlas是静态JSON文件,不支持直接写入变量,没法用var这种动态值控制帧坐标,但可以通过两种方式实现你的需求:

1. 按方向分组切换帧(适配现有atlas结构)

你已经把不同方向的帧按f0_*、f1_*、f2_*、f3_*分组,直接在代码里根据方向键切换帧的前缀即可:

from kivy.app import App
from kivy.uix.image import Image
from kivy.clock import Clock
from kivy.core.window import Window

class Player(Image):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.current_dir = 0  # 0-3对应四个方向
        self.frame_index = 1
        Clock.schedule_interval(self.update_frame, 0.1)
        # 绑定键盘事件
        self._keyboard = Window.request_keyboard(self._keyboard_closed, self)
        self._keyboard.bind(on_key_down=self._on_key_down)

    def _keyboard_closed(self):
        self._keyboard.unbind(on_key_down=self._on_key_down)
        self._keyboard = None

    def _on_key_down(self, keyboard, keycode, text, modifiers):
        if keycode[1] == 'w':
            self.current_dir = 0
        elif keycode[1] == 's':
            self.current_dir = 1
        elif keycode[1] == 'a':
            self.current_dir = 2
        elif keycode[1] == 'd':
            self.current_dir = 3
        return True

    def update_frame(self, dt):
        self.frame_index = self.frame_index % 9 + 1
        self.source = f'atlas://frames/player/f{self.current_dir}_{self.frame_index}'

class GameApp(App):
    def build(self):
        return Player()

if __name__ == '__main__':
    GameApp().run()

2. 动态计算帧坐标(绕开atlas静态限制)

如果不想依赖atlas的帧命名,直接加载整张精灵图,在代码里动态计算uv坐标显示对应帧:

from kivy.app import App
from kivy.uix.image import Image
from kivy.clock import Clock
from kivy.core.window import Window

class Player(Image):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.source = 'frames/player.png'
        self.current_dir = 0
        self.frame_index = 0
        self.frame_width = 64
        self.frame_height = 50
        self.y_offsets = [0, 50, 101, 150]  # 四个方向的y偏移
        Clock.schedule_interval(self.update_frame, 0.1)
        # 绑定键盘事件
        self._keyboard = Window.request_keyboard(self._keyboard_closed, self)
        self._keyboard.bind(on_key_down=self._on_key_down)

    def _keyboard_closed(self):
        self._keyboard.unbind(on_key_down=self._on_key_down)
        self._keyboard = None

    def _on_key_down(self, keyboard, keycode, text, modifiers):
        if keycode[1] == 'w':
            self.current_dir = 0
        elif keycode[1] == 's':
            self.current_dir = 1
        elif keycode[1] == 'a':
            self.current_dir = 2
        elif keycode[1] == 'd':
            self.current_dir = 3
        return True

    def update_frame(self, dt):
        self.frame_index = (self.frame_index + 1) % 9
        # 计算uv坐标(Kivy的y轴从下往上,需反向计算)
        x = self.frame_index * self.frame_width
        y = self.y_offsets[self.current_dir]
        self.uvpos = (x / self.texture.width, (self.texture.height - y - self.frame_height) / self.texture.height)
        self.uvsize = (self.frame_width / self.texture.width, self.frame_height / self.texture.height)

class GameApp(App):
    def build(self):
        return Player()

if __name__ == '__main__':
    GameApp().run()

第一种方式更贴合你现有的atlas结构,代码简洁;第二种方式灵活性更高,适合需要精细控制帧的场景。


内容的提问来源于stack exchange,提问作者Justin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.22 04:54:25