簡體   English   中英

Python pygame檢測鼠標是否在表面的非透明部分上

[英]Python pygame Detect if mouse is over non transparent part of surface

我正在嘗試為我的游戲制作一個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

pygame的

兩個可能的答案:

1)靜態創建一個與屏幕一樣大的真或假的2D數組 - 如果單擊此處則為True將單擊UI,如果單擊此處則為False將不會單擊UI。 測試此陣列中位置的點擊次數。

2)使用“繪制和檢查”算法(不記得真實姓名)。 你知道當你繪制到屏幕時繪制背景,然后是背景對象,然后是前景對象嗎? 你可以使用類似的技巧來檢測你點擊的對象 - 用一種純色繪制背景,用另一種純色繪制每個對象,用另一種純色繪制每個UI元素等等......只要每種純色都是unique,您可以在此緩沖區中測試光標下的像素,並使用它來確定鼠標可見和點擊的內容。

您可以創建UI的掩碼(如果UI包含在一個表面然后應用於屏幕表面,這將是最簡單的),並將掩碼的閾值設置為適當的值,以便將透明像素設置為掩碼中為0

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

使用mask對象的get_at((x,y))函數,您可以測試是否設置了掩碼的特定像素(如果設置了像素,則返回非零值)。

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

如果傳入鼠標的位置,如果收到非零值,則可以驗證它是否在UI的可見部分上。

好吧,我認為這是最好的選擇,而不是其他一些選擇。 如果這是否有效,將使每個人都保持最新狀態。

全局點擊變量在dict中存儲數據對象有層變量,范圍從1到? 從最低層到最高層(類似於html zIndex)

  1. 主循環
    1. 重置全局點擊變量
    2. 點擊事件獲取位置
  2. 循環遍歷可點擊的對象以獲取鼠標下的所有內容
    1. 循環鼠標下的所有內容以獲得最高層
    2. 返回全局click var
  3. 在對象中運行單擊代碼。

當前可以修改的層組織。

zOrder圖層

  1. 背景
  2. 瓷磚
  3. 平鋪選擇器
  4. 面板
  5. 主菜單
  6. GUI按鈕

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

getCordInImage

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

暫無
暫無

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

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