Bouncing an image in a polygonal way with pygame

我与影子孤独终老i 提交于 2019-12-25 02:58:52

问题


Hey guys am new to pygame .I have to make a ball image ball.jpg to bounce in polygonal way.I have also an another ball image which is running in a square way.What i need is to add an another ball image and bounce it in a polygonal way. My code is

import pygame
from itertools import cycle
pygame.init() 
screen = pygame.display.set_mode((300, 300)) 
s_r = screen.get_rect()
ball = pygame.image.load('ball.jpg')
player = pygame.Rect((100, 100, 50, 50))
timer = pygame.time.Clock()
speed = 5
up, down, left, right = (0, -speed), (0, speed), (-speed, 0), (speed, 0)

dirs = cycle([up, right, down, left])
dir = next(dirs)

while True:

for event in pygame.event.get():
    if event.type == pygame.QUIT:
        raise

# move player
player.move_ip(dir)
# if it's outside the screen
if not s_r.contains(player):
    # put it back inside
    player.clamp_ip(s_r)
    # and switch to next direction
    dir = next(dirs)

screen.fill(pygame.color.Color('Black'))
screen.blit(ball,player)

pygame.display.flip()
timer.tick(25)

This code works perfectly with one image ..What i need is to add an another image and it must run in polygonal shape on pygame window..

Hope you guys can help me out ..Thanks


回答1:


You'll need some vector math to do this.

Create a list of points that describe the path the object should move, then calculate a vector describing the direction from the current position to the target position. Then move the object by using that vector. Once you hit your target, aim for the next point to move.

Here's an example:

import pygame
import math
from itertools import cycle

# some simple vector helper functions, stolen from http://stackoverflow.com/a/4114962/142637
def magnitude(v):
    return math.sqrt(sum(v[i]*v[i] for i in range(len(v))))

def add(u, v):
    return [ u[i]+v[i] for i in range(len(u)) ]

def sub(u, v):
    return [ u[i]-v[i] for i in range(len(u)) ]    

def dot(u, v):
    return sum(u[i]*v[i] for i in range(len(u)))

def normalize(v):
    vmag = magnitude(v)
    return [ v[i]/vmag  for i in range(len(v)) ]

screen = pygame.display.set_mode((300, 300))
clock = pygame.time.Clock()    

class Ball(object):
    def __init__(self, path):
        self.x, self.y = (0, 0)
        self.speed = 2.5
        self.color = (200, 200, 200)
        self.path = cycle(path)
        self.set_target(next(self.path))

    @property
    def pos(self):
        return self.x, self.y

    # for drawing, we need the position as tuple of ints
    # so lets create a helper property
    @property
    def int_pos(self):
        return map(int, self.pos)

    @property
    def target(self):
        return self.t_x, self.t_y

    @property
    def int_target(self):
        return map(int, self.target)   

    def next_target(self):
        self.set_target(self.pos)
        self.set_target(next(self.path))

    def set_target(self, pos):
        self.t_x, self.t_y = pos

    def update(self):
        # if we won't move, don't calculate new vectors
        if self.int_pos == self.int_target:
            return self.next_target()

        target_vector = sub(self.target, self.pos) 

        # a threshold to stop moving if the distance is to small.
        # it prevents a 'flickering' between two points
        if magnitude(target_vector) < 2: 
            return self.next_target()

        # apply the balls's speed to the vector
        move_vector = [c * self.speed for c in normalize(target_vector)]

        # update position
        self.x, self.y = add(self.pos, move_vector)

    def draw(self):
        pygame.draw.circle(screen, self.color, self.int_pos, 4)

pygame.init()
quit = False

path = [(26, 43),
        (105, 110),
        (45, 225),
        (145, 295),
        (266, 211),
        (178, 134),
        (250, 56),
        (147, 12)]

path2 = [(26, 43),
         (105, 10),
         (45, 125),
         (150, 134),
         (150, 26),
         (107, 12)]

ball = Ball(path)
ball.speed = 1.9

ball2 = Ball(path2)
ball2.color = (200, 200, 0)

balls = [ball, ball2]

while not quit:
    quit = pygame.event.get(pygame.QUIT)
    pygame.event.poll()

    map(Ball.update, balls)

    screen.fill((0, 0, 0))

    map(Ball.draw, balls)

    pygame.display.flip()
    clock.tick(60)


Here's an example without a custom class:

import pygame
import math
from itertools import cycle

# some simple vector helper functions, stolen from http://stackoverflow.com/a/4114962/142637
def magnitude(v):
    return math.sqrt(sum(v[i]*v[i] for i in range(len(v))))

def sub(u, v):
    return [ u[i]-v[i] for i in range(len(u)) ]    

def normalize(v):
    vmag = magnitude(v)
    return [ v[i]/vmag  for i in range(len(v)) ]

screen = pygame.display.set_mode((300, 300))
clock = pygame.time.Clock()    

pygame.init()
quit = False

path = [(26, 43),
        (105, 110),
        (45, 225),
        (145, 295),
        (266, 211),
        (178, 134),
        (250, 56),
        (147, 12)]
path = cycle(path)         
target = next(path)
ball = pygame.rect.Rect(target[0], target[1], 10, 10)
speed = 3.6

while not quit:
    quit = pygame.event.get(pygame.QUIT)
    pygame.event.poll()

    if ball.topleft == target:
        target = next(path)

    target_vector = sub(target, ball.topleft) 

    if magnitude(target_vector) < 2: 
        target = next(path)
    else:
        move_vector = [c * speed for c in normalize(target_vector)]
        ball.move_ip(move_vector)

    screen.fill((0, 0, 0))
    pygame.draw.rect(screen, pygame.color.Color('Grey'), ball)
    pygame.display.flip()
    clock.tick(60)


来源:https://stackoverflow.com/questions/24510688/bouncing-an-image-in-a-polygonal-way-with-pygame

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!