Отрегулируйте масштаб / размер частиц на основе разрешения устройства в Kivy Custom Shader - PullRequest
0 голосов
/ 30 января 2020

Я работаю над своей игрой Kivy, но пытаюсь понять, как моя игра будет выглядеть на нескольких устройствах, потому что я использую пользовательский шейдер Kivy. Одно из преимуществ использования Custom Shader заключается в том, что вам придется обрабатывать все, как position, size, rotation, touch events, texture coordinates et c ... самостоятельно. Вот небольшое объяснение моей проблемы.

Если я взял изображение, которое имеет значение 128x128, и отображает это изображение на устройстве с разрешением 240x480, изображение будет выглядеть примерно на 1/4 экрана устройства. Если я возьму то же изображение и выведу его на экран с разрешением 4000x4000, изображение будет выглядеть очень очень маленьким, потому что с увеличением разрешения размер этого изображения также должен быть увеличен. Я пробовал несколько способов масштабировать размер изображения, чтобы сохранить одинаковый воспринимаемый размер при любом разрешении, но все кажется неэффективным.

Вот как я масштабирую изображение

def ineffectiveScale(self):
    ws = Window.size
    part = 600
    whole = ws[1]
    dif = whole-part
    percent = 100 * float(dif)/float(whole)
    if ws[1] <= 1000:
        self.size = 0.7+(percent * 0.8) / 100.0
    elif ws[1] >= 1000 and ws[1] <= 2000:
        self.size = 1.1+(percent * 1.2) / 100.0
    elif ws[1] >= 2000 and ws[1] <= 3000:
        self.size = 1.6+(percent * 1.7) / 100.0
    elif ws[1] >= 3000 and ws[1] <= 4000:
        self.size = 2.0+(percent * 2.1) / 100.0
    elif ws[1] >= 4000:
        self.size = 2.5+(percent * 2.6) / 100.0

Как сделать все масштабируется соответствующим образом, если разрешение больше или меньше. Если вы можете взглянуть на то, как у меня это происходит сейчас, и, возможно, помочь мне понять, как это «должно» быть, чтобы извлечь из этого максимум пользы?

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", "w")  as wr:
    wr.write(GLSL)

def load_atlas():
    atlas = json.loads('''{"img.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 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 ScaleTest(Particle):
    tex_name = 'Elien' 
    texture_size = 129

    def reset(self, created=False):
        self.x = random.randint(15, self.parent.right-15)
        self.y = random.uniform(-100, -2500)
        self.size = 1 #FULL SIZE BEFORE RESIZED
        self.ineffectiveScale() #Comment this line to see the problem of large resolution screens

    def ineffectiveScale(self):
        ws = Window.size
        part = 600
        whole = ws[1]
        dif = whole-part
        percent = 100 * float(dif)/float(whole)
        if ws[1] <= 1000:
            self.size = 0.7+(percent * 0.8) / 100.0
        elif ws[1] >= 1000 and ws[1] <= 2000:
            self.size = 1.1+(percent * 1.2) / 100.0
        elif ws[1] >= 2000 and ws[1] <= 3000:
            self.size = 1.6+(percent * 1.7) / 100.0
        elif ws[1] >= 3000 and ws[1] <= 4000:
            self.size = 2.0+(percent * 2.1) / 100.0
        elif ws[1] >= 4000:
            self.size = 2.5+(percent * 2.6) / 100.0

    def advance(self, nap):
        self.y += 100 * 2 * nap
        if self.y > self.parent.top:
            self.reset()

class Game(GameScreen):
    def initialize(self):
        self.make_particles(ScaleTest, 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()
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...