簡體   English   中英

在不使用Builder / .kv文件和NumericProperty的情況下在Kivy中旋轉圖像

[英]Rotate image in Kivy without using Builder / .kv file and NumericProperty

因此,基於許多不同的示例,我將示例Kivy應用程序拼湊在一起,該應用程序使用Kivy 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來更新動畫。 如果我手動處理動畫,效果很好,但是我想使用Kivy Animation對象。

是否有執行此操作的純Python方法?

示例輸出

是的,有可能,這是您的Sprite類,僅使用python代碼進行旋轉。 這里唯一的是-制作kv lang是有原因的! 它使這些工作變得容易得多。 我強烈建議保留kv代碼。無論如何,要回答您的問題:關鍵是1)在self.rot小部件而不是self小部件上啟動動畫2)從self.center開始重置self.rot.origin變量是(0,0)初始化小部件的時間(在將其實際放置在屏幕上之前,為其賦予適當的self.center)。

另外,您可以使用bind方法。 例如,設置self.rot.angle = self.angle ,然后設置self.rot.angle = self.angle self.bind(angle=on_angle)on_angle self.angle更改,它將調用on_angle函數。 您將必須定義一個self.on_angle函數,該函數應重置self.rot.angle = self.angle KV lang自動為您執行此操作,從而節省了大量代碼。 在kv中, angle: self.angle每當self.angle變量更改時angle: self.angle自動更新angle變量,這意味着不使用bind函數。

這是您的Sprite類別。 注意兩行self.rot.origin = self.centerself.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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM