2017-01-13 1 views
0

화면 가장자리에서 튀어 나와서 상자가 튀어 나오는 애니메이션을 만들려고합니다. 그리고 시간 기반 애니메이션과 더러운 직사각형을 사용하여이를 수행하려고합니다.파이 게임의 고르지 애니메이션

상자를 움직일 수있었습니다. 그러나 애니메이션이 고르지 않습니다.

30 FPS : https://www.youtube.com/watch?v=0de8ENxn7GQ

60 FPS : 여기 https://www.youtube.com/watch?v=b5sXgeOlgHU

그리고 내 코드입니다 : 아무것도 내가

import sys 
import random 

import pygame 


class Box: 

    def __init__(self, x, y): 
     self.width = 38 
     self.height = 38 
     self.color = (255, 0, 0) 
     self.x = x 
     self.y = y 
     self.old_x = x 
     self.old_y = y 
     self.d_x = 1 
     self.d_y = -1 
     self.px_per_second = 200 

    def move(self): 
     self.old_x = self.x 
     self.old_y = self.y 
     if self.x <= 0: 
      self.d_x *= -1 
     if self.x + self.width >= task.width: 
      self.d_x *= -1 
     if self.y <= 0: 
      self.d_y *= -1 
     if self.y + self.height >= task.height: 
      self.d_y *= -1 
     self.x += ((self.px_per_second*self.d_x)* 
        (task.ms_from_last_frame/1000.0)) 
     self.y += ((self.px_per_second*self.d_y)* 
        (task.ms_from_last_frame/1000.0)) 

    def draw(self): 
     self.x_i = int(self.x) 
     self.y_i = int(self.y) 
     self.old_x_i = int(self.old_x) 
     self.old_y_i = int(self.old_y) 
     _old_rect = (pygame.Rect(self.old_x_i, self.old_y_i, 
           self.width, self.height)) 
     _new_rect = (pygame.Rect(self.x_i, self.y_i, self.width, self.height)) 
     if _old_rect.colliderect(_new_rect): 
      task.dirty_rects.append(_old_rect.union(_new_rect)) 
     else: 
      task.dirty_rects.append(_old_rect) 
      task.dirty_rects.append(_new_rect) 
     pygame.draw.rect(task.screen, task.bg_color, _old_rect) 
     pygame.draw.rect(task.screen, (self.color), _new_rect) 


class ObjectTask: 

    def __init__(self, width, height): 
     pygame.init() 
     self.max_fps = 60 
     self.clock = pygame.time.Clock() 
     self.width = width 
     self.height = height 
     self.bg_color = (255, 255, 255) 
     self.dirty_rects = [] 
     self.screen = pygame.display.set_mode((self.width, self.height), 
               pygame.FULLSCREEN) 
     self.screen.fill(self.bg_color) 
     pygame.display.update() 

    def animation_loop(self): 
     self.box1 = Box(self.width/2, self.height/2) 
     while 1: 
      self.ms_from_last_frame = self.clock.tick(self.max_fps) 
      self.box1.move() 
      self.box1.draw() 
      pygame.display.update(self.dirty_rects) 
      self.dirty_rects = [] 
      for event in pygame.event.get(): 
       if event.type == pygame.QUIT: 
        pygame.quit() 


if __name__ == "__main__": 
    task = ObjectTask(726, 546) 
    task.animation_loop() 

거기에 여기에 대해 무엇을 이야기하고있는 것을 도시 두 개의 동영상이 있습니다 choppiness을 줄이기 위해 할 수 있습니까? 또한, 나는 파이 게임 (Pygame)에 익숙하지 않기 때문에 내가 잘못하고/비효율적으로하는 것을 보았다면 알려주십시오.

12 비트 RAM이 장착 된 64 비트 Windows 7, i5-6300u 컴퓨터에서 애니메이션을 실행하고 있습니다. 파이썬 2.7.12와 파이 게임 1.9.2를 사용하고 있습니다.

미리 감사드립니다.

+1

많은 불필요한 속성. 'self.x_i','self.old_x_i' (그리고 y's)는 지역 변수가 될 수 있습니다. 'self.d_x'는'200'과'self.d_y = -200'이므로'self.px_per_second'는 필요 없습니다. 'self.box1'은 또한 지역 변수가 될 수 있습니다. 그리고 단순화를 위해'_old_rect = pygame.Rect (self.x, self.y, self.height, self.width)'를 사용하여 새로운 사각형을 만들 수 있습니다. x와 y를 암시 적으로 정수로 변환하므로 필요가 없습니다. 너 스스로해라. 귀하의 비디오를 기반으로하면 귀하의 더러운 rects에 문제가있는 것 같습니다. 잠깐 살펴 보겠습니다. 몇 가지 간단한 팁을 공유 할 수있을 것 같아요. –

답변

1

나는 약간의 시간이 끝났으며 내가이 프로그램을 어떻게 쓸 것인지 생각해 보았습니다. 나는 모든 것이 주석에서 무엇을하는지 설명하려고 노력했다. 내가 당신의 ObjectTask 클래스를 제거했다. 왜냐하면 모든 것이 하나의 함수에 들어갈 수 있었고 함수가 깔끔했기 때문이다 (그들은 더 빠르고 읽기 쉽다.).

변수를 전역 변수 (task 개체)에서 읽는 대신 메서드로 전달하므로 프로그램을 모듈화하고 변경하기가 쉬우므로/refactor로 변경했습니다.

마지막으로 몇 가지 특성을 하나에 넣었습니다. xy이 연결되어 있으므로 하나의 공통 속성 인 position에 넣습니다.

import pygame 
pygame.init() 


# It's convenient if all your visible objects inherit 'pygame.sprite.Sprite'. It allows you to use sprite groups and 
# some useful collision detection functions. 
class Box(pygame.sprite.Sprite): 
    def __init__(self, x, y, screen_width, screen_height): 
     super(Box, self).__init__() # Initialize the 'pygame.sprite.Sprite' (the super class). 
     self.size = (38, 38) 
     self.color = (255, 0, 0) 
     self.position = pygame.math.Vector2(x, y) # Vector is a 2-element tuple with some neat methods shown later. 
     self.velocity = pygame.math.Vector2(200, -200) 
     self.screen_size = (screen_width, screen_height) 

     # Instead of drawing the rectangle onto the screen we're creating an image which we 'blit' (put) onto the screen 
     self.image = pygame.Surface(self.size) 
     self.image.fill(self.color) 

     # We create a rectangle same size as our image and where the top left of the rectangle is positioned at our 
     # 'position'. 
     self.rect = self.image.get_rect(topleft=self.position) 

    # Changing name to update. Game objects usually have two methods 'update' and 'draw', where 'update' is the function 
    # that will be called every game loop and update the object, and 'draw' draws the game object every game loop. 
    def update(self, dt): # 'dt' (delta time) is what you formerly called task.ms_from_last_frame. 
     # unpack the variables so it's easier to read. Not necessary, but nice. 
     width, height = self.size 
     x, y = self.position 
     screen_width, screen_height = self.screen_size 

     if x <= 0 or x + width >= screen_width: # Only one if-statement needed. 
      self.velocity[0] *= -1 # First element is the x-velocity. 
     if y <= 0 or y + height >= screen_height: 
      self.velocity[1] *= -1 # Second element is y-velocity. 

     # Addition and subtraction works element-wise with vectors. Adding our two vectors 'position' and 'velocity': 
     # position += velocity <=> position = position + velocity 
     # is the same as this: 
     # position_x, position_y = position_x + velocity_x, position_y + position_y 
     # 
     # Multiplication and division works on all elements. So 'velocity * dt/1000' is the same as: 
     # velocity_x * dt/1000, velocity_y * dt/1000 
     self.position += self.velocity * dt/1000 

     # Instead of creating a new rect we just move the top left corner of our rect to where we calculated our 
     # position to be. 
     self.rect.topleft = self.position 

    # 'surface' is the Surface object you want to draw on (in this case the screen). 
    def draw(self, surface): 
     # This puts our image unto the screen at the given position. 
     surface.blit(self.image, self.position) 


def main(): 
    max_fps = 60 
    clock = pygame.time.Clock() 
    bg_color = (255, 255, 255) 
    width, height = 726, 546 
    screen = pygame.display.set_mode((width, height)) 
    screen.fill(bg_color) 

    box1 = Box(width/2, height/2, width, height) 
    sprite_group = pygame.sprite.Group(box1) 
    while 1: 
     # First handle time. 
     dt = clock.tick(max_fps) 

     # Then handle events. 
     for event in pygame.event.get(): 
      if event.type == pygame.QUIT: 
       quit() # 'pygame.quit' does not quit the program! It only uninitialize the pygame modules. 
      elif event.type == pygame.KEYDOWN: 
       if event.key == pygame.K_ESCAPE: 
        quit() 

     # Update your objects. 
     sprite_group.update(dt) # Calls the update method on all sprites in the group. 

     # Draw your objects. 
     screen.fill(bg_color) # Clear the screen. 
     sprite_group.draw(screen) # Draws all sprites on the screen using the 'image' and 'rect' attributes. 

     # Display everything you've drawn. 
     pygame.display.update() 


if __name__ == "__main__": 
    main() 

이 예제에서 나는 더러운 직사각형을 추적하지 않았습니다. 나는 그것이 지터의 원인이 무엇인지 경험했습니다. 필자가 제공 한이 예제는 적절하게 작동해야하지만 때때로 지터가 발생합니다. 당신이 더러운의 구형 추적이 예를 시도 할 경우, 단지 변경 :

sprite_group = pygame.sprite.Group(box1) 

sprite_group = pygame.sprite.RenderUpdates(box1) 

sprite_group.draw(screen) # Draws all sprites on the screen using the 'image' and 'rect' attributes. 

# Display everything you've drawn. 
pygame.display.update() 

에 사용중인

dirty_rects = sprite_group.draw(screen) # Draws all sprites on the screen using the 'image' and 'rect' attributes. 

# Display everything you've drawn. 
pygame.display.update(dirty_rects) # Update only the areas that have changes 
관련 문제