微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

Pygame 中的蒙版碰撞

如何解决Pygame 中的蒙版碰撞

我正在制作一个无尽的跑步类型游戏,玩家在尝试避开障碍物的同时驾驶宇宙飞船。我在船和障碍物之间使用掩码碰撞检测。玩家还可以激活应该摧毁其路径上的小行星的激光。我正在尝试为此使用相同的碰撞检测方法,但它不起作用。那可能是因为我有一个改变图像的激光动画。我该如何解决这个问题?

######################
#
# Pls help
#
# Written by: Theo
# Date: December 2020 - march 2021
#
# Version 1: an endless runner game where the player
# controls a ship traveling through space,dodging obstacles


import pygame
import math
import time
import random
import RiftObstacles



global ship
global rot_ship
global shipX
global moonMask

pygame.init()
FPS = 100
clock = pygame.time.Clock()
size = pygame.display.Info()
WIDTH = 1000
HEIGHT = 1000
pygame.display.set_caption('Parallax Nebula')
screen = pygame.display.set_mode((WIDTH,HEIGHT))


########## Rift Variables
ship = pygame.image.load("Images/Rift/Ship.PNG")
ship = pygame.transform.scale(ship,(85,125))
rot_ship = ship
shipX = 450
shipY = 700


A1 = pygame.image.load("Images/Rift/Asteroids/1.PNG")
A1 = pygame.transform.scale(A1,(100,100))
A1 = pygame.Surface.convert_alpha(A1)

A2 = pygame.image.load("Images/Rift/Asteroids/2.PNG")
A2 = pygame.transform.scale(A2,100))
A2 = pygame.Surface.convert_alpha(A2)

A3 = pygame.image.load("Images/Rift/Asteroids/3.PNG")
A3 = pygame.transform.scale(A3,100))
A3 = pygame.Surface.convert_alpha(A3)

A4 = pygame.image.load("Images/Rift/Asteroids/4.PNG")
A4 = pygame.transform.scale(A4,100))
A4 = pygame.Surface.convert_alpha(A4)

A5 = pygame.image.load("Images/Rift/Asteroids/5.PNG")
A5 = pygame.transform.scale(A5,100))
A5 = pygame.Surface.convert_alpha(A5)

A6 = pygame.image.load("Images/Rift/Asteroids/6.PNG")
A6 = pygame.transform.scale(A6,100))
A6 = pygame.Surface.convert_alpha(A6)

A7 = pygame.image.load("Images/Rift/Asteroids/7.PNG")
A7 = pygame.transform.scale(A7,100))
A7 = pygame.Surface.convert_alpha(A7)

A8 = pygame.image.load("Images/Rift/Asteroids/8.PNG")
A8 = pygame.transform.scale(A8,100))
A8 = pygame.Surface.convert_alpha(A8)

A9 = pygame.image.load("Images/Rift/Asteroids/9.PNG")
A9 = pygame.transform.scale(A9,100))
A9 = pygame.Surface.convert_alpha(A9)

A10 = pygame.image.load("Images/Rift/Asteroids/10.PNG")
A10 = pygame.transform.scale(A10,100))
A10 = pygame.Surface.convert_alpha(A10)

A11 = pygame.image.load("Images/Rift/Asteroids/11.PNG")
A11 = pygame.transform.scale(A11,100))
A11 = pygame.Surface.convert_alpha(A11)

A12 = pygame.image.load("Images/Rift/Asteroids/12.PNG")
A12 = pygame.transform.scale(A12,(60,100))
A12 = pygame.Surface.convert_alpha(A12)

F1 = pygame.image.load("Images/Rift/Fuel/1.PNG")
F1 = pygame.transform.scale(F1,(150,150))

F2 = pygame.image.load("Images/Rift/Fuel/2.PNG")
F2 = pygame.transform.scale(F2,150))

F3 = pygame.image.load("Images/Rift/Fuel/3.PNG")
F3 = pygame.transform.scale(F3,150))

F4 = pygame.image.load("Images/Rift/Fuel/4.PNG")
F4 = pygame.transform.scale(F4,150))

F5 = pygame.image.load("Images/Rift/Fuel/5.PNG")
F5 = pygame.transform.scale(F5,150))

F6 = pygame.image.load("Images/Rift/Fuel/6.PNG")
F6 = pygame.transform.scale(F6,150))

comet = pygame.image.load("Images/Rift/Comet.PNG")
comet = pygame.transform.scale(comet,(80,250))


moon = pygame.image.load("Images/Rift/Moon - WIP.PNG")
moon = pygame.transform.smoothscale(moon,(1200,1200))
moon = pygame.Surface.convert_alpha(moon)
moonMask = pygame.mask.from_surface(moon)

angle = 0
lasers = []
stretch = []
for i in range(60):
    laserImg = pygame.image.load("Images/Rift/Laser/"+str(i+1)+".PNG")
    laserImg = pygame.Surface.convert_alpha(laserImg)
    stretchTemp = int(15*math.cos(math.pi*i/30))
    stretch.append(50 - stretchTemp)
    laserImg = pygame.transform.scale(laserImg,(50-stretchTemp,1050))
    lasers.append(laserImg)



angle = 0

RiftBG = pygame.image.load("Images/Rift/Background/BG.PNG")
RiftBG = pygame.Surface.convert_alpha(RiftBG)
RiftBG = pygame.transform.smoothscale(RiftBG,(1000,1000))





#Transparent comet warning
def warning(surface,color,rect):
    shape_surf = pygame.Surface(pygame.Rect(rect).size,pygame.SRCALPHA)
    pygame.draw.rect(shape_surf,shape_surf.get_rect())
    surface.blit(shape_surf,rect)
    
#Moving the ship 
def moveShip(shipX,X,angle):
    if (X >= 0 and shipX > 100) or (X <= 0 and shipX < 800):
        shipX -= X    
    else:
        shipX -= X
        angle -= (X*speed)/11
        
                
    rot_ship = pygame.transform.rotate(ship,angle)
    return(shipX,rot_ship,angle)

#Pulling ship towards the middle of the screen
def riftpull(shipX,angle,rot_ship):
    if shipX < 440:
        if angle > -25:
            angle -= 0.1 * speed
        else:
            angle += 0.1 * speed
        shipX,angle = moveShip(shipX,(angle/2.5),angle)
                
    elif shipX > 460:
        if angle < 25:
            angle += 0.1 * speed
        else:
            angle -= 0.1 * speed
        shipX,angle)
    
    elif 440 < shipX < 460:
        if abs(angle) > 1:
            angle = angle/1.2
        else:
            angle = 0
        shipX,angle)
    return shipX,rot_ship  


#Ship Travel through the rift    
def rift():
    global ship
    global rot_ship
    global shipX
    global speed
    global moon
    global moonOutline
    global moonMask
    global distance
    speed = 5
    angle = 0
    laserOn = 2*FPS
    laserAnimation = int(FPS/30)
    laserFrame = 0
    distanceTimer = 0
    delay = FPS
    laserMode = False
    crash = False
    key = pygame.key.get_pressed()
    wallX = 470
    wallY = [-1000,-3000]
    
    
    rocks = [A1,A2,A3,A4,A5,A6,A7,A8,A9,A10,A11,A12]
    fuel = [F1,F2,F3,F4,F5,F6]
    numRock,rockX,rockY,numComet,cometX,cometY,numMoon,moonX,moonY,moonScale,numFuel,fuelX,fuelY = RiftObstacles.path()
    rockType = []
    rockAngle = []  
    rockAngle2 = []
    rockRot = []
    for i in range(numRock):
        rockType.append(random.choice(rocks))
        rockAngle.append(random.uniform(-0.2,0.2))
        rockAngle2.append(rockAngle[i])

    fuelType = []
    fuelAngle = []
    fuelAngle2 = []
    fuelRot = []
    for i in range(numFuel):
        fuelType.append(random.choice(fuel))
        fuelAngle.append(random.uniform(-0.2,0.2))
        fuelAngle2.append(fuelAngle[i])
        
    warningWidth = []
    for i in range(numComet):
        warningWidth.append(10)

    endRift = False
    while endRift == False:
        screen.blit(RiftBG,(0,0))
           
        #displaying obstacles       
        for i in range(numRock):
            rockRot.append(pygame.transform.rotate(rockType[i],rockAngle2[i]))
            screen.blit(rockRot[i],(rockX[i],rockY[i]))

        for i in range(numComet):
            screen.blit(comet,(cometX[i],cometY[i]))
            if -2000 < cometY[i] < HEIGHT:
                warningHEIGHT = HEIGHT - cometY[i]
                cometWarning = pygame.Rect(cometX[i]+40 - warningWidth[i]/2,cometY[i]+100,warningWidth[i],warningHEIGHT)
                if warningWidth[i] < 78:
                    warningWidth[i] += 1.5
                warning(screen,(250,200,3,127),(cometWarning))

        for i in range(numFuel):
            fuelRot.append(pygame.transform.rotate(fuelType[i],fuelAngle2[i]))
            screen.blit(fuelRot[i],(fuelX[i],fuelY[i]))
        

        if laserMode == True:
            laserOn -= 1
            if laserOn <= 0:
                laserMode = False

            rot_laser = pygame.transform.rotate(lasers[laserFrame],angle)
            laserAnimation -= 1
            if -1 < laserAnimation < 1:
                laserAnimation = FPS/30
                if laserFrame < 59:
                    laserFrame += 1
            laserRect = rot_laser.get_rect()
            if angle == 0:
                correction = 50*math.sin((angle*math.pi)/180)
                laserRect.midbottom = (shipX + 42 - correction,shipY+100)
                
            elif angle <= 1:
                correction = angle*9
                laserRect.midbottom = (shipX + 50 - correction,shipY+100)
            
            else:
                correction = angle*7
                laserRect.midbottom = (shipX + 30 - correction,shipY+100)
                
            screen.blit(rot_laser,laserRect)
                
        if laserMode == False:
            laserOn = 180
            laserFrame = 0
            
        for i in range(numMoon):
            moon = pygame.transform.smoothscale(moon,(int(100*moonScale[i]),int(100*moonScale[i])))
            screen.blit(moon,(moonX[i],moonY[i]))
            
    



        
        #Ship Movement                
        screen.blit(rot_ship,(int(shipX),shipY))
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                quit()
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_LEFT or event.key == pygame.K_a:
                    key = 'left'
                elif event.key == pygame.K_RIGHT or event.key == pygame.K_d:
                    key = 'right'

                #Activating the laser
                elif event.key == pygame.K_SPACE:
                    if laserMode == False:
                        laserMode = True
                    
                else:
                    key = 'up'
                    
            if event.type == pygame.KEYUP:
                key = 'up'

        if key == 'left':
            if angle < 35 and shipX > 50:
                angle += 0.2*speed
                
            shipX,angle)

        elif key == 'right':
            if angle > -35 and shipX < 850:
                angle -= 0.2*speed
                
            shipX,angle)
            
        elif key == 'up':
            shipX,rot_ship = riftpull(shipX,rot_ship)


        #Collision detection
        shipRect = pygame.Rect(shipX,shipY,85,125)
        shipMask = pygame.mask.from_surface(rot_ship)
        if laserMode == True:
            rot_laser = pygame.transform.rotate(lasers[laserFrame],angle)
            laserRect = rot_laser.get_rect()
            laserMask = pygame.mask.from_surface(rot_laser)
            
        remove = []
        for i in range(numRock):
            rockRect = pygame.Rect(rockX[i],rockY[i],100,100)
            if laserMode == True:
                if rockRect.colliderect(laserRect):
                    #print('laser')
                    #print('o')
                    rockMask = pygame.mask.from_surface(rockRot[i])
                    offset_x = laserRect.x - rockRect.x
                    offset_y = laserRect.y - rockRect.y
                    laserHit = rockMask.overlap(laserMask,(offset_x,offset_y))
                    if laserHit:
                        remove.append(i)


            
            if rockRect.colliderect(shipRect):
                rockMask = pygame.mask.from_surface(rockRot[i])
                offset_x = shipRect.x - rockRect.x
                offset_y = shipRect.y - rockRect.y
                crash = rockMask.overlap(shipMask,offset_y))
                
        for i in range(len(remove)):
                numRock -= 1
                rockX.pop(remove[i])
                rockY.pop(remove[i])
                rockType.pop(remove[i])
                rockAngle.pop(remove[i])
                rockAngle2.pop(remove[i])
                rockRot.pop(remove[i])
                
        remove = []                    
        for i in range(numComet):
            cometRect = pygame.Rect(cometX[i],cometY[i],80,250)
            if cometRect.colliderect(shipRect):
                cometMask = pygame.mask.from_surface(comet)
                offset_x = shipRect.x - cometRect.x
                offset_y = shipRect.y - cometRect.y
                crash = cometMask.overlap(shipMask,offset_y))

        remove = []        
        for i in range(numMoon):
            moonRect = pygame.Rect(moonX[i],moonY[i],int(100*moonScale[i]),int(100*moonScale[i]))
            if int(50*moonScale[i]+60)**2 >= ((shipX+40 - moonX[i]-int(50*moonScale[i]))**2 + (shipY+100 - moonY[i]-int(50*moonScale[i]))**2) and not crash:
                moonMask = pygame.mask.from_surface(moon)
                offset_x = shipRect.x - moonRect.x
                offset_y = shipRect.y - moonRect.y
                crash = moonMask.overlap(shipMask,offset_y))

        remove = []
        for i in range(numFuel):
            fuelRect = pygame.Rect(fuelX[i],fuelY[i],100)
            if fuelRect.colliderect(shipRect):
                fuelMask = pygame.mask.from_surface(fuelRot[i])
                offset_x = shipRect.x - fuelRect.x
                offset_y = shipRect.y - fuelRect.y
                fuelHit = fuelMask.overlap(shipMask,offset_y))
                if fuelHit:
                    remove.append(i)
                
        for i in range(len(remove)):
            numFuel -= 1
            fuelX.pop(remove[i])
            fuelY.pop(remove[i])
            fuelType.pop(remove[i])
            fuelAngle.pop(remove[i])
            fuelAngle2.pop(remove[i])
            fuelRot.pop(remove[i])
            
        remove = []           
        #Moves objects down screen
        rockRot = []
        fuelRot = []
        for i in range(numRock):
            rockY[i] += speed
            rockAngle2[i] += rockAngle[i]

        for i in range(numMoon):
            moonY[i] += speed
                
        for i in range(numComet):
            cometY[i] += speed * 5
            if cometY[i] > HEIGHT:
                 warningWidth[i] = 10

        for i in range(numFuel):
            fuelY[i] += speed
            fuelAngle2[i] += fuelAngle[i]


        
                
        #Choosing a new path      
        rockPassed = HEIGHT+1
        cometPassed = HEIGHT+1
        moonPassed = HEIGHT+1
        if len(rockY) != 0:
            rockPassed = rockY[-1]
        if len(cometY) != 0:
            cometPassed = cometY[-1]
        if len(moonY) != 0:
            moonPassed = moonY[-1]
        if rockPassed > HEIGHT and cometPassed > HEIGHT and moonPassed > HEIGHT:
            numRock,fuelY = RiftObstacles.path()
            rockType = []
            rockAngle = []
            rockAngle2 = []
            rockRot = []
            fuelType = []
            fuelAngle = []
            fuelAngle2 = []
            fuelRot = []
            for i in range(numRock):
                rockType.append(random.choice(rocks))
                rockAngle.append(random.uniform(-0.2,0.2))
                rockAngle2.append(rockAngle[i])

            for i in range(numFuel):
                fuelType.append(random.choice(fuel))
                fuelAngle.append(random.uniform(-0.2,0.2))
                fuelAngle2.append(fuelAngle[i])

                
            warningWidth = []
            for i in range(numComet):
                warningWidth.append(10)

        #Shows that collision between the ship works with obstacles
        if crash:
            #print('crash')
            crash = False
            
        pygame.display.update()
        clock.tick(FPS)


distance = 0
active = True
while active:
    rift()

pygame.quit()

解决方法

pygame.Surface.get_rect.get_rect() 返回一个具有 Surface 对象大小的矩形,该矩形总是从 (0,0) 开始,因为 Surface 对象没有位置。 表面 blit 位于屏幕上的某个位置。矩形的位置可以通过关键字参数指定。例如,矩形的中心可以用关键字参数 center 指定。这些关键字参数在返回之前应用于 pygame.Rect 的属性(有关关键字参数的完整列表,请参阅 pygame.Rect)。

确保始终设置 laserRect 的位置。位置设置在这里:

laserRect = rot_laser.get_rect()
if angle == 0:
   correction = 50*math.sin((angle*math.pi)/180)
   laserRect.midbottom = (shipX + 42 - correction,shipY+100)

但是这里没有设置:

if laserMode == True:
   rot_laser = pygame.transform.rotate(lasers[laserFrame],angle)
   laserRect = rot_laser.get_rect()
   laserMask = pygame.mask.from_surface(rot_laser)

由于laserRect之前设置正确,以后就不需要get了

if laserMode == True:
    rot_laser = pygame.transform.rotate(lasers[laserFrame],angle)
    
    # delete
    #laserRect = rot_laser.get_rect()
    
    laserMask = pygame.mask.from_surface(rot_laser)

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。