Pygame:在窗口边缘移动旋转图像

时间:2013-10-24 18:26:24

标签: python pygame

我有一项任务要求我执行以下操作:

使用Google的高级图片搜索功能,可以找到合理大小的球形图像,该图像可以自由重复使用并且包含透明度。修改示例代码,以便您的球在屏幕底部来回滑动。球从左侧向右侧需要2秒钟。 改进问题5的动画,使球准确地旋转,好像它来回滚动一样。 修改问题6的动画,使球绕屏幕边缘逆时针移动

我在最后一部分。尝试修改问题6的动画来执行此操作:(1:24) http://www.youtube.com/watch?v=CEiLc_UFNLI&feature=c4-overview&list=UUpbgjjXBL3hdTKDZ0gZvdWg

我很难过。我似乎无法理解我将如何让球从一个点慢慢移动到另一个点。球是一个图像。这是我到目前为止所做的,但它不起作用。

"""Some simple skeleton code for a pygame game/animation

This skeleton sets up a basic 800x600 window, an event loop, and a
redraw timer to redraw at 30 frames per second.
"""
from __future__ import division
import math
import sys
import pygame


class MyGame(object):
    def __init__(self):
        """Initialize a new game"""
        pygame.mixer.init()
        pygame.mixer.pre_init(44100, -16, 2, 2048)
        pygame.init()

        # set up a 640 x 480 window
        self.width = 800
    self.height = 600
    self.img = pygame.image.load('ball.png')
    self.screen = pygame.display.set_mode((self.width, self.height))
    self.x = 0
    self.y = 0
    self.angle = 0
    self.rotate_right=True
    self.first = True
    #0: Move bottomleft to bottomright 1: Move from bottomright to topright 2:Move from topright to topleft 3:Move from topleft to bottomleft
    self.mode = 0
    # use a black background
    self.bg_color = 0, 0, 0

    # Setup a timer to refresh the display FPS times per second
    self.FPS = 30
    self.REFRESH = pygame.USEREVENT+1
    pygame.time.set_timer(self.REFRESH, 1000//self.FPS)


def get_mode(self):
    rect = self.img.get_rect()

    if self.first == True:
        self.first = False 
        return

    if (self.x, self.y) == (0, self.height - rect.height):
        #Our starting point, bottom left
        self.mode = 0
    elif (self.x, self.y) == (self.width-rect.width, self.height-rect.height):
        #Bottom right
        self.mode = 1
    elif (self.x, self.y) == (self.width-rect.width, 0):
        #Top Right
        self.mode = 2
    elif (self.x, self.y) == (0,0):
        #Top Left
        self.mode = 3

def get_target(self):
    rect = self.img.get_rect()

    if self.mode == 0:
        targetPosition = (0, self.height - rect.height)

    elif self.mode == 1:
        targetPosition = (self.width-rect.width, self.height-rect.height)

    elif self.mode == 2:
        targetPosition = (self.width-rect.width, 0)

    elif self.mode == 3:
        targetPosition = (0,0)

    return targetPosition

def get_angle(self):
    if self.angle == 360:
        self.rotate_right = False
    elif self.angle == 0:
        self.rotate_right = True

    if self.rotate_right == True:
        self.angle+=12
    else:
        self.angle-=12

def run(self):
    """Loop forever processing events"""
    running = True
    while running:
        event = pygame.event.wait()

        # player is asking to quit
        if event.type == pygame.QUIT:
            running = False

        # time to draw a new frame
        elif event.type == self.REFRESH:
            self.draw()

        else:
            pass # an event type we don't handle            

def draw(self):
    """Update the display"""
    # everything we draw now is to a buffer that is not displayed
    self.screen.fill(self.bg_color)

    #Draw img
    rect = self.img.get_rect()

    #Note: this can be made dynamic, but right now since this is typically a poor structure, we will use static values.
    #80 is the padding, so it hits right before.

    #0,0 : top left
    #self.width-rect.width, 0  : top right
    #0, self.height-rect.height : bottom left  
    #self.width-rect.width, self.height-rect.height : bottom right

    targetPosition = ()

    #img = pygame.transform.rotate(self.img, self.angle)
    img = self.img

    self.get_angle()
    self.get_mode()

    targetPosition = self.get_target()

    print targetPosition
    print self.x, self.y
    if self.x < targetPosition[0]:
        self.x+= targetPosition[0]-self.x//self.FPS

    elif self.x > targetPosition[0]:
        self.x-= targetPosition[0]+self.x//self.FPS

    if self.y < targetPosition[1]:
        print "s"
        self.y+= targetPosition[1]-self.y//self.FPS

    elif self.y > targetPosition[1]:
        self.y-= targetPosition[1]+self.y//self.FPS 


    rect = rect.move(self.x, self.y)

    self.screen.blit(img, rect)

    # flip buffers so that everything we have drawn gets displayed
    pygame.display.flip()


MyGame().run()
pygame.quit()
sys.exit()

1 个答案:

答案 0 :(得分:0)

正在发生的事情是你的球从(0,0)(左上角)开始,目标为(0,550)(左下角),发现它的目标位于y以下,

迅速继续增加其地位

targetPosition[1] - (self.y // self.FPS)

当然等于550,所以它会立即捕捉到屏幕的底部。

然后在下一个绘制循环中,get_mode()出现并说'好吧,我在(0, 550),所以我会继续将模式设置为0'。然后get_target()出现并说'好吧,我处于模式0,让我们转到(0, 550)

然后在下一个绘制循环中再次发生这种情况,下一个和下一个...当然,你的球不会去任何地方。

您需要做一些事情来修复您的示例:

  • 将您的目标位置修复为get_target()。现在他们的目标是触发这些模式的过渡点,因此你的球不会去任何地方。
  • 更仔细地考虑你的速度陈述:现在他们的行为有些奇怪。正确执行此操作的一种方法是确定(dx, dy) - 即从您到目的地的绝对向量 - 然后对此向量进行标准化,使其指向相同的方向,但其幅度等于您所需的速度。这种方法适用于您想要的任何目标位置。

详细阐述第二点:

假设我们在(x, y),我们正试图前往(target_x, target_y)

dx = target_x - x, dy = target_y - y。这应该是没有争议的:我们只是差一点。

然后我们记住毕达哥拉斯定理:给出一个带有边a, b, c和斜边c的直角三角形,我们记得len(c)**2 == len(a)**2 + len(b)**2。向量的含义相同:向量(x, y)的长度是边长为xy的直角三角形的斜边。如果你想自己证明这一点,你可以在一张纸上画出来。

鉴于此,我们可以找到(dx, dy)的长度:它只是L(dx, dy) = sqrt(dx*dx + dy*dy)。这有助于一个奇怪的观察:如果我们将dxdy乘以标量k,我们也会将长度乘以k,因为sqrt(dx*k*dx*k + dy*k*dy*k) == sqrt(k*k*(dx*dx + dy*dy)) == k*sqrt(dx*dx + dy*dy)

通过将(dx, dy)dx除以dy,我们可以找到与L(dx, dy)平行且长度为1的向量。预先计算L以避免一些潜在问题。将这个新矢量乘以你想要的速度:这是你想要的速度。