游戏介绍

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

功能实现如下:支持小鸟类型:红色小鸟,蓝色小鸟,黄色小鸟。

支持障碍物的类型:玻璃,木头,石头。

支持障碍物的形状:各种长度的长方形,正方形和圆形。

使用json文件保存关卡信息,设置小猪和障碍物的位置。

游戏截图如下:

图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.

交流群:632408235

import pymunk as pm

class Physics():

def __init__(self):

self.reset()

def reset(self, level=None):

self.level = level

# init space: set gravity and dt

self.space = pm.Space()

self.space.gravity = (0.0, -700.0)

self.dt = 0.002

self.birds = []

self.pigs = []

self.blocks = []

self.path_timer = 0

self.check_collide = False

self.setup_lines()

self.setup_collision_handler()

def setup_lines(self):

# Static Ground

x, 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.95

line.friction = 1

line.collision_type = COLLISION_LINE

self.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)

Return the CollisionHandler for collisions between objects of type collision_type_a and 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 = 4

def 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.shapes

my_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_line

self.space.add_collision_handler(

COLLISION_PIG, COLLISION_BIRD).post_solve = post_solve_pig_bird

self.space.add_collision_handler(

COLLISION_PIG, COLLISION_LINE).post_solve = post_solve_pig_line

self.space.add_collision_handler(

COLLISION_PIG, COLLISION_BLOCK).post_solve = post_solve_pig_block

self.space.add_collision_handler(

COLLISION_BLOCK, COLLISION_BIRD).post_solve = post_solve_block_bird

def 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.8

else:

damage = impulse // MIN_DAMAGE_IMPULSE

pig.set_damage(damage)

# must init as a global parameter to use in the post_solve handler

my_phy = Physics()

创建一个pymunk物体

创建物体一般有下面五个步骤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)

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

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

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

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

摩擦系数(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.

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

pymunk.Space.add(*objs)

Add one or many shapes, bodies or joints to the space

class PhyPig():

def __init__(self, x, y, radius, space):

mass = 5

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.elasticity = 0.95

shape.friction = 1

shape.collision_type = COLLISION_PIG

space.add(body, shape)

self.body = body

self.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 stability

for 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.shape

p = to_pygame(poly.body.position)

x, y = p

w, h = pig.image.get_size()

# change to [left, top] position of pygame

x -= w * 0.5

y -= h * 0.5

angle_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

完善后的代码已打包成python教程,交流群:632408235 可到当中获取

python 物理引擎 摩擦力_Python 愤怒的小鸟代码实现:物理引擎pymunk使用相关推荐

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

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

  2. python编译为机器码_Python FAQ2-python代码编译问题

    本篇是关于py2.7.9-docs的FAQ.pdf中关于python编译的问题"3.13 Can Python be compiled to machine code, C or some ...

  3. 如何把python可视化到前端_Python一行代码搞定炫酷可视化,就用这个工具!

    学过Python数据分析的朋友都知道,在可视化的工具中,有很多优秀的三方库,比如matplotlib,seaborn,plotly,Boken,pyecharts等等.这些可视化库都有自己的特点,在实 ...

  4. python炫酷可视化_Python 一行代码搞定炫酷可视化,你需要了解一下 Cuffl

    前言 学过Python数据分析的朋友都知道,在可视化的工具中,有很多优秀的三方库,比如matplotlib,seaborn,plotly,Boken,pyecharts等等.这些可视化库都有自己的特点 ...

  5. python 点到围栏距离_Python一行代码处理地理围栏

    最近在工作中遇到了这个一个需求,用户设定地理围栏,后台获取到实时位置信息后通过与围栏比较,判断是否越界等. 这个过程需要用到数据协议为GEOjson,通过查阅资料后,发现python的shapely库 ...

  6. 用python写爱你_python表白代码-520使用Python实现quot;我爱你”表白

    摘要: 每到情人节.七夕节,不少小伙伴大伙伴们都会遇到这样一个世纪问题――怎么给女朋友/老婆一个与众不同的节日惊喜.今天给大家分享一个独特的表白方法――用"我爱你"拼出心爱人的模样 ...

  7. python京东预约抢购_Python参考代码:京东抢券脚本

    一.参数获取 要实现发送请求抢券,需要获取券的URL,并定制请求头Request Headers,下面所有参数都来自Chrome的开发者工具.大多浏览器都有开发者工具,可以按需选择. 准备步骤:登录网 ...

  8. python编写脚本教程_python脚本编写教程gee引擎解密工具

    尽管能够这样做,你也不可能一下把握全句的逻辑关系使用骨架.Spring Initializr创建项目时,往往自动导入了Junit的依赖,看一下pom.xml中有没有,没有就导入 原理等同上面方法,将会 ...

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

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

最新文章

  1. 机器学习数据整合+pandas方法astype、merge、drop、to_numeric、concat等
  2. LOJ #6280. 数列分块入门 4-分块(区间加法、区间求和)
  3. openSUSE中启用apache mod_rewrite
  4. UFLDL教程: Exercise:Self-Taught Learning
  5. [js] js源代码压缩都有哪些方法?它们的压缩原理分别是什么
  6. JavaScript中一些常用的方法整理
  7. html5两个静态页面传值,如何使用HTML5Viewer 进行参数传递
  8. DIV+CSS专题:第一天 XHTML CSS基础知识
  9. 访问限制:由于对必需的库E:\j2sdk\jre\lib\rt.jar具有一定限制,因此无法访问类型JFrame
  10. 人都“爆”了有这么好的东西《vtdakz.com》顶硬了!
  11. Linux安装Beyond Compare
  12. 计算机网络怎么连接两台机器,两台电脑怎么连接局域网,小编教你两台电脑怎么连接局域网...
  13. esri默认底图的加载
  14. 机器学习代码学习(一)-first-dichotomy
  15. JS 下载 URL 链接文件(点击按钮、点击a标签、支持代理与非代理下载)
  16. 基于评论的跨境电商产品满意度分析_kaic
  17. 关于对齐次裁剪空间及HLSL语义的理解
  18. 自定义ImageView实现播放帧动画
  19. 视频直播APP开发的主要功能
  20. win10系统禁用笔记本自带键盘的有效方法

热门文章

  1. 调用libcurl获取https的url文件的大小
  2. hge source explor 0xA graphics Ⅰ
  3. use of CGLib-based proxies by setting proxyTargetClass=true on @EnableAsync and/or @EnableCaching
  4. 服务器未响应 重新投递中,邮件无法收到
  5. 图像算法OR音视频传输
  6. matlab 罗德里格 公式,旋转矩阵,四元素,欧拉角
  7. 2022-2028全球车顶升降系统行业调研及趋势分析报告
  8. 编程器P800-ISP在线编程器接口介绍
  9. Android 高效播放apng文件(支持在RecycleView、ListView中显示)
  10. 【入门AUTOSAR网络管理测试】BSM-RMS状态转换