5

First of all, I have to say that I'm french (so that you understand why I make all these mistakes lol)

I'm working on a physic game with python, pygame and pymunk : A ball (I'll call it X) will have to reach a Y point. It's a platformer 2d game. To help the ball reach that Y point, the user will have to add balls (right-click) and to make shapes to help the X move.

But... When I discovered (very recently, after I've started to code) the existence of classes and methods, and sprites in pygame, I was surprised and found that my code was "ugly", and too messy. But I don't want to rewrite the code, and my goal is to add an area in the "space" (the window) where, when X collides with it, an event happens (for example; next level, a picture appears, etc).

Can anyone help me ? I've been asking on french forums but can't find a solution. I hope that the stack-overflow's community will resolve that ^^

Thanks everybody :)

(CODE:)

    import pygame
from pygame.locals import *
from pygame.color import *

import random
import math
import pymunk
from pymunk import Vec2d
import pymunk as pm

X,Y = 0,1
### Physics collision types
COLLTYPE_DEFAULT = 0
COLLTYPE_MOUSE = 1
COLLTYPE_BALL = 2


def flipy(y):
    """Small hack to convert chipmunk physics to pygame coordinates"""
    return -y+600


def mouse_coll_func(space,arbiter):
    s1,s2 = arbiter.shapes
    s2.unsafe_set_radius(s2.radius + 0.15)
    return False

def main():

pygame.init()

fen1 = pygame.display.set_mode((1200, 675))
pygame.display.set_caption('Niveau 1')



marche = True

#Elements physiques
space = pm.Space()
space.gravity = Vec2d(0.0, -900.0)
clock = pygame.time.Clock()

#Balles
logos = []
logo_img = pygame.image.load("pringles.png").convert_alpha()
balls = []
ball_static = []


###Mouvements à la souris
mouse_body = pm.Body()
mouse_shape = pm.Circle(mouse_body, 3, Vec2d(99,99)) #0,0
mouse_shape.collision_type = COLLTYPE_MOUSE
space.add(mouse_shape)

space.add_collision_handler(COLLTYPE_MOUSE, COLLTYPE_BALL, None, mouse_coll_func, None, None)   

# Static line
static_body = pymunk.Body()
static_lines = [pymunk.Segment(static_body, (139.0, 480.0), (137.0, 479.0), 0.0)
               ,pymunk.Segment(static_body, (18.0, 497.0),  (249.0, 496.0), 0.0)
               ,pymunk.Segment(static_body, (252.0, 496.0), (309.0, 479.0), 0.0)
               ,pymunk.Segment(static_body, (309.0, 477.0), (358.0, 443.0), 0.0)
               ,pymunk.Segment(static_body, (358.0, 443.0), (407.0, 374.0), 0.0)
               ,pymunk.Segment(static_body, (407.0, 374.0), (433.0, 287.0), 0.0)
               ,pymunk.Segment(static_body, (482.0, 79.0),  (520.0, 34.0), 0.0)

               ,pymunk.Segment(static_body, (433.0, 287.0), (449.0, 193.0), 0.0)
               ,pymunk.Segment(static_body, (450.0, 193.0), (458.0, 130.0), 0.0)
               ,pymunk.Segment(static_body, (458.0, 130.0), (480.0, 79.0), 0.0)
               ,pymunk.Segment(static_body, (521.0, 34.0),  (573.0, 8.0), 0.0)
               ,pymunk.Segment(static_body, (573.0, 8.0), (645.0, -12.0), 0.0)

               ,pymunk.Segment(static_body, (645.0, -12.0), (714.0, -17.0), 0.0)
               ,pymunk.Segment(static_body, (714.0, -17.0), (805.0, -15.0), 0.0)
               ,pymunk.Segment(static_body, (805.0, -15.0), (889.0, -6.0), 0.0)
               ,pymunk.Segment(static_body, (890.0, -5.0), (995.0, 13.0), 0.0)
               ,pymunk.Segment(static_body, (995.0, 13.0), (1077.0, 23.0), 0.0)
               ,pymunk.Segment(static_body, (1077.0, 23.0), (1199.0, 24.0), 0.0)
               ,pymunk.Segment(static_body, (18.0, 497.0), (0.0, 515.0), 0.0)          
               ,pymunk.Segment(static_body, (1197.0, 598.0), (1197.0, -71.0), 0.0)]

#apparition de GES
rt = 200, 502
bodyrt = pm.Body(20, 100)
bodyrt.position = rt
shapert = pm.Circle(bodyrt, 40, (0,0))
shapert.friction = 90
shapert.collision_type = COLLTYPE_BALL
space.add(bodyrt, shapert)
#image = pygame.image.load("perso.png").convert_alpha()
ball_static.append(shapert)



# Static line
line_point1 = None
#static_lines = []
run_physics = True

###Friction avec les lignes 
for l in static_lines:
    l.friction = 0.5
space.add(static_lines)

#Fonctions à la souris 
while marche:
    for event in pygame.event.get():
        if event.type == QUIT:
            marche = False
        elif event.type == KEYDOWN and event.key == K_ESCAPE:
            marche = False
        elif event.type == KEYDOWN and event.key == K_p:
            pygame.image.save(fen1, "test_image.jpg")


        elif event.type == MOUSEBUTTONDOWN and event.button == 1:
            p = event.pos[X], flipy(event.pos[Y])
            body = pm.Body(20, 100)
            body.position = p
            shape = pm.Circle(body, 20, (0,0))
            shape.friction = 90
            shape.collision_type = COLLTYPE_BALL
            space.add(body, shape)
            balls.append(shape)


        elif event.type == MOUSEBUTTONDOWN and event.button == 3: 
            if line_point1 is None:
                line_point1 = Vec2d(event.pos[X], flipy(event.pos[Y]))
        elif event.type == MOUSEBUTTONUP and event.button == 3: 
            if line_point1 is not None:

                line_point2 = Vec2d(event.pos[X], flipy(event.pos[Y]))
                print (line_point1, line_point2)
                body = pm.Body()
                shape= pm.Segment(body, line_point1, line_point2, 0.0)
                shape.friction = 0.99
                space.add(shape)
                static_lines.append(shape)
                line_point1 = None

        elif event.type == KEYDOWN and event.key == K_SPACE:    
            run_physics = not run_physics


    p = pygame.mouse.get_pos()
    mouse_pos = Vec2d(p[X],flipy(p[Y]))
    mouse_body.position = mouse_pos




    #mise à jour
    dt = 1.0/60.0
    for x in range(1):
        space.step(dt)

    #################################################


    ### Dessiner fond

    fond1=pygame.image.load("niveau_1.gif")
    pygame.display.flip()
    fen1.blit(fond1, (0,0))

    for ball in balls:           
        r = ball.radius
        v = ball.body.position
        rot = ball.body.rotation_vector
        p = int(v.x), int(flipy(v.y))
        p2 = Vec2d(rot.x, -rot.y) * r * 0.9
        pygame.draw.circle(fen1, THECOLORS["blue"], p, int(r), 2)
        pygame.draw.line(fen1, THECOLORS["yellow"], p, p+p2)
        pe = pygame.image.load("pringles.png")
        pf = pygame.image.load("pringles3.png")
        fen1.blit(pe, (p2,v))  #essayer p2,v
        #fen1.blit(pf, (p, p2))

        ####

    for ball in ball_static:           
        r = ball.radius
        v = ball.body.position
        rot = ball.body.rotation_vector
        p = int(v.x), int(flipy(v.y))
        pt = int(v.x), int(flipy(v.y)) -90
        p2 = Vec2d(rot.x, -rot.y) * r * 0.9
        fdr = pygame.image.load("pringles2.png")
        pygame.draw.circle(fen1, THECOLORS["yellow"], p, int(r), 2)
        pygame.draw.line(fen1, THECOLORS["red"], p, p+p2)
        fen1.blit(fdr,(pt,pt))

    #   ESSAI
    if pygame.collide_rect(static_ball, static_lines):
        print ('....')

            ###

    if line_point1 is not None:
        p1 = line_point1.x, flipy(line_point1.y)
        p2 = mouse_pos.x, flipy(mouse_pos.y)
        pygame.draw.lines(fen1, THECOLORS["black"], False, [p1,p2])

    for line in static_lines:
        body = line.body

        pv1 = body.position + line.a.rotated(body.angle)
        pv2 = body.position + line.b.rotated(body.angle)
        p1 = pv1.x, flipy(pv1.y)
        p2 = pv2.x, flipy(pv2.y)
        pygame.draw.lines(fen1, THECOLORS["lightgray"], False, [p1,p2])
        ##########################################################









  if __name__ == '__main__':
      main()
1
  • 5
    I strongly recommend adding functions and classes to your game. It will make it far easier to manage as you continue to add to it, and it would make it a whole lot easier for other folks to read the code. Commented May 1, 2014 at 15:03

2 Answers 2

2

Since you are already using pymunk why not use it to detect the collision (instad of pygame as in the other answer).

Basically you need to create and add a pymunk.Shape object defining your goal, set its collision type and add a collision handler between the object and your player ball X.

Something like this should do it (pymunk 5.0 and later):

# Add a new collision type
COLLTYPE_GOAL = 3

# Define collision callback function, will be called when X touches Y 
def goal_reached(space, arbiter):
    print "you reached the goal!"
    return True

# Setup the collision callback function
h = space.add_collision_handler(COLLTYPE_BALL, COLLTYPE_GOAL)
h.begin = goal_reached

# Create and add the "goal" 
goal_body = pymunk.Body()
goal_body.position = 100,100
goal = pymunk.Circle(goal_body, 50)
goal.collision_type = COLLTYPE_GOAL
space.add(goal)

In older versions a handler is set in this way instead:

# Setup the collision callback function
space.add_collision_handler(COLLTYPE_BALL, COLLTYPE_GOAL, goal_reached, None, None, None)   
Sign up to request clarification or add additional context in comments.

6 Comments

Thank you for the answer :) I tried your method and, contrary to what I've already tried before, this seems to work :a kind of ray of hope. But I've got this error code : "Traceback (most recent call last): File "_ctypes/callbacks.c", line 285, in 'converting callback result' TypeError: an integer is required (got type NoneType) Exception in <function Space._get_cf1.<locals>.cf at 0x075B1420> ignored You Won" at infinite, when the ball collides with the area. I've already try to add i.e : text = int("2014") and the 2014 appears at infinite. I can't add a string or another type of objects.
Sorry! I had a small error in the code, the callback function must return a bool to indicate if the collision should count or not. I have updated my example.
Could you update this answer? It looks like Space.add_collision_handler doesn't take callback functions anymore (in pymunk 5.1). How does it work now?
@skrx Nowadays you get a container object back that you use to set the callbacks with, I updated the example.
@viblo It worked. But can i know what shapes collided ?
|
0

As I understand it, what you need is to know if sprites are colliding, and then if they are you want to do something. Pygame has a spritecollide function. Here is a wrapper function that makes it a bit easier, it will return True if two sprites are colliding.

def collides(sprite1,sprite2):
    sprite1_group = pygame.sprite.RenderUpdates()    #this creates a render updates group, as the sprite collide function requires one of its arguments to be a group.
    sprite1_group.add(sprite1)
    collisions = pygame.sprite.spritecollide(sprite2, sprite1_group, False)  #runs spritecollide, specifying the sprite, the group, and the last parameter, which should almost always be false.
    for other in collisions:
        if other != sprite2:     #spritecollide registers a sprites collision with itself, so this filters it
            return True

now you have a function that can detect collisions, like so:

if collides(sprite1,sprite2)

If you need to handle this event without disrupting your regular code, you can always use threading.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.