[英]Python pygame Detect if mouse is over non transparent part of surface
I am trying to make a UI for my game and there are some curves to the UI. 我正在尝试为我的游戏制作一个UI,并且UI有一些曲线。 Now I can detect collision between two surfaces.
现在我可以检测两个表面之间的碰撞。 I can detect by pixel between two sprites, but it seems mouse detection by pixel is alluding me.
我可以通过两个精灵之间的像素检测,但似乎像素的鼠标检测暗指我。 Basically I want to detect when the mouse is over the UI and then ignore everything below that while getting the UI.
基本上我想检测鼠标何时在UI上,然后在获取UI时忽略下面的所有内容。
This is a picture of what I have so far. 这是我到目前为止所拥有的图片。 If you notice the pink square the mouse is over the GUI while the yellow selector box is over a tile.
如果您注意到粉红色正方形,则鼠标位于GUI上方,而黄色选择器框位于图块上方。 The yellow selector is a box frame over a tile.
黄色选择器是瓷砖上方的框架。
I am using pygame with openGL but at this point I am looking for ANY solution to this. 我正在使用pygame和openGL,但此时我正在寻找任何解决方案。 I can adapt pretty easily as I am not new to programming and pretty much looking for any solution.
我可以很容易地适应,因为我不是编程新手,而是非常寻找任何解决方案。 Also I would post the code but to much code to post so if thing specific is needed let me know.
此外,我会发布代码,但要发布很多代码,所以如果需要特定的东西让我知道。
One thing to note is that the GUI is flexable in that the upper left area will slide in and out. 需要注意的一点是,GUI是灵活的,左上区域将滑入和滑出。 Also the white is just placeholder so final colors are not used and would be difficult to check.
此外白色只是占位符,因此不使用最终颜色,并且很难检查。 Is it possible to get the surface elements under the mouse when clicked by z order?
当按z顺序点击时,是否可以在鼠标下面获取表面元素?
Texture 质地
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 Class 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
Two possible answers: 两个可能的答案:
1) Statically create a 2D array of True or False that is as big as the screen - True if clicking here would click on the UI, False if clicking here would not click on the UI. 1)静态创建一个与屏幕一样大的真或假的2D数组 - 如果单击此处则为True将单击UI,如果单击此处则为False将不会单击UI。 Test clicks against the position in this array.
测试此阵列中位置的点击次数。
2) Use the 'paint and check' algorithm (don't recall the real name). 2)使用“绘制和检查”算法(不记得真实姓名)。 You know how when you draw to the screen you draw the background, then background objects, then foreground objects?
你知道当你绘制到屏幕时绘制背景,然后是背景对象,然后是前景对象吗? You can use a similar trick to detect what object you have clicked on - draw the background in one solid colour, each object in another solid colour, each UI element in another solid colour, etc... and as long as each solid colour is unique, you can test what colour pixel is under the cursor in this buffer and use it to determine what was visible and clicked on by the mouse.
你可以使用类似的技巧来检测你点击的对象 - 用一种纯色绘制背景,用另一种纯色绘制每个对象,用另一种纯色绘制每个UI元素等等......只要每种纯色都是unique,您可以在此缓冲区中测试光标下的像素,并使用它来确定鼠标可见和点击的内容。
You could create a mask of the UI (this would be easiest if the UI is contained in one surface which is then applied to the screen surface), and set the threshold of the mask to the appropriate value so that your transparent pixels are set to 0
in the mask. 您可以创建UI的掩码(如果UI包含在一个表面然后应用于屏幕表面,这将是最简单的),并将掩码的阈值设置为适当的值,以便将透明像素设置为掩码中为
0
。
http://www.pygame.org/docs/ref/mask.html#pygame.mask.from_surface http://www.pygame.org/docs/ref/mask.html#pygame.mask.from_surface
With the mask object's get_at((x,y))
function you can test if a specific pixel of the mask is set (a non-zero value is returned if the pixel is set). 使用mask对象的
get_at((x,y))
函数,您可以测试是否设置了掩码的特定像素(如果设置了像素,则返回非零值)。
http://www.pygame.org/docs/ref/mask.html#pygame.mask.Mask.get_at http://www.pygame.org/docs/ref/mask.html#pygame.mask.Mask.get_at
If you pass in the mouse's position, you can verify that it is over a visible part of the UI if you receive a non-zero value. 如果传入鼠标的位置,如果收到非零值,则可以验证它是否在UI的可见部分上。
Okay I am thinking of this as the best option rather then some of the alternatives. 好吧,我认为这是最好的选择,而不是其他一些选择。 Will keep everyone up to date if this works or not.
如果这是否有效,将使每个人都保持最新状态。
global click variable to store data in a dict Objects have layer variable ranging from 1 to ? 全局点击变量在dict中存储数据对象有层变量,范围从1到? from lowest to greatest layer(similar to html zIndex)
从最低层到最高层(类似于html zIndex)
Layer organization currently which can be modified. 当前可以修改的层组织。
zOrder Layers zOrder图层
Loop 环
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 getCordInImage
def getCordInImage(self, x, y, t):
return [x - t.x, y - t.y]
getAlphaOfPixel 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 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 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.