【问题标题】:How to fix aspect ratio of a kivy game?如何修复kivy游戏的纵横比?
【发布时间】:2015-04-27 01:17:19
【问题描述】:

我已经开始玩 Kivy,但我对这一切还很陌生,并且已经在苦苦挣扎。

我正在尝试制作棋盘游戏 - 我希望窗口可以调整大小,但我不希望调整窗口大小以弄乱游戏的纵横比(换句话说,我希望窗口如果窗口的大小调整为内容的预期纵横比以外的大小,则在内容上方或两侧会出现黑条)

我认为确保这一点的最简单方法是:

a) 锁定窗口本身的纵横比,使其始终为 10:9(板和所有屏幕元素的纵横比) - 即使是全屏。

b) 使用某种以窗口为中心并锁定 10:9 纵横比的小部件/表面/布局。然后,我随后将其用作放置所有其他图像、小部件、网格等的基础。

但是,我真的不知道该怎么做。我不确定我是否可以锁定窗口纵横比,我发现的唯一可以让我锁定纵横比的特定于 kivy 的对象来自 kivy.graphics.image ......我似乎不是能够用作我其他东西的“基础”。

编辑:到目前为止,我已经编写了以下代码:它创建了一个布局(并将其着色为略带红色),每当调整大小时“修复”它自己的纵横比。但是,它仍然没有在窗口中居中,而且更成问题的是,它会导致无限循环(可能是因为方面修复代码更正了大小,但随后 kivy 将其大小“更正”回了窗口的大小,再次触发方面修复,以为我可能错了)。

编辑:再次修改代码,但它仍然是一个无限循环。我虽然只参考父母的尺寸信息可以解决这个问题,但显然不是。

如果有人帮助我修复我的代码,我将不胜感激。

代码如下:

test.py

from kivy.app import App
from kivy.uix.widget import Widget
from kivy.uix.image import Image
from kivy.uix.anchorlayout import AnchorLayout
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.relativelayout import RelativeLayout
from kivy.properties import (ObjectProperty,
                             NumericProperty,
                             ReferenceListProperty)
from kivy.graphics.context_instructions import Color
from kivy.graphics.vertex_instructions import Rectangle

class Board(AnchorLayout):
    pass

class BackgroundLayout(RelativeLayout):
    def FixAspectRatio(self, *args):
        correctedsize = self.parent.size
        if correctedsize[0] > correctedsize[1]*(10/9):
            correctedsize[0] = correctedsize[1]*(10/9)
        elif correctedsize[0] < correctedsize[1]*(10/9):
            correctedsize[1] = correctedsize[0]/(10/9)
        return correctedsize

class test(App):
    game = ObjectProperty(None)

    def build(self):
        self.game = Board()
        return self.game

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

test.kv

<Board>
    BackgroundLayout:
        canvas.before:
            Color:
                rgba: 1, 0, 0, 0.5
            Rectangle:
                size: self.size
                pos: self.pos
        size: self.FixAspectRatio(self.parent.size)
        pos: self.parent.pos

【问题讨论】:

    标签: python layout resize kivy aspect-ratio


    【解决方案1】:

    一种方法是创建一个在给定纵横比的情况下始终最大化子级的布局。这是一个例子::

    from kivy.lang import Builder
    from kivy.app import App
    from kivy.uix.relativelayout import RelativeLayout
    from kivy.properties import NumericProperty
    
    kv = """
    ARLayout:
        Widget:
            canvas:
                Color:
                    rgb: 1, 0, 0
                Rectangle:
                    size: self.size
                    pos: self.pos
    """
    
    class ARLayout(RelativeLayout):
        # maximize the children given the ratio
        ratio = NumericProperty(10 / 9.)
    
        def do_layout(self, *args):
            for child in self.children:
                self.apply_ratio(child)
            super(ARLayout, self).do_layout()
    
        def apply_ratio(self, child):
            # ensure the child don't have specification we don't want
            child.size_hint = None, None
            child.pos_hint = {"center_x": .5, "center_y": .5}
    
            # calculate the new size, ensure one axis doesn't go out of the bounds
            w, h = self.size
            h2 = w * self.ratio
            if h2 > self.height:
                w = h / self.ratio
            else:
                h = h2
            child.size = w, h
    
    
    class TestApp(App):
        def build(self):
            return Builder.load_string(kv)
    
    TestApp().run()
    

    【讨论】:

      【解决方案2】:

      在 kivy 聊天中 kived 的大力帮助下,我设法找到了一个令我满意的解决方案。

      下面的游戏边界基于“背景”图像,然后在该背景图像上放置一个相对布局。对于所有后续的孩子,坐标 (0, 0) 将参考(锁定的)背景图像的左下角,他们可以使用背景的“放大”属性来根据屏幕大小调整他们的大小/位置.

      提供任何 gamebounds.png 图像,下面的代码将实现这一点。请注意,RelativeLayout 带有红色阴影(透明度为 50%)只是为了显示其位置(并表明它始终与 gamebounds.png 图像大小和位置匹配):

      test.py

      from kivy.app import App
      from kivy.uix.widget import Widget
      from kivy.uix.image import Image
      from kivy.uix.anchorlayout import AnchorLayout
      from kivy.uix.floatlayout import FloatLayout
      from kivy.uix.relativelayout import RelativeLayout
      from kivy.properties import (ObjectProperty,
                                   NumericProperty,
                                   ReferenceListProperty,
                                   ListProperty)
      from kivy.graphics.context_instructions import Color
      from kivy.graphics.vertex_instructions import Rectangle
      
      class Game(FloatLayout):
          pass
      
      class Background(Image):
          offset = ListProperty()
          magnification = NumericProperty(0)
      
      
      class Bounds(RelativeLayout):
          pass
      
      class test(App):
          game = ObjectProperty(None)
      
          def build(self):
              self.game = Game()
              return self.game
      
      if __name__ == '__main__':
          test().run()
      

      test.kv

      <Game>
          Background:
              id: BackgroundId
              #Provide the image that will form the aspect-locked bounds of the
              #game.  Image widgets have aspect_lock set to True by default.
              source: 'gamebounds.png'
              #All the image to stretch to fill the available window space.
              allow_stretch: True
              size: self.parent.size
              #Find the coordinates of the bottom-left corner of the image from
              #the bottom-left corner of the window.  Call this the 'offset'.
              offset: [self.center_x - (self.norm_image_size[0]/2),
              self.center_y - (self.norm_image_size[1]/2)]
              #Find out the factor by which the image is magnified/shrunk from
              #its 'default' value:
              magnification: self.norm_image_size[0] / self.texture_size[0]
      
              Bounds:
                  #The canvas below isn't needed, it's just used to show the 
                  #position of the RelativeLayout
                  canvas:
                      Color:
                          rgba: 1, 0, 0, 0.5
                      Rectangle:
                          size: self.size
                          pos: (0, 0)
                  #Set the position of the RelativeLayout so it starts at the
                  #bottom left of the image
                  pos: self.parent.offset
                  #Set the size of the RelativeLayout to be equal to the size of
                  #the image in Background
                  size: self.parent.norm_image_size
      

      【讨论】:

        猜你喜欢
        • 2021-05-24
        • 2011-10-26
        • 2011-10-27
        • 1970-01-01
        • 2018-07-28
        • 1970-01-01
        • 1970-01-01
        • 2021-12-09
        • 2020-03-25
        相关资源
        最近更新 更多