1

我正在尝试为我的游戏制作 UI,并且 UI 有一些曲线。现在我可以检测到两个表面之间的碰撞。我可以在两个精灵之间按像素检测,但似乎按像素检测鼠标是在暗示我。基本上我想检测鼠标何时在 UI 上,然后在获取 UI 时忽略下面的所有内容。

这是我到目前为止所拥有的照片。如果您注意到粉红色方块,则鼠标位于 GUI 上方,而黄色选择框位于图块上方。黄色选择器是图块上的框框。

我正在将 pygame 与 openGL 一起使用,但此时我正在寻找任何解决方案。我可以很容易地适应,因为我对编程并不陌生并且几乎在寻找任何解决方案。另外我会发布代码,但要发布很多代码,所以如果需要特定的东西,请告诉我。

需要注意的一点是,GUI 是灵活的,因为左上角区域可以滑入和滑出。此外,白色只是占位符,因此不使用最终颜色并且难以检查。按z顺序单击时是否可以获得鼠标下的表面元素?

质地

import pygame
from OpenGL.GL import *
from OpenGL.GLU import *

class Texture(object):
    image = None
    rect = None
    src = ''
    x = 0
    y = 0
    '''
    zOrder Layers
    0  - background
    1  - 
    2  - 
    3  - Tile Selector
    s  - Tiles
    5  - 
    6  - 
    7  - Panels
    8  - Main Menu
    9  - GUI Buttons
    10 - 

    '''

    def __init__(self, src):
        self.src = src
        self.image = pygame.image.load(src)
        self.image.set_colorkey(pygame.Color(255,0,255,0))
        self.rect = self.image.get_rect()
        texdata = pygame.image.tostring(self.image,"RGBA",0)
        # create an object textures
        self.texid = glGenTextures(1)

        # bind object textures 
        glBindTexture(GL_TEXTURE_2D, self.texid)

        # set texture filters
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)

        # Create texture image
        glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA,self.rect.w,self.rect.h,0,GL_RGBA,GL_UNSIGNED_BYTE,texdata)


        self.newList = glGenLists(2)
        glNewList(self.newList, GL_COMPILE)
        glBindTexture(GL_TEXTURE_2D, self.texid)
        glBegin(GL_QUADS)
        glTexCoord2f(0, 0); glVertex3f(0, 0 ,0)
        glTexCoord2f(0, 1); glVertex3f(0, self.rect.h, 0)
        glTexCoord2f(1, 1); glVertex3f(self.rect.w, self.rect.h, 0)
        glTexCoord2f(1, 0); glVertex3f(self.rect.w, 0, 0)

        glEnd()
        glEndList()

    def getImg(self):
        return self.image

    def getPos(self):
        rect = self.getImg().get_rect()
        pos = dict(x=self.x,y=self.y,w=rect[2],h=rect[3])
        return pos

    def draw(self,x,y,rotate=0):
        glLoadIdentity()
        self.x = int(x)
        self.y = int(y-self.rect.h+32)

        glTranslatef(x,y-self.rect.h+32,0)

        glPushAttrib(GL_TRANSFORM_BIT)
        glMatrixMode(GL_TEXTURE)
        glLoadIdentity()
        glRotatef(rotate,0,0,1)
        glPopAttrib()

        if glIsList(self.newList):
            glCallList(self.newList)

gui类

import hashlib, string, pygame
from classes.texture import Texture

'''
Created on Jun 2, 2013

@author: Joel
'''

class gui(object):
    INSTANCES = 0           # Count of instances of buildings
    ID = 0                  # Building ID
    TYPE = 0                # Building type
    NAME = ''               # name of Building
    DESCRIPTION = ''        # Description of building
    IMAGE = ''              # Image name of building 

    zOrder = 0
    clickable = True

    def __init__(self, Game, name = 'Building', description = '', image = 'panel'):
        self.INSTANCES += 1
        self.setName(name)
        self.setDescription(description)
        self.setImage(Game, Game.SETTING["DIR"]["IMAGES"] + Game.SETTING["THEME"] + '\\gui\\'+image+'.png')
        self.setType(name.lower())
        self.setZ(6)

    def getDescription(self):
        return self.DESCRIPTION

    def setDescription(self, description):
        self.DESCRIPTION = description

    def getID(self):
        return self.ID

    def setID(self, i):
        allchr = string.maketrans('','')
        nodigits = allchr.translate(allchr, string.digits)
        s = hashlib.sha224(i).hexdigest()
        s = s.translate(allchr, nodigits)
        self.ID = s[-16:]

    def getImage(self):
        return self.IMAGE

    def setImage(self, Game, i):
        self.IMAGE = Texture(Game.CWD + '\\' + i)

    def getName(self):
        return self.NAME

    def setName(self, name):
        self.NAME = name

    def getType(self):
        return self.TYPE

    def setType(self, t):
        self.TYPE = t

    def click(self, x, y):
        if pygame.mouse.get_pressed()[0] == 1:
            if x > self.x and x < (self.x + self.rect.w):
                if y > self.y and y < (self.y + self.rect.h):
                    print("Clicked: " + str(self.x) + ', ' + str(self.y) + ', ' + str(self.rect.w) + ', ' + str(self.rect.y))

    def getClickable(self):
        return self.clickable

    def setClickable(self, c):
        self.clickable = c

    def getZ(self):
        return self.zOrder

    def setZ(self, z):
        self.zOrder = z

游戏

4

3 回答 3

2

您可以创建 UI 的蒙版(如果 UI 包含在一个表面中,然后将其应用于屏幕表面,这将是最简单的),并将蒙版的阈值设置为适当的值,以便将透明像素设置为0在面具中。

http://www.pygame.org/docs/ref/mask.html#pygame.mask.from_surface

使用遮罩对象的get_at((x,y))函数,您可以测试是否设置了遮罩的特定像素(如果设置了像素,则返回非零值)。

http://www.pygame.org/docs/ref/mask.html#pygame.mask.Mask.get_at

如果传入鼠标的位置,如果收到非零值,则可以验证它是否位于 UI 的可见部分上。

于 2013-06-07T13:59:50.927 回答
1

好的,我认为这是最好的选择,而不是一些替代方案。无论这是否有效,都会让每个人都了解最新信息。

将数据存储在 dict 中的全局点击变量对象的层变量范围从 1 到 ? 从最低层到最高层(类似于 html zIndex)

  1. 主回路
    1. 重置全局点击变量
    2. 点击事件获取位置
  2. 遍历可点击对象以获取鼠标下的所有内容
    1. 遍历鼠标下的所有内容以获得最高层
    2. 返回全局点击变量
  3. 在对象中运行点击代码。

当前可以修改的图层组织。

zOrder 层

  1. 背景
  2. 瓷砖
  3. 瓷砖选择器
  4. 面板
  5. 主菜单
  6. 图形用户界面按钮

环形

for i in range(len(self.OBJECTS)):
    #img = Texture(see op)
    img = self.OBJECTS[i].IMAGE
    print(img)
    e = None
    if self.OBJECTS[i].zOrder == 4: # is isometric image
        # tx and ty are translated positions for screen2iso. See Below
        if ((self.tx >= 0 and self.tx < self.SETTING['MAP_WIDTH']) and (self.ty >= 0 and self.ty < self.SETTING['MAP_HEIGHT'])):
            # map_x and map_y are starting points for the map its self.
            ix, iy = self.screen2iso(
                (x - (self.map_x + (self.SETTING['TILE_WIDTH'] / 2))),
                (y - (self.map_y))
            )
            imgx, imgy = self.screen2iso(
                (img.x - (self.map_x + (self.SETTING['TILE_WIDTH'] / 2))),
                (img.y - (self.map_y))
            )
            if (imgx+2) == ix:
                if (imgy+1) == iy:
                    e = self.OBJECTS[i]
                else:
                    continue
            else:
                continue
    else: # Not an isometric image
        if x > img.x and x < (img.x + img.rect[2]):
            if y > img.y and y < (img.y + img.rect[3]):
                #is click inside of visual area of image?
                if self.getCordInImage(x, y, self.OBJECTS[i].IMAGE):
                    if self.getAlphaOfPixel(self.OBJECTS[i]) != 0:
                        e = self.OBJECTS[i]
                else:
                    continue
            else:
                continue
        else:
            continue
    if e != None:
        if self.CLICKED['zOrder'] < e.getZ():
            self.CLICKED['zOrder'] = e.getZ()
            self.CLICKED['e'] = e
        else:
            continue
    else:
        continue

获取CordInImage

def getCordInImage(self, x, y, t):
    return [x - t.x, y - t.y]

getAlphaOfPixel

def getAlphaOfPixel(self, t):
    mx,my = pygame.mouse.get_pos()
    x,y = self.getCordInImage(mx,my,t.IMAGE)
    #mask = pygame.mask.from_surface(t.IMAGE.image)
    return t.IMAGE.image.get_at([x,y])[3]

screen2iso

def screen2iso(self, x, y):
    x = x / 2
    xx = (y + x) / (self.SETTING['TILE_WIDTH'] / 2)
    yy = (y - x) / (self.SETTING['TILE_WIDTH'] / 2)
    return xx, yy

iso2screen

def iso2screen(self, x, y):
    xx = (x - y) * (self.SETTING['TILE_WIDTH'] / 2)
    yy = (x + y) * (self.SETTING['TILE_HEIGHT'] / 2)
    return xx, yy
于 2013-06-08T20:41:01.003 回答
1

两个可能的答案:

1) 静态创建一个与屏幕一样大的 True 或 False 二维数组 - 如果单击此处将单击 UI,则为 True,如果单击此处不会单击 UI,则为 False。针对此数组中的位置测试点击次数。

2)使用'paint and check'算法(不记得真实姓名)。您知道当您在屏幕上绘制时如何绘制背景,然后是背景对象,然后是前景对象吗?您可以使用类似的技巧来检测您单击的对象 - 以一种纯色绘制背景,以另一种纯色绘制每个对象,以另一种纯色绘制每个 UI 元素,等等......只要每种纯色都是独特的,您可以测试此缓冲区中光标下的颜色像素,并使用它来确定鼠标可见和单击的内容。

于 2013-06-07T05:15:46.110 回答