[英]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
兩個可能的答案:
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)
當前可以修改的層組織。
zOrder圖層
環
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.