0

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 Answers1

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)

enter image description here


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)
sloth
  • 99,095
  • 21
  • 171
  • 219
  • ..this is what exactly i wanted ..:D – user3792941 Jul 01 '14 at 13:30
  • ..since am not in math ..its very difficult to do this ..:D ..thanx for the help anyways – user3792941 Jul 01 '14 at 13:31
  • ..but how can i add my image file instead of that balls which we have create..i have tried replacing pygame.draw.circle(screen, self.color, self.int_pos, 4) to screen.blit(ball) ..but it didnt worked.. – user3792941 Jul 01 '14 at 13:34
  • @user3792941 should be `screen.blit(ball, self.int_pos)`. make sure you loaded the image into a variable named `ball`. – sloth Jul 01 '14 at 13:37
  • but how can i load an image into varibale with class ..is it like self.ball = pygame.image.load()..and on which function ?? – user3792941 Jul 01 '14 at 13:44
  • @user3792941 Yes. You can use `self.img = pygame.image.load('path_to_image')` in the `__init__` function, then use `screen.blit(self.img, self.int_pos)` in the `draw` function. – sloth Jul 01 '14 at 13:48
  • ..this one helped ..but i still have a doubt when i gone through the code..where have you defined self.pos ? – user3792941 Jul 01 '14 at 13:56
  • It's a property that calls the function `pos()`, defined as `@property def pos(self):` – sloth Jul 01 '14 at 14:04
  • thanx ..but i still have a doubt .in the last part you have shown me to move the image in squarely manner with some single pieces of code ..but you have used classes here ...can we do like polgonobject.move_ip(dir) as like of the last question ? – user3792941 Jul 01 '14 at 14:15
  • ..you are just an experts so its really easy to understand it for you ..am just a beginner in pygame so for me its bit hard to understand the code in classes ..do you know how to rotate the image in polygonal way without classes..Just like you did in last answer :) – user3792941 Jul 01 '14 at 14:31
  • I added an example without classes – sloth Jul 01 '14 at 14:50
  • thanks for the help.now it makes some sence for me ..:D – user3792941 Jul 01 '14 at 15:05
  • ..in the edit you gave me loads only 1 image ..but i want to load the two images – user3792941 Jul 01 '14 at 15:41
  • it would be really helpful if you edit the updated code for the functioning of two images – user3792941 Jul 01 '14 at 15:46
  • ..do i need to ask a new question or can you help me with this ? – user3792941 Jul 01 '14 at 16:07
  • http://stackoverflow.com/questions/24523607/start-event-when-button-is-clicked-with-pygame ..please have a look at this – user3792941 Jul 02 '14 at 05:44