我正在尝试为我的游戏制作用户界面,并且有一些用户界面的曲线。现在我可以检测两个表面之间的碰撞。我可以通过两个精灵之间的像素检测,但似乎像素的鼠标检测暗指我。基本上我想检测鼠标何时在UI上,然后在获取UI时忽略下面的所有内容。
这是我到目前为止的照片。如果您注意到粉红色正方形,则鼠标位于GUI上方,而黄色选择器框位于图块上方。黄色选择器是瓷砖上方的框架。
我正在使用带有openGL的pygame,但此时我正在寻找任何解决方案。我可以很容易地适应,因为我不是编程新手,而是非常寻找任何解决方案。 此外,我会发布代码,但要发布很多代码,所以如果需要特定的东西,请告诉我。
需要注意的一点是,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 Class
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
答案 0 :(得分:1)
两个可能的答案:
1)静态创建一个与屏幕一样大的True或False的2D数组 - 如果单击此处则为True将单击UI,如果单击此处则为False将不会单击UI。测试此阵列中位置的点击次数。
2)使用“绘画和检查”算法(不记得真实姓名)。你知道当你绘制到屏幕时绘制背景,然后是背景对象,然后是前景对象吗?你可以使用类似的技巧来检测你点击的对象 - 用一种纯色绘制背景,用另一种纯色绘制每个对象,用另一种纯色绘制每个UI元素等等......只要每种纯色都是unique,您可以在此缓冲区中测试光标下的像素,并使用它来确定鼠标可见和点击的内容。
答案 1 :(得分:1)
您可以创建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的可见部分上。
答案 2 :(得分:1)
好吧我认为这是最好的选择而不是其他一些选择。如果这有效,将使每个人都保持最新状态。
全局点击变量,用于在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