如何防止精灵彼此重叠

时间:2019-09-23 13:57:34

标签: python python-3.x pygame

所以我对Pygame并没有那么丰富的经验,我想知道如何防止敌人重叠。我尝试了几种方法,但收效甚微。我想听听您对我该如何做的想法。我认为一个好主意是通过碰撞检测。但是我不太确定那将如何工作。

这是敌人代码:

class Enemy:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def draw(self):
        global characterradius, characterradius1, characterradius2, characterradius3, characterradius4, characterradius5
        global characterradius6, characterradius7, estanding, emoveup, emovedown, emoveleft, emoveright, enemyradiusshow
        global eradius1, eradius2, eradius3, eradius4

        self.enemyradiusshow = True
        self.estanding = False
        emoveup = False
        emovedown = False
        emoveleft = False
        emoveright = False

        if moveup:
            self.y += speed
        if movedown:
            self.y -= speed
        if moveleft:
            self.x += speed
        if moveright:
            self.x -= speed

        enemyhitbox = pygame.Rect(self.x + 6, self.y + 5, 50, 80)
        self.enemyhitbox = pygame.Rect(self.x + 6, self.y + 5, 50, 80)
        enemyhitboxvisible = True
        self.enemyhitboxvisible = False
        playerradiusvisible = False

        if self.enemyhitboxvisible:
            pygame.draw.rect(win, (255, 255, 255), (self.x + 6, self.y + 5, 50, 80))
        if enemyhitboxvisible:
            pygame.draw.rect(win, (255, 255, 255), (self.x + 6, self.y + 5, 50, 80))

        if playerradiusvisible:
            pygame.draw.rect(win, (80, 200, 50), (character_x - 180, character_y - 180, 150.5, 150.5))
            pygame.draw.rect(win, (200, 80, 50), (character_x + 80, character_y - 180, 150.5, 150.5))
            pygame.draw.rect(win, (80, 50, 200), (character_x - 180, character_y + 90, 150.5, 150.5))
            pygame.draw.rect(win, (200, 150, 50), (character_x + 80, character_y + 90, 150.5, 150.5))

            pygame.draw.rect(win, (150, 150, 50), (character_x - 180, character_y - 30, 150.5, 120))
            pygame.draw.rect(win, (200, 70, 50), (character_x + 80, character_y - 30, 150.5, 120))
            pygame.draw.rect(win, (50, 150, 200), (character_x - 30, character_y - 180, 110, 150.5))
            pygame.draw.rect(win, (50, 150, 200), (character_x - 30, character_y + 90, 110, 150.5))

        characterradius = pygame.Rect(character_x - 180, character_y - 180, 150.5, 150.5)
        characterradius1 = pygame.Rect(character_x + 80, character_y - 180, 150.5, 150.5)
        characterradius2 = pygame.Rect(character_x - 180, character_y + 90, 150.5, 150.5)
        characterradius3 = pygame.Rect(character_x + 80, character_y + 90, 150.5, 150.5)
        character_hitbox = pygame.Rect(character_x + 80, character_y + 90, 150.5, 150.5)

        characterradius4 = pygame.Rect(character_x - 180, character_y - 30, 150.5, 120)
        characterradius5 = pygame.Rect(character_x + 80, character_y - 30, 150.5, 120)
        characterradius6 = pygame.Rect(character_x - 30, character_y - 180, 110, 150.5)
        characterradius7 = pygame.Rect(character_x - 30, character_y + 90, 110, 150.5)

        self.enemyspeed = 1

        if characterradius.colliderect(self.enemyhitbox):
            self.x += self.enemyspeed
            self.y += self.enemyspeed
            emoveleft = True
        if characterradius1.colliderect(self.enemyhitbox):
            self.x -= self.enemyspeed
            self.y += self.enemyspeed
            emoveright = True
        if characterradius2.colliderect(self.enemyhitbox):
            self.x += self.enemyspeed
            self.y -= self.enemyspeed
            emoveleft = True
        if characterradius3.colliderect(self.enemyhitbox):
            self.x -= self.enemyspeed
            self.y -= self.enemyspeed
            emoveright = True
        if characterradius4.colliderect(self.enemyhitbox):
            self.x += self.enemyspeed
            emoveleft = True
        if characterradius5.colliderect(self.enemyhitbox):
            self.x -= self.enemyspeed
            emoveright = True
        if characterradius6.colliderect(self.enemyhitbox):
            self.y += self.enemyspeed
            emovedown = True
        if characterradius7.colliderect(self.enemyhitbox):
            self.y -= self.enemyspeed
            emoveup = True

        if emoveup:
            win.blit(zombieupimage, (self.x, self.y))
            self.emovedown = False
            self.emoveleft = False
            self.emoveright = False
            self.emoveup = True
        if emovedown:
            win.blit(zombieimage, (self.x - 5.5, self.y - 4))
            self.emovedown = True
            self.emoveleft = False
            self.emoveright = False
            self.emoveup = False
        if emoveleft:
            win.blit(zombieleftimage, (self.x, self.y))
            self.emovedown = False
            self.emoveleft = True
            self.emoveright = False
            self.emoveup = False
        if emoveright:
            win.blit(zombierightimage, (self.x, self.y))
            self.emovedown = False
            self.emoveleft = False
            self.emoveright = True
            self.emoveup = False

        if not emoveup:
            self.estanding = True
        if not emovedown:
            self.estanding = True
        if not emoveleft:
            self.estanding = True
        if not emoveright:
            self.estanding = True

        if characterradius.colliderect(self.enemyhitbox):
            self.estanding = False
        if characterradius1.colliderect(self.enemyhitbox):
            self.estanding = False
        if characterradius2.colliderect(self.enemyhitbox):
            self.estanding = False
        if characterradius3.colliderect(self.enemyhitbox):
            self.estanding = False
        if characterradius4.colliderect(self.enemyhitbox):
            self.estanding = False
        if characterradius5.colliderect(self.enemyhitbox):
            self.estanding = False
        if characterradius6.colliderect(self.enemyhitbox):
            self.estanding = False
        if characterradius7.colliderect(self.enemyhitbox):
            self.estanding = False

以下是完整的代码,以备您需要时使用:

import pygame
import time
import os
import random

pygame.init()

# Screen Resolution
screen_width = 800
screen_height = 600

# Character Variables
character_x = 380
character_y = 250

# Background Variables
backgroundx = -375
backgroundy = -255

# Images
bgimage = pygame.image.load('bg.png')
characterimage = pygame.image.load('character.png')
characterbackimage = pygame.image.load('characterback.png')
characterleftimage = pygame.image.load('characterright.png')
characterrightimage = pygame.image.load('characterleft.png')

zombieimage = pygame.image.load('zombie.png')
zombieupimage = pygame.image.load('zombieback.png')
zombieleftimage = pygame.image.load('zombieleft.png')
zombierightimage = pygame.image.load('zombieright.png')

healthbarimage = pygame.image.load('healthbar.png')
hungerbarimage = pygame.image.load('hungerbar.png')
thirstbarimage = pygame.image.load('thirstbar.png')
energybarimage = pygame.image.load('energybar.png')

healthimage = pygame.image.load('health.png')
hungerimage = pygame.image.load('hunger.png')
thirstimage = pygame.image.load('thirst.png')

vignetteimage = pygame.image.load('vignette.png')

# Movement Fix
characterbackx = 6.5
characterbacky = 5
characterleftx = 5
characterlefty = 4
characterrightx = 7.5
characterrighty = 4.5

# Bars
healthbarx = 580
healthbary = 555
hungerbarx = 580
hungerbary = 520
thirstbarx = 580
thirstbary = 485
energybarx = 765
energybary = 430

energybardraw_x = 770
energybardraw_y = 432.5
energybardraw_width = 15
energybardraw_height = 1

thirstbardraw_x = 581
thirstbardraw_y = 490.7
thirstbardraw_width = 1
thirstbardraw_height = 15

hungerbardraw_x = 581
hungerbardraw_y = 524
hungerbardraw_width = 1
hungerbardraw_height = 15

thirsttimer = 0
hungertimer = 0
notsprintthirst = True
notsprinthunger = True
sprintthirst = False
sprinthunger = False

# Settings Variables
vignettex = 0
vignettey = 0

# Settings
vignette_on = True
vignette_off = False

# Movement
timerdown = 0
timerup = 0
timerleft = 0
timerright = 0

movingdown = True
movingleft = False
movingright = False
movingup = False

able_to_move = True

moveup = False
movedown = False
moveleft = False
moveright = False
sprint = False
speed = 2.5


def loadinscreen():

    loadingscreen = pygame.image.load('loadingscreen.png')
    os.environ['SDL_VIDEO_CENTERED'] = '1'
    pygame.init()
    screen = pygame.display.set_mode((500, 80), pygame.NOFRAME)
    bg = pygame.Surface(screen.get_size())
    bg.fill((0, 244, 0))
    screen.blit(loadingscreen, (0, 0))
    pygame.display.update()
    time.sleep(1)

# Tiers / Level Ups


speedtier_1 = True

# Hitboxes Variables

win = pygame.display.set_mode((screen_width, screen_height))
character = win.blit(characterimage, (character_x, character_y))

class Enemy:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def draw(self):
        global characterradius, characterradius1, characterradius2, characterradius3, characterradius4, characterradius5
        global characterradius6, characterradius7, estanding, emoveup, emovedown, emoveleft, emoveright, enemyradiusshow
        global eradius1, eradius2, eradius3, eradius4

        self.enemyradiusshow = True
        self.estanding = False
        emoveup = False
        emovedown = False
        emoveleft = False
        emoveright = False

        if moveup:
            self.y += speed
        if movedown:
            self.y -= speed
        if moveleft:
            self.x += speed
        if moveright:
            self.x -= speed

        enemyhitbox = pygame.Rect(self.x + 6, self.y + 5, 50, 80)
        self.enemyhitbox = pygame.Rect(self.x + 6, self.y + 5, 50, 80)
        enemyhitboxvisible = True
        self.enemyhitboxvisible = False
        playerradiusvisible = False

        if self.enemyhitboxvisible:
            pygame.draw.rect(win, (255, 255, 255), (self.x + 6, self.y + 5, 50, 80))
        if enemyhitboxvisible:
            pygame.draw.rect(win, (255, 255, 255), (self.x + 6, self.y + 5, 50, 80))

        if playerradiusvisible:
            pygame.draw.rect(win, (80, 200, 50), (character_x - 180, character_y - 180, 150.5, 150.5))
            pygame.draw.rect(win, (200, 80, 50), (character_x + 80, character_y - 180, 150.5, 150.5))
            pygame.draw.rect(win, (80, 50, 200), (character_x - 180, character_y + 90, 150.5, 150.5))
            pygame.draw.rect(win, (200, 150, 50), (character_x + 80, character_y + 90, 150.5, 150.5))

            pygame.draw.rect(win, (150, 150, 50), (character_x - 180, character_y - 30, 150.5, 120))
            pygame.draw.rect(win, (200, 70, 50), (character_x + 80, character_y - 30, 150.5, 120))
            pygame.draw.rect(win, (50, 150, 200), (character_x - 30, character_y - 180, 110, 150.5))
            pygame.draw.rect(win, (50, 150, 200), (character_x - 30, character_y + 90, 110, 150.5))

        characterradius = pygame.Rect(character_x - 180, character_y - 180, 150.5, 150.5)
        characterradius1 = pygame.Rect(character_x + 80, character_y - 180, 150.5, 150.5)
        characterradius2 = pygame.Rect(character_x - 180, character_y + 90, 150.5, 150.5)
        characterradius3 = pygame.Rect(character_x + 80, character_y + 90, 150.5, 150.5)
        character_hitbox = pygame.Rect(character_x + 80, character_y + 90, 150.5, 150.5)

        characterradius4 = pygame.Rect(character_x - 180, character_y - 30, 150.5, 120)
        characterradius5 = pygame.Rect(character_x + 80, character_y - 30, 150.5, 120)
        characterradius6 = pygame.Rect(character_x - 30, character_y - 180, 110, 150.5)
        characterradius7 = pygame.Rect(character_x - 30, character_y + 90, 110, 150.5)

        self.enemyspeed = 1

        if characterradius.colliderect(self.enemyhitbox):
            self.x += self.enemyspeed
            self.y += self.enemyspeed
            emoveleft = True
        if characterradius1.colliderect(self.enemyhitbox):
            self.x -= self.enemyspeed
            self.y += self.enemyspeed
            emoveright = True
        if characterradius2.colliderect(self.enemyhitbox):
            self.x += self.enemyspeed
            self.y -= self.enemyspeed
            emoveleft = True
        if characterradius3.colliderect(self.enemyhitbox):
            self.x -= self.enemyspeed
            self.y -= self.enemyspeed
            emoveright = True
        if characterradius4.colliderect(self.enemyhitbox):
            self.x += self.enemyspeed
            emoveleft = True
        if characterradius5.colliderect(self.enemyhitbox):
            self.x -= self.enemyspeed
            emoveright = True
        if characterradius6.colliderect(self.enemyhitbox):
            self.y += self.enemyspeed
            emovedown = True
        if characterradius7.colliderect(self.enemyhitbox):
            self.y -= self.enemyspeed
            emoveup = True

        if emoveup:
            win.blit(zombieupimage, (self.x, self.y))
            self.emovedown = False
            self.emoveleft = False
            self.emoveright = False
            self.emoveup = True
        if emovedown:
            win.blit(zombieimage, (self.x - 5.5, self.y - 4))
            self.emovedown = True
            self.emoveleft = False
            self.emoveright = False
            self.emoveup = False
        if emoveleft:
            win.blit(zombieleftimage, (self.x, self.y))
            self.emovedown = False
            self.emoveleft = True
            self.emoveright = False
            self.emoveup = False
        if emoveright:
            win.blit(zombierightimage, (self.x, self.y))
            self.emovedown = False
            self.emoveleft = False
            self.emoveright = True
            self.emoveup = False

        if not emoveup:
            self.estanding = True
        if not emovedown:
            self.estanding = True
        if not emoveleft:
            self.estanding = True
        if not emoveright:
            self.estanding = True

        if characterradius.colliderect(self.enemyhitbox):
            self.estanding = False
        if characterradius1.colliderect(self.enemyhitbox):
            self.estanding = False
        if characterradius2.colliderect(self.enemyhitbox):
            self.estanding = False
        if characterradius3.colliderect(self.enemyhitbox):
            self.estanding = False
        if characterradius4.colliderect(self.enemyhitbox):
            self.estanding = False
        if characterradius5.colliderect(self.enemyhitbox):
            self.estanding = False
        if characterradius6.colliderect(self.enemyhitbox):
            self.estanding = False
        if characterradius7.colliderect(self.enemyhitbox):
            self.estanding = False

        if self.estanding:
            win.blit(zombieimage, (self.x, self.y))

        if self.enemyradiusshow:
            pygame.draw.rect(win, (255, 0, 0), (self.x - 11, self.y + 40, 15, 15))
            pygame.draw.rect(win, (0, 255, 0), (self.x + 23.5, self.y + 87, 15, 15))
            pygame.draw.rect(win, (0, 0, 255), (self.x + 58, self.y + 40, 15, 15))
            pygame.draw.rect(win, (155, 155, 155), (self.x + 23.5, self.y - 12, 15, 15))

        eradius1 = pygame.Rect (self.x - 11, self.y + 40, 15, 15)
        eradius2 = pygame.Rect (self.x + 23.5, self.y + 87, 15, 15)
        eradius3 = pygame.Rect (self.x + 58, self.y + 40, 15, 15)
        eradius4 = pygame.Rect (self.x + 23.5, self.y - 12, 15, 15)




enemies = []
randomposx = 500
randomposy = 500
max_enemies = 10
milliseconds_delay = 1
spawn_event = pygame.USEREVENT + 1
enemie_size = zombieimage.get_size()

pygame.time.set_timer(spawn_event, milliseconds_delay)
run = True

while run:

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            run = False

        elif event.type == spawn_event:
            if len(enemies) < max_enemies:
                x = random.randint(1, randomposx - enemie_size[0])
                y = random.randint(1, randomposy - enemie_size[1])
                e = Enemy(x, y)
                enemies.append(e)

        elif event.type == pygame.KEYDOWN:
            if event.key == pygame.K_w:
                moveup = True
            elif event.key == pygame.K_s:
                movedown = True
            elif event.key == pygame.K_a:
                moveleft = True
            elif event.key == pygame.K_d:
                moveright = True
            elif event.key == pygame.K_LSHIFT:
                sprint = True
        if event.type == pygame.KEYUP:
            if able_to_move:
                if event.key == pygame.K_w:
                    moveup = False
                elif event.key == pygame.K_s:
                    movedown = False
                elif event.key == pygame.K_a:
                    moveleft = False
                elif event.key == pygame.K_d:
                    moveright = False
                elif event.key == pygame.K_LSHIFT:
                    sprint = False

    keys = pygame.key.get_pressed()
    pygame.display.update()

    # Hitboxes

    def background():
        win.blit(bgimage, (backgroundx, backgroundy))

    background()
    for e in enemies:
        e.draw()

    def vignette():
        if vignette_on:
            win.blit(vignetteimage, (vignettex, vignettey))

    vignette()

    class Bars:
        win.blit(healthbarimage, (healthbarx, healthbary))
        win.blit(hungerbarimage, (hungerbarx, hungerbary))
        win.blit(thirstbarimage, (thirstbarx, thirstbary))
        win.blit(energybarimage, (energybarx, energybary))

        win.blit(healthimage, (735, 556.2))
        win.blit(hungerimage, (735, 520.5))
        win.blit(thirstimage, (733.5, 486.6))

    def drawbars():
        pygame.draw.rect(win, (0, 0, 0), (energybardraw_x, energybardraw_y, energybardraw_width, energybardraw_height))
        pygame.draw.rect(win, (0, 0, 0), (thirstbardraw_x, thirstbardraw_y, thirstbardraw_width, thirstbardraw_height))
        pygame.draw.rect(win, (0, 0, 0), (hungerbardraw_x, hungerbardraw_y, hungerbardraw_width, hungerbardraw_height))

    drawbars()

    def hitboxvisible():
        pygame.draw.rect(win, (200, 10, 50), (character_x, character_y, 50, 80))

    if movingdown:
        character = win.blit(characterimage, (character_x, character_y))
    if movingleft:
        characterleft = win.blit(characterleftimage, (character_x + characterleftx, character_y + characterlefty))
    if movingright:
        characterright = win.blit(characterrightimage, (character_x + characterrightx, character_y + characterrighty))
    if movingup:
        characterback = win.blit(characterbackimage, (character_x + characterbackx, character_y + characterbacky))

    if moveup:
        goingdown = False
        movingleft = False
        movingright = False
        movingup = True
        backgroundy += speed
    if movedown:
        movingleft = False
        movingright = False
        movingup = False
        movingdown = True
        backgroundy -= speed
    if moveleft:
        movingdown = False
        movingleft = True
        movingright = False
        movingup = False
        backgroundx += speed
    if moveright:
        movingdown = False
        movingleft = False
        movingright = True
        movingup = False
        backgroundx -= speed

    def energybar_gain():
        global energybardraw_height
        energybardraw_height -= 0.8

    if speedtier_1:
        if sprint:
            speed = 4
            energybardraw_height += 2
            sprintthirst = True
            notsprintthirst = False
            sprinthunger = True
            notsprinthunger = False
        if not sprint:
            speed = 3
            energybar_gain()
            sprintthirst = False
            notsprintthirst = True
            sprinthunger = False
            notsprinthunger = True

        if energybardraw_height < 0:
            energybardraw_height = 1
        if energybardraw_height > 146:
            energybardraw_height = 146
            sprint = False

    if notsprintthirst:
        thirsttimer += 0.5
    if sprintthirst:
        thirsttimer += 1

    if thirsttimer == 150:
        thirstbardraw_width += 2
    if thirsttimer > 150:
        thirsttimer = 0

    if notsprinthunger:
        hungertimer += 0.5
    if sprinthunger:
        hungertimer += 1
    if hungertimer == 175:
        hungerbardraw_width += 2
    if hungertimer > 175:
        hungertimer = 0

    if moveup or movedown or moveleft or moveright:
        timerdown += 1
        if timerdown > 12:
            timerdown = 0

        if timerdown == 1:
            character_y -= 1
        if timerdown == 2:
            character_y -= 1
        if timerdown == 3:
            character_y -= 1
        if timerdown == 4:
            character_y -= 1

        if timerdown == 5:
            character_y += 1
        if timerdown == 6:
            character_y += 1
        if timerdown == 7:
            character_y += 1
        if timerdown == 8:
            character_y += 1

    # Zombies Only

    pygame.display.update()

1 个答案:

答案 0 :(得分:0)

这更多是游戏设计问题,但通常为防止精灵重叠,您可以检测碰撞,然后将其位置设置为恰好不重叠的位置。最初,您可能会认为这是个怪诞的传送,但是如果每秒检测到30次碰撞(帧速率),则玩家看不到它们传送的微小距离。

检测碰撞的最简单方法是为它们提供一个由半径指定的圆形命中框。这不是一个完美的解决方案,但是它将使您按计划进行优化,并考虑一种更适合您的最佳方法。

作为旁注,我对PyGame并不熟悉,但是我确定他们有一些Vector Vector库。 Vector2本质上是[self.xPos,self.yPos]的数组,具有一些额外的辅助功能,例如使用勾股定理找到距离。

半个伪代码/半个python看起来像这样:

for enemy1 in enemies: 
    for enemy2 in enemies:
        if enemy1 == enemy2: #if both are the same enemy
            continue
        # Find the dist between both enemies
        # *Assumes sprite anchor is in center
        distanceBetween = Vector2.DistanceBetween(enemy1, enemy2)  
        combinedHitbox = enemy1.radius + enemy2.radius

        if combinedHitbox < distanceBetween:
            # Calculate the delta position (difference between)
            positionDiff = enemy2.position - enemy1.position
            # Move them away from each other half of the distance between them.
            enemy2.position += positionDiff /2
            enemy1.position -= positionDiff /2

PyGame还可能有一些更好的方法来检测Hitbox,这将在后台进行,但我认为重要的是所有游戏开发人员至少应尝试一次实现自己的目的,以了解其工作原理。

相关问题