Враг не остается в исходном месте

#python #pygame #collision-detection #pygame-surface

#python #pygame #обнаружение столкновений #pygame-поверхность

Вопрос:

Итак, я пытался заставить моего врага двигаться в том же месте, пока мой игрок перемещает камеру, но это не работает, когда экран перемещается, мой враг будет медленно перемещаться со своего исходного места, но как только он выйдет из своего исходного места, он начнет давать сбои. Также, когда мой игрок сталкивается со стороной платформы, мой враг будет двигаться так же, как и мой игрок, но быстрее, например: https://gyazo.com/926207e82cd9849266decd68c08ea84d

Часть движения моей камеры (не работает)

 if keys[pygame.K_d]:
        for Platform in platforms:
            Platform.x -= playerman.speed
        for Snake in snakes:
            Snake.scroll(-playerman.speed,0)
        for Rule in rules:
            Rule.x -= playerman.speed
        if not playerman.isJump:
            playerman.direction = "right"
  

Мой полный код

 import pygame
pygame.init()

window = pygame.display.set_mode((700,500))
pygame.display.set_caption("Noobs First Game")


move = pygame.image.load("WASD.png")


# Playerman
class Player:
    def __init__(self,x,y,width,height,color):
        self.x = x
        self.y = y
        self.width = width
        self.height = height
        self.color = color
        self.speed = 5
        self.isJump = False
        self.JumpCount = 10
        self.idle =[pygame.image.load("player_idel_1.png"),
                            pygame.image.load("player_idel_2.png"),
                            pygame.image.load("player_idel_3.png"),
                            pygame.image.load("player_idel_4.png"),
                            pygame.image.load("player_idel_5.png"),
                            pygame.image.load("player_idel_6.png"),
                            pygame.image.load("player_idel_7.png"),
                            pygame.image.load("player_idel_8.png")
                            ]

        self.idlel = [pygame.image.load("Player_idel_left1.png"),
                         pygame.image.load("Player_idel_left2.png"),
                         pygame.image.load("Player_idel_left3.png"),
                         pygame.image.load("Player_idel_left4.png"),
                         pygame.image.load("Player_idel_left5.png"),
                         pygame.image.load("Player_idel_left6.png"),
                         pygame.image.load("Player_idel_left7.png"),
                         pygame.image.load("Player_idel_left8.png")
                         ]
        self.right = [pygame.image.load("Player_walk_right1.png"),
                      pygame.image.load("Player_walk_right2.png"),
                      pygame.image.load("Player_walk_right3.png")]
        
        self.left = [pygame.image.load("Player_walk_left1.png"),
                     pygame.image.load("Player_walk_left2.png"),
                     pygame.image.load("Player_walk_left3.png")]

        self.jump1 = [pygame.image.load("Player_jump5.png")]

        
        self.jump2 = [
                     pygame.image.load("Player_rjump1.png")]
        

        self.fall = 0
        self.rect = pygame.Rect(x,y,height,width)
        self.idle = [pygame.transform.scale(image,(image.get_width()*2,image.get_height()*2)) for image in self.idle]
        self.idlel = [pygame.transform.scale(image,(image.get_width()*2,image.get_height()*2)) for image in self.idlel]
        self.right = [pygame.transform.scale(image,(image.get_width()*2,image.get_height()*2)) for image in self.right]
        self.left = [pygame.transform.scale(image,(image.get_width()*2, image.get_height()*2)) for image in self.left]
        self.jump1 = [pygame.transform.scale(image,(image.get_width()*2,image.get_height()*2)) for image in self.jump1]
        self.jump2 = [pygame.transform.scale(image,(image.get_width()*2,image.get_height()*2)) for image in self.jump2]
        self.fps = 10
        self.clock = pygame.time.Clock()
        self.anim_index = 0
        self.direction = "idle"
        self.direction = "right"
        self.direction = "left"
        self.dierection = "idleleft"
        self.dierection = "jump1"
        self.dierection = "jump2"
        self.next_frame_time = 0
    def get_rect(self):
        self.rect.topleft = (self.x,self.y)
        return self.rect
        pygame.draw.rect(self.color,self.rect)
    
    def draw(self):
        if self.direction == "idle":
            image_list = self.idle
        if self.direction == "right":
            image_list = self.right
        if self.direction == "left":
            image_list = self.left
        if self.direction == "idlel":
            image_list = self.idlel
        if self.direction == "jump1":
            image_list = self.jump1
        if self.direction == "jump2":
            image_list = self.jump2
    

         

        # Is it time to show the next animation frame?
        time_now = pygame.time.get_ticks()
        if ( time_now > self.next_frame_time ):
            # set the time for the next animation-frame
            inter_frame_delay = 1000 // self.fps   
            self.next_frame_time = time_now   inter_frame_delay  # in the future
            # move the current image to the next (with wrap-around)
            self.anim_index  = 1
            if self.anim_index >= len( image_list ):
                self.anim_index = 0
                    
        if self.anim_index >= len(image_list):
            self.anim_index = 0
        player_image = image_list[self.anim_index]

        pygame.draw.rect( window, self.color, self.get_rect(), 2 )
        player_image = image_list[self.anim_index]

        player_rect = player_image.get_rect(center = self.get_rect().center)
        player_rect.centerx  = 3
        player_rect.centery -= 13
        window.blit(player_image, player_rect)

class Snake:
    def __init__(self, x, y, width, height, end):
        self.x = x
        self.y = y
        self.width = width
        self.height = height
        self.path = [x, end]
        self.walkCount = 0
        self.vel = 3
        self.visible = True
        self.no = pygame.image.load("Player_jump5.png")
        self.rect = pygame.Rect(x,y,width,height)
    def draw(self):
        self.move()
        self.rect.topleft = (self.x,self.y)
        window.blit(self.no,self.rect)

    def move(self):
        if self.visible:
            # turn around if the move would go out-of-bounds
            proposed_move = self.x   self.vel
            if ( proposed_move < self.path[0] or proposed_move > self.path[1] ):
                # Move hits a boundary, so we need to turn around
                self.vel = -self.vel
                self.Walking_index = 0
            # now make the correct move
            self.x  = self.vel   # add  /- velocity
    def scroll(self,sx,sy):
        self.x  = sx
        self.y  = sy
        self.path[0]  = sx
        self.path[1]  = sx


class Platform:
    def __init__(self,x,y,width,height,color):
        self.x = x
        self.y =y
        self. width = width
        self.color = color
        self.height = height
        self.color = color
        self.speed = 4
        self.rect = pygame.Rect(x,y,width,height)
    def get_rect(self):
        self.rect.topleft = (self.x,self.y)
        return self.rect
    def draw(self):
        pygame.draw.rect(window,self.color,self.get_rect())


class Rule:
    def __init__(self,x,y,width,height,color):
        self.x = x
        self.y =y
        self. width = width
        self.color = color
        self.height = height
        self.color = color
        self.speed = 4
        self.rect = pygame.Rect(x,y,width,height)
    def draw(self):
        self.rect.topleft = (self.x,self.y)


# Colors for hitbox
white = (255,255,255)
green = (0,255,0)

# Drawing Player
playerman = Player(350,445,40,40,white)

#Drawing Platforms
platform1 = Platform(300,-9.1,40,500,green)
platform2 = Platform(330,451,2000,40,green)
platform3 = Platform(2300,-9.1,40,500,green)

# Drawing Rule
rule1 = Rule(340,-9.1,220,500,green)
rule2 = Rule(20000,-9,1,5,green)

snake1 = Snake(100, 110, 64, 64, 300)

# List
platforms = [platform1,platform2,platform3]

rules = [rule1,rule2]

snakes = [snake1]


# draws map
platformGroup = pygame.sprite.Group
Level = [
"                                         1   1",
"                                         1    ",
"                         1  1        111 1    ",
"                         1  1         1  1    ",
"                         11 1      1  1 11    ",
"                         1  1         1  1    ",
"                         1  1    1    11 1    ",
"           1   1   111   1 11         1  1    ",
"           1   1  11111        1      1          ",]

for iy,row in enumerate(Level):
    for ix, col in enumerate(row):
        if col == "1":
            new_platforms = Platform(ix*50,iy*50.2,50,50,(255,255,255))
            platforms.append(new_platforms)
    
            

# Windows color
def redrawwindow():
    window.fill((0,0,0))

    # Drawing the player and other stuff to the screen
    playerman.draw()

    for Platform in platforms:
        Platform.draw()
    for Rule in rules:
        Rule.draw()
    for Snake in snakes:
        Snake.draw()

x = 10
y = 10
x_change = 0
y_change = 0
old_x = x
old_y = y
fps = (30)
clock = pygame.time.Clock()

run = True
while run:
    clock.tick(fps)
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            run = False

    
            

        


 # part of player screen movment
    if playerman.y < 250:
        playerman.y  = 1
        for Platform in platforms:
            Platform.y  = playerman.speed

        for Snake in snakes:
            Snake.scroll(0,  playerman.speed)

    if playerman.y > 410:
        playerman.y -= playerman.fall
        for Platform in platforms:
            Platform.y -= playerman.fall
        for Snake in snakes:
            Snake.scroll(0, -playerman.fall)

    # part of side colliding    
    if event.type == pygame.KEYDOWN:
        if event.key == pygame.K_d:
            x_change = -7
            for Snake in snakes:
                Snake.scroll(playerman.speed,0)
            
        if event.key == pygame.K_a:
            x_change = 7
            for Snake in snakes:
                Snake.scroll(-playerman.speed,0)

    if event.type == pygame.KEYUP:
        if event.key == pygame.K_d or event.key == pygame.K_a:
            x_change = 0

        x  = x_change
        if x > 500 - playerman.width or x < 0:
            x = old_x
           
        # lets player move
    keys = pygame.key.get_pressed()
    px, py = playerman.x, playerman.y

    for Platform in platforms:    
        if playerman.fall > 0 and keys[pygame.K_SPACE]:
            if keys[pygame.K_d]:
                playerman.direction = "jump1"
        else:
            if playerman.direction == "left":
                if keys[pygame.K_SPACE]:
                    playerman.direction = "jump2"

               

 # direction for player animation and screen movment
    if keys[pygame.K_d]:
        for Platform in platforms:
            Platform.x -= playerman.speed
        for Snake in snakes:
            Snake.scroll(-playerman.speed,0)
        for Rule in rules:
            Rule.x -= playerman.speed
        if not playerman.isJump:
            playerman.direction = "right"

        
    elif keys[pygame.K_a]:
        for Platform in platforms:
            Platform.x  = playerman.speed
        for Rule in rules:
            Rule.x  = playerman.speed
        if not playerman.isJump:
            playerman.direction = "left"
        for Snake in snakes:
            Snake.scroll(playerman.speed,0)






            
    else:
        if playerman.direction == "left" and playerman.direction == "idlel":
         
            playerman.direction = "idlel"
        else:
            if playerman.direction == "right" and playerman.direction == "idle":
                
                playerman.direction = "idle"


    if playerman.direction == "right" and keys[pygame.K_SPACE]:
        playerman.direction = "jump1"
            
    if playerman.direction == "left":
        if keys[pygame.K_SPACE]:
            playerman.direction = "jump2"

    
    # sides for player and player screen movment
    platform_rect_list = [p.rect for p in platforms]
    player_rect = playerman.get_rect()
    player_rect.topleft = (px, py)

    playerman.y = py
    if player_rect.collidelist(platform_rect_list) < 0:
        playerman.x = px

    move_right = keys[pygame.K_d]
    move_left = keys[pygame.K_a]
    if move_right: 
        for Platform in platforms:
            Platform.x -= playerman.speed
        for Rule in rules:
            Rule.x -= playerman.speed     # <---
        for Snake in snakes:
            Snake.scroll(-playerman.speed,0)

    if move_left:
        for Platform in platforms:
            Platform.x  = playerman.speed
        for Rule in rules:
            Rule.x  = playerman.speed     # <---
        for Snake in snakes:
            Snake.scroll(playerman.speed,0)

    platform_rect_list = [p.get_rect() for p in platforms] # get_rect()
    player_rect = playerman.get_rect()
    player_rect.topleft = (px, py)

    playerman.y = py
    cI = player_rect.collidelist(platform_rect_list)
    if cI >= 0:
        # undo movement of platforms dependent on the direction and intersection distance
        dx = 0
        if move_right: 
            dx = platform_rect_list[cI].left - player_rect.right
        if move_left:
            dx = platform_rect_list[cI].right - player_rect.left
        for Platform in platforms:
            Platform.x -= dx
            Platform.get_rect() # update rectangle
        for Rule in rules:
            Rule.x -= dx             # <---
        for Snake in snakes:
            Snake.x -= dx


##############                
  
    # About isJump
    if not playerman.isJump:
        playerman.y  = playerman.fall
        playerman.fall  = 1
        playerman.isJump = False

        # this part lets you jump on platform only the top 
        collide = False
        for Platform in platforms:
            if playerman.get_rect().colliderect(Platform.rect):
                collide = True
                playerman.isJump = False
                playerman.y = Platform.rect.top - playerman.height
                if playerman.rect.right > Platform.rect.left and playerman.rect.left < Platform.rect.left - playerman.width:
                    playerman.x = Platform.rect.left - playerman.width
                if playerman.rect.left < Platform.rect.right and playerman.rect.right > Platform.rect.right   playerman.width:
                    playerman.x = Platform.rect.right
                       
            # colliding with floor      
            if playerman.rect.bottom >= 500:
                collide = True
                playerman.isJump = False
                playerman.Jumpcount = 10
                playerman.y = 500 - playerman.height

        # Jumping
        if collide:
            if keys[pygame.K_SPACE]:
                playerman.isJump = True
                py -= playerman.speed
            playerman.fall = 0
            

    # Jump Count

    else:
        if playerman.JumpCount >= 0:
            playerman.y -= (playerman.JumpCount*abs(playerman.JumpCount))*0.3
            playerman.JumpCount -= 1
        else:
            playerman.isJump = False
            playerman.JumpCount = 10

    redrawwindow()
    if playerman.rect.colliderect(rule1.rect):
        window.blit(move,(-40,-100))
    
    pygame.display.update()
pygame.quit()

  

Ответ №1:

Улучшите надежность вашего кода. Убедитесь, что движение a Snake работает, даже если положение змеи далеко от path . Если proposed_move меньше self.path[0]-self.vel или self.path[1] self.vel , то Snake никогда не вернется к пути, потому self.vel что будет постоянно инвертироваться. Убедитесь, что направление движения всегда устанавливается вправо, если proposed_move < self.path[0] и убедитесь, что направление движения всегда устанавливается влево, если proposed_move > self.path[1] :

 class Snake:
    # [...]

    def move(self):
        if self.visible:
            # turn around if the move would go out-of-bounds
            proposed_move = self.x   self.vel

            # Move hits a boundary, so we need to turn around
            if proposed_move < self.path[0]:
                self.vel = abs(self.vel)
                self.Walking_index = 0
            if proposed_move > self.path[1]:
                self.vel = -abs(self.vel)
                self.Walking_index = 0

            # now make the correct move
            self.x  = self.vel   # add  /- velocity
  

Сделайте то же самое для Bat :

 class Bat:
    # [...]

    def move(self):
        if self.visible:
            # relizes when it hits bounds
            proposed_move = self.x   self.vel
            if proposed_move < self.path[0]:
                self.vel = abs(self.vel)
                self.Walking_index = 0
            if proposed_move > self.path[1]:
                self.vel = -abs(self.vel)
                self.Walking_index = 0
                # starting movment
            self.x  = self.vel
  

Вы должны упростить свой код.

Сохраните начальную позицию игрока ( start_x , start_y ) и методы класса player, которые возвращают текущую позицию игрока по отношению к начальной позиции ( get_x , get_y ):

 class Player:
    def __init__(self,x,y,width,height,color):
        self.start_x = x
        self.start_y = y
        self.x = x
        self.y = y
        #[...]

    def get_x(self):
        return self.x - self.start_x
    def get_y(self):
        return self.y - self.start_y
  

Вычислите позиции Snake , Bat , Platform и Rule по отношению к игроку:

 class Snake:
    # [...]

    def draw(self):
        self.move()
        self.rect.topleft = (self.x-playerman.get_x(), self.y-playerman.get_y())
        window.blit(self.no,self.rect)
  
 class Bat:
    # [...]

    def draw(self):
        self.move()
        self.rect.topleft = (self.x-playerman.get_x(), self.y-playerman.get_y())
        window.blit(self.no, self.rect)
  
 class Platform:
    # [...]

    def get_rect(self):
        self.rect.topleft = (self.x-playerman.get_x(), self.y-playerman.get_y())
        return self.rect
    def draw(self):
        pygame.draw.rect(window,self.color,self.get_rect())
  
 class Rule:
    # [...]

    def draw(self):
        self.rect.topleft = (self.x-playerman.get_x(), self.y-playerman.get_y())
  

Избавьтесь от компенсации перемещения игрока ( scroll и т.д.). В этом больше нет необходимости, поскольку объекты отображаются по отношению к игроку. Завершите основной цикл:

 run = True
while run:
    clock.tick(fps)
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            run = False
 
    # lets player move
    keys = pygame.key.get_pressed()
    
    if playerman.fall > 0 and keys[pygame.K_SPACE]:
        if keys[pygame.K_d]:
            playerman.direction = "jump1"
    else:
        if playerman.direction == "left":
            if keys[pygame.K_SPACE]:
                playerman.direction = "jump2"
 
    # direction for player animation and screen movment x
    if keys[pygame.K_d]:
        if not playerman.isJump:
            playerman.direction = "right"
    elif keys[pygame.K_a]:
        if not playerman.isJump:
            playerman.direction = "left"
    
    if playerman.direction == "right" and keys[pygame.K_SPACE]:
        playerman.direction = "jump1"
    if playerman.direction == "left" and keys[pygame.K_SPACE]:
        playerman.direction = "jump2"
 
    px, py = playerman.x, playerman.y

    # sides for player and player screen movment
    platform_rect_list = [p.rect for p in platforms]
    player_rect = playerman.get_rect()
    player_rect.topleft = (px, py)
 
    playerman.y = py
    if keys[pygame.K_d]:
        playerman.x  = playerman.speed
    if keys[pygame.K_a]:
        playerman.x -= playerman.speed
    if player_rect.collidelist(platform_rect_list) > 0:
        playerman.x = px      
 
    # About isJump
    if not playerman.isJump:
        playerman.y  = playerman.fall
        playerman.fall  = 1
        playerman.isJump = False
 
        # this part lets you jump on platform only the top 
        collide = False
        for Platform in platforms:
            player_rect = playerman.get_rect()
            player_rect.topleft = (playerman.x, playerman.y)   
            platform_rect = Platform.get_rect()
            if playerman.get_rect().colliderect(platform_rect):
                collide = True
                playerman.isJump = False
                if platform_rect.top > playerman.x:
                    playerman.y = platform_rect.top - playerman.height
                if player_rect.right > platform_rect.left and player_rect.left < platform_rect.left:
                    playerman.x = platform_rect.left - playerman.width
                if player_rect.left < platform_rect.right and player_rect.right > platform_rect.right:
                    playerman.x = platform_rect.right
 
            # colliding with floor      
            if player_rect.bottom >= 500:
                collide = True
                playerman.isJump = False
                playerman.Jumpcount = 10
                playerman.y = 500 - playerman.height
 
        # Jumping
        if collide:
            if keys[pygame.K_SPACE]:
                playerman.isJump = True
                playerman.y -= playerman.speed
            playerman.fall = 0
 
 
    # Jump Count
 
    else:
        if playerman.JumpCount >= 0:
            playerman.y -= (playerman.JumpCount*abs(playerman.JumpCount))*0.3
            playerman.JumpCount -= 1
        else:
            playerman.isJump = False
            playerman.JumpCount = 10
 
    redrawwindow()
    if playerman.rect.colliderect(rule1.rect):
        window.blit(move,(-40,-100))
 
    pygame.display.update()
  

Комментарии:

1. Итак, каждый раз, когда я касаюсь сторон моей платформы, это портит движение gyazo.com/0c25eef02a971d7b69b65eff40f330f2

2. Я только что удалил bats, и у меня все еще возникает проблема, я не знаю почему.

3. Каждый раз, когда я касаюсь сторон моей платформы, мой враг перестает двигаться влево и вправо и перемещает, скажем, игрока. Например, если я нажму d при столкновении со стороной моей платформы, мой враг переместится вправо