代码之家  ›  专栏  ›  技术社区  ›  Kingsley

在Kivy中旋转图像而不使用Builder/。kv文件和数字属性

  •  0
  • Kingsley  · 技术社区  · 7 年前

    Animation 旋转图像。

    我想知道如何在不使用 .kv 文件(或 Builder.load_string

    #! /usr/bin/env python3
    import kivy
    kivy.require('1.9.1')
    
    from kivy.app import App
    from kivy.uix.widget import Widget
    from kivy.uix.label import Label
    from kivy.uix.image import Image
    from kivy.uix.floatlayout import FloatLayout
    from kivy.graphics import Rectangle, Color, Rotate, PushMatrix, PopMatrix
    from kivy.core.window import Window
    from kivy.clock import Clock
    from kivy.graphics.svg import Svg
    from kivy.animation import Animation
    from kivy.lang import Builder
    from kivy.properties import NumericProperty
    
    import random
    
    WINDOW_WIDTH, WINDOW_HEIGHT = Window.size
    
    Builder.load_string('''
    <Sprite>:
        canvas.before:
            PushMatrix
            Rotate:
                angle: self.angle
                axis: (0, 0, 1)
                origin: self.center
        canvas.after:
            PopMatrix
    ''')
    
    
    class Sprite( Image ):
        angle = NumericProperty(0)
    
        def __init__( self, x=0, y=0, **kwargs ):
            super( Sprite, self ).__init__( **kwargs )
    
            self.size_hint = (None, None)  # tell the layout not to size me
            self.angle     = 0
            self.source    = 'alien.png'
            self.size      = self.texture.size 
    
            if ( x == 0 and y == 0 ):
                self.pos   = ( random.randrange(0,WINDOW_WIDTH) , random.randrange(0,WINDOW_HEIGHT) )
            else:
                self.pos   = ( x,y )
    
            self.animate() # start moving animation
    
        def animateComplete( self, *kargs ):
            Animation.cancel_all( self ) # is this needed?
            self.angle = 0
            self.animate()
    
        def animate( self ):
            self.anim = Animation( angle=360, duration=1 )
            self.anim.bind( on_complete=self.animateComplete )
            self.anim.repeat = True
            self.anim.start( self )
    
    
    class FPSText( Label ):
        def __init__( self, **kwargs ):
            super( FPSText, self ).__init__( **kwargs )
            self.size_hint = (None, None)  # tell the layout not to size me
            self.pos_hint = { 'right':1, 'top':1 }
    
        def update( self, count ):
            self.text = "%d aliens / %3.1f FPS" % ( count, Clock.get_fps() ) 
            self.size = self.texture_size
    
    
    class AlienGame( FloatLayout ):
        def __init__(self, **kwargs):
            super( AlienGame, self).__init__(**kwargs)
            self.aliens = []
            self.fps_text = FPSText()
            self.add_widget( self.fps_text )
            self.addAlien( WINDOW_WIDTH//2, WINDOW_HEIGHT//2 )
    
        def addAlien( self, x=0, y=0 ):
            new_alien = Sprite( x, y )
            self.aliens.append( new_alien )
            self.add_widget( new_alien )
    
        def update( self, dt ):
            self.fps_text.text = '--'
            self.fps_text.update( len( self.aliens ) )
    
        def on_touch_down( self, touch ):
            if ( touch.is_double_tap ):
                for i in range( 7 ):
                    self.addAlien()
            else: #if ( touch.is_single_tap ):  (no single tap property)
                self.addAlien( touch.pos[0], touch.pos[1]  )
    
    class RotApp( App ):
        def build( self ):
            game = AlienGame()
            Clock.schedule_interval(game.update, 1.0 / 60.0)
            return game
    
    
    if ( __name__ == '__main__' ):    
        RotApp().run()
    

    我试过这样的方法:

    class Sprite( Image ):
        def __init__( self, x=0, y=0, **kwargs ):
            super( Sprite, self ).__init__( **kwargs )
    
            self.size_hint = (None, None)  # tell the layout not to size me
            self.source    = 'alien.png'
            self.size      = self.texture.size
    
            # define the rotation
            with self.canvas.before:
                PushMatrix()
                self.rot = Rotate()
                self.rot.angle  = 0
                self.rot.origin = self.center
                self.rot.axis = (0, 0, 1)
            with self.canvas.after:
                PopMatrix()
    

    但没能拿到 self.rot.angle 动画 对象

    example output

    0 回复  |  直到 7 年前
        1
  •  2
  •   Erik    7 年前

    是的,这是可能的,这是您的Sprite类,它只使用python代码进行旋转。这里唯一的一件事是——kv lang的诞生是有原因的!这让这件事变得容易多了。我强烈建议保留kv代码。无论如何,回答你的问题:关键是

    或者,您可以使用 bind self.rot.angle = self.angle 然后后来,, self.bind(angle=on_angle) 哪一个叫你的 on_angle self.angle 变化。你必须定义一个 self.on_angle 应该重置的功能 自己旋转角度=自身。角 . KV lang会自动为您执行此操作,为您节省大量代码。以千伏为单位, angle: self.angle 自动更新 angle 在任何时候都是可变的 变量变化,意味着不玩 作用

    这是你的雪碧课。注意这两行 self.rot.origin = self.center self.anim.start(self.rot)

    class Sprite( Image ):
        angle = NumericProperty(0)
    
        def __init__( self, x=0, y=0, **kwargs ):
            super( Sprite, self ).__init__( **kwargs )
            # define the rotation
            with self.canvas.before:
                PushMatrix()
                self.rot = Rotate()
                self.rot.angle  = 0
                self.rot.origin = self.center
                self.rot.axis = (0, 0, 1)
            with self.canvas.after:
                PopMatrix()
    
            self.size_hint = (None, None)  # tell the layout not to size me
            self.angle     = 0
            self.source    = 'alien.png'
            self.size      = self.texture.size 
    
            if ( x == 0 and y == 0 ):
                self.pos   = ( random.randrange(0,WINDOW_WIDTH) , random.randrange(0,WINDOW_HEIGHT) )
            else:
                self.pos   = ( x,y )
    
            self.rot.origin = self.center # Reset the center of the Rotate canvas instruction
            self.animate() # start moving animation
    
        def animateComplete( self, *kargs ):
            Animation.cancel_all( self ) # is this needed?
            self.rot.angle = 0
            self.animate()
    
        def animate( self ):
            self.anim = Animation( angle=360, duration=1 )
            self.anim.bind( on_complete=self.animateComplete )
            self.anim.repeat = True
            self.anim.start( self.rot ) # Start rotating the self.rot widget instead of the self widget