为什么重新安排时钟间隔会导致图像位置重置?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了为什么重新安排时钟间隔会导致图像位置重置?相关的知识,希望对你有一定的参考价值。

在程序中,人们可以看到,随着球的反弹,人们可以从右上角打开设置页面。这样做会暂停球的运动并打开设置页面。

很抱歉,如果这是一个显而易见的问题,但我再次被Kivy奇怪的内部运作所困扰,并且文档在这些类型的问题上没有多大用处。

问题

球总是从中心位置开始。在切换屏幕之前想要球从之前的位置继续/恢复吗?

重建问题的步骤

  1. 点击标签“点击开始”。球开始从中心位置反弹
  2. 单击齿轮图像。显示设置屏幕
  3. 单击“x”关闭“设置”屏幕。球开始从中心位置反弹。

码:

from kivy.lang import Builder
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.image import Image
from kivy import Config
from kivy.uix.screenmanager import ScreenManager, Screen, FadeTransition,
SlideTransition
from kivy.uix.widget import Widget
from kivy.animation import Animation
from kivy.properties import NumericProperty, ReferenceListProperty,
ObjectProperty
from kivy.clock import Clock
from kivy.vector import Vector
from random import randint

Builder.load_string('''
<Ball>:
    size_hint: None, None
    source: '58-Breakout-Tiles.png'
    pos: self.pos
    size: 15, 15



<SettingsScreen>:
    close: close
    AnchorLayout:
        anchor_x: 'left'
        anchor_y: 'top'
        Image:
            id: close
            size_hint: .03, .03
            source: 'grey_crossGrey.png'

    GridLayout:
        cols: 2
        Label:
            font_name: 'vgafix.fon'
            text: 'Music: '
        Switch:
            active: True
        Label:
            font_name: 'vgafix.fon'
            text: 'Sounds: '
        Switch:
            active: True

<MenuScreen>:
    cog: cog
    AnchorLayout:
        anchor_x: 'right'
        anchor_y: 'top'
        Image:
            id: cog
            size_hint: .03, .03
            source: 'settings-cog.png'

    BoxLayout:
        orientation: 'vertical'
        Image:
            source: 'brickbreaker log.png'
        Label:
            font_name: 'vgafix.fon'
            text: 'Tap to start'

<GameScreen>:
    ball: ball
    cog: cog
    AnchorLayout:
        anchor_x: 'right'
        anchor_y: 'top'
        Image:
            id: cog
            size_hint: .03, .03
            source: 'settings-cog.png'

    Ball:
        id: ball
        size_hint: None, None
        center: self.parent.center
''')

Config.set('graphics', 'multisamples', '0')



class Ball(Image):
    velocityX, velocityY = NumericProperty(0), NumericProperty(0)
    velocity = ReferenceListProperty(velocityX, velocityY)

    def move(self):
        self.pos = Vector(*self.velocity) + self.pos

class Player(Widget):
    pass

class Brick(Widget):
    pass




class SettingsScreen(Screen):
    def __init__(self, **kwargs):
        super(SettingsScreen, self).__init__(**kwargs)
        self.previous = False

    def on_touch_down(self, touch):
        if self.close.collide_point(*touch.pos):
            sm.transition = SlideTransition(direction = 'right')
            if self.previous == 'game':
                sm.get_screen('game').interval()
            sm.current = self.previous

class MenuScreen(Screen):
    def __init__(self, **kwargs):
        super(MenuScreen, self).__init__(**kwargs)

    def on_touch_down(self, touch):
        if self.cog.collide_point(*touch.pos):
            sm.transition = SlideTransition(direction = 'left')
            sm.get_screen('settings').previous = 'menu'
            sm.current = 'settings'
        else:
            sm.transition = FadeTransition()
            sm.current = 'game'

class GameScreen(Screen):
    def __init__(self, **kwargs):
        super(GameScreen, self).__init__(**kwargs)
        self.initBall()
        self.interval = Clock.schedule_interval(self.update, 1.0/60.0)

    def on_touch_down(self, touch):
        if self.cog.collide_point(*touch.pos):
            sm.transition = SlideTransition(direction = 'left')
            sm.get_screen('settings').previous = 'game'
            self.interval.cancel()
            sm.current = 'settings'

    def initBall(self):
        self.ball.center = self.center
        self.ball.velocity = Vector(0, 4).rotate(randint(0, 360))

    def update(self, dt):
        self.ball.move()
        if (self.ball.y < 0) or (self.ball.y > self.height-15):
            self.ball.velocityY *= -1
        # bounce off left and right
        if (self.ball.x < 0) or (self.ball.x > self.width-15):
            self.ball.velocityX *= -1


sm = ScreenManager(transition = FadeTransition())
sm.add_widget(MenuScreen(name='menu'))
sm.add_widget(GameScreen(name='game'))
sm.add_widget(SettingsScreen(name='settings'))



class BrickBreakerInsanityApp(App):
    def build(self):
        return sm

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

代码资产(必填):

https://drive.google.com/open?id=1GAnv5DfjNUuAXTybmsan90Dm0OuSVOfb

https://i.stack.imgur.com/rR799.png

https://i.stack.imgur.com/ngYvL.png

https://i.stack.imgur.com/AuxI3.png

https://i.stack.imgur.com/ypd7C.png

答案

Root cause

SlideTransitiondirection让球从中心开始。

Solution

删除对SlideTransition的所有引用。

Example

from kivy.lang import Builder
from kivy.app import App
from kivy.uix.image import Image
from kivy import Config
from kivy.uix.screenmanager import ScreenManager, Screen, FadeTransition,     
from kivy.uix.widget import Widget
from kivy.properties import NumericProperty, ReferenceListProperty, StringProperty
from kivy.clock import Clock
from kivy.vector import Vector
from random import randint

Builder.load_string('''
<Ball>:
    size_hint: None, None
    source: './assets/icons/58-Breakout-Tiles.png'
    pos: self.pos
    size: 15, 15

<SettingsScreen>:
    close: close
    AnchorLayout:
        anchor_x: 'left'
        anchor_y: 'top'
        Image:
            id: close
            size_hint: .03, .03
            source: './assets/icons/grey_crossGrey.png'

    GridLayout:
        cols: 2
        Label:
            font_name: "./assets/fonts/vgafix.fon"
            text: 'Music: '
        Switch:
            active: True
        Label:
            font_name: "./assets/fonts/vgafix.fon"
            text: 'Sounds: '
        Switch:
            active: True

<MenuScreen>:
    cog: cog

    AnchorLayout:
        anchor_x: 'right'
        anchor_y: 'top'
        Image:
            id: cog
            size_hint: .03, .03
            source: './assets/icons/settings-cog.png'

    BoxLayout:
        orientation: 'vertical'
        Image:
            source: "./assets/icons/brickbreaker log.png"
        Label:
            font_name: "./assets/fonts/vgafix.fon"
            text: 'Tap to start'

<GameScreen>:
    ball: ball
    cog: cog

    AnchorLayout:
        anchor_x: 'right'
        anchor_y: 'top'
        Image:
            id: cog
            size_hint: .03, .03
            source: './assets/icons/settings-cog.png'

    Ball:
        id: ball
        size_hint: None, None
        center: self.parent.center
''')

Config.set('graphics', 'multisamples', '0')


class Ball(Image):
    velocityX, velocityY = NumericProperty(0), NumericProperty(0)
    velocity = ReferenceListProperty(velocityX, velocityY)

    def move(self):
        self.pos = Vector(*self.velocity) + self.pos


class Player(Widget):
    pass


class Brick(Widget):
    pass


class SettingsScreen(Screen):

    def __init__(self, **kwargs):
        super(SettingsScreen, self).__init__(**kwargs)
        self.previous = StringProperty('')

    def on_touch_down(self, touch):
        if self.close.collide_point(*touch.pos):
            self.manager.current = self.previous


class MenuScreen(Screen):

    def on_touch_down(self, touch):
        if self.cog.collide_point(*touch.pos):
            self.manager.get_screen('settings').previous = self.manager.current
            self.manager.current = 'settings'
        else:
            self.manager.transition = FadeTransition()
            self.manager.current = 'game'


class GameScreen(Screen):

    def __init__(self, **kwargs):
        super(GameScreen, self).__init__(**kwargs)
        self.initBall()

    def on_pre_enter(self, *args):
        self.interval = Clock.schedule_interval(self.update, 1.0 / 60.0)

    def on_touch_down(self, touch):
        if self.cog.collide_point(*touch.pos):
            self.manager.get_screen('settings').previous = self.manager.current
            self.manager.current = 'settings'

    def initBall(self):
        self.ball.center = self.center
        self.ball.velocity = Vector(0, 4).rotate(randint(0, 360))

    def update(self, dt):
        self.ball.move()
        if (self.ball.y < 0) or (self.ball.y > self.height - 15):
            self.ball.velocityY *= -1
        # bounce off left and right
        if (self.ball.x < 0) or (self.ball.x > self.width - 15):
            self.ball.velocityX *= -1

    def on_pre_leave(self, *args):
        self.interval.cancel()


sm = ScreenManager(transition=FadeTransition())
sm.add_widget(MenuScreen(name='menu'))
sm.add_widget(GameScreen(name='game'))
sm.add_widget(SettingsScreen(name='settings'))


class BrickBreakerInsanityApp(App):
    def build(self):
        return sm


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

以上是关于为什么重新安排时钟间隔会导致图像位置重置?的主要内容,如果未能解决你的问题,请参考以下文章

切换片段时导航重置

Android Studio - 选项卡式活动如何将片段重置为默认视图?

为啥上传文件 ~2,5 MiB 或更大会导致连接重置?

wrapRootElement + contextAPI :页面更改导致提供者重新渲染,因此重置状态

ViewPager2 中未显示图像(片段重新打开时)

在pygame中,重置每个子画面位置的最有效方法是什么?