python⾃由落体_pymunk教程_⾃由落体⼩球_Pymunk滑动和
铰接演⽰教程
使⽤Pymunk之前的准备⼯作
这是Pymunk⾃带的例⼦slide_and_pinjointl.py的教程。在阅读这个教程之间需要安装好python3,Pygame(⽤pip install pygame –user安装和Pymunk。Pygame在这个例⼦中是必需的,但Pymunk并不能依赖pygame。你可以Pymunk和Pyglet结合重写此教程。
Pymunk使⽤2D物理库Chipmunk。Chipmunk是⽤c语⾔写的。通过Cffi 库能把c语⾔模块翻译到python语⾔。如果在某些操作系统上没有Cffi模块,那你必需⾃⼰做这个了。不过实际上当你⽤pip install pymunk安装时,会帮你安装好Cffi 。
在使⽤pymunk前,在IDLE中导⼊⼀下pymunk看它是否正常。如果导⼊pymunk时发⽣了错误,可能是没有到chipmunk 库。如果⽤pip或setup.py install安装的,应该都会被正确地安装。
⼀个空的简单模拟
为了学习pymunk,⾸先要学习⼏个概念。
刚体
刚体具有物体的物理性质。(质量、坐标、旋转⾓度、速度等)它本⾝没有形状。如果你以前做过粒⼦效果这样的物理实验,刚体的区别主要在于它们能够旋转。
碰撞形状
通过将形状附加到实体,可以定义实体的形状。可以将多个形状附加到单个实体以定义复杂形状,如果不需要形状,则可以不附加任何形状。
约束与关节
你可以在两个实体之间附加关节以约束它们的⾏为。
空间
空间是Chipmunk的基本模拟单元。你可以将实体、形状和关节添加到空间,然后整体更新空间。
结合pygame的简单物理模拟空⽰例
import sys
import pygame
from pygame.locals import *
import pymunk #1
def main():
pygame.init() # pygame初始化
screen = pygame.display.set_mode((600, 600)) # 新建屏幕对象,它是⼀个surface,应该是最先渲染的⾯
pygame.display.set_caption("结合pygame的最简pymunk例⼦_翻译:李兴球")#显⽰标题
clock = pygame.time.Clock() # 新建时钟对象
space = pymunk.Space() #2
while True:
for event in (): # 遍历事件
pe == QUIT:
pe == KEYDOWN and event.key == K_ESCAPE:# 按键检测
screen.fill((255,255,255)) # 填充screen为⽩⾊
space.step(1/50.0) #3
pygame.display.flip() # 刷新整个屏幕
clock.tick(50) # 设定fps
python新建项目教程if __name__ == '__main__':
上⾯的代码只会显⽰⼀个空⽩窗⼝,⼀个抽像的啥东西也没有的物理空间。
#1这⾥是导⼊pymunk罢了。
#2这⾥新建物理空间。下⾯的代码是设定重⼒加速度啥的。你可以⾃⼰选定⼀个重⼒参数以适合⾃⼰的游戏需求。
#3这是让物理空间的抽象实体在指定的时间步长⾥前进⼀步(我的理解是更新坐标⽅向啥的)。重要的是不要修改这个步长,在恒定的步长下,物理模拟会更好地⼯作。
⾃由落体⼩球
圆形在游戏中容易处理,也容易重画。下⾯的例⼦,我们让程序运⾏的时候不断地产⽣⼩球。我们把程序分解成⼏个函数。⾸先是下⾯这个函数:
def add_ball(space):
mass = 1
radius = 14
moment = _for_circle(mass, 0, radius) # 1
body = pymunk.Body(mass, moment) # 2
x = random.randint(120, 380)
body.position = x, 550 # 3
shape = pymunk.Circle(body, radius) # 4
space.add(body, shape) # 5
return shape
#1、所有物理的惯性必需要设置好。这⾥是使⽤pymunk的moment_for_circle函数根据质量和半径计算出来的。你也可以根据经验⾃⼰写⼀个,好⽤就⾏了呗。
#2、惯性计算好了就根据质量和moment⽣成刚体。
#3、这⾥是设置刚体的坐标。
#4、刚体只是个概念,如果要让它参与碰撞检测,那么要让赋予它形状。(就像⼈有灵魂,但没有躯壳⼀样,是⽆法产⽣碰撞的)
#5、最后我们把实体,形状添加到物理空间。
现在我们可以创建⼩球,把它们显⽰出来。pymunk⾃带了实⽤包,有space.debug_draw⽅法,能把整个空间直接给渲染出来。为了理解原理,我们也可以⼿⼯做⼀下这个⼯作。debug drawing函数的代码⼯作原理像下⾯这样:
def draw_ball(screen, ball):
p = int(ball.body.position.x), 600-int(ball.body.position.y)
pygame.draw.circle(screen, (0,0,255), p, int(ball.radius), 2)
在循环⾥,我们要⼀个⼀个来渲染它们。假设有⼀个球列表叫balls,space.debug_draw⽅法还要⼀个⼀个把它们画出来,代码像下在这样:
for ball in balls:
draw_ball(screen, ball)
在这个例⼦中,我们就简单化,不⾃⼰写上⾯的代码了,⽤Pymunk⾃带的函数完成上⾯的任务。⾸先⽤下⾯的命令创建draw_options。
draw_options = pymunk.pygame_util.DrawOptions(screen)
然后在pygame的游戏循环中⼀下⼦重画所有形状,⽤以下命令:
space.debug_draw(draw_options)
⼤多数的pymunk作品都是⽤⾃带的实⽤函数完成以上任务。下⾯是⾃由落体⼩球代码:
import sys, random
import pygame
from pygame.locals import *
import pymunk
def add_ball(space):
mass = 1
radius = 14
moment = _for_circle(mass, 0, radius) # 1
body = pymunk.Body(mass, moment) # 2
x = random.randint(120, 380)
body.position = x, 550 # 3
shape = pymunk.Circle(body, radius) # 4
space.add(body, shape)
def main():
pygame.init()
screen = pygame.display.set_mode((600, 600))
pygame.display.set_caption("Joints. Just wait and the L will tip over")
clock = pygame.time.Clock()
space = pymunk.Space()
balls = []
draw_options = pymunk.pygame_util.DrawOptions(screen)
ticks_to_next_ball = 10
while True:
for event in ():
pe == QUIT:
pe == KEYDOWN and event.key == K_ESCAPE:
ticks_to_next_ball -= 1
if ticks_to_next_ball <= 0:
ticks_to_next_ball = 25
ball_shape = add_ball(space)
balls.append(ball_shape)
space.step(1/50.0)
screen.fill((255,255,255))
space.debug_draw(draw_options)
pygame.display.flip()
clock.tick(50)
if __name__ == '__main__':
main()
L形静⽌拦板
单单⼏个⼩球⾃由落体,很多⼈不⽤物理引擎也能完成。这体现不出pymunk的强⼤。下⾯我们创建⼀个L形的拦板,让⼩球掉在上⾯。 我们通过创建⼀个函数来完成这个任务,以下是代码:
def add_static_L(space):
body = pymunk.Body(body_type = pymunk.Body.STATIC) # 1
body.position = (300, 300)
l1 = pymunk.Segment(body, (-150, 0), (255, 0), 5) # 2
l2 = pymunk.Segment(body, (-150, 0), (-150, 50), 5)
space.add(l1, l2) # 3
return l1,l2
#1、这⾥创建的是静⽌的实体,重要的是不要把它加到space中。注意这个body类型是pymunk.Body.STATIC。
#2、添加线条,坐标相对于body
#3、把l1和l2添加到空间。
在这个例⼦中使⽤的是Space.debug_draw来渲染整个空间。所以我们不需要给以上⽤Segment创建的线条⼿⼯写代码,为了了解原理,下⾯代码演⽰了渲染线条的功能:
def draw_lines(screen, lines):
for line in lines:
body = line.body
pv1 = body.position + ated(body.angle) # 1
pv2 = body.position + ated(body.angle)
p1 = to_pygame(pv1) # 2
p2 = to_pygame(pv2)
pygame.draw.lines(screen, THECOLORS["lightgray"], False, [p1,p2])
#1、我们做了个计算,这是为了得到旋转后线条两端的点的坐标。line.a是线条的第⼀个点,line.b是线条的第⼆个点。虽然现在线条是静⽌的,但是接下来会让它旋转,所以要做这个计算。ated(body.angle)是向量旋转,结果加上body.position,那么点a就是新的坐标了。 如果对向量旋转不太明⽩,可以复习⼀下相关知识。
#2、由于pygame和pymunk的坐标系不同。下⾯的to_pygame函数把坐标转换成pygame坐标系的坐标点。
def to_pygame(p):
"""Small hack to convert pymunk to pygame coordinates"""
return int(p.x), int(-p.y+600)
现在,我们能看到不断掉落的⼩球,碰到L形拦板的效果了,下⾯是代码:
import sys, random
import pygame
from pygame.locals import *
import pymunk
import math
#def to_pygame(p):
#def add_ball(space):
#def add_static_l(space):
def main():
pygame.init()
screen = pygame.display.set_mode((600, 600))
pygame.display.set_caption("Joints. Just wait and the L will tip over")
clock = pygame.time.Clock()
space = pymunk.Space()
lines = add_static_L(space)
balls = []
draw_options = pymunk.pygame_util.DrawOptions(screen)
ticks_to_next_ball = 10

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。