Pygame碰撞代码

5
首先,我必须说一下我是法国人(这样你就明白我为什么会犯这些错误了,哈哈)
我正在使用Python、Pygame和Pymunk开发一个物理游戏:一个小球(我将它称为X)需要到达一个Y点。这是一个2D平台游戏。为了帮助球到达Y点,用户需要添加球(右键单击)并创建形状来帮助X移动。
但是...当我最近发现Pygame中存在类、方法和精灵时,我感到惊讶,并发现我的代码"丑陋"而且太乱了。但我不想重写代码,我的目标是在“空间”(窗口)中添加一个区域,当X与之碰撞时,会发生一个事件(例如:下一级别,出现一张图片等)。
有谁能帮我吗?我在法国论坛上问过,但找不到解决方案。希望Stack Overflow社区能解决这个问题^^
谢谢大家 :)
(代码:)
    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()

5
我强烈建议在你的游戏中添加函数和类。这将使你在不断添加内容时更容易管理,并且可以使其他人更轻松地阅读代码。 - dano
2个回答

2

既然您已经在使用pymunk,为什么不使用它来检测碰撞(而不是像其他答案中使用pygame)。

基本上,您需要创建并添加一个pymunk.Shape对象来定义您的目标,设置其碰撞类型并在对象和您的球X之间添加碰撞处理程序。

像这样的东西应该可以解决问题(pymunk 5.0及更高版本):

# 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)

在旧版本中,处理程序是以以下方式设置的:
# Setup the collision callback function
space.add_collision_handler(COLLTYPE_BALL, COLLTYPE_GOAL, goal_reached, None, None, None)   

谢谢您的回答 :) 我尝试了您的方法,与我之前尝试过的相反,这似乎有效:一种希望的曙光。但是我遇到了这个错误代码: “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" 当球与区域碰撞时,会出现无限的情况。 我已经尝试添加例如:text = int("2014"),然后2014会无限出现。我无法添加字符串或其他类型的对象。 - user3593048
抱歉!我的代码有一个小错误,回调函数必须返回一个布尔值来指示是否应该计算碰撞。我已经更新了我的示例。 - viblo
你能更新一下这个答案吗?看起来 Space.add_collision_handler 在 pymunk 5.1 中不再接受回调函数。现在它是怎么工作的呢? - skrx
1
现在你会得到一个容器对象,你可以使用它来设置回调函数,我已经更新了示例。 - viblo
@viblo 它起作用了。但我能知道哪些形状发生了碰撞吗? - ghost21blade
你可以从仲裁器 http://www.pymunk.org/en/latest/pymunk.html#pymunk.Arbiter.shapes 获取涉及到的形状。 - viblo

0

据我所知,您需要知道精灵是否发生了碰撞,如果发生了碰撞,您想要执行某些操作。Pygame有一个spritecollide函数。这里有一个包装函数,使它变得更容易,如果两个精灵发生碰撞,它将返回True。

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

现在你有一个可以检测碰撞的函数,就像这样:

现在你有一个可以检测碰撞的函数,就像这样:

if collides(sprite1,sprite2)

如果您需要在不干扰常规代码的情况下处理此事件,您可以随时使用线程。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接