超好用的物理引擎pymunk,想自己做游戏的童鞋,快快收藏吧

超好用的物理引擎pymunk,想自己做游戏的童鞋,快快收藏吧

首页休闲益智collision circle更新时间:2024-04-27


游戏介绍

最近比较忙,周末正好有时间写了python版本的愤怒的小鸟,使用了物理引擎pymunk,图片资源是从github上下载的,实现了一个可玩的简单版本。

功能实现如下:

游戏截图如下:

图2

图3

完整代码

游戏实现代码的github链接 愤怒的小鸟

这边是csdn的下载链接 愤怒的小鸟

Pymunk介绍

pymunk是一个2D的物理引擎, 它实际是封装了 c语言写的2D物理引擎Chipmunk,可以实现碰撞,旋转等物理运动。

安装pymunk,可以直接使用pip工具,安装最新的pymunk 5.5.0:

1 pip install pymunk

介绍下在pymunk中会使用到的四个基本的类:

2020年最新人工智能python教程和电子书

如果你看好人工智能产业,处于想学python或者找不到合适的入门教程,那么赶快来领取吧

获取方式:

1.转发此文 关注

2.私信小编关键词 “ 资料 ”,即可免费获取哦!

还不会私信的小伙伴,可以按照以下步骤操作:

1、打开头条,点击右下角“我的”

2、在个人界面点击“关注”,当然这需要你先关注小编

3、在关注中找到小编,点击小编的头像进入他的个人界面,随后点击“私信” 

4、随后进入私信发送界面,这样就可以愉快的私信聊天了;

代码实现

将物理引擎相关的代码单独放在了一个文件 (source\component\physics.py)中,减少代码的耦合。

定义了一个Physics类,向外提供所有物理引擎相关的函数。

这篇文章只介绍physics.py 中pymunk相关的代码。

pymunk相关初始化

reset函数初始化了 空间类(pm.Space), 设置了两个参数

setup_lines函数设置了一条直线,作为地面。

Segment类创建了一条从点a 到 点b的直线。

1 class pymunk.Segment(body, a, b, radius) 2 Bases: pymunk.shapes.Shape 3 A line segment shape between two point. Meant mainly as a static shape.

1 import pymunk as pm 2 3 class Physics(): 4 def __init__(self): 5 self.reset() 6 7 def reset(self, level=None): 8 self.level = level 9 # init space: set gravity and dt 10 self.space = pm.Space() 11 self.space.gravity = (0.0, -700.0) 12 self.dt = 0.002 13 self.birds = [] 14 self.pigs = [] 15 self.blocks = [] 16 self.path_timer = 0 17 self.check_collide = False 18 self.setup_lines() 19 self.setup_collision_handler() 20 21 def setup_lines(self): 22 # Static Ground 23 x, y = to_pymunk(c.SCREEN_WIDTH, c.GROUND_HEIGHT) 24 static_body = pm.Body(body_type=pm.Body.STATIC) 25 static_lines = [pm.Segment(static_body, (0.0, y), (x, y), 0.0)] 26 27 for line in static_lines: 28 line.elasticity = 0.95 29 line.friction = 1 30 line.collision_type = COLLISION_LINE 31 self.space.add(static_lines) 32 self.static_lines = static_lines

setup_collision_handler函数用来设置在两种类型的物体在碰撞发生时,可以由用户使用的回调函数。

add_collision_handler函数添加两种类型物体a和b碰撞时会调用的handler。比如小猪和小鸟这两种类型物体的注册函数就是:add_collision_handler(COLLISION_PIG, COLLISION_BIRD)

1 add_collision_handler(collision_type_a, collision_type_b) 2 Return the CollisionHandler for collisions between objects of type collision_type_a and collision_type_b.

我们这里只用到了 post_solve 回调函数,在两个物体碰撞结束后,获取碰撞冲击力(collision impulse)。

1 post_solve 2 Two shapes are touching and their collision response has been processed. 3 func(arbiter, space, data) 4 You can retrieve the collision impulse or kinetic energy at this time if you want to use it to calculate sound volumes or damage amounts. See Arbiter for more info.

比如handle_pig_collide函数在小猪和障碍物碰撞后,会根据冲击力的大小来相应减去小猪的生命。

1 COLLISION_BIRD = 1 2 COLLISION_PIG = 2 3 COLLISION_BLOCK = 3 4 COLLISION_LINE = 4 5 6 def setup_collision_handler(self): 7 def post_solve_bird_line(arbiter, space, data): 8 if self.check_collide: 9 bird_shape = arbiter.shapes[0] 10 my_phy.handle_bird_collide(bird_shape, True) 11 def post_solve_pig_bird(arbiter, space, data): 12 if self.check_collide: 13 pig_shape = arbiter.shapes[0] 14 my_phy.handle_pig_collide(pig_shape, MAX_IMPULSE) 15 def post_solve_pig_line(arbiter, space, data): 16 if self.check_collide: 17 pig_shape = arbiter.shapes[0] 18 my_phy.handle_pig_collide(pig_shape, arbiter.total_impulse.length, True) 19 def post_solve_pig_block(arbiter, space, data): 20 if self.check_collide: 21 if arbiter.total_impulse.length > MIN_DAMAGE_IMPULSE: 22 pig_shape = arbiter.shapes[0] 23 my_phy.handle_pig_collide(pig_shape, arbiter.total_impulse.length) 24 def post_solve_block_bird(arbiter, space, data): 25 if self.check_collide: 26 block_shape, bird_shape = arbiter.shapes 27 my_phy.handle_bird_collide(bird_shape) 28 if arbiter.total_impulse.length > 1100: 29 my_phy.handle_block_collide(block_shape, arbiter.total_impulse.length) 30 31 self.space.add_collision_handler( 32 COLLISION_BIRD, COLLISION_LINE).post_solve = post_solve_bird_line 33 34 self.space.add_collision_handler( 35 COLLISION_PIG, COLLISION_BIRD).post_solve = post_solve_pig_bird 36 37 self.space.add_collision_handler( 38 COLLISION_PIG, COLLISION_LINE).post_solve = post_solve_pig_line 39 40 self.space.add_collision_handler( 41 COLLISION_PIG, COLLISION_BLOCK).post_solve = post_solve_pig_block 42 43 self.space.add_collision_handler( 44 COLLISION_BLOCK, COLLISION_BIRD).post_solve = post_solve_block_bird 45 46 def handle_pig_collide(self, pig_shape, impulse, is_ground=False): 47 for pig in self.pigs: 48 if pig_shape == pig.phy.shape: 49 if is_ground: 50 pig.phy.body.velocity = pig.phy.body.velocity * 0.8 51 else: 52 damage = impulse // MIN_DAMAGE_IMPULSE 53 pig.set_damage(damage) 54 55 # must init as a global parameter to use in the post_solve handler 56 my_phy = Physics()

创建一个pymunk物体

创建物体一般有下面五个步骤

  1. moment_for_circle函数根根据质量和转动惯量来创建一个刚体(pymunk.Body)。

1 pymunk.moment_for_circle(mass, inner_radius, outer_radius, offset=(0, 0)) 2 Calculate the moment of inertia for a hollow circle 3 inner_radius and outer_radius are the inner and outer diameters. (A solid circle has an inner diameter of 0)

据质量(mass), 圆的半径 来计算出刚体的转动惯量(Moment Of Inertia),惯量就像刚体的旋转质量。

1 class pymunk.Body(mass=0, moment=0, body_type=)

根据刚体,和形状类型创建一个碰撞形状,比如圆形就是 pymunk.Circle。

1 class pymunk.Circle(body, radius, offset=(0, 0))Bases: pymunk.shapes.ShapeA circle shape defined by a radius

  1. 设置形状的一些属性

摩擦系数(friction)

1 Friction coefficient. 2 Pymunk uses the Coulomb friction model, a value of 0.0 is frictionless. 3 A value over 1.0 is perfectly fine.

弹力 (elasticity)

1 Elasticity of the shape. 2 A value of 0.0 gives no bounce, while a value of 1.0 will give a ‘perfect’ bounce.

最后将这个刚体和碰撞形状都添加到空间中。

1 pymunk.Space.add(*objs) 2 Add one or many shapes, bodies or joints to the space

1 class PhyPig(): 2 def __init__(self, x, y, radius, space): 3 mass = 5 4 inertia = pm.moment_for_circle(mass, 0, radius, (0, 0)) 5 body = pm.Body(mass, inertia) 6 body.position = x, y 7 shape = pm.Circle(body, radius, (0, 0)) 8 shape.elasticity = 0.95 9 shape.friction = 1 10 shape.collision_type = COLLISION_PIG 11 space.add(body, shape) 12 self.body = body 13 self.shape = shape

PhyPig 类的初始化函数创建了一个小猪物体,参数有物体的位置(x,y), 可以将小猪作为一个圆形物体,所以参数有圆的半径(radius), 参数space就是我们上面创建的空间类。

pymunk 状态更新

update函数是更新函数,代码只显示了小猪相关的代码。

step 函数的参数dt值就是上面设置的时间段值,表示这次调用 该空间经过了多少时间,pymunk 根据这个时间值更新空间中的所有物体的状态(比如速度,位置等)。按照pymunk 文档的说明,将dt值设小一点,每次调用多次会使得模拟更稳定和精确,所以这里每次调用5次step函数。

1 pymunk.Space.step(dt) 2 Update the space for the given time step.

遍历所有的小猪:

pygame 和 pymunk 中对于位置的值是不同的, y轴的坐标需要进行转换,具体看 to_pygame 函数,600是高度。pymunk 中 body.position的值是物体的中间位置,对应pygame 中 rect 的centerx 和 centery,所以需要转成[left, top]位置。

1 def to_pygame(p): 2 """Convert position of pymunk to position of pygame""" 3 return int(p.x), int(-p.y 600) 4 5 def update(self, game_info, level, mouse_pressed): 6 pigs_to_remove = [] 7 8 #From pymunk doc:Performing multiple calls with a smaller dt 9 # creates a more stable and accurate simulation 10 #So make five updates per frame for better stability 11 for x in range(5): 12 self.space.step(self.dt) 13 ... 14 for pig in self.pigs: 15 pig.update(game_info) 16 if pig.phy.body.position.y < 0 or pig.life <= 0: 17 pigs_to_remove.append(pig) 18 poly = pig.phy.shape 19 p = to_pygame(poly.body.position) 20 x, y = p 21 w, h = pig.image.get_size() 22 # change to [left, top] position of pygame 23 x -= w * 0.5 24 y -= h * 0.5 25 angle_degree = math.degrees(poly.body.angle) 26 pig.update_position(x, y, angle_degree) 27 28 for pig in pigs_to_remove: 29 self.space.remove(pig.phy.shape, pig.phy.shape.body) 30 self.pigs.remove(pig) 31 level.update_score(c.PIG_SCORE) 32 ...

查看全文
大家还看了
也许喜欢
更多游戏

Copyright © 2024 妖气游戏网 www.17u1u.com All Rights Reserved