python - Pygame鼠标点击和矩形交集

标签 python pygame

我正在设计一款基于生存的游戏,但我无法让玩家从树上收集木材。

下面的函数检查我的鼠标是否被按下,如果玩家与任何树矩形碰撞,它们的木材数量就会增加一。我使用刻度来确保每九个刻度仅添加一根木头。

def check(self):
    global tick
    if pygame.mouse.get_pressed()[0]: 
        for tree in resources:
            tree_rect=tree.rect                                
            if self.rect.colliderect(tree_rect) and tick>=9:
                self.inventory['wood']+=1
                tick=0

但是,每当我单击时,有时会添加木头,有时则不会,无论我的玩家类别是否与任何树木发生碰撞。

我尝试使用pygame.sprite.spritecollide(),但结果是一样的。如有任何帮助,我们将不胜感激。

完整代码:

import pygame
from pygame.locals import * 
import sys
import math
import pygame.gfxdraw
import random

pygame.init()

black=(0,0,0)
white=(255,255,255)
forest=(34,139,34)
red=(255,0,0)
blue=(0,0,255)
green=(0,255,0)
light_green=(0,120,0)
dark_green=(0,90,0)
skin=(255,224,189)
yellow=(255,255,0)

wood_image=pygame.image.load('./assets/images/wood.png')
stone_image=pygame.image.load('./assets/images/stone.png')
player_image=pygame.image.load('./assets/images/player.png')

tick=0

def terminate():
    pygame.quit()
    sys.exit()

def drawTextcenter(text,font,screen,x,y,color):
    textobj=font.render(text,True,color)
    textrect=textobj.get_rect(center=(x,y))
    screen.blit(textobj,textrect)

def drawText(text, font, surface, x, y,color):
    textobj=font.render(text, 1, color)
    textrect=textobj.get_rect()
    textrect.topleft=(x, y)
    surface.blit(textobj, textrect)

class Button(object):
    global screen_width,screen_height,screen
    def __init__(self,x,y,width,height,text_color,background_color,text):
        self.rect=pygame.Rect(x,y,width,height)
        self.x=x
        self.y=y
        self.width=width
        self.height=height
        self.text=text
        self.text_color=text_color
        self.background_color=background_color
        self.angle=0

    def check(self):
        return self.rect.collidepoint(pygame.mouse.get_pos())

    def draw(self):
        pygame.draw.rect(screen,self.background_color,(self.rect),0)
        drawTextcenter(self.text,font,screen,self.x+self.width/2,self.y+self.height/2,self.text_color)  
        pygame.draw.rect(screen,self.text_color,self.rect,3) 

class Bar(object):
    def __init__(self,x,y,length,color):
        self.rect=pygame.Rect(x,y,length,17.5)
        self.image=pygame.draw.rect(screen,white,(self.rect),)
        self.x=x
        self.y=y
        self.width=100
        self.height=17.5
        self.color=color
        self.multiplier=length/100

    def draw(self,num): 
        rect=pygame.Rect(self.x,self.y,num*self.multiplier,self.height)
        pygame.draw.rect(screen,self.color,self.rect,3)
        pygame.draw.rect(screen,self.color,rect,0)

class Player(pygame.sprite.Sprite):
    def __init__(self,x,y):
        super(Player,self).__init__()
        self.image=player_image
        self.original_image=self.image
        self.rect=self.image.get_rect(center=(x,y))
        self.change_x=0
        self.change_y=0
        self.speed=7.5
        self.inventory={'wood':0}

    def changespeed(self,x,y):
        self.change_x+=x
        self.change_y+=y

    def update(self,rect):
        self.rotate(camera)
        self.rect.x+=self.change_x
        self.rect.y+=self.change_y
        rect = camera.apply(self)
        screen.blit(self.image,rect)

    def check(self):
        global tick
        if pygame.mouse.get_pressed()[0]: 
            for tree in resources:
                tree_rect=tree.rect                                
                if self.rect.colliderect(tree_rect) and tick>=9:
                    self.inventory['wood']+=1
                    tick=0

    def rotate(self,camera):
        mouse_x,mouse_y=pygame.mouse.get_pos()
        mouse_x-=camera.state.x
        mouse_y-=camera.state.y
        rel_x,rel_y= mouse_x - self.rect.centerx, mouse_y -self.rect.centery
        angle = -math.degrees(math.atan2(rel_y, rel_x))
        self.image = pygame.transform.rotozoom(self.original_image, angle,1)
        self.rect = self.image.get_rect(center=self.rect.center)

class Tree(pygame.sprite.Sprite):
    def __init__(self,x,y):
        super(Tree,self).__init__()
        self.rect=pygame.Rect(x,y,100,100)
        self.rect.x=x
        self.rect.y=y

    def update(self,rect):
        pygame.gfxdraw.filled_circle(screen,rect.x,rect.y,80,light_green)
        pygame.gfxdraw.aacircle(screen,rect.x,rect.y,80,light_green)

class Rock(pygame.sprite.Sprite):
    def __init__(self):
        pass

class Camera(object):
    def __init__(self,camera_func,width,height):
        self.camera_func=camera_func
        self.state=pygame.Rect(0,0,width,height)

    def apply(self,target):
        return target.rect.move(self.state.topleft)

    def update(self,target):
        self.state=self.camera_func(self.state,target.rect)

def complex_camera(camera, target_rect):
    l, t = target_rect.center
    _,_,w,h = camera
    l,t,_,_ = -l+screen_width/2, -t+screen_height/2, w, h

    l = min(0, l)                           
    l = max(-(camera.width-screen_width), l)
    t = max(-(camera.height-screen_height), t)
    t = min(0, t)                           

    return pygame.Rect(l, t, w, h)

clock=pygame.time.Clock()
font=pygame.font.SysFont(None,40)

screen_width=1440
screen_height=800
screen=pygame.display.set_mode([screen_width,screen_height])
pygame.display.set_caption('Survival')

total_level_width=screen_width*5
total_level_height=screen_height*5
camera = Camera(complex_camera, total_level_width, total_level_height)

player=Player(random.randint(100,7900),random.randint(100,5900))
friendlies=pygame.sprite.Group()
friendlies.add(player)

player_health_bar=Bar(125,15,200,green)
player_health=100
player_food_bar=Bar(437.5,15,200,red)
player_food=100
player_thirst_bar=Bar(750,15,200,blue)
player_thirst=100
player_energy_bar=Bar(1100,15,200,yellow)
player_energy=100

resources=pygame.sprite.Group()

wood=False
inventory={}

for i in range(1000):
    tree=Tree(random.randint(100,7900),random.randint(100,5900))
    resources.add(tree)

done1=False
while not done1:
    screen.fill(black)
    font=pygame.font.SysFont(None, 90)
    text_width,text_height=font.size('Survival')
    drawText('Survival', font, screen, (screen_width/2-text_width/2), (screen_height / 2-375),white)
    font=pygame.font.SysFont(None, 40)
    start_button=Button(screen_width/2-125,450,250,50,white,black,'Play')
    start_button.draw()
    back_button=Button(screen_width/2-125,725,250,50,white,black,'Back')
    pygame.display.flip()
    done2=False
    while not done2:
        for event in pygame.event.get():
            if event.type==QUIT:
                terminate()
            elif event.type==pygame.MOUSEBUTTONDOWN:
                if start_button.check()==True: 
                    done3=False
                    pause_back=False
                    while not done3:             
                        tick+=1
                        for event in pygame.event.get():
                            if event.type==pygame.QUIT:
                                terminate()
                            elif event.type==pygame.KEYDOWN:
                                if event.key==pygame.K_a:
                                    player.changespeed(-(player.speed), 0)
                                elif event.key==pygame.K_d:
                                    player.changespeed(player.speed, 0)
                                elif event.key==pygame.K_w:
                                    player.changespeed(0, -(player.speed))
                                elif event.key==pygame.K_s:
                                    player.changespeed(0, player.speed)
                                elif event.key==pygame.K_p:
                                    font=pygame.font.SysFont(None, 90)
                                    text_width,text_height=font.size('Paused')
                                    drawText('Paused', font, screen, (screen_width / 2-(text_width/2)), (screen_height / 2-375),white)
                                    resume_button=Button(screen_width/2-125,650,250,50,white,black,'Resume')
                                    resume_button.draw()
                                    back_button.draw()
                                    pygame.display.flip()
                                    back=False
                                    while not back:
                                        for event in pygame.event.get():
                                            if event.type==QUIT:
                                                terminate()
                                            elif event.type==pygame.MOUSEBUTTONDOWN:
                                                if resume_button.check()==True:
                                                    back=True
                                                elif back_button.check()==True:
                                                    done3=True
                                                    done2=True
                                                    pause_back=True
                                                    back=True

                            elif event.type == pygame.KEYUP:
                                if event.key == pygame.K_a:
                                    player.changespeed(player.speed, 0)
                                elif event.key == pygame.K_d:
                                    player.changespeed(-(player.speed), 0)
                                elif event.key == pygame.K_w:
                                    player.changespeed(0, player.speed)
                                elif event.key == pygame.K_s:
                                    player.changespeed(0, -(player.speed))   

                        camera.update(player)

                        if player.rect.x<0:
                            player.rect.x=0
                        if player.rect.right>total_level_width:
                            player.rect.right=total_level_width
                        if player.rect.y<0:
                            player.rect.y=0
                        if player.rect.bottom>total_level_height:
                            player.rect.bottom=total_level_height

                        screen.fill(dark_green)

                        player.update(camera)

                        for resource in resources:
                            resource.update(camera.apply(resource))

                        player_health_bar.draw(player_health)
                        #player_thirst_bar.draw(player_thirst)
                        #player_endergy_bar.draw(player_energy)
                        font=pygame.font.SysFont(None, 40)
                        drawText('Health:',font,screen,20,10,green)
                        #drawText('Food:',font,screen,350,10,red)
                        #drawText('Thirst:',font,screen,650,10,blue)
                        #drawText('Energy:', font, screen, 975, 10, yellow)
                        pygame.draw.rect(screen,forest,(50,675,100,100))
                        pygame.draw.rect(screen,forest,(175,675,100,100))
                        pygame.draw.rect(screen,forest,(300,675,100,100))

                        player.check()

                        for item in player.inventory:
                            if item=='wood' and player.inventory['wood']>0:
                                wood=True

                        if wood:
                            screen.blit(wood_image,(62.5,687.5))
                            drawTextcenter(str(player.inventory['wood']),font,screen,100,735,black)

                        pygame.display.flip()

                        clock.tick(100)

                        if pause_back==True:
                                break
                    if pause_back==True:
                        break
                    screen.fill(black)
                    font=pygame.font.SysFont(None, 90)
                    text_width,text_height=font.size("Game Over")
                    drawText('Game Over', font, screen, (screen_width/2-text_width/2), (screen_height / 2-200),white)
                    font=pygame.font.SysFont(None, 40)
                    retry_button=Button(screen_width/2-125,650,250,50,white,black,'Retry')
                    retry_button.draw()
                    back_button.draw()
                    pygame.display.flip()
                    back=False 
                    while not back:
                        for event in pygame.event.get():
                                if event.type==QUIT:
                                    terminate()
                                elif event.type==pygame.MOUSEBUTTONDOWN:
                                    if retry_button.check()==True:
                                        back=True
                                    if back_button.check()==True:
                                        back=True
                                        done2=True
                                        done3=True        
                elif back_button.check()==True: 
                    done2=True
                    done1=True

最佳答案

Tree.update方法中绘制rect,您就会发现问题所在。

pygame.draw.rect(screen, (120, 50, 0), rect)

您使用 rectxy(topleft)坐标作为中心圆的点,因此矩形将位于树的右下象限。

    =  =    
 =        =
=      ____=___
=     |    =   |
 =    |   =    |
    = |=       |
      |________|

改用centerxcentery坐标:

pygame.gfxdraw.filled_circle(screen, rect.centerx, rect.centery, 80, light_green)
pygame.gfxdraw.aacircle(screen, rect.centerx, rect.centery, 80, light_green)

关于python - Pygame鼠标点击和矩形交集,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51072884/

相关文章:

python - 如何在Pygame中截取屏幕的特定部分

python - python 中的嵌套列表和 for 循环程序给了我一个疯狂的结果

python - 报告用户 Django 错误报告

php - 如何从php执行python文件来更新mysql表?

python - 将带有列表的列的 pandas DF 写入文件,如何读回它?

python - 为什么这个文本打印函数在 pygame 中会产生延迟?

python - 在 python 中跳过 for 循环中的迭代?

text - 将字符串中的单个单词设为粗体

python - 为什么 pyinstaller 创建的 .exe 文件不起作用?

python - Pygame 类型错误 : __init__ takes exactly 4 arguments (1 given)