簡體   English   中英

我如何創建有效的方法來檢測python中字典中矩形之間的沖突(使用pygame進行仿真)?

[英]How can i create an effective way for collision detection between rectangles in a dictionary in python, (using pygame to emmulate)?

我知道這個問題很長,但是請幫助我,您的時間將不勝感激,與寫作相比,這個問題不是很復雜,我只是不確定如何處理,請幫助我。 (您只需要閱讀我嘗試鏈接的詞典中的代碼,其余的就在您需要時)

I have been working tirelessly on this game which i am making for a project, it has all been running relatively smoothly until just recently i have found a rather large issue and i am not sure how to overcome it. I have been working tirelessly on this game which i am making for a project, it has all been running relatively smoothly until just recently i have found a rather large issue and i am not sure how to overcome it.

我的問題如下:

當我為對象創建字典時,它將在屏幕上做某事。

(在這種情況下,玩家的子彈):

我能夠將所有詞典對象放置在屏幕上,並使其執行所有必要的操作,例如向上移動,在某個點處將其自身刪除並使其顯示。 當我嘗試將某些鏈接彼此時,會發生問題。 例如。 我能夠正確地將播放器的矩形鏈接到“ yummy ”字典,如果我的播放器觸摸了該矩形,則'score'得到了更多的分數,並且刪除了“ yummy ”。 當我嘗試在“ bullet ”和氣泡之間進行碰撞檢測時,也是如此,它會刪除氣泡,子彈並給出更多點,這正是我想要的。 雖然如果我嘗試使用與其他方法相同的方法'z.colliderect(x,y)' ,則它不起作用。 例如,如果我嘗試鏈接“ bigbullet ”和“ yummy ”字典矩形以檢測'bigbullet'是否命中了“ yummy ”並在發生這種情況時采取措施,我會收到一條消息,說:

'File "E:\Bubble Dash\practice\bubbledashworking1.py", line 347, in play
    if u['rect'].colliderect(u['rect']):
UnboundLocalError: local variable 'u' referenced before assignment'

我真的為此感到無比興奮,因為我不太擅長編程,我真的很想知道如何做到這一點,這樣我就可以 以我控制的相同方式控制所有詞典 'bubble'到“ bullet'詞典,在這里我可以刪除'bigbullet' ,如果碰到“ bubble ”,則給我40分。

#Additional Information: ###########################################################
enemyImage = pygame.image.load('enemy2.png')

yummyImage = pygame.image.load('bubble.png')

bulletImage = pygame.image.load('Haduoken.png')

playerImage = pygame.image.load('player.png')
playerImage2 = pygame.image.load('sadplayer.png')
playerStretchedImage = pygame.transform.scale(playerImage, (40, 40))

def play(PLAY, playing, highscore):

    baddie = []
    yummy = []
    bullet = []
    bigbullet = []
    movex,movey = 0,0
    charx, chary= WindowWidth /2 - 20, 800
    enemyy, enemyx = 10, 10
    moveright = False
    moveleft = False
    spawn = False
    direction = 'down'

    score = 0
    level1min = 2
    level1max = 7
    level2min = 3
    level2max = 9
    level3min = 5
    level3max = 15
    level1 = False
    level2 = False
    level3 = False
    boom = False
    cheat = False

    #for i in range(20):
        #baddie.append(pygame.Rect(random.randint(0, WindowWidth - 40), random.randint(0, WindowHeight - 40), 40, 80))
    #enemycounter = 0
    #newenemy = 40
    while True: 
        for event in pygame.event.get():

            if event.type == KEYDOWN:
                if event.key == ord('m'):
                    pygame.mixer.music.pause()
                    music = False
                if event.key == ord('n'):
                    pygame.mixer.music.unpause()
                    music = True
                if event.key == ord('a'):
                    moveleft = True
                if event.key == ord('d'):
                    moveright = True
                if event.key == ord('w'):
                    movey = -5
                    if score > 100:
                        movey = -7
                    if score > 500:
                        movey = -10
                    if score > 1000:
                        movey = -12
                if event.key == ord('s'):
                    movey = 5
                    if score > 100:
                        movey = 7
                    if score > 500:
                        movey = 10
                    if score > 1000:
                        movey = 12
                if event.key == ord('p'):
                    time.sleep(5)

            if event.type ==KEYUP:
                if event.key == ord('a'):
                    moveleft = False
                    if moveleft == False:
                        movex = 0
                if event.key == ord('c'):
                    cheat = True
                if event.key == ord('x'):
                    cheat = False
                if event.key == ord('d'):
                    moveright = False
                    if moveright == False:
                        movex = 0
                if event.key == ord('w'):
                    movey = 0
                if event.key == ord('s'):
                    movey = 0
            if event.type == QUIT:
                pygame.quit()
                sys.exit()

        screen.blit(playscreenStretchImage,(0,0))
        player = pygame.Rect(charx, chary, 40, 40)  

        if direction == 'down':
            enemyy += 0.5
        if moveright ==True:
            movex = 5
            if score > 100:
                movex = 7
            if score > 500:
                movex = 10
            if score > 1000:
                movex = 12
        if moveleft ==True:
            movex = -5
            if score > 100:
                movex = -7
            if score > 500:
                movex = -10
            if score > 1000:
                movex = -12
        #for bad in baddie[:]:
            #if player.colliderect(bad):
               # print('COLLISION')

        if player.bottom > WindowHeight:
            chary = WindowHeight - 40
            movey = 0
            print'bottom'
        if player.top < 0:
            chary = 1
            movey = 0
            print'top'
        if player.left < 0:
            charx = -1
            movex = 0
            if event.type == KEYDOWN:
                if event.key == ord('d'):
                    movex = 5
            print 'left'
        if player.right > WindowWidth:
            charx = WindowWidth  - 39
            movex = 0
            if event.type == KEYDOWN:
                if event.key == ord('a'):
                    movex = -5
            print'right'

        if playing != False:
            score +=1
            score_render = font.render("score: %.0f"%score, True, (255,255,255))
            time_passed = clock.tick(60)
            time_passed_seconds = time_passed*1000

            if score in range(40, 60):
                screen.blit(countdown3, (WindowWidth / 2, WindowHeight / 2))
            if score in range(61, 80):
                screen.blit(countdown2, (WindowWidth / 2, WindowHeight / 2))
            if score in range(81, 100):
                screen.blit(countdown1, (WindowWidth / 2, WindowHeight / 2))
            if score in range(440, 460):
                screen.blit(countdown3, (WindowWidth / 2, WindowHeight / 2))
            if score in range(461, 480):
                screen.blit(countdown2, (WindowWidth / 2, WindowHeight / 2))
            if score in range(481, 500):
                screen.blit(countdown1, (WindowWidth / 2, WindowHeight / 2))
            if score in range(940, 960):
                screen.blit(countdown3, (WindowWidth / 2, WindowHeight / 2))
            if score in range(961, 980):
                screen.blit(countdown2, (WindowWidth / 2, WindowHeight / 2))
            if score in range(981, 1000):
                screen.blit(countdown1, (WindowWidth / 2, WindowHeight / 2))






            screen.blit(score_render, (0,0))
            if score > highscore:
                highscore = score
            finalscore = score
            score_render = font.render("%0.f"%score, True, (255,255,255))
            highscore_render = font.render("Highscore:%.0f"%highscore, True, (255,255,255))
            maxscore_render = font.render("%.0f"%highscore, True, (255,255,255))
            screen.blit(highscore_render, (200,0))
#Here is the dictionaries i am trying to link:#########################################
            #BULLETS
            if len(bullet) <1:
                bulletSize = 30
                newBullet = {'rect': pygame.Rect(charx, chary, bulletSize, bulletSize),
                             'speed': -20,
                             'surface': pygame.transform.scale(bulletImage, (bulletSize, bulletSize))}
                bullet.append(newBullet)

            for l in bullet[:]:
                l['rect'].move_ip(0, l['speed'])
            for l in bullet[:]:
                if l['rect'].top < 0:
                    bullet.remove(l)
            for l in bullet[:]:
                screen.blit(l['surface'], l['rect'])

            #BIGBULLETS
                if len(bigbullet) < 1:
                    bigbulletSize = 200
                    newBigBullet = {'rect': pygame.Rect(0, WindowHeight - bigbulletSize, bigbulletSize, bigbulletSize),
                                    'speed': -5,
                                    'surface': pygame.transform.scale(bulletImage, (bigbulletSize,bigbulletSize))}
                if score in range(100, 200):
                    bigbullet.append(newBigBullet)
                for u in bigbullet[:]:
                    u['rect'].move_ip(0, u['speed'])
                    boom = False
                for u in bigbullet[:]:
                    screen.blit(u['surface'], u['rect'])



            #YUMMYYY
            if len(yummy)<5:
                if score < 100:
                    yummySize = 100
                    for y in yummy[:]:
                        if score == 100:
                            yummy.remove(y)
                if score > 100:

                    yummySize = 75
                    for y in yummy[:]:
                        if score == 500:
                            yummy.remove(y)
                if score >= 500:
                    yummySize = 50
                    for y in yummy[:]:
                        if score == 1000:
                            yummy.remove(y)
                if score >= 1000:
                    yummySize = 25




                newYummy = {'rect': pygame.Rect(random.randint(0, WindowWidth - yummySize), random.randint(0, WindowHeight-yummySize), yummySize-yummySize/2.2 , yummySize-yummySize/2.2),
                            'speed': random.randint(eminspeed, emaxspeed),
                            'surface': pygame.transform.scale(yummyImage, (yummySize, yummySize)),}
                yummy.append(newYummy)

            for y in yummy[:]:
                y['rect'].move_ip(0, y['speed'])
            for y in yummy[:]:
                if y['rect'].top > WindowHeight:
                    yummy.remove(y)
            for y in yummy[:]:
                if player.colliderect(y['rect']):
                    yummy.remove(y)
                    score += 20
            for y in yummy[:]:
                if l['rect'].colliderect(y['rect']):
                    yummy.remove(y)
                    bullet.remove(l)
                    score +=40
##            for y in yummy[:]:
##                if u['rect'].colliderect(y['rect']):
##                    yummy.remove(y)
##                    score +=200
##           
            for y in yummy:
                screen.blit(y['surface'], y['rect'])

            #BADDDIESS
            if len(baddie)<30:
                eminsize = 10
                emaxsize = 40
                if score >= 900:
                    eminsize = 30
                    emaxsize = 60


                enemySize = random.randint(eminsize, emaxsize)
                newEnemy = {'rect': pygame.Rect(random.randint(0, WindowWidth- enemySize),0-enemySize, enemySize, enemySize),
                            'speed': random.randint(eminspeed, emaxspeed),
                            'level1':random.randint(level1min, level1max),
                            'level2': random.randint(level2min, level2max),
                            'level3': random.randint(level3min, level3max),
                            'surface': pygame.transform.scale(enemyImage, (enemySize, enemySize)),}
                baddie.append(newEnemy)


            for b in baddie:
                if not level1 and not level2 and not level3 and not cheat:
                    b['rect'].move_ip(0, b['speed'])
                if score >= 100:
                    level1 = True
                    if level1 and not cheat == True:
                        b['rect'].move_ip(0, b['level1'])
                if cheat and level1 == True:
                    b['rect'].move_ip(0, 0)
                if score >= 500:
                    level1 = False
                    level2 = True
                    if level2 and not cheat == True:
                        b['rect'].move_ip(0, b['level2'])
                    elif cheat == True:
                        b['rect'].move_ip(0, 0)

                if cheat and level2 == True:
                    b['rect'].move_ip(0, 0)
                if score >= 1000:
                    level2 = False
                    level3 = True
                    if level3 and not cheat == True:
                        b['rect'].move_ip(0, b['level3'])

                if cheat and level3 == True:
                    b['rect'].move_ip(0, 0)
                if cheat == True:
                    b['rect'].move_ip(0,0)
            for b in baddie[:]:
                if level1 == True:
                    screen.blit(level1text, (400, 0))
                elif level2 == True:
                    screen.blit(level2text, (400, 0))
                elif level3 == True:
                    screen.blit(level3text, (400, 0))
            for b in baddie[:]:
                if b['rect'].top > WindowHeight:
                    baddie.remove(b)

            for b in baddie[:]:
                if player.colliderect(b['rect']):
                    baddie.remove(b)

                    charx, chary= WindowWidth /2 - 50, 340
                    playing = False

            for b in baddie:
#Additional Information:#############################################################
        while playing == False:

                for event in pygame.event.get():
                    if event.type == KEYDOWN:
                        if event.key == ord('m'):
                            pygame.mixer.music.pause()
                        if event.key == ord('n'):
                            pygame.mixer.music.play()
                        if event.key == K_ESCAPE:
                            pygame.quit()
                            sys.exit()
                        if event.key == ord('r'):
                            playing = True
                            play(PLAY, playing, highscore)
                        if event.key == ord('b'):
                            presskey(instrtomenu, highscore)
                    if event.type == QUIT:
                        pygame.quit()
                        sys.exit()

                    if event.type == MOUSEBUTTONDOWN:
                        x, y = event.pos
                        if (x in range (28, 598)) and (y in range(570, 642)):
                            playing = True
                            play(PLAY, playing, highscore)
                        if (x in range (24, 712)) and (y in range(688, 760)):
                            presskey(instrtomenu, highscore)

                score += 0

                screen.blit(gameoverscreenStretchImage, (0,0))
                screen.blit(score_render, (494, 14))
                screen.blit(maxscore_render, (506 ,66))
                screen.blit(playerStretchedImage3, (0,227))

                if finalscore in range(1100, 1199):
                    screen.blit(gunterLabel, (450, 408))
                    screen.blit(gunterLabel2, (450, 463))
                    screen.blit(gunterStretchImage, (500, 519))
                pygame.display.update()
        screen.blit(playerStretchedImage, player)
        charx+=movex
        chary+=movey
        clock.tick(FPS)

        pygame.display.update()

恐怕您可能需要對程序的結構進行較大的檢查。 字典確實不能做到這一點,您應該使用類,尤其是精靈。 此代碼是包含內置沖突檢測器的sprite的示例。

class collidable(pygame.sprite.Sprite):
    def __init__(self,coordinates,image):            #this method is called on an instance of a class upon creation. it is always nescessary to pass in "self" as the first argument to a def that is part of a class
        pygame.sprite.Sprite.__init__(self)
        self.image = image
        self.rect = self.image.get_rect()
        self.rect.center = coordinates
    def collide(self,other):                         #pass in the other sprite to check for a collision, this will return a True/False value of whether or not you are colliding with the other sprite
        mycollisions = pygame.sprite.spritecollide(self,other,False)
        for collision in mycollisions:
            if collision != self:
                return True
        return False

您可能對類和對象不是很了解,並且由於主題太寬,我無法解釋,所以我建議您查看關於該主題的python文檔,該文檔相當廣泛。 這是鏈接: http : //docs.python.org/2/tutorial/classes.html

另外,這可能沒有多大意義,所以我將嘗試介紹基礎知識。 Python是一種面向對象的語言。 python中幾乎所有的東西都是一個對象,包括數字,字符串等(當您添加數字時,實際上是在第一個數字上調用def以將其添加到幕后的另一個對象中)。 類是用戶可以用來創建新對象的一種特定類型的對象。 您可以定義一個類並為其創建多個實例。 一個類在其中包含一個變量和函數的列表,因此它將管理與其自身有關的所有其他對象。 這在pygame中是必需的,因為:

a:pygame提供了一個為您做很多工作的sprite類,您應該使用它。b:類是更好的組織數據的方法,即使它們乍一看似乎令人困惑。 您當前使用的字典可以提供類似的功能,但是構建了類來填補這一位置,並且做得更好。 諸如在屏幕上移動實體之類的事物需要管理某些事物,如位置。 字典可以做到這一點,但是類可以做到這一點。

將屬性分配給一個類后,您可以使用

<classname>.<attributename>

例如,要調用我們在可碰撞類的兩個實例之間創建的碰撞函數,我們可以這樣做:

mysprite = collidable((200,200),pygame.image.load("image_path.png").convert_alpha())
myothersprite = collidable((300,300),pygame.image.load("image_path.png").convert_alpha())
if mysprite.collide(myothersprite):
    print "sprites are colliding"

我傾向於同意某人或某人的觀點,您在程序上的編碼更少了,這將使調試和編寫變得非常困難。

剛開始編碼時,我以程序編寫了30頁的游戲,並告訴您,使用類/函數將極大地幫助您。

無論如何,進行碰撞檢測的一種非常簡單的方法是在精靈上放置一個圓圈,然后當對象A的坐標在圓圈內時(使用半徑來確定),然后為此設置一個觸發器。

您也可以使用正方形甚至更復雜的形狀。 例如,在正方形的情況下,您只需確定對象a的坐標何時大於包含正方形的“西北”點且小於“東南”點。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM