游戏介绍

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

功能实现如下:

  • 支持小鸟类型:红色小鸟,蓝色小鸟,黄色小鸟。
  • 支持障碍物的类型:玻璃,木头,石头。
  • 支持障碍物的形状:各种长度的长方形,正方形和圆形。
  • 使用json文件保存关卡信息,设置小猪和障碍物的位置。

老规矩,需要完整项目的小伙伴关注小编,申请QQ群:721195303免费领取

游戏截图如下:

图2

图3

完整代码

游戏实现代码的github链接 愤怒的小鸟
这边是csdn的下载链接 愤怒的小鸟

Pymunk介绍

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

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

    pip install pymunk

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

  • 刚体 (pymunk.Body):一个刚体具有物体的物理属性(质量、坐标、旋转角度、速度等),它自己是没有形状的。
  • 碰撞形状 (pymunk.Circle, pymunk.Segment and pymunk.Poly):通过将形状附加到实体,你可以定义一个实体的形状。你可以将多个形状附加到单个实体上来定义一个复杂的形状,如果不需要形状,则可以不附加任何形状。
  • 约束/关节 (pymunk.constraint.PinJoint, pymunk.constraint.SimpleMotor):你可以在两个实体之间附加关节以约束它们的行为。比如在两个实体间保持一个固定的距离。
  • 空间 (pymunk.Space): 空间是pymunk中基本的模拟单元。你可以添加实体,形状和关节到空间,然后整体更新空间。pymunk会控制空间中所有的实体,形状和关节如何相互作用。

代码实现

将物理引擎相关的代码单独放在了一个文件 (source\component\physics.py)中,减少代码的耦合。
定义了一个Physics类,向外提供所有物理引擎相关的函数。
这篇文章只介绍physics.py 中pymunk相关的代码。

pymunk相关初始化

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

  • gravity : 重力
  • dt (Time step length) : 表示pymunk中每次更新的时间段值,比如dt值是0.002,表示时间段是0.002秒。

setup_lines函数设置了一条直线,作为地面。
Segment类创建了一条从点a 到 点b的直线。

class pymunk.Segment(body, a, b, radius)
Bases: pymunk.shapes.Shape
A line segment shape between two point. Meant mainly as a static shape.
import pymunk as pmclass Physics():def __init__(self):self.reset()def reset(self, level=None):self.level = level# init space: set gravity and dtself.space = pm.Space()self.space.gravity = (0.0, -700.0)self.dt = 0.002self.birds = []self.pigs = []self.blocks = []self.path_timer = 0self.check_collide = Falseself.setup_lines()self.setup_collision_handler()def setup_lines(self):# Static Groundx, y = to_pymunk(c.SCREEN_WIDTH, c.GROUND_HEIGHT)static_body = pm.Body(body_type=pm.Body.STATIC)static_lines = [pm.Segment(static_body, (0.0, y), (x, y), 0.0)]for line in static_lines:line.elasticity = 0.95line.friction = 1line.collision_type = COLLISION_LINEself.space.add(static_lines)self.static_lines = static_lines

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

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

add_collision_handler(collision_type_a, collision_type_b)

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

post_solve
Two shapes are touching and their collision response has been processed.
func(arbiter, space, data)
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函数在小猪和障碍物碰撞后,会根据冲击力的大小来相应减去小猪的生命。

COLLISION_BIRD = 1
COLLISION_PIG = 2
COLLISION_BLOCK = 3
COLLISION_LINE = 4def setup_collision_handler(self):def post_solve_bird_line(arbiter, space, data):if self.check_collide:bird_shape = arbiter.shapes[0]my_phy.handle_bird_collide(bird_shape, True)def post_solve_pig_bird(arbiter, space, data):if self.check_collide:pig_shape = arbiter.shapes[0]my_phy.handle_pig_collide(pig_shape, MAX_IMPULSE)def post_solve_pig_line(arbiter, space, data):if self.check_collide:pig_shape = arbiter.shapes[0]my_phy.handle_pig_collide(pig_shape, arbiter.total_impulse.length, True)def post_solve_pig_block(arbiter, space, data):if self.check_collide:if arbiter.total_impulse.length > MIN_DAMAGE_IMPULSE:pig_shape = arbiter.shapes[0]my_phy.handle_pig_collide(pig_shape, arbiter.total_impulse.length)def post_solve_block_bird(arbiter, space, data):if self.check_collide:block_shape, bird_shape = arbiter.shapesmy_phy.handle_bird_collide(bird_shape)if arbiter.total_impulse.length > 1100:my_phy.handle_block_collide(block_shape, arbiter.total_impulse.length)self.space.add_collision_handler(COLLISION_BIRD, COLLISION_LINE).post_solve = post_solve_bird_lineself.space.add_collision_handler(COLLISION_PIG, COLLISION_BIRD).post_solve = post_solve_pig_birdself.space.add_collision_handler(COLLISION_PIG, COLLISION_LINE).post_solve = post_solve_pig_lineself.space.add_collision_handler(COLLISION_PIG, COLLISION_BLOCK).post_solve = post_solve_pig_blockself.space.add_collision_handler(COLLISION_BLOCK, COLLISION_BIRD).post_solve = post_solve_block_birddef handle_pig_collide(self, pig_shape, impulse, is_ground=False):for pig in self.pigs:if pig_shape == pig.phy.shape:if is_ground:pig.phy.body.velocity = pig.phy.body.velocity * 0.8else:damage = impulse // MIN_DAMAGE_IMPULSEpig.set_damage(damage)# must init as a global parameter to use in the post_solve handler
my_phy = Physics()

创建一个pymunk物体

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

  1. moment_for_circle 函数根根据质量和转动惯量来创建一个刚体(pymunk.Body)。
pymunk.moment_for_circle(mass, inner_radius, outer_radius, offset=(0, 0)) Calculate the moment of inertia for a hollow circle inner_radius and outer_radius are the inner and outer diameters. (A solid circle has an inner diameter of 0)
  1. 据质量(mass), 圆的半径 来计算出刚体的转动惯量(Moment Of Inertia),惯量就像刚体的旋转质量。
class pymunk.Body(mass=0, moment=0, body_type=<class 'CP_BODY_TYPE_DYNAMIC'>)

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

class pymunk.Circle(body, radius, offset=(0, 0))Bases: pymunk.shapes.ShapeA circle shape defined by a radius复制代码
  1. 设置形状的一些属性

摩擦系数(friction)

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

弹力 (elasticity)

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

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

class PhyPig():def __init__(self, x, y, radius, space):mass = 5inertia = pm.moment_for_circle(mass, 0, radius, (0, 0))body = pm.Body(mass, inertia)body.position = x, yshape = pm.Circle(body, radius, (0, 0))shape.elasticity = 0.95shape.friction = 1shape.collision_type = COLLISION_PIGspace.add(body, shape)self.body = bodyself.shape = shape
class PhyPig():def __init__(self, x, y, radius, space):mass = 5inertia = pm.moment_for_circle(mass, 0, radius, (0, 0))body = pm.Body(mass, inertia)body.position = x, yshape = pm.Circle(body, radius, (0, 0))shape.elasticity = 0.95shape.friction = 1shape.collision_type = COLLISION_PIGspace.add(body, shape)self.body = bodyself.shape = shape

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

pymunk 状态更新

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

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

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

遍历所有的小猪:

  • 检查小猪的状态,如果生命小于零或者y轴位置超出了范围,删除这个小猪。
  • 更新小猪的位置

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

  • pygame中,以左上角的位置为(0,0)
  • pymunk中,以左下角的位置为(0,0)
def to_pygame(p):"""Convert position of pymunk to position of pygame"""return int(p.x), int(-p.y+600)def update(self, game_info, level, mouse_pressed):pigs_to_remove = []#From pymunk doc:Performing multiple calls with a smaller dt#                creates a more stable and accurate simulation#So make five updates per frame for better stabilityfor x in range(5):self.space.step(self.dt)...for pig in self.pigs:pig.update(game_info)if pig.phy.body.position.y < 0 or pig.life <= 0:pigs_to_remove.append(pig)poly = pig.phy.shapep = to_pygame(poly.body.position)x, y = pw, h = pig.image.get_size()# change to [left, top] position of pygamex -= w * 0.5y -= h * 0.5angle_degree = math.degrees(poly.body.angle)pig.update_position(x, y, angle_degree)for pig in pigs_to_remove:self.space.remove(pig.phy.shape, pig.phy.shape.body)self.pigs.remove(pig)level.update_score(c.PIG_SCORE)...

编译环境

python3.7 + pygame1.9 + pymunk 5.5.0

老规矩,需要完整项目的小伙伴关注小编,申请QQ群:721195303免费领取

在这里还是要推荐下我自己建的Python学习群:721195303,群里都是学Python的,如果你想学或者正在学习Python ,欢迎你加入,大家都是软件开发党,不定期分享干货(只有Python软件开发相关的),包括我自己整理的一份2021最新的Python进阶资料和零基础教学,欢迎进阶中和对Python感兴趣的小伙伴加入!

Python 愤怒的小鸟代码实现:物理引擎pymunk使用相关推荐

  1. python 物理引擎 摩擦力_Python 愤怒的小鸟代码实现:物理引擎pymunk使用

    游戏介绍 最近比较忙,周末正好有时间写了python版本的愤怒的小鸟,使用了物理引擎pymunk,图片资源是从github上下载的,实现了一个可玩的简单版本. 功能实现如下:支持小鸟类型:红色小鸟,蓝 ...

  2. Python 愤怒的小鸟代码实现(1):物理引擎pymunk使用

    python 愤怒的小鸟代码实现(1):物理引擎pymunk使用 游戏介绍 完整代码 Pymunk介绍 代码实现 pymunk相关初始化 创建一个pymunk物体 pymunk 状态更新 编译环境 游 ...

  3. pygame教程实例(五)物理引擎pymunk

    上一篇:pygame教程实例(四)小球弹跳(事件) 下一篇:pygame教程实例(六)你从来没玩过的俄罗斯方块 本教程使用python3 在前几个教程中,我们模拟了小球和星球的运动. 但是,在游戏中我 ...

  4. 蹦起来!Python 用物理引擎Pymunk写一个解压小游戏

    用鼠标创建小球,一个蹦来蹦去的解压小游戏-- 本次需要的外置包:pygame,pymunk,cmd运行该命令安装: pip install pygame pip install pymunk 首先,导 ...

  5. python box2d 教程_python下的Box2d物理引擎的配置

    I come back! 由于已经大四了,正在找工作 导致了至今以来第二长的时间内没有更新博客.向大家表示道歉 前言 Box2d物理引擎 Box2d是一款开源的2d物理引擎,存在很多的版本,C++,J ...

  6. VUE,使用物理引擎Box2D设计类愤怒小鸟的击球游戏--基本架构设置

    我们都玩过愤怒的小鸟,该游戏一大特点是,两物体碰撞后,它会模拟现实世界物体碰撞后的反弹效果,因此游戏特别具有体感和逼真感,本节我们利用物理引擎Box2D,制作一个类似愤怒小鸟类型的碰撞游戏. 游戏的基 ...

  7. CreatorPrimer | 物理小游戏(物理引擎管理器)

    前面两篇我们介绍了物理投篮小游戏的界面布局.物理组件的基本使用方法,从今天开始进入编程篇的内容.难度在逐渐加深,为了不给大家造成阅读负担,程序篇会分成多次来讲,每篇教程尽量简单,就算没有编程基础,跟着 ...

  8. 【日常点滴016】python游戏库arcade结合Tiled map editor地图编辑器和Pymunk物理引擎制作游戏过程记录,并最终打包为exe文件

    独此一家,建议收藏 前言 一.创建一个空白窗口 step001.py代码示例 二.创建很多全局能用的常量 step002.py代码示例 三.创建实例变量即代表各种精灵等的变量 step003.py代码 ...

  9. python愤怒的小鸟简单模拟程序_Python物理引擎

    """ 这是用Python的海龟画图模块和pymunk模块制作的愤怒的小鸟简单版本程序. physicbox是我编写的一个模块,它有PhysicBall类用来生成物理角色 ...

  10. Python版经典小游戏愤怒的小鸟源代码,基于pygame+pymunk

    Python版经典小游戏愤怒的小鸟源代码,基于pygame+pymunk 程序依赖:pygame2.0.1, pymunk5.5.0 直接运行main.py 完整代码下载地址:Python版经典小游戏 ...

最新文章

  1. 支付宝二面:Mybatis接口Mapper内的方法为啥不能重载吗?我直接懵逼了...
  2. 存储过程中执行动态Sql语句
  3. css预编译工具less使用心得
  4. 1095. 山脉数组中查找目标值(三分+二分)
  5. 通过mvn dependency:tree 查看依赖树,解决依赖jar冲突问题
  6. C语言、嵌入式中几个非常实用的宏技巧
  7. android动画入门,Android动画之入门篇(一)
  8. Kafka Metrics指标监控
  9. Golang 笔记 2 函数、结构体、接口、指针
  10. 鸟哥-服务器 学习笔记
  11. ENVI完整安装步骤
  12. 生产排程遇难题?APS系统来解决
  13. 微信支付分开通了,来看看你有多少分
  14. MySQL 性能优化:8 种常见 SQL 错误用法!
  15. MYSQL查询员工信息练习
  16. 9个非常有意思的HTML5动画推荐
  17. word文件损坏打不开如何修复?文件丢失怎么办?
  18. java微信实现窗口自动输入(微信骚扰机)
  19. 式创新:移动互联网时代的生存法则 读后感
  20. APS排产提高生产效率的五大妙招

热门文章

  1. 云风专访|近40年码龄,从通宵写代码到三思而后行
  2. 有关Nodejs的视频教程
  3. 自动化测试运维|Selenuim IDE使用Firefox
  4. RPM 包的构建 - SPEC 基础知识-01
  5. 合肥工业大学计算机网络题库,合肥工业大学试卷计算机系统结构(A、B卷)
  6. 新手学java用什么电脑?需要安装什么软件
  7. 扫码点餐系统可以免费使用了
  8. 演讲实录:“分布式数据库海量数据存储和实时查询实现与应用”
  9. 上海市住房公积金销户提取的步骤
  10. 关于windows10在学习爬虫是用到appium配置java的jdk出现了,javac不是内部命令的解决方法(¥57)