【问题标题】:Pygame mouse movement failingPygame鼠标移动失败
【发布时间】:2013-05-19 01:51:34
【问题描述】:

我正在学习 pygame 教程,目前我正在尝试弄清楚如何选择一个正在发射球的圆圈,其中一个球击中另一个球,进而将一个盒子击倒。当球击中盒子时,敲击盒子效果很好。但是,当我添加鼠标移动以便我可以再次选择球并将其放置在相同的位置以便可以再次击中它时,框会再次敲击。球只是向后滚动,没有发射第二个球来敲击盒子。这是前面的代码,一个球发射另一个球但没有鼠标移动,即不允许选择和拖动球。

import pygame
from pygame.locals import *
from pygame.color import *
import pymunk as pm
from pymunk import Vec2d
import sys
from random import randint

def to_pygame(p):
    """Small hack to convert pymunk to pygame coordinates"""
    return int(p[0]), int(-p[1]+600)


def draw_ball(screen, ball, colour):
    r = ball.radius
    rot = ball.body.rotation_vector
    p = to_pygame(ball.body.position)
    p2 = Vec2d(rot.x, -rot.y) * r * 0.9
    pygame.draw.line(screen, THECOLORS["red"], p, p+p2)
    pygame.draw.circle(screen, colour, p, int(r), 3)


def add_ball(space, x=0, y=130):
    mass = 1.3
    radius = 20
    inertia = pm.moment_for_circle(mass, 0, radius, (0,0))
    body = pm.Body(mass, inertia)
    body.position = (x,y)
    shape = pm.Circle(body, radius, (0,0))
    shape.friction = 10.0
    shape.elasticity = 1.0
    space.add(body, shape)

    return shape


def add_box(space, size, pos, mass=0.3):
    points = [(-size, -size), (-size, size), (size,size), (size, -size)]
    moment = pm.moment_for_poly(int(mass), points, (0,0))

    body = pm.Body(mass, moment)
    body.position = pos

    shape = pm.Poly(body, points, (0,0))
    shape.friction = 1
    space.add(body,shape)

    return shape

def draw_box(screen, box):
    ps = box.get_points()
    ps.append(ps[0])
    newps = [to_pygame(x) for x in ps]
    pygame.draw.polygon(screen, THECOLORS["blue"], newps, 3)


def main():
    pygame.init()
    screen = pygame.display.set_mode((600, 600))
    pygame.display.set_caption("Impulsive balls")
    clock = pygame.time.Clock()

    balls = []
    space = pm.Space()
    space.gravity = (0.0, -300.0)

    # ground
    body = pm.Body()
    shape = pm.Segment(body, (0,100), (450,100), .0)
    shape.friction = 6.0
    space.add(shape)

    # hidden ramp
    body = pm.Body()
    slope = pm.Segment(body, (0,100), (180,150), .0)
    space.add(slope)

    balls.append(add_ball(space, 10, 130))
    balls.append(add_ball(space, 100, 150))
    #joint = pm.PinJoint(balls[0].body, balls[1].body)
    #joint.distance = 90

    mass = 1.0
    size = 20
    box = add_box(space, size, (400,100+size), mass)
    count = 0

    while 1:
        space.step(1/30.0)
        clock.tick(30)

        for event in pygame.event.get():
            if event.type == QUIT:
                pygame.quit()
                sys.exit(0)
            elif event.type == KEYDOWN:
                if event.key == K_ESCAPE:
                    pygame.quit()
                    sys.exit(0)

        if count == 10:
            pm.Body.apply_impulse(balls[0].body, (450,0))

        screen.fill(THECOLORS["white"])
        pygame.draw.line(screen, THECOLORS["red"], to_pygame((0,100)), to_pygame((450,100)), 3)

        pygame.draw.line(screen, THECOLORS["red"], to_pygame((0,100)), to_pygame((180,150)), 3)

        draw_box(screen, box)
        for ball in balls:
            draw_ball(screen, ball, THECOLORS["green"])

        pygame.display.flip()
        count += 1

if __name__ == '__main__':
    main()

这是我添加鼠标移动代码的第二个版本

import pygame
from pygame.locals import *
from pygame.color import *
import pymunk as pm
from pymunk import Vec2d
import sys
from random import randint

def to_pygame(p):
    """Small hack to convert pymunk to pygame coordinates"""
    return int(p[0]), int(-p[1]+600)
def from_pygame(p):
    return to_pygame(p)

def draw_ball(screen, ball, colour):
    r = ball.radius
    rot = ball.body.rotation_vector
    p = to_pygame(ball.body.position)
    p2 = Vec2d(rot.x, -rot.y) * r * 0.9
    pygame.draw.line(screen, THECOLORS["blue"], p, p+p2)
    pygame.draw.circle(screen, colour, p, int(r), 3)


def add_ball(space, x=0, y=130):
    mass = 1.3 #1.5
    radius = 20
    inertia = pm.moment_for_circle(mass, 0, radius, (0,0))
    body = pm.Body(mass, inertia)
    body.position = (x,y)
    shape = pm.Circle(body, radius, (0,0))
    shape.friction = 10.0
    shape.elasticity = 1.0
    space.add(body, shape)

    return shape


def add_box(space, size, pos, mass=0.3):
    points = [(-size, -size), (-size, size), (size,size), (size, -size)]
    moment = pm.moment_for_poly(int(mass), points, (0,0))

    body = pm.Body(mass, moment)
    body.position = pos

    shape = pm.Poly(body, points, (0,0))
    shape.friction = 1
    space.add(body,shape)

    return shape

def draw_box(screen, box):
    ps = box.get_points()
    ps.append(ps[0])
    newps = [to_pygame(x) for x in ps]
    pygame.draw.polygon(screen, THECOLORS["blue"], newps, 3)


def main():
    pygame.init()
    screen = pygame.display.set_mode((600, 600))
    pygame.display.set_caption("Impulsive balls")
    clock = pygame.time.Clock()
    body = []
    selected = None
    balls = []
    space = pm.Space()
    space.gravity = (0.0, -300.0)

    # ground
    body = pm.Body()
    shape = pm.Segment(body, (0,100), (450,100), .0)
    shape.friction = 6.0
    space.add(shape)

    # hidden ramp
    body = pm.Body()
    slope = pm.Segment(body, (0,100), (180,150), .0)
    space.add(slope)

    balls.append(add_ball(space, 10, 130))
    balls.append(add_ball(space, 100, 150))
    #joint = pm.PinJoint(balls[0].body, balls[1].body)
    #joint.distance = 90

    mass = 1.0
    size = 20
    box = add_box(space, size, (400,100+size), mass)
    count = 0

    while 1:
        space.step(1/30.0)
        clock.tick(30)

        for event in pygame.event.get():
            if event.type == QUIT:
                pygame.quit()
                sys.exit(0)
            elif event.type == KEYDOWN:
                if event.key == K_ESCAPE:
                    pygame.quit()
                    sys.exit(0)
                if count == 10:
                    pm.Body.apply_impulse(balls[0].body, (450,0))
                if event.key == K_p:
                    balls[0].body.apply_impulse((450,0))
                if event.key == K_s:
                    balls[0].body.apply_impulse((-450,0))



            elif event.type == MOUSEBUTTONDOWN:
                p = from_pygame(Vec2d(event.pos))
                selected = space.point_query_first(p)
            elif event.type == MOUSEBUTTONUP:
                if selected != None:
                    selected = None
            elif event.type == MOUSEMOTION:
                if selected != None:
                    selected.body.position = from_pygame(event.pos)

        screen.fill(THECOLORS["white"])
        pygame.draw.line(screen, THECOLORS["red"], to_pygame((0,100)), to_pygame((450,100)), 3)

        pygame.draw.line(screen, THECOLORS["red"], to_pygame((0,100)), to_pygame((180,150)), 3)

        draw_box(screen, box)
        for ball in balls:
            draw_ball(screen, ball, THECOLORS["green"])

        pygame.display.flip()
        count += 1

if __name__ == '__main__':
    main()

另外,我怎样才能让球在同一位置,以便我可以拖动它并推动另一个球来敲击盒子而不是让球滚回,这样我以后可以再次选择发射的球并放置它在球旁边不回滚

【问题讨论】:

    标签: python pygame game-physics


    【解决方案1】:

    对于您的第一个问题,在第二个文件中球没有发射。问题是您已将该代码放入事件块中,这仅在触发外部事件时发生(例如按下键)。要修复它,需要将该块移出 for 循环,如下所示:

    ...
    
    while 1:
        space.step(1/30.0)
        clock.tick(30)
    
        for event in pygame.event.get():
            if event.type == QUIT:
                pygame.quit()
                sys.exit(0)
            elif event.type == KEYDOWN:
                if event.key == K_ESCAPE:
                    pygame.quit()
                    sys.exit(0)
                if event.key == K_p:
                    balls[0].body.apply_impulse((450,0))
                if event.key == K_s:
                    balls[0].body.apply_impulse((-450,0))
            elif event.type == MOUSEBUTTONDOWN:
                p = from_pygame(Vec2d(event.pos))
                selected = space.point_query_first(p)
            elif event.type == MOUSEBUTTONUP:
                if selected != None:
                    selected = None
            elif event.type == MOUSEMOTION:
                if selected != None:
                    selected.body.position = from_pygame(event.pos)
    
        if count == 10:
            pm.Body.apply_impulse(balls[0].body, (450,0))
    
    ...
    

    为了防止球移动,我建议将它们放在平坦的地面上。我对 main 进行了以下更改以说明我的意思。请注意,我禁用了球发射,以便您可以看到球保持在原位。我还建议您在屏幕上设置一些看不见的墙,以使所有对象都卡在框架内。

    ...
    
    def main():
        pygame.init()
        screen = pygame.display.set_mode((600, 600))
        pygame.display.set_caption("Impulsive balls")
        clock = pygame.time.Clock()
        body = []
        selected = None
        balls = []
        space = pm.Space()
        space.gravity = (0.0, -300.0)
    
        # ground
        body = pm.Body()
        shape = pm.Segment(body, (0,100), (450,100), .0)
        shape.friction = 6.0
        space.add(shape)
    
        # hidden ramp
        body = pm.Body()
        slope = pm.Segment(body, (20,100), (180,150), .0)
        space.add(slope)
        body = pm.Body()
        slopetop = pm.Segment(body, (180,150), (190,150), .0)
        space.add(slopetop)
    
        balls.append(add_ball(space, 10, 130))
        balls.append(add_ball(space, 185, 170))
        #joint = pm.PinJoint(balls[0].body, balls[1].body)
        #joint.distance = 90
    
        mass = 1.0
        size = 20
        box = add_box(space, size, (400,100+size), mass)
        count = 0
    
        while 1:
            space.step(1/30.0)
            clock.tick(30)
    
            for event in pygame.event.get():
                if event.type == QUIT:
                    pygame.quit()
                    sys.exit(0)
                elif event.type == KEYDOWN:
                    if event.key == K_ESCAPE:
                        pygame.quit()
                        sys.exit(0)
                    if event.key == K_p:
                        balls[0].body.apply_impulse((450,0))
                    if event.key == K_s:
                        balls[0].body.apply_impulse((-450,0))
                elif event.type == MOUSEBUTTONDOWN:
                    p = from_pygame(Vec2d(event.pos))
                    selected = space.point_query_first(p)
                elif event.type == MOUSEBUTTONUP:
                    if selected != None:
                        selected = None
                elif event.type == MOUSEMOTION:
                    if selected != None:
                        selected.body.position = from_pygame(event.pos)
    
            if count == 10 and 0:
                pm.Body.apply_impulse(balls[0].body, (450,0))
    
            screen.fill(THECOLORS["white"])
            pygame.draw.line(screen, THECOLORS["red"], to_pygame((0,100)), to_pygame((450,100)), 3)
            pygame.draw.line(screen, THECOLORS["red"], to_pygame((20,100)), to_pygame((180,150)), 3)
            pygame.draw.line(screen, THECOLORS["red"], to_pygame((180,150)), to_pygame((190,150)), 3)
    
            draw_box(screen, box)
            for ball in balls:
                draw_ball(screen, ball, THECOLORS["green"])
    
            pygame.display.flip()
            count += 1
    ...
    

    【讨论】:

    • 我怎样才能使底部的球可以被拖动来击打顶部的球?意思是底部的球保持在它的位置并且在发射顶部的球时变得可以拖动?
    • 我不确定我是否理解这个问题。我认为您要问的是第一个球在击中顶部球后立即停止并且直到被拖动才移动。如果是这样,那么你将不得不花一些时间来计算出恰到好处的物理学。或者,您可以创建一个事件,在球击球后立即将球的动量设置为零。
    猜你喜欢
    • 1970-01-01
    • 2022-11-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多