2017-12-03 30 views
1

파이 게임에서 낙하 효과를 만들려고하는데 특정 문제가 있습니다. 플레이어가 떨어지거나 플랫폼과 충돌 할 때마다 플레이어 클래스가 위아래로 진동하기 시작합니다. 나는 이것이 내 업데이트 루프와 관련이 있다고 확신하지만 그것이 정확히 무엇인지 확신 할 수 없다. 난 아무 소용이 계층 구조를 다시 정렬 같은 여러 가지 방법을 시도했다. 나는 온라인 검색을 끝내지 만 대답이 없다. 그래서 누군가가 이것을 도울 수 있다면 정말 고맙겠습니다.파이 게임 충돌로 인해 플레이어가 위아래로 진동합니다.

고맙습니다!

player.pos.y = hit[0].rect.top - hit[0].rect.height 

그것은 아무 의미 :

import pygame as pg 
import os 

#vector 
VEC = pg.math.Vector2 

def paint(parent, color=None): 
    """ fills the background for surfaces. 
     color: for none sprite surfaces optional parameter if given 
    """ 

    #set background color based on surface type 
    if color: 
     #class based surfaces or sprites 
     background = pg.Color(color) 
    else: 
     #none sprite surfaces usuallly not class 
     background = pg.Color(parent.background) 

    #check for image attribure 
    #if found fill the image's backround 
    if hasattr(parent, "image"): 
     parent.image.fill(background) 
    #if "image" not found fill the surface itself 
    else: 
     parent.fill(background) 



class Asset(pg.sprite.Sprite): 
    """ asset class functions as base class for various assets in this case 
     either a player asset or a block asset group """ 

    #if the given family name(see bellow in constructor) is block, 
    #all instances of block will be added to this group else its ignored 
    GROUP = pg.sprite.Group() 
    def __init__(self, parent=None, family=None, pos=None): 
     """ 
      parent:surface asset is being rendered to 
      family:type of asset(type is not used due to it being a buil-in) 
      pos: position of asset 
     """ 
     super().__init__() 

     self.parent = parent 
     self.family = family 

     self.pos = VEC(pos) 
     self.size = [20, 20] 
     #background will be based on family 
     self.background = {"block":"#000000","player":"#ff0000"}[self.family] 

     self.image, self.rect = self.set_image() 

     #see class documention for explanation 
     if self.family == "block": 
      Asset.GROUP.add(self) 
     #if family is player add essential fields for physics 
     else: 
      #velocity 
      self.vel = VEC(3, 3) 
      #acceleration(x:friction, y:gravity) 
      self.ac = VEC(.3, .3) 
      #jump height 
      self.height = 5 


    def update(self): 
     if self.family == "player": 
      #fall code 
      self.vel.y += self.ac.y 
      self.pos.y += self.vel.y 

      #prevents player from falling of the edge and adds teleportation 
      if self.pos.x + self.size[0] <= 0: 
       self.pos.x = 399 
      elif self.pos.x >= 400: 
       self.pos.x = 1 - self.size[0] 

     #updates asset rect postion 
     self.rect.topleft = self.pos 

    def render(self): 
     """ renders image to parent surface """ 
     self.parent.blit(self.image, self.rect) 


    def set_image(self): 
     """creates initial image and rect for sprite""" 
     self.image = pg.Surface(self.size) 
     paint(self) 

     self.rect = self.image.get_rect() 
     self.rect.topleft = self.pos 

     return self.image, self.rect 

    def move(self, key): 
     """handles player movmet""" 
     for i in range(2): 
      #checks for right or left movment 
      if key[[pg.K_LEFT, pg.K_RIGHT][i]]: 
       self.pos.x += self.vel.x*[-1, 1][i] 

    def jump(self): 
     """ handles jumping """ 
     self.vel.y = -self.height 


def block_collision(player, blocks): 
    """collision detection between blocks and player""" 
    hit = pg.sprite.spritecollide(player, blocks, False) 

    if hit: 
     if player.rect.bottom >= hit[0].rect.top: 
      player.pos.y = hit[0].rect.top - hit[0].rect.height 
      player.vel.y = 0 


def main(): 
    POS = [0, 0] 
    SIZE = [400, 400] 
    TITLE = "Test" 
    BACKGROUND = "#ffffff" 

    CLOCK = pg.time.Clock() 
    FPS = 60 
    RUN = True 
    os.environ["SDL_VIDEO_CENTERED"] = "1" 

    win = pg.display.set_mode(SIZE) 
    pg.display.set_caption(TITLE) 

    # create blocks group 
    #NOTE:blocks do not need a variable instance because they are 
    #automatically added to the class group on construction 
    for x in range(20): 
     Asset(family="block", pos=[x*20, 380]) 

    #set player filed 
    player = Asset(win, family="player", pos=[20, 20]) 


    while RUN: 
     for event in pg.event.get(): 
      if event.type == pg.QUIT: 
       RUN = False 
      elif event.type == pg.KEYDOWN: 
       if event.key == pg.K_UP: 
        #player jump 
        player.jump() 

     #player movement 
     player.move(pg.key.get_pressed()) 

     #fill window background 
     paint(win, BACKGROUND) 

     #check for collision 
     block_collision(player, Asset.GROUP) 

     #update player 
     player.update() 
     #update block group 
     Asset.GROUP.update() 

     #render player 
     player.render() 
     #render block group 
     Asset.GROUP.draw(win) 

     pg.display.update() 
     CLOCK.tick(FPS) 


if __name__ == '__main__': 
    main() 
+0

변수의 값,'if/else' 문 등의 결과를 보려면'print()'를 먼저 사용하십시오. 왜 제대로 작동하지 않는지 알아내는 데 도움이됩니다. – furas

답변

2

함께 문제를

첫 번째 줄 두 실수 있습니다. top - heightbottom 그래서 당신이

player.pos.y = hit[0].rect.bottom 

이 같은를 제공하지만, 당신은 당신이 player.pos를 사용하는 이유는 항상 player.rect 값이 같다면 나도 몰라 여기 player.rect.bottom

player.rect.bottom = hit[0].rect.top 
player.pos.y = player.rect.y 

(와 함께 hit[0].rect.top 필요 그리고 rect에는 rect.bottom, rect.center 등과 같은 유용한 필드가 있으며 rect.bottom, rect.center 등을 변경하면 rect.x, rect.y 등이 자동으로 다시 계산됩니다.

당신은 모든 이동을해야 확인 collisionts

# player movement 
    player.move(pg.key.get_pressed()) 

    # update player 
    player.update() 

    #update block group 
    Asset.GROUP.update() 

    # check for collision - after all moves 
    block_collision(player, Asset.GROUP) 

전체 코드

import pygame as pg 
import os 

#vector 
VEC = pg.math.Vector2 

def paint(parent, color=None): 
    """ fills the background for surfaces. 
     color: for none sprite surfaces optional parameter if given 
    """ 

    #set background color based on surface type 
    if color: 
     #class based surfaces or sprites 
     background = pg.Color(color) 
    else: 
     #none sprite surfaces usuallly not class 
     background = pg.Color(parent.background) 

    #check for image attribure 
    #if found fill the image's backround 
    if hasattr(parent, "image"): 
     parent.image.fill(background) 
    #if "image" not found fill the surface itself 
    else: 
     parent.fill(background) 



class Asset(pg.sprite.Sprite): 
    """ asset class functions as base class for various assets in this case 
     either a player asset or a block asset group """ 

    #if the given family name(see bellow in constructor) is block, 
    #all instances of block will be added to this group else its ignored 
    GROUP = pg.sprite.Group() 
    def __init__(self, parent=None, family=None, pos=None): 
     """ 
      parent:surface asset is being rendered to 
      family:type of asset(type is not used due to it being a buil-in) 
      pos: position of asset 
     """ 
     super().__init__() 

     self.parent = parent 
     self.family = family 

     self.pos = VEC(pos) 
     self.size = [20, 20] 
     #background will be based on family 
     self.background = {"block":"#000000","player":"#ff0000"}[self.family] 

     self.image, self.rect = self.set_image() 

     #see class documention for explanation 
     if self.family == "block": 
      Asset.GROUP.add(self) 
     #if family is player add essential fields for physics 
     else: 
      #velocity 
      self.vel = VEC(3, 3) 
      #acceleration(x:friction, y:gravity) 
      self.ac = VEC(.3, .3) 
      #jump height 
      self.height = 5 


    def update(self): 
     if self.family == "player": 
      #fall code 
      self.vel.y += self.ac.y 
      self.pos.y += self.vel.y 

      #prevents player from falling of the edge and adds teleportation 
      if self.pos.x + self.size[0] <= 0: 
       self.pos.x = 399 
      elif self.pos.x >= 400: 
       self.pos.x = 1 - self.size[0] 

     #updates asset rect postion 
     self.rect.topleft = self.pos 

    def render(self): 
     """ renders image to parent surface """ 
     self.parent.blit(self.image, self.rect) 


    def set_image(self): 
     """creates initial image and rect for sprite""" 
     self.image = pg.Surface(self.size) 
     paint(self) 

     self.rect = self.image.get_rect() 
     self.rect.topleft = self.pos 

     return self.image, self.rect 

    def move(self, key): 
     """handles player movmet""" 
     for i in range(2): 
      #checks for right or left movment 
      if key[[pg.K_LEFT, pg.K_RIGHT][i]]: 
       self.pos.x += self.vel.x*[-1, 1][i] 

    def jump(self): 
     """ handles jumping """ 
     self.vel.y = -self.height 


def block_collision(player, blocks): 
    """collision detection between blocks and player""" 
    hit = pg.sprite.spritecollide(player, blocks, False) 

    if hit: 
     if player.rect.bottom >= hit[0].rect.top: 
      #player.pos.y = hit[0].rect.top - hit[0].rect.height 
      player.rect.bottom = hit[0].rect.top 
      player.pos.y = player.rect.y 
      player.vel.y = 0 


def main(): 
    POS = [0, 0] 
    SIZE = [400, 400] 
    TITLE = "Test" 
    BACKGROUND = "#ffffff" 

    CLOCK = pg.time.Clock() 
    FPS = 60 
    RUN = True 
    os.environ["SDL_VIDEO_CENTERED"] = "1" 

    win = pg.display.set_mode(SIZE) 
    pg.display.set_caption(TITLE) 

    # create blocks group 
    #NOTE:blocks do not need a variable instance because they are 
    #automatically added to the class group on construction 
    for x in range(20): 
     Asset(family="block", pos=[x*20, 380]) 

    #set player filed 
    player = Asset(win, family="player", pos=[20, 20]) 


    while RUN: 

     # --- events --- 

     for event in pg.event.get(): 
      if event.type == pg.QUIT: 
       RUN = False 
      elif event.type == pg.KEYDOWN: 
       if event.key == pg.K_UP: 
        #player jump 
        player.jump() 

     #player movement 
     player.move(pg.key.get_pressed()) 

     # --- updates -- 

     #update player 
     player.update() 

     #update block group 
     Asset.GROUP.update() 

     #check for collision 
     block_collision(player, Asset.GROUP) 

     # --- draws --- 

     #fill window background 
     paint(win, BACKGROUND) 

     #render player 
     player.render() 

     #render block group 
     Asset.GROUP.draw(win) 

     pg.display.update() 
     CLOCK.tick(FPS) 

    # ---- end --- 
    pg.quit() 

if __name__ == '__main__': 
    main() 
전에 :

그래서 제 1 보정은

if hit: 
    if player.rect.bottom >= hit[0].rect.top: 
     #player.pos.y = hit[0].rect.top - hit[0].rect.height 

     player.rect.bottom = hit[0].rect.top 
     player.pos.y = player.rect.y 

     player.vel.y = 0 

두 번째입니다