0

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

使用 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()
4

1 回答 1

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)。这引起了一个奇怪的观察:如果我们将dx和乘以dy一个标量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)长度为 1 。预先计算以避免一些潜在的问题。将这个新向量乘以你想要的速度:这是你想要的速度。dxdyL(dx, dy)L

于 2013-10-24T21:37:31.957 回答