【问题标题】:How to make a mouse event for clicks on a masked image [Pygame]如何在蒙版图像上单击鼠标事件 [Pygame]
【发布时间】:2014-07-29 01:11:55
【问题描述】:

所以我真的是编程新手,我正在开发一款有点像 Cookie Clicker 的游戏,但有一个转折点(采矿)。它是在 python/pygame 中制作的。无论如何,我有一块巨石的图像,每次点击它时,我都想在游戏中的库存中添加一块石头。

有人帮我在课堂上设置了 point_collide。我承认并说我不完全理解它是如何工作的,但它应该检测我的鼠标是否在我的岩石图像的不透明部分上。

我希望游戏仅在您点击我已移动到屏幕中间的巨石图像的不透明部分时才给您一块石头。

小问题:如何设置游戏以仅在蒙版图像上注册点击?

PS:我知道先学习编程基础知识会更好,但我只是通过直接投入到一个项目中学到了很多东西(它让我继续前进,而且比读书更有趣)。

代码链接:https://www.refheap.com/88634

代码:

import pygame, sys
from pygame.locals import *
from datetime import datetime

if (__name__ == "__main__"):

pygame.init()
pygame.font.init()
pygame.display.set_caption("Miner Click")

clock = pygame.time.Clock()
screen = pygame.display.set_mode((960,600))
width = 960
height = 600

GREEN = (0,255,0)
RED = (255,0,0)
BLUE = (0,0,255)
BLACK = (0,0,0)
WHITE = (255,255,255)
BROWN = (84,27,1) 
GREY = (198,198,198)

greenbg = pygame.image.load("greenbg.jpg").convert()
rockbutton = pygame.image.load("rockbutton.png").convert_alpha()
woodbutton = pygame.image.load("woodbutton.png").convert_alpha()

pygame.mouse.set_visible(True)
pick = pygame.image.load("pick.png").convert_alpha()
axe = pygame.image.load("axesmall.png").convert_alpha()

rockwidth = 544
rockheight = 274

clicks = 0
wood = 0

stonefont = pygame.font.SysFont("verdana", 29, True)
woodfont = pygame.font.SysFont("verdana", 29, True)
clicktext = stonefont.render('Rock: ' +str(clicks), 2, (GREY))
woodtext = woodfont.render('Wood: ' +str(wood), 2, (BROWN))
boxsize = clicktext.get_rect()
RocksX = 125
WoodX = 113

class Rock(pygame.sprite.Sprite):

def __init__(self, color = BLUE, width = 544, height = 274):
    super(Rock, self ).__init__()

    self.image = pygame.Surface((width, height))
    self.set_properties()
    self.image.fill(color)

def set_properties(self):
    self.rect = self.image.get_rect()
    self.origin_x = self.rect.centerx
    self.origin_y = self.rect.centery

def set_position(self, x, y):
    self.rect.x = 250
    self.rect.y = 230

def set_image(self, filename = None):
    if (filename != None):
        self.image = pygame.image.load(filename).convert_alpha()

def point_collide(self, point):
    x, y = point
    x -= self.rect.x
    y -= self.rect.y
    try:
        return self.mask.get_at((x,y))
    except IndexError:
        return False

#below is my clueless attempt at getting it to work
def checkForCursorPressed(x,y):
    if pygame.mouse.get_pressed() and pygame.mouse.get_pos() == (x,y):
        clicks+=1

coordfont = pygame.font.SysFont("verdana", 12, True)
rock_group = pygame.sprite.Group()
rock = Rock()
rock.set_image("rock.png")
rock.set_position(width/2, height/2)
rock_group.add(rock)

while True:
    clock.tick(60)
    screen.fill((255,255,255))
    screen.blit(greenbg, (0,0))
    x,y = pygame.mouse.get_pos()
    coords = x,y
    now = datetime.now()
    date = '%s/%s/%s' % (now.month, now.day, now.year)
    label = coordfont.render("Coordinates: "+str(coords), 1, (GREY))
    date = coordfont.render("Date: "+str(date), 1, (GREY))
    screen.blit(date, (650,10))
    screen.blit(label, (790, 10))
    screen.blit(rockbutton, (25,25))
    screen.blit(woodbutton, (25,100))
    clicktext = stonefont.render(' ' +str(clicks), 2, (GREY))
    woodtext = woodfont.render(' ' +str(wood), 2, (BROWN))
    screen.blit(clicktext, [RocksX,38])
    screen.blit(woodtext, [139,WoodX])
    rock_group.draw(screen)
    screen.blit(pick, (x-10,y-50))
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
           sys.exit()
        elif event.type == KEYDOWN and event.key == K_ESCAPE: 
           sys.exit()


        pygame.display.update()

   #in case i need the below again
   #if x>249 and x<(795) and y>210 and y<(484): 

【问题讨论】:

    标签: python python-3.x pygame


    【解决方案1】:

    点击将创建一个 MOUSEBUTTONDOWN 事件,因此您应该能够在事件处理循环中处理点击,例如:

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
           sys.exit()
        elif event.type == KEYDOWN and event.key == K_ESCAPE:
           sys.exit()
        elif event.type == MOUSEBUTTONDOWN:
            click_position = event.pos
            if rock.point_collide(click_position):
                print('Clicked within the rock')
                clicks += 1
                # Any other events that have to happen
                #   when the rock is clicked
    

    【讨论】:

    • 嘿,谢谢!这就是我一直在寻找的 :) 虽然我收到错误第 72 行“Rock”对象没有属性“掩码”
    【解决方案2】:

    我也不明白 point_collide() 是如何工作的,我得到一个 AttributeError: 'Rock' does not have attribute 'mask'。 所以我会使用另一种可能性来检测是否有人点击了图像的不透明部分,使用 colorkey。

    colorkey 定义了 blitting 时的透明颜色。就我而言,它是白色的:

    def set_image(self, filename = None):
        ...
        #sets colorkey to white, depends on the image
        self.image.set_colorkey((255,255,255))
    

    point_collide() 的新版本:

    def point_collide(self, point):
       x, y = point
       x -= self.rect.x
       y -= self.rect.y
       #detects if click hits the image
       if 0 <= x < self.image.get_width():
           if 0 <= y < self.image.get_height():
               #detects if color at clicking position != colorkey-color(transparent)
               if self.image.get_at((x,y))[0:3] != self.image.get_colorkey()[0:3]:
                   return True
       return False
    

    如何获取鼠标事件已经回答完毕。

    【讨论】:

    • 这看起来是个不错的选择,还没有测试过,所以我不知道它是否适合我。我确实找到了 AttributeError: 'Rock' does not have attribute 'mask' 的解决方案(在下面的回答中解释了它)无论如何感谢您的帮助,如果我遇到更多问题,我会尝试这种方法 :)
    【解决方案3】:

    好的,我搞定了 :)

    如果其他人尝试做类似的事情,我会在这里解释。

    将以下内容放入您的代码中(这解决了我遇到的“Rock has no attribute mask”错误)

    self.mask = pygame.mask.from_surface(self.image)
    

    这是我把它放在我的代码中的地方(在我的 set_image def 中)

    def set_image(self, filename = None):
        if (filename != None):
            self.image = pygame.image.load(filename).convert_alpha()
            self.mask = pygame.mask.from_surface(self.image)
    

    现在将这段代码与 Marius 结合起来,它就可以完美运行了!

    【讨论】:

      猜你喜欢
      • 2022-01-25
      • 2022-08-07
      • 2012-06-30
      • 1970-01-01
      • 2017-10-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多