簡體   English   中英

旋轉單個 Kivy 元件

[英]Rotate individual Kivy elements

我有一個助手 class 用於在屏幕上生成旋轉圖像。 問題是,當我嘗試旋轉圖像時,整個布局會旋轉,盡管我確實使用了 PushMatrix 和 PopMatrix。 它們似乎沒有效果,我不明白為什么。

我還嘗試使用 canvas.before 和 canvas.after 將所有內容分開,但得到了相同的結果。

助手 class:

class WidgetDrawer(Widget):

    def __init__(self, imageStr, windowsize, **kwargs):
        super(WidgetDrawer, self).__init__(**kwargs)
        # this is part of the**kwargs notation
        # if you haven't seen with before, here's a link
        # http://effbot.org/zone/python-with-statement.html
        self.WindowHeigth, self.WindowWidth = windowsize

        with self.canvas:
            PushMatrix()

            # setup a default size for the object
            self.size = (self.WindowWidth*.002*25, self.WindowWidth*.002*25)
            # center the widget
            self.pos = (self.center_x, self.center_y)
            self.rot = Rotate()
            self.rot.origin = self.pos
            self.rot.axis = (0, 0, 1)
            self.rot.angle = 30
            # this line creates a rectangle with the image drawn on top
            self.rect_bg = Rectangle(source=imageStr,
                                     pos=self.pos,
                                     size=self.size)
            PopMatrix()
            # this line calls the update_graphics_pos function every time the
            # position variable is modified
            self.bind(pos=self.update_graphics_pos)

            self.velocity_x = 0  # initialize velocity_x and velocity_y
            self.velocity_y = 0

    def update_graphics_pos(self, instance, value):
        # if the widgets position moves, the rectangle that contains the image
        # is also moved
        self.rect_bg.pos = value

    # use this function to change widget position
    def setPos(self, xpos, ypos):
        self.x = xpos
        self.y = ypos

    def move(self):
        self.x = self.x + self.velocity_x
        self.y = self.y + self.velocity_y

        if self.y > self.WindowHeigth*0.95:
            # don't let the ship go up too high
            self.y = self.WindowHeigth*0.95
        if self.y <= 0:
            self.y = 0  # set heigth to 0 if ship too low

    def update(self):
        # the update function moves the astreoid. Other things could happen
        # here as well (speed changes for example)
        self.move()

編輯:添加了上述 class 正在使用的最小可重復示例:波紋管代碼產生 go 從右到左的項目(並且應該旋轉,但整個布局會旋轉)

from kivy.config import Config

# don't make the app re-sizeable
Config.set('graphics', 'resizable', False)

from kivy.app import App
from kivy.uix.widget import Widget
from kivy.uix.label import Label
from kivy.uix.button import Button
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.image import Image
from kivy.core.window import Window
from kivy.clock import Clock
from kivy.graphics.vertex_instructions import Rectangle
from kivy.properties import partial
from kivy.graphics.context_instructions import PopMatrix, PushMatrix, Rotate

from random import randint


class WidgetDrawer(Widget):
    # This widget is used to draw all of the objects on the screen
    # it handles the following:
    # widget movement, size, positioning
    # whever a WidgetDrawer object is created, an image string needs to be
    # specified, along with the windowsize tuple
    # example:    wid - WidgetDrawer('./image.png', (Window.height, Window.width))
    # windowsize is used for the default size and position,
    # but can pe updated later

    def __init__(self, imageStr, windowsize, **kwargs):
        super(WidgetDrawer, self).__init__(**kwargs)
        # this is part of the**kwargs notation
        # if you haven't seen with before, here's a link
        # http://effbot.org/zone/python-with-statement.html
        self.WindowHeigth, self.WindowWidth = windowsize

        with self.canvas:
            PushMatrix()

            # setup a default size for the object
            self.size = (self.WindowWidth*.002*25, self.WindowWidth*.002*25)
            # center the widget
            self.pos = (self.center_x, self.center_y)
            self.rot = Rotate()
            self.rot.origin = self.pos
            self.rot.axis = (0, 0, 1)
            self.rot.angle = 30
            # this line creates a rectangle with the image drawn on top
            self.rect_bg = Rectangle(source=imageStr,
                                     pos=self.pos,
                                     size=self.size)
            PopMatrix()
            # this line calls the update_graphics_pos function every time the
            # position variable is modified
            self.bind(pos=self.update_graphics_pos)

            self.velocity_x = 0  # initialize velocity_x and velocity_y
            self.velocity_y = 0

    def update_graphics_pos(self, instance, value):
        # if the widgets position moves, the rectangle that contains the image
        # is also moved
        self.rect_bg.pos = value

    # use this function to change widget position
    def setPos(self, xpos, ypos):
        self.x = xpos
        self.y = ypos

    def move(self):
        self.x = self.x + self.velocity_x
        self.y = self.y + self.velocity_y

        if self.y > self.WindowHeigth*0.95:
            # don't let the ship go up too high
            self.y = self.WindowHeigth*0.95
        if self.y <= 0:
            self.y = 0  # set heigth to 0 if ship too low

    def update(self):
        # the update function moves the astreoid. Other things could happen
        # here as well (speed changes for example)
        self.move()


class Asteroid(WidgetDrawer):
    # Asteroid class. The flappy ship will dodge these
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

    def update(self):
        # self.rot.angle += 1  # this should animate the object, but rotates the layout
        super().update()


class Game(Widget):
    # this is the main widget that contains the game.
    def __init__(self, **kwargs):
        super(Game, self).__init__(**kwargs)
        self.windowsize = (Window.height, Window.width)
        self.asteroidList = []  # use this to keep track of asteroids
        self.minProb = 1700  # this variable used in spawning asteroids

    def addAsteroid(self):
        # add an asteroid to the screen
        # self.asteroid
        imageNumber = randint(1, 4)
        imageStr = './sandstone_'+str(imageNumber)+'.png'  #change the image here
        tmpAsteroid = Asteroid(imageStr, self.windowsize)
        tmpAsteroid.x = Window.width*0.99

        # randomize y position
        ypos = randint(0, 16)

        ypos = ypos*Window.height*.0625

        tmpAsteroid.y = ypos
        tmpAsteroid.velocity_y = 0
        vel = 10
        tmpAsteroid.velocity_x = -0.1*vel

        self.asteroidList.append(tmpAsteroid)
        self.add_widget(tmpAsteroid)

    def update(self, dt):
        # This update function is the main update function for the game
        # All of the game logic has its origin here
        # events are setup here as well

        # update game objects

        # update asteroids
        # randomly add an asteroid
        tmpCount = randint(1, 1800)
        if tmpCount > self.minProb:
            self.addAsteroid()
        if self.minProb < 1700:
            self.minProb = 1900
        self.minProb = self.minProb - 1

        for k in self.asteroidList:
            if k.x < -20:
                self.remove_widget(k)
                self.asteroidList.remove(k)

            k.update()


class ClientApp(App):
    def build(self):
        # this is where the root widget goes
        # should be a canvas
        parent = Widget()  # this is an empty holder for buttons, etc
        Window.clearcolor = (0, 0, 0, 1.)

        game = Game()
        # Start the game clock (runs update function once every (1/60) seconds
        # Clock.schedule_interval(app.update, 1.0/60.0)
        parent.add_widget(game)
        Clock.schedule_interval(game.update, 1.0/60.0)
        # use this hierarchy to make it easy to deal w/buttons
        return parent


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

您的代碼將所有Asteroids旋轉相同的量,並且旋轉不會隨着時間的推移而變化。 您可以通過在每次調用update()時更新旋轉來解決此問題。 嘗試像這樣修改您的代碼:

首先在其__init__()方法中為每個 Asteroid 定義一個delta_angle

self.delta_angle = randint(-3, 3)

這使每個Asteroid都有自己的隨機旋轉。

然后創建一個方法來實際更新WidgetDrawer中的旋轉:

def rotate(self):
    self.rot.origin = self.center
    self.rot.angle += self.delta_angle

然后從update()方法調用這個新方法:

def update(self):
    # the update function moves the astreoid. Other things could happen
    # here as well (speed changes for example)
    self.move()
    self.rotate()

現在,隨着時間的推移,每顆Asteroid都應該獨立旋轉。

暫無
暫無

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

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