<small id='4EP00'></small><noframes id='4EP00'>

<legend id='4EP00'><style id='4EP00'><dir id='4EP00'><q id='4EP00'></q></dir></style></legend>

        <bdo id='4EP00'></bdo><ul id='4EP00'></ul>
      <tfoot id='4EP00'></tfoot>

      <i id='4EP00'><tr id='4EP00'><dt id='4EP00'><q id='4EP00'><span id='4EP00'><b id='4EP00'><form id='4EP00'><ins id='4EP00'></ins><ul id='4EP00'></ul><sub id='4EP00'></sub></form><legend id='4EP00'></legend><bdo id='4EP00'><pre id='4EP00'><center id='4EP00'></center></pre></bdo></b><th id='4EP00'></th></span></q></dt></tr></i><div id='4EP00'><tfoot id='4EP00'></tfoot><dl id='4EP00'><fieldset id='4EP00'></fieldset></dl></div>

        Kivy 自定义着色器触摸事件

        时间:2023-06-07

            <legend id='7flvE'><style id='7flvE'><dir id='7flvE'><q id='7flvE'></q></dir></style></legend>
            • <tfoot id='7flvE'></tfoot>
                <bdo id='7flvE'></bdo><ul id='7flvE'></ul>

                    <tbody id='7flvE'></tbody>
                  <i id='7flvE'><tr id='7flvE'><dt id='7flvE'><q id='7flvE'><span id='7flvE'><b id='7flvE'><form id='7flvE'><ins id='7flvE'></ins><ul id='7flvE'></ul><sub id='7flvE'></sub></form><legend id='7flvE'></legend><bdo id='7flvE'><pre id='7flvE'><center id='7flvE'></center></pre></bdo></b><th id='7flvE'></th></span></q></dt></tr></i><div id='7flvE'><tfoot id='7flvE'></tfoot><dl id='7flvE'><fieldset id='7flvE'></fieldset></dl></div>

                  <small id='7flvE'></small><noframes id='7flvE'>

                  本文介绍了Kivy 自定义着色器触摸事件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着跟版网的小编来一起学习吧!

                  问题描述

                  我在我的游戏中使用自定义着色器,我必须因为性能.现在我想将触摸事件绑定到我的粒子/不明飞行物,以便我可以决定当有人触摸它们时该怎么做,但我不知道如何计算它们的宽度和高度.我目前能够判断触摸事件发生的位置,但我的 collide_point 函数总是返回 False 因为我没有正确的 Width 和 <我的游戏粒子的代码>高度.collide_point函数需要粒子的righttop,粒子的right和top需要粒子的widthheight 工作.在文档中说

                  Am using custom shader on my game, and i must because of performance. Now i am at the point where i want to bind touch events to my particles/Ufo so that i can decide what to do when someone touches them, but i don't know how i can calculate their width and height. I am currently able to tell where a touch event happened but my collide_point function always return False because i don't have the correct Width and Height of my game particle's. collide_point function require particle's right and top and particle's right and top requires particle's width and height to work. In the documentation it is said that

                  widthheight 属性受布局逻辑影响

                  the width and the height property is subject to layout logic

                  但我没有使用任何 Layout,而是使用 Widget.如何计算我的游戏粒子的宽度和高度.下面是代码

                  but am not using any Layout, am using Widget instead. How can i calculate my game particle's width and height. Below is the code

                  from __future__ import division
                  from collections import namedtuple
                  import json
                  import math
                  import random
                  from kivy import platform
                  from kivy.app import App
                  from kivy.base import EventLoop
                  from kivy.clock import Clock
                  from kivy.core.image import Image
                  from kivy.core.window import Window
                  from kivy.graphics import Mesh
                  from kivy.graphics.instructions import RenderContext
                  from kivy.uix.widget import Widget
                  from kivy.utils import get_color_from_hex
                  import base64
                  
                  UVMapping = namedtuple('UVMapping', 'u0 v0 u1 v1 su sv')
                  
                  GLSL = """
                  ---vertex
                  $HEADER$
                  
                  attribute vec2  vCenter;
                  attribute float vScale;
                  
                  void main(void)
                  {
                      tex_coord0 = vTexCoords0;
                      mat4 move_mat = mat4
                          (1.0, 0.0, 0.0, vCenter.x,
                           0.0, 1.0, 0.0, vCenter.y,
                           0.0, 0.0, 1.0, 0.0,
                           0.0, 0.0, 0.0, 1.0);
                      vec4 pos = vec4(vPosition.xy * vScale, 0.0, 1.0)
                          * move_mat;
                      gl_Position = projection_mat * modelview_mat * pos;
                  }
                  
                  ---fragment
                  $HEADER$
                  
                  void main(void)
                  {
                      gl_FragColor = texture2D(texture0, tex_coord0);
                  }
                  
                  """
                  
                  with open("game.glsl", "wb")  as glslc:
                      glslc.write(GLSL)
                  
                  def load_atlas():
                      atlas = json.loads('''{"game-0.png": {"Elien": [2, 26, 100, 100]}}''') 
                  
                      tex_name, mapping = atlas.popitem()
                      data = '''iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAYAAADDPmHLAAACJklEQVR4nO3dy1ICQRAF0YLw/39ZVxMBGCjEMF23JvOsXPgounMaN61VQrtsH3x3TqFfLv9/ykdcq9z8RKv25Lro5yiUAcAZAJwBwBkAnAHAGQCcAcAZAJwBwBkAnAHAGQCcAcAZAJwBwBkAnAHAGQCcAcAZAJwBwBkAnAHAfXUPsNM79ydWXbYZZVoAey7MPH6tQdScAI64KbV9T3QI6QGsuCKHDiH5l8DVd1aRd2QTT4DOjcCdBmknQMpTmDLH4ZICSFv0tHkOkRJA6mKnzvUxCQGkL3L6fLskBKBG3QFMebqmzPm2zgCmLeq0eV/SfQKoWVcAU5+mqXM/5QkA1xHA9Kdo+vx3PAHgDADOAOBWB3CW98+zvA5PADoDgDMAOAOAMwA4A4AzADgDgDMAuNUBnOXCxVlehycAnQHAGQBcRwDT3z+nz3/HEwCuK4CpT9HUuZ/yBIDrDGDa0zRt3pd0nwBTFnXKnG/rDkDNEgJIf7rS59slIYCq3EVOnetjUgKoylvstHkOkRRAVc6ip8xxuMS/E7gtfsflC8zGb9JOgFurNwO3+VWZJ8CtFacBcuM36QFsjggBvfGbKQFsHjfNfxix07QAHrmpOyX/EqgFDADOAOAMAM4A4AwAzgDgDADOAOAMAM4A4AwAzgDgDADOAOAMAM4A4AwAzgDgDADOAOAMAM4A4AwA7lrl7YpE7okkSZIkSZIkSZIkSZIkSZIkSZL+9AMvSSThyPfOhQAAAABJRU5ErkJggg=='''
                      with open(tex_name, "wb")  as co:
                          co.write(base64.b64decode(data))
                      tex = Image(tex_name).texture
                      tex_width, tex_height = tex.size
                  
                      uvmap = {}
                      for name, val in mapping.items():
                          x0, y0, w, h = val
                          x1, y1 = x0 + w, y0 + h
                          uvmap[name] = UVMapping(
                              x0 / tex_width, 1 - y1 / tex_height,
                              x1 / tex_width, 1 - y0 / tex_height,
                              0.5 * w, 0.5 * h)
                  
                      return tex, uvmap
                  
                  
                  class Particle:
                      x = 0
                      y = 0
                      size = 1
                  
                      def __init__(self, parent, i):
                          self.parent = parent
                          self.vsize = parent.vsize
                          self.base_i = 4 * i * self.vsize
                          self.reset(created=True)
                  
                      def update(self):
                          for i in range(self.base_i,
                                         self.base_i + 4 * self.vsize,
                                         self.vsize):
                              self.parent.vertices[i:i + 3] = (
                                  self.x, self.y, self.size)
                  
                      def reset(self, created=False):
                          raise NotImplementedError()
                  
                      def advance(self, nap):
                          raise NotImplementedError()
                  
                  
                  class GameScreen(Widget):
                      indices = []
                      vertices = []
                      particles = []
                  
                      def __init__(self, **kwargs):
                          Widget.__init__(self, **kwargs)
                          self.canvas = RenderContext(use_parent_projection=True)
                          self.canvas.shader.source = "game.glsl"
                  
                          self.vfmt = (
                              (b'vCenter', 2, 'float'),
                              (b'vScale', 1, 'float'),
                              (b'vPosition', 2, 'float'),
                              (b'vTexCoords0', 2, 'float'),
                          )
                  
                          self.vsize = sum(attr[1] for attr in self.vfmt)
                          self.texture, self.uvmap = load_atlas()
                  
                      def on_touch_down(self, touch):
                          for w in self.particles:
                              if w.collide_point(*touch.pos):
                                  w.reset() #Not Working
                          return super(GameScreen, self).on_touch_down(touch) 
                  
                      def on_touch_move(self, touch):
                          for w in self.particles:
                              if w.collide_point(*touch.pos):
                                  w.reset() #Not Working
                          return super(GameScreen, self).on_touch_move(touch) 
                  
                      def make_particles(self, Ap, num):
                          count = len(self.particles)
                          uv = self.uvmap[Ap.tex_name]
                  
                          for i in range(count, count + num):
                              j = 4 * i
                              self.indices.extend((
                                  j, j + 1, j + 2, j + 2, j + 3, j))
                  
                              self.vertices.extend((
                                  0, 0, 1, -uv.su, -uv.sv, uv.u0, uv.v1,
                                  0, 0, 1,  uv.su, -uv.sv, uv.u1, uv.v1,
                                  0, 0, 1,  uv.su,  uv.sv, uv.u1, uv.v0,
                                  0, 0, 1, -uv.su,  uv.sv, uv.u0, uv.v0,
                              ))
                  
                              p = Ap(self, i)
                              self.particles.append(p)
                  
                      def update_glsl(self, nap):
                          for p in self.particles:
                              p.advance(nap)
                              p.update()
                  
                          self.canvas.clear()
                  
                          with self.canvas:
                              Mesh(fmt=self.vfmt, mode='triangles',
                                   indices=self.indices, vertices=self.vertices,
                                   texture=self.texture)
                  
                  class Ufo(Particle):
                      plane = 2.0
                      tex_name = 'Elien' 
                      texture_size = 129
                      right = top = 129
                  
                      def reset(self, created=False):
                          self.plane = random.uniform(2.0, 2.8)
                          self.x = random.randint(15, self.parent.right-15)
                          self.y = self.parent.top+random.randint(100, 2500)
                          self.size = random.uniform(0.5, 1.0) #every particle must have a random size
                          self.top = self.size * self.texture_size 
                          self.right = self.size * self.texture_size 
                  
                      def collide_point(self, x, y):
                          '''Check if a point (x, y) is inside the Ufo's axis aligned bounding box.'''
                          with open('TouchFeedback.txt', 'wb') as c:
                              c.write(str(x)+', '+str(y)) 
                  
                          return self.x <= x <= self.right and self.y <= y <= self.top
                  
                      def advance(self, nap):
                          self.y -= 100 * self.plane * nap
                          if self.y < 0:
                              self.reset()
                  
                  class Game(GameScreen):
                      def initialize(self):
                          self.make_particles(Ufo, 20)
                  
                      def update_glsl(self, nap):
                          GameScreen.update_glsl(self, nap)
                  
                  class GameApp(App):
                      def build(self):
                          EventLoop.ensure_window()
                          return Game()
                  
                      def on_start(self):
                          self.root.initialize()
                          Clock.schedule_interval(self.root.update_glsl, 60 ** -1)
                  
                  if __name__ == '__main__':
                      Window.clearcolor = get_color_from_hex('111110')
                      GameApp().run()
                  

                  推荐答案

                  我认为你没有计算/更新 Ufo 的 topright 属性 对象.此外,由于您的 GL 代码将 (x,y) 视为您的圆心,但 Kivy 认为 (x,y) 要成为对象的左下角,您需要牢记这一点.为了正确计算 collide_point(),我在您的 Ufo 中添加了 leftbottom 属性,并使用这些属性来计算碰撞.以下是包含这些更改的代码的更新版本:

                  I think you are not calculating/updating your top and right properties of your Ufo objects. Also, since your GL code considers (x,y) to be the center of your circle, but Kivy considers (x,y) to be the lower left corner of an object, you need to keep that in mind. In order to correctly calculate collide_point(), I have added left and bottom properties to your Ufo, and use those properties to calculate collisions. Here is an updated version of your code with those changes:

                  from __future__ import division
                  import kivy
                  from kivy.config import Config
                  from kivy.graphics.context_instructions import Color
                  from kivy.graphics.vertex_instructions import Rectangle
                  from kivy.lang import Builder
                  
                  Config.set('modules', 'monitor', '')
                  
                  
                  from collections import namedtuple
                  import json
                  import math
                  import random
                  from kivy import platform
                  from kivy.app import App
                  from kivy.base import EventLoop
                  from kivy.clock import Clock
                  from kivy.core.image import Image
                  from kivy.core.window import Window
                  from kivy.event import EventDispatcher
                  from kivy.graphics import Mesh
                  from kivy.graphics.instructions import RenderContext
                  from kivy.properties import NumericProperty
                  from kivy.uix.widget import Widget
                  from kivy.utils import get_color_from_hex
                  import base64
                  
                  UVMapping = namedtuple('UVMapping', 'u0 v0 u1 v1 su sv')
                  
                  GLSL = """
                  ---vertex
                  $HEADER$
                  
                  attribute vec2  vCenter;
                  attribute float vScale;
                  
                  void main(void)
                  {
                      tex_coord0 = vTexCoords0;
                      mat4 move_mat = mat4
                          (1.0, 0.0, 0.0, vCenter.x,
                           0.0, 1.0, 0.0, vCenter.y,
                           0.0, 0.0, 1.0, 0.0,
                           0.0, 0.0, 0.0, 1.0);
                      vec4 pos = vec4(vPosition.xy * vScale, 0.0, 1.0)
                          * move_mat;
                      gl_Position = projection_mat * modelview_mat * pos;
                  }
                  
                  ---fragment
                  $HEADER$
                  
                  void main(void)
                  {
                      gl_FragColor = texture2D(texture0, tex_coord0);
                  }
                  
                  """
                  
                  with open("game.glsl", "wb")  as glslc:
                      glslc.write(GLSL.encode())
                  
                  def load_atlas():
                      atlas = json.loads('''{"game-0.png": {"Elien": [2, 26, 100, 100]}}''')
                  
                      tex_name, mapping = atlas.popitem()
                      data = '''iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAYAAADDPmHLAAACJklEQVR4nO3dy1ICQRAF0YLw/39ZVxMBGCjEMF23JvOsXPgounMaN61VQrtsH3x3TqFfLv9/ykdcq9z8RKv25Lro5yiUAcAZAJwBwBkAnAHAGQCcAcAZAJwBwBkAnAHAGQCcAcAZAJwBwBkAnAHAGQCcAcAZAJwBwBkAnAHAfXUPsNM79ydWXbYZZVoAey7MPH6tQdScAI64KbV9T3QI6QGsuCKHDiH5l8DVd1aRd2QTT4DOjcCdBmknQMpTmDLH4ZICSFv0tHkOkRJA6mKnzvUxCQGkL3L6fLskBKBG3QFMebqmzPm2zgCmLeq0eV/SfQKoWVcAU5+mqXM/5QkA1xHA9Kdo+vx3PAHgDADOAOBWB3CW98+zvA5PADoDgDMAOAOAMwA4A4AzADgDgDMAuNUBnOXCxVlehycAnQHAGQBcRwDT3z+nz3/HEwCuK4CpT9HUuZ/yBIDrDGDa0zRt3pd0nwBTFnXKnG/rDkDNEgJIf7rS59slIYCq3EVOnetjUgKoylvstHkOkRRAVc6ip8xxuMS/E7gtfsflC8zGb9JOgFurNwO3+VWZJ8CtFacBcuM36QFsjggBvfGbKQFsHjfNfxix07QAHrmpOyX/EqgFDADOAOAMAM4A4AwAzgDgDADOAOAMAM4A4AwAzgDgDADOAOAMAM4A4AwAzgDgDADOAOAMAM4A4AwA7lrl7YpE7okkSZIkSZIkSZIkSZIkSZIkSZL+9AMvSSThyPfOhQAAAABJRU5ErkJggg=='''
                      with open(tex_name, "wb")  as co:
                          co.write(base64.b64decode(data))
                      tex = Image(tex_name).texture
                      tex_width, tex_height = tex.size
                  
                      uvmap = {}
                      for name, val in mapping.items():
                          x0, y0, w, h = val
                          x1, y1 = x0 + w, y0 + h
                          uvmap[name] = UVMapping(
                              x0 / tex_width, 1 - y1 / tex_height,
                              x1 / tex_width, 1 - y0 / tex_height,
                              0.5 * w, 0.5 * h)
                  
                      return tex, uvmap
                  
                  
                  class Particle(EventDispatcher):
                      # x = 0
                      # y = 0
                      x = NumericProperty(0)
                      y = NumericProperty(0)
                      size = 1
                  
                      def __init__(self, parent, i):
                          super(Particle, self).__init__()
                          self.parent = parent
                          self.vsize = parent.vsize
                          self.base_i = 4 * i * self.vsize
                          self.reset(created=True)
                  
                      def update(self):
                          for i in range(self.base_i,
                                         self.base_i + 4 * self.vsize,
                                         self.vsize):
                              self.parent.vertices[i:i + 3] = (
                                  self.x, self.y, self.size)
                  
                      def reset(self, created=False):
                          raise NotImplementedError()
                  
                      def advance(self, nap):
                          raise NotImplementedError()
                  
                  
                  class GameScreen(Widget):
                      indices = []
                      vertices = []
                      particles = []
                  
                      def __init__(self, **kwargs):
                          Widget.__init__(self, **kwargs)
                          self.canvas = RenderContext(use_parent_projection=True)
                          self.canvas.shader.source = "game.glsl"
                  
                          self.vfmt = (
                              (b'vCenter', 2, 'float'),
                              (b'vScale', 1, 'float'),
                              (b'vPosition', 2, 'float'),
                              (b'vTexCoords0', 2, 'float'),
                          )
                  
                          self.vsize = sum(attr[1] for attr in self.vfmt)
                          self.texture, self.uvmap = load_atlas()
                  
                      def on_touch_down(self, touch):
                          for w in self.particles:
                              if w.collide_point(*touch.pos):
                                  w.reset() #Not Working
                          return super(GameScreen, self).on_touch_down(touch)
                  
                      def on_touch_move(self, touch):
                          for w in self.particles:
                              if w.collide_point(*touch.pos):
                                  w.reset() #Not Working
                          return super(GameScreen, self).on_touch_move(touch)
                  
                      def make_particles(self, Ap, num):
                          count = len(self.particles)
                          uv = self.uvmap[Ap.tex_name]
                  
                          for i in range(count, count + num):
                              j = 4 * i
                              self.indices.extend((
                                  j, j + 1, j + 2, j + 2, j + 3, j))
                  
                              self.vertices.extend((
                                  0, 0, 1, -uv.su, -uv.sv, uv.u0, uv.v1,
                                  0, 0, 1,  uv.su, -uv.sv, uv.u1, uv.v1,
                                  0, 0, 1,  uv.su,  uv.sv, uv.u1, uv.v0,
                                  0, 0, 1, -uv.su,  uv.sv, uv.u0, uv.v0,
                              ))
                  
                              p = Ap(self, i)
                              self.particles.append(p)
                  
                      def update_glsl(self, nap):
                          for p in self.particles:
                              p.advance(nap)
                              p.update()
                  
                          self.canvas.clear()
                          self.canvas.before.clear()  # temporary
                  
                          with self.canvas.before:  # temporary code block
                              for p in self.particles:
                                  Rectangle(pos=(p.left, p.bottom), size=(p.size*p.texture_size, p.size*p.texture_size))
                  
                          with self.canvas:
                              Mesh(fmt=self.vfmt, mode='triangles',
                                   indices=self.indices, vertices=self.vertices,
                                   texture=self.texture)
                  
                  
                  class Ufo(Particle):
                      plane = 2.0
                      tex_name = 'Elien'
                      texture_size = 129
                      right = NumericProperty(129)
                      top = NumericProperty(129)
                      left = NumericProperty(0)
                      bottom = NumericProperty(0)
                  
                      def reset(self, created=False):
                          self.plane = random.uniform(2.0, 2.8)
                          self.size = random.uniform(0.5, 1.0) #every particle must have a random size
                          self.x = random.randint(15, self.parent.right-15)
                          self.y = self.parent.top+random.randint(100, 2500)
                  
                      def collide_point(self, x, y):
                          '''Check if a point (x, y) is inside the Ufo's axis aligned bounding box.'''
                          return self.left <= x <= self.right and self.bottom <= y <= self.top
                  
                      def advance(self, nap):
                          self.y -= 100 * self.plane * nap
                          if self.y < 0:
                              self.reset()
                  
                      def on_x(self, instance, new_x):
                          self.right = new_x + self.size * self.texture_size / 2.0
                          self.left = new_x - self.size * self.texture_size / 2.0
                  
                      def on_y(self, instance, new_y):
                          self.top = new_y + self.size * self.texture_size / 2.0
                          self.bottom = new_y - self.size * self.texture_size / 2.0
                  
                  class Game(GameScreen):
                      def initialize(self):
                          self.make_particles(Ufo, 20)
                  
                      def update_glsl(self, nap):
                          GameScreen.update_glsl(self, nap)
                  
                  class GameApp(App):
                      def build(self):
                          EventLoop.ensure_window()
                          return Game()
                  
                      def on_start(self):
                          self.root.initialize()
                          Clock.schedule_interval(self.root.update_glsl, 60 ** -1)
                  
                  if __name__ == '__main__':
                      Window.clearcolor = get_color_from_hex('111110')
                      GameApp().run()
                  

                  我还添加了使用 canvas.before 绘制 Ufo 边界框.这只是为了可视化每个 Ufoclickable 区域,并且可以轻松移除.

                  I have also adding drawing the Ufo bounding box using canvas.before. This is just to visualize the clickable area for each Ufo, and can be easily removed.

                  这篇关于Kivy 自定义着色器触摸事件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持跟版网!

                  <legend id='XfQhT'><style id='XfQhT'><dir id='XfQhT'><q id='XfQhT'></q></dir></style></legend>

                    <tfoot id='XfQhT'></tfoot>

                    <small id='XfQhT'></small><noframes id='XfQhT'>

                        <bdo id='XfQhT'></bdo><ul id='XfQhT'></ul>
                        • <i id='XfQhT'><tr id='XfQhT'><dt id='XfQhT'><q id='XfQhT'><span id='XfQhT'><b id='XfQhT'><form id='XfQhT'><ins id='XfQhT'></ins><ul id='XfQhT'></ul><sub id='XfQhT'></sub></form><legend id='XfQhT'></legend><bdo id='XfQhT'><pre id='XfQhT'><center id='XfQhT'></center></pre></bdo></b><th id='XfQhT'></th></span></q></dt></tr></i><div id='XfQhT'><tfoot id='XfQhT'></tfoot><dl id='XfQhT'><fieldset id='XfQhT'></fieldset></dl></div>
                            <tbody id='XfQhT'></tbody>