|
@@ -1,33 +1,33 @@
|
|
|
---
|
|
|
title: Defold 中的物理系统
|
|
|
-brief: Defold includes physics engines for 2D and 3D. They allow you to simulate Newtonian physics interactions between different types of collision objects. This manual explains how this works.
|
|
|
+brief: Defold 包含的物理引擎可以基于牛顿物理定律模拟物体运动碰撞时的物理效果. 本教程介绍了物理引擎的使用方法.
|
|
|
---
|
|
|
|
|
|
-# Physics
|
|
|
+# 物理
|
|
|
|
|
|
-Defold includes a modified version of the [Box2D](http://www.box2d.org) physics engine (version 2.1) for 2D physics simulations and the Bullet physics engine (version 2.77) for 3D physics. It allows you to simulate Newtonian physics interactions between different types of _collision objects_. This manual explains how this works.
|
|
|
+Defold 包含一个修改版的 [Box2D](http://www.box2d.org) 物理引擎 (版本 2.1) 用于模拟2D物理效果和一个 Bullet physics 引擎 (版本 2.77) 用来模拟3D物理效果. 物理引擎可以基于牛顿物理定律模拟各种 _碰撞物体_ 运动碰撞时的物理效果. 本教程介绍了物理引擎的使用方法.
|
|
|
|
|
|
-## Collision objects
|
|
|
+## 碰撞对象
|
|
|
|
|
|
-A collision object is a component you use to give a game object physical behaviour. A collision object has physical properties like weight, restitution and friction and its spatial extension is defined by one or more _shapes_ that you attach to the component. Defold supports the following types of collision objects:
|
|
|
+碰撞对象是能给与游戏对象物理行为的组件. 碰撞对象包含许多物理属性比如重量, 弹性, 阻力等等. 组件上定义的一个或多个 _形状_ 决定了它在物理空间中的样子. Defold 支持以下的碰撞对象:
|
|
|
|
|
|
Static objects
|
|
|
-: Static objects never move but a dynamic object that collides with a static object will react by bouncing and/or sliding. Static objects are very useful for building level geometry (i.e. ground and walls) that does not move. They are also cheaper performance-wise than dynamic objects. You cannot move or otherwise change static objects.
|
|
|
+: 静态对象不会移动但是能和移动物体进行碰撞. 静态对象很适合制作游戏固定场景元素 (比如地板和墙). 它们比动态对象性能消耗少. 静态对象不能被移动和修改.
|
|
|
|
|
|
Dynamic objects
|
|
|
-: Dynamic objects are simulated by the physics engine. The engine solves all collisions and applies resulting forces. Dynamic objects are good for objects that should behave realistically but you *cannot* directly manipulate the position and orientation of a dynamic object. The only way to affect them is indirectly, by applying forces.
|
|
|
+: 动态对象由物理引擎负责计算位移. 处理碰撞然后给予力. 动态对象看起来很有真实感但是你 *不能* 直接控制它的位置与方向. 要想对其施加影响, 只能向它施加力的作用.
|
|
|
|
|
|
Kinematic objects
|
|
|
-: Kinematic objects register collisions with other physics objects, but the physics engine do not perform any automatic simulation. The job of resolving collisions, or ignoring them, is left to you. Kinematic objects are very good for player or script controlled objects that require fine grained control of the physical reactions, like a player character.
|
|
|
+: 动画对象可以和其他对象产生碰撞, 但是物理引擎并不处理它们. 忽略碰撞, 或者交给你来处理. 动画对象很适合用作由脚本控制的又能对物理做出反应的物体, 比如游戏角色.
|
|
|
|
|
|
Triggers
|
|
|
-: Triggers are objects that register simple collisions. They are good for objects that just need to register a hit (like a bullet) or as part of game logic where you want to trigger certain actions when an object reaches a specific point. Trigger are computationally cheaper than kinematic objects and should be used in favor of those if possible.
|
|
|
+: 触发器是记录碰撞的物体. 很适合用作碰撞检测 (比如子弹碰撞) 或者接触后触发时间的场景. 触发器比动画对象节省性能所以可以多用一些.
|
|
|
|
|
|
-## Adding a collision object component
|
|
|
+## 加入 collision object 组件
|
|
|
|
|
|
-A collision object component has a set of *Properties* that sets its type and physics properties. It also contains one or more *Shapes* that define the whole shape of the physics object.
|
|
|
+碰撞对象组件包含一系列 *属性* 用以设定其类型和物理特性. 还包含一个或多个 *形状* 用以定义这个物体的物理形态.
|
|
|
|
|
|
-To add a collision object component to a game object:
|
|
|
+在游戏对象上添加碰撞对象组件:
|
|
|
|
|
|
1. In the *Outline* view, <kbd>right click</kbd> the game object and select <kbd>Add Component ▸ Collision Object</kbd> from the context menu. This creates a new component with no shapes.
|
|
|
2. <kbd>Right click</kbd> the new component and select <kbd>Add Shape ▸ Box / Capsule / Sphere</kbd>. This adds a new shape to the collision object component. You can add any number of shapes to the component. You can also use a tilemap or a convex hull to define the shape of the physics object.
|
|
@@ -37,207 +37,209 @@ To add a collision object component to a game object:
|
|
|
{srcset="images/physics/[email protected] 2x"}
|
|
|
|
|
|
Id
|
|
|
-: The identity of the component.
|
|
|
+: 组件名.
|
|
|
|
|
|
Collision Shape
|
|
|
-: This property is used for tile map geometry that does not use ordinary primitive shapes. See below for more information.
|
|
|
+: 这个是针对瓷砖地图的几何形状设置. 详见下文.
|
|
|
|
|
|
Type
|
|
|
-: The type of collision object: `Dynamic`, `Kinematic`, `Static` or `Trigger`. If you set the object to dynamic you _must_ set the *Mass* property to a non zero value. For dynamic or static objects you should also check that the *Friction* and *Restitution* values are good for your use-case.
|
|
|
+: 碰撞对象的类型有: `Dynamic`, `Kinematic`, `Static` 和 `Trigger`. 如果设为动态就 _必须_ 设置其 *Mass* 属性为非0的值. 动态静态碰撞对象都需要为其设置适当的 *Friction* 和 *Restitution* 值.
|
|
|
|
|
|
Friction
|
|
|
-: Friction makes it possible for objects to slide realistically against each other. The friction value is usually set between `0` (no friction at all---a very slippery object) and `1` (strong friction---an abrasive object). However, any positive value is valid.
|
|
|
+: 摩擦可以做出一个物体在另一个物体上滑动的效果. 一般摩擦系数取值范围从 `0` (无摩擦---超级光滑) 到 `1` (强摩擦---超级粗糙) 之间. 但其实任何正数值都有效.
|
|
|
|
|
|
- The friction strength is proportional to the normal force (this is called Coulomb friction). When the friction force is computed between two shapes (`A` and `B`), the friction values of both objects are combined by the geometric mean:
|
|
|
+ 摩擦力于法方向上的力成正比 (称为库伦摩擦). 计算两个物体 (`A` 和 `B`) 间的摩擦力时, 摩擦系数取两个物体的几何平均值:
|
|
|
|
|
|
$$
|
|
|
F_{combined} = \sqrt{ F_A \times F_B }
|
|
|
$$
|
|
|
|
|
|
- This means that if one of the objects has zero friction then the contact between them will have zero friction.
|
|
|
+ 也就是说只要有一个物体是0摩擦的, 两个物体之间就不会有摩擦力.
|
|
|
|
|
|
Restitution
|
|
|
-: The restitution value sets the "bounciness" of the object. The value is usually between 0 (inelastic collision—the object does not bounce at all) and 1 (perfectly elastic collision---the object's velocity will be exactly reflected in the bounce)
|
|
|
+: 弹性是物体的 "反弹性能". 一般取值范围从 0 (非弹性碰撞—一点也不反弹) 到 1 (完全弹性碰撞---物体速度在碰撞后完全反向)
|
|
|
|
|
|
- Restitution values between two shapes (`A` and `B`) are combined using the following formula:
|
|
|
+ 两个物体 (`A` 和 `B`) 之间的弹性计算基于以下公式:
|
|
|
|
|
|
$$
|
|
|
R = \max{ \left( R_A, R_B \right) }
|
|
|
$$
|
|
|
|
|
|
- When a shape develops multiple contacts, restitution is simulated approximately because Box2D uses an iterative solver. Box2D also uses inelastic collisions when the collision velocity is small to prevent bounce-jitter
|
|
|
+ 当一个形状发生多处碰撞时, 弹性模拟并不精确因为 Box2D 使用的是迭代解算器. Box2D 在碰撞相对速度很小时也使用非弹性碰撞代替, 以防止反弹抖动.
|
|
|
|
|
|
|
|
|
Linear damping
|
|
|
-: Linear damping reduces the linear velocity of the body. It is different from friction, which only occurs during contact, and can be used to give objects a floaty appearance, like they are moving through something thicker than air. Valid values are between 0 and 1.
|
|
|
+: 线性阻尼会减小刚体的线性速度. 不像摩擦只在物体接触时产生, 线性阻尼始终应用与线性移动的物体上, 给人一种物体飘进比空气密度大的环境中的感觉. 取值范围 0 到 1.
|
|
|
|
|
|
- Box2D approximates damping for stability and performance. At small values, the damping effect is independent of the time step while at larger damping values, the damping effect varies with the time step. If you run your game with a fixed time step, this never becomes an issue.
|
|
|
+ Box2D 并不精确计算阻尼. 值很小时阻尼与时间无关, 值很大时阻尼随时间变化. 如果时间步固定, 这不会造成问题.
|
|
|
|
|
|
Angular damping
|
|
|
-: Angular damping works like linear damping but reduces the angular velocity of the body. Valid values are between 0 and 1.
|
|
|
+: 角阻尼与线性阻尼类似, 不同的是它减小的是刚体角速度. 取值范围 0 到 1.
|
|
|
|
|
|
Locked rotation
|
|
|
-: Setting this property totally disables rotation on the collision object, no matter what forces are brought to it.
|
|
|
+: 关闭碰撞对象的旋转, 无论力如何施加都不会旋转.
|
|
|
|
|
|
Group
|
|
|
-: The name of the collison group the object should belong to. You can have 16 different groups and you name them as you see fit for your game. For example "players", "bullets", "enemies" and "world". If the *Collision Shape* is set to a tile map, this field is not used but the groups names are taken from the tile source.
|
|
|
+: 此碰撞对象所归属的碰撞组. 可以自由定义16个组. 比如 "players", "bullets", "enemies" 或 "world". 如果瓷砖地图上设置了 *Collision Shape*, 则使用的是瓷砖图源里的组名而不是该属性定义的组名.
|
|
|
|
|
|
Mask
|
|
|
-: The other _groups_ this object should collide with. You can name one group or specify multiple groups in a comma separated list. If you leave the Mask field empty, the object will not collide with anything.
|
|
|
+: 可以与此对象进行碰撞的 _组_. 如果指定多个, 组名以逗号分割. 如果值为空, 则此对象不与任何物体进行碰撞.
|
|
|
|
|
|
### Collision shapes
|
|
|
|
|
|
-A collision component can either use several primitive shapes or a single complex shape. The primitive shapes are *box*, *sphere* and *capsule*. A complex shape can either be created from a tilemap component or from a convex hull shape.
|
|
|
+碰撞对象的形状可以由多个简单形状组成也可以由一个复杂形状代替. 简单形状有 *box*, *sphere* 和 *capsule*. 复杂形状可以由瓷砖地图生成或者使用凸多边形.
|
|
|
|
|
|
### Box shape
|
|
|
-A box has a position, rotation and dimensions (width, height and depth):
|
|
|
+方形设定由位置, 旋转和尺寸 (宽度, 高度和深度) 组成:
|
|
|
|
|
|

|
|
|
|
|
|
### Sphere shape
|
|
|
-A sphere has a position, rotation and diameter:
|
|
|
+圆形设定由位置, 旋转和直径组成:
|
|
|
|
|
|

|
|
|
|
|
|
### Capsule shape
|
|
|
-A capsule has a position, rotation, diameter and height:
|
|
|
+胶囊形设定由位置, 旋转, 直径和高度组成:
|
|
|
|
|
|

|
|
|
|
|
|
-### Tilemap collision shape
|
|
|
-Defold includes a feature allowing you to easily generate physics shapes for a tile map. The [Tilemap manual](/manuals/tilemap/) explains how to add collision groups to a tile source and assign tiles to collision groups ([example](/examples/tilemap/collisions/)).
|
|
|
+### 瓷砖地图碰撞形状
|
|
|
+Defold 包含一个功能就是从瓷砖地图中自动生成物理碰撞形状. [瓷砖地图教程](/manuals/tilemap/) 介绍了新建瓷砖图源的碰撞组与把瓷砖分配给碰撞组的 ([例子](/examples/tilemap/collisions/)).
|
|
|
|
|
|
-To add collision to a tile map:
|
|
|
+在瓷砖地图上添加碰撞:
|
|
|
|
|
|
-1. Add the tilemap to a game object by <kbd>right-clicking</kbd> the game object and selecting <kbd>Add Component File</kbd>. Select the tile map file.
|
|
|
-2. Add a collision object component to the game object by <kbd>right-clicking</kbd> the game object and selecting <kbd>Add Component ▸ Collision Object</kbd>.
|
|
|
-3. Instead of adding shapes to the component, set the *Collision Shape* property to the *tilemap* file.
|
|
|
-4. Set up the collision object component *Properties* as usual.
|
|
|
+1. <kbd>右键点击</kbd> 游戏对象, 选择 <kbd>Add Component File</kbd>. 来选取瓷砖地图文件.
|
|
|
+2. <kbd>右键点击</kbd> 游戏对象, 选择 <kbd>Add Component ▸ Collision Object</kbd> 加入碰撞对象组件.
|
|
|
+3. 不加入形状, 而是配置 *Collision Shape* 属性为 *瓷砖地图* 文件.
|
|
|
+4. 设置碰撞对象的其他 *属性*.
|
|
|
|
|
|
{srcset="images/physics/[email protected] 2x"}
|
|
|
|
|
|
-::: important
|
|
|
-Note that the *Group* property is **not** used here since the collision groups are defined in the tile map's tile source.
|
|
|
+::: 注意
|
|
|
+这里的 *Group* 属性 **不** 生效, 因为碰撞组已在瓷砖图源中定义好了.
|
|
|
:::
|
|
|
|
|
|
-### Convex hull shape
|
|
|
-Defold includes a feature allowing you to create a convex hull shape from three or more points. You can use an external tool such as the [Defold Polygon Editor](/assets/defoldpolygoneditor/) or the [Physics Body Editor](/assets/physicsbodyeditor/) to create a convex hull shape.
|
|
|
+### 凸多边形
|
|
|
+Defold 有一个功能就是让你用3个或多个点建立凸多边形. 可以使用资源 [Defold 多边形编辑器](/assets/defoldpolygoneditor/) 或者 [物理刚体编辑器](/assets/physicsbodyeditor/) 来创建凸多边形.
|
|
|
|
|
|
-1. Create convex hull shape file (file extension `.convexshape`) using an external editor.
|
|
|
-2. Instead of adding shapes to the collision object component, set the *Collision Shape* property to the *convex shape* file.
|
|
|
+1. 新建凸多边形文件 (扩展名 `.convexshape`).
|
|
|
+2. 不在碰撞对象上加入形状, 而是设置 *Collision Shape* 属性为 *凸多边形文件*.
|
|
|
|
|
|
-::: sidenote
|
|
|
-The shape will not be drawn in the editor. You can [enable Physics debugging](/manuals/debugging/#debugging-problems-with-physics) at runtime to see the shape.
|
|
|
+::: 注意
|
|
|
+编辑器里不显示形状. 只有 [开启物理调试](/manuals/debugging-game-logic/#物理引擎调试) 才能在运行时看到形状.
|
|
|
:::
|
|
|
|
|
|
|
|
|
-### Scaling collision shapes
|
|
|
+### 缩放碰撞形状
|
|
|
|
|
|
-It is possible to let the collision object and its shapes inherit the scale of the game object. Check the [Allow Dynamic Transforms](/manuals/project-settings/#allow-dynamic-transforms) checkbox in the Physics section of *game.project* to enable this. Note that only uniform scaling is supported and that the smallest scale value will be used if the scale isn't uniform.
|
|
|
+可以让碰撞形状继承游戏对象的缩放. 在 *game.project* 里的物理部分勾选 [Allow Dynamic Transforms](/manuals/project-settings/#Allow Dynamic Transforms) 即可. 注意缩放继承只支持等比缩放, 如果不等比, 去三周最小值.
|
|
|
|
|
|
|
|
|
-### Rotating collision shapes
|
|
|
+### 旋转碰撞形状
|
|
|
|
|
|
-### Rotating collision shapes in 3D physics
|
|
|
-Collision shapes in 3D physics can be rotated around all axis.
|
|
|
+#### 在3D物理世界中旋转碰撞形状
|
|
|
+在3D物理中物体在各个轴上都可以进行旋转.
|
|
|
|
|
|
|
|
|
-### Rotating collision shapes in 2D physics
|
|
|
-Collision shapes in 2D physics can only be rotated around the z-axis. Rotation around the x or y axis will yield incorrect results and should be avoided, even when rotating 180 degrees to essentially flip the shape along the x or y axis. To flip a physics shape it is recommended to use [`physics.set_hlip(url, flip)`](/ref/stable/physics/?#physics.set_hflip:url-flip) and [`physics.set_vlip(url, flip)`](/ref/stable/physics/?#physics.set_vflip:url-flip).
|
|
|
+#### 在2D物理世界中旋转碰撞形状
|
|
|
+在3D物理中物体只能在z轴上旋转. 其他轴旋转会造成错误结果, 即使旋转180度用于翻转形状也不行. 要翻转物理形状推荐使用 [`physics.set_hlip(url, flip)`](/ref/stable/physics/?#physics.set_hflip:url-flip) 和 [`physics.set_vlip(url, flip)`](/ref/stable/physics/?#physics.set_vflip:url-flip) 函数.
|
|
|
|
|
|
|
|
|
-### Units used by the physics engine simulation
|
|
|
+### 物理引擎单位
|
|
|
|
|
|
-The physics engine simulates Newtonian physics and it is designed to work well with meters, kilograms and seconds (MKS) units. Furthermore, the physics engine is tuned to work well with moving objects of a size in the 0.1 to 10 meters range (static objects can be larger) and by default the engine treats 1 unit (pixel) as 1 meter. This conversion between pixels and meters is convenient on a simulation level, but from a game creation perspective it isn't very useful. With default settings a collision shape with a size of 200 pixels would be treated as having a size of 200 meters which is well outside of the recommended range, at least for a moving object. In general it is required that the physics simulation is scaled for it to work well with the typical size of objects in a game. The scale of the physics simulation can be changed in `game.project` via the [physics scale setting](/manuals/project-settings/#physics). Setting this value to for instance 0.02 would mean that 200 pixels would be treated as a 4 meters. Do note that the gravity (also changed in `game.project`) has to be increased to accommodate for the change in scale.
|
|
|
+设计上按照牛顿物理学单位米, 千克和秒 (MKS) 的标准单位. 模拟物尺寸 0.1 到 10 米范围 (静态对象可以更大) 效果较好, 默认一像素 (pixel) 当作 1 米. 这种转换是物理模拟器层次上的, 对游戏来说并不适用.
|
|
|
+默认一个200像素的物体在物理世界相当于200米超过了最佳模拟范围. 一般需要对游戏里的物体进行物理上的缩放. 可以在 `game.project` 里的 [物理缩放设置](/manuals/project-settings/#Physics) 处指定缩放值.
|
|
|
+比如设置为 0.02 意味着 1:50, 那么200像素就是 4 米. 注意重力 (也在 `game.project` 里进行设定) 也需要基于缩放值进行调整.
|
|
|
|
|
|
-## Group and mask
|
|
|
+## 碰撞组与碰撞掩码
|
|
|
|
|
|
-The physics engine allows you to group your physics objects and filter how they should collide. This is handled by named _collision groups_. For each collision object you create two properties control how the object collides with other objects, *Group* and *Mask*.
|
|
|
+物理引擎通过组与掩码处理碰撞. 这个组就是 _碰撞组_. 每个碰撞对象都有2个属性用以控制其与其他物体的碰撞, *Group* 和 *Mask*.
|
|
|
|
|
|
-For a collision between two objects to register both objects must mutually specify each other's groups in their *Mask* field.
|
|
|
+碰撞只发生在两个物体所处的组分别被包含在对方的 *碰撞掩码* 之中的情况下.
|
|
|
|
|
|
{srcset="images/physics/[email protected] 2x"}
|
|
|
|
|
|
-The *Mask* field can contain multiple group names, allowing for complex interaction scenarios.
|
|
|
+*掩码* 可包含多个组名, 以实现复杂的碰撞控制.
|
|
|
|
|
|
|
|
|
-## Collision messages
|
|
|
+## 碰撞消息
|
|
|
|
|
|
-When two objects collide, the engine will broadcast messages to all components in both objects:
|
|
|
+两个物体发生碰撞时, 消息会广播到两个物体上的所有组件中:
|
|
|
|
|
|
**`"collision_response"`**
|
|
|
|
|
|
-This message is sent for all collision objects. It has the following fields set:
|
|
|
+碰撞对象会收到此消息. 其包含以下数据内容:
|
|
|
|
|
|
`other_id`
|
|
|
-: the id of the instance the collision object collided with (`hash`)
|
|
|
+: 另一个碰撞物的id (`hash`过的)
|
|
|
|
|
|
`other_position`
|
|
|
-: the world position of the instance the collision object collided with (`vector3`)
|
|
|
+: 另一个碰撞物的世界坐标 (`vector3`类型)
|
|
|
|
|
|
`other_group`
|
|
|
-: the collision group of the other collision object (`hash`)
|
|
|
+: 另一个碰撞物所在的碰撞组 (`hash`过的)
|
|
|
|
|
|
-The collision_response message is only adequate to resolve collisions where you don't need any details on the actual intersection of the objects, for example if you want to detect if a bullet hits an enemy. There is only one of these messages sent for any colliding pair of objects each frame.
|
|
|
+如果不需要很详细的信息, 碰撞响应消息就足够了, 比如检测子弹是否碰撞了敌人. 每帧每对碰撞物只有一个能收到此消息.
|
|
|
|
|
|
**`"contact_point_response"`**
|
|
|
|
|
|
-This message is sent when one of the colliding objects is dynamic or kinematic. It has the following fields set:
|
|
|
+这个消息由 dynamic 或 kinematic 碰撞对物体其中之一接收. 附带如下数据:
|
|
|
|
|
|
`position`
|
|
|
-: world position of the contact point (`vector3`).
|
|
|
+: 接触点世界坐标 (`vector3`类型).
|
|
|
|
|
|
`normal`
|
|
|
-: normal in world space of the contact point, which points from the other object towards the current object (`vector3`).
|
|
|
+: 接触点世界坐标系法向量, 方向是从另一物体指向当前物体 (`vector3`类型).
|
|
|
|
|
|
`relative_velocity`
|
|
|
-: the relative velocity of the collision object as observed from the other object (`vector3`).
|
|
|
+: 两个接触物体之间的相对速度, 方向是从另一物体指向当前物体 (`vector3`类型).
|
|
|
|
|
|
`distance`
|
|
|
-: the penetration distance between the objects -- non negative (`number`).
|
|
|
+: 两个接触物体之间穿透距离 -- 非负数 (`number`类型).
|
|
|
|
|
|
`applied_impulse`
|
|
|
-: the impulse the contact resulted in (`number`).
|
|
|
+: 两个接触物体间的冲量大小 (`number`类型).
|
|
|
|
|
|
`life_time`
|
|
|
-: (*not currently used!*) life time of the contact (`number`).
|
|
|
+: (*目前未使用*) 接触时长 (`number`类型).
|
|
|
|
|
|
`mass`
|
|
|
-: the mass of the current collision object in kg (`number`).
|
|
|
+: 当前物体质量, 单位千克 (`number`类型).
|
|
|
|
|
|
`other_mass`
|
|
|
-: the mass of the other collision object in kg (`number`).
|
|
|
+: 另一个物体质量, 单位千克 (`number`类型).
|
|
|
|
|
|
`other_id`
|
|
|
-: the id of the instance the collision object is in contact with (`hash`).
|
|
|
+: 另一个物体的id (`hash`过的).
|
|
|
|
|
|
`other_position`
|
|
|
-: the world position of the other collision object (`vector3`).
|
|
|
+: 另一个物体的世界坐标 (`vector3`类型).
|
|
|
|
|
|
`group`
|
|
|
-: the collision group of the other collision object (`hash`).
|
|
|
+: 另一个物体所处的碰撞组 (`hash`过的).
|
|
|
|
|
|
-For a game or application where you need to separate objects perfectly, the `"contact_point_response"` message gives you all information you need. However, note that for any given collision pair, several `"contact_point_response"` messages can be received each frame, depending on the nature of the collision. See below for more information.
|
|
|
+要让相碰撞的物体好好分离, 用 `"contact_point_response"` 消息里的数据就够了. 注意每帧每对碰撞物可能不止收到一个 `"contact_point_response"` 消息, 取决于接触的多少. 详情请见下文.
|
|
|
|
|
|
-## Trigger messages
|
|
|
+## 触发器消息
|
|
|
|
|
|
-Triggers are light weight collision objects. Thay are similar to ray casts in that they read the physics world as opposed to interacting with it.
|
|
|
+触发器是精简版的碰撞物体. 根投射射线类似, 它们迭代物理世界物品但不与之进行交互.
|
|
|
|
|
|
-In a trigger collision `"collision_response"` messages are sent. In addition, triggers also send a special `"trigger_response"` message when the collision begins and ends. The message has the following fields:
|
|
|
+触发器碰撞时发出 `"collision_response"` 消息. 而且在碰撞开始和结束时都会发送 `"trigger_response"` 消息. 消息包含如下信息:
|
|
|
|
|
|
`other_id`
|
|
|
-: the id of the instance the collision object collided with (`hash`).
|
|
|
+: 另一个物体的id (`hash`过的).
|
|
|
|
|
|
`enter`
|
|
|
-: `true` if the interaction was an entry into the trigger, `false` if it was an exit. (`boolean`).
|
|
|
+: 如果另一个物体进入触发器为 `true`, 离开为 `false`. (`boolean`类型).
|
|
|
|
|
|
-## Resolving kinematic collisions
|
|
|
+## 动画碰撞对象
|
|
|
|
|
|
-Using kinematic collision objects require you to resolve collisions yourself and move the objects as a reaction. A naive implementation of separating two colliding objects looks like this:
|
|
|
+对于动画碰撞对象的碰撞必须手动处理. 一个想当然的处理方法如下:
|
|
|
|
|
|
```lua
|
|
|
function on_message(self, message_id, message, sender)
|
|
|
- -- Handle collision
|
|
|
+ -- 处理碰撞
|
|
|
if message_id == hash("contact_point_response") then
|
|
|
local newpos = go.get_position() + message.normal * message.distance
|
|
|
go.set_position(newpos)
|
|
@@ -245,68 +247,68 @@ function on_message(self, message_id, message, sender)
|
|
|
end
|
|
|
```
|
|
|
|
|
|
-This code will separate your kinematic object from other physics object it penetrates, but the separation often overshoots and you will see jitter in many cases. To understand the problem better, consider the following case where a player character has collided with two objects, *A* and *B*:
|
|
|
+动画碰撞对象的确离开了碰撞穿透, 但是分离之后经常会过冲, 这在许多情况下会产生抖动. 为了便于理解, 想象游戏主角碰到了两个物体, *A* 和 *B*:
|
|
|
|
|
|
{srcset="images/physics/[email protected] 2x"}
|
|
|
|
|
|
-The physics engine will send multiple `"contact_point_response"` message, one for object *A* and one for object *B* the frame the collision occurs. If you move the character in response to each penetration, as in the naive code above, the resulting separation would be:
|
|
|
+碰撞发生的那一帧里, 物理引擎发出多个 `"contact_point_response"` 消息, 一个给 *A* 一个给 *B*. 如果按上面那样移动角色, 结果会是这样:
|
|
|
|
|
|
-- Move the character out of object *A* according to its penetration distance (the black arrow)
|
|
|
-- Move the character out of object *B* according to its penetration distance (the black arrow)
|
|
|
+- 根据 *A* 的穿透距离把角色向上移 (黑色箭头)
|
|
|
+- 根据 *B* 的穿透距离把角色向左上移 (黑色箭头)
|
|
|
|
|
|
-The order of these is arbitrary but the result is the same either way: a total separation that is the *sum of the individual penetration vectors*:
|
|
|
+顺序无所谓结果是一样的: 最终位移是 *每个穿透向量的矢量和*:
|
|
|
|
|
|
{srcset="images/physics/[email protected] 2x"}
|
|
|
|
|
|
-To properly separate the character from objects *A* and *B*, you need to handle each contact point's penetration distance and check if any previous separations have already, wholly or partially, solved the separation.
|
|
|
+要想正确地将角色移出 *A* 和 *B*, 需要处理碰撞点的穿透距离并检测上一个位移是否, 完全或部分, 分离了它们.
|
|
|
|
|
|
-Suppose that the first contact point message comes from object *A* and that you move the character out by *A*'s penetration vector:
|
|
|
+假设第一次碰撞从 *A* 开始, 然后针对 *A* 做位移:
|
|
|
|
|
|
{srcset="images/physics/[email protected] 2x"}
|
|
|
|
|
|
-Then the character has already been partially separated from *B*. The final compensation necessary to perform full separation from object *B* is indicated by the black arrow above. The length of the compensation vector can be calculated by projecting the penetration vector of *A* onto the penetration vector of *B*:
|
|
|
+这样一来角色也部分离开了 *B*. 最后只剩下 *B* 黑色箭头那点穿透. 这段位移应该是 *A* 向量映射到 *B* 剩余的补偿:
|
|
|
|
|
|
{srcset="images/physics/[email protected] 2x"}
|
|
|
|
|
|
$$l = vmath.project(A, B) \times vmath.length(B)$$
|
|
|
|
|
|
-The compensation vector can be found by reducing the length of *B* by *l*. To calculate this for an arbitrary number of penetrations, you can accumulate the necessary correction in a vector by, for each contact point, and starting with a zero length correction vector:
|
|
|
+补偿向量等于 *B* 向量减去 *l* 向量. 所以计算位移的时候, 对于每个碰撞点, 可以引入矫正向量按以下步骤进行矫正:
|
|
|
|
|
|
-1. Project the current correction against the contact's penetration vector.
|
|
|
-2. Calculate what compensation is left from the penetration vector (as per the formula above).
|
|
|
-3. Move the object by the compensation vector.
|
|
|
-4. Add the compensation to the accumulated correction.
|
|
|
+1. 把当前矫正向量映射到碰撞穿透向量上.
|
|
|
+2. 计算穿透向量的补偿 (按照上述公式).
|
|
|
+3. 依照补偿向量移动对象.
|
|
|
+4. 把补偿向量累加到矫正向量中.
|
|
|
|
|
|
-A complete implementation looks like this:
|
|
|
+完整的代码实现如下:
|
|
|
|
|
|
```lua
|
|
|
function init(self)
|
|
|
- -- correction vector
|
|
|
+ -- 校正向量
|
|
|
self.correction = vmath.vector3()
|
|
|
end
|
|
|
|
|
|
function update(self, dt)
|
|
|
- -- reset correction
|
|
|
+ -- 重置矫正向量
|
|
|
self.correction = vmath.vector3()
|
|
|
end
|
|
|
|
|
|
function on_message(self, message_id, message, sender)
|
|
|
- -- Handle collision
|
|
|
+ -- 处理碰撞
|
|
|
if message_id == hash("contact_point_response") then
|
|
|
- -- Get the info needed to move out of collision. We might
|
|
|
- -- get several contact points back and have to calculate
|
|
|
- -- how to move out of all of them by accumulating a
|
|
|
- -- correction vector for this frame:
|
|
|
+ -- 获取位移计算所需数据.
|
|
|
+ -- 当前帧可能有多个碰撞点需要处理,
|
|
|
+ -- 通过累积矫正向量,
|
|
|
+ -- 达到正确计算位移的目的:
|
|
|
if message.distance > 0 then
|
|
|
- -- First, project the accumulated correction onto
|
|
|
- -- the penetration vector
|
|
|
+ -- 第一步, 把矫正向量投射到
|
|
|
+ -- 穿透向量上.
|
|
|
local proj = vmath.project(self.correction, message.normal * message.distance)
|
|
|
if proj < 1 then
|
|
|
- -- Only care for projections that does not overshoot.
|
|
|
+ -- 没有过冲的才需要补偿.
|
|
|
local comp = (message.distance - message.distance * proj) * message.normal
|
|
|
- -- Apply compensation
|
|
|
+ -- 应用补偿向量.
|
|
|
go.set_position(go.get_position() + comp)
|
|
|
- -- Accumulate correction done
|
|
|
+ -- 积累矫正向量.
|
|
|
self.correction = self.correction + comp
|
|
|
end
|
|
|
end
|
|
@@ -314,87 +316,88 @@ function on_message(self, message_id, message, sender)
|
|
|
end
|
|
|
```
|
|
|
|
|
|
-## Ray casts
|
|
|
+## 射线投射
|
|
|
|
|
|
-Ray casts are used to read the physics world along a linear ray. To cast a ray into the physics world, you provide a start and end position as well as a set of collision groups to test against.
|
|
|
+射线用于收集延一条投射射线所遇到的物理世界的物体. 只要提供起止点和碰撞组, 就可以投射射线了.
|
|
|
|
|
|
-If the ray hits a physics object you will get information about the object it hit. Rays intersect with dynamic, kinematic and static objects. They do not interact with triggers.
|
|
|
+射线碰到的物体数据都会被记录下来. 包括动态, 静态和动画碰撞对象. 不包括触发器对象.
|
|
|
|
|
|
```lua
|
|
|
function update(self, dt)
|
|
|
- -- request ray cast
|
|
|
+ -- 投射射线
|
|
|
local my_start = vmath.vector3(0, 0, 0)
|
|
|
local my_end = vmath.vector3(100, 1000, 1000)
|
|
|
local my_groups = { hash("my_group1"), hash("my_group2") }
|
|
|
|
|
|
local result = physics.raycast(my_start, my_end, my_groups)
|
|
|
if result then
|
|
|
- -- act on the hit (see 'ray_cast_response' message for all values)
|
|
|
+ -- 处理射线碰撞结果 (所有数据参见 'ray_cast_response' 消息)
|
|
|
print(result.id)
|
|
|
end
|
|
|
end
|
|
|
```
|
|
|
|
|
|
-::: sidenote
|
|
|
-Ray casts will ignore collision objects that contain the starting point of the ray. This is a limitation in Box2D.
|
|
|
+::: 注意
|
|
|
+结果不包括射线起始点位置的碰撞物体. 这是 Box2D 做的限制.
|
|
|
:::
|
|
|
|
|
|
-## Joints
|
|
|
+## 关节
|
|
|
|
|
|
-Defold supports joints for 2D physics. A joint connects two collision objects using some kind of constraint. The supported joint types are:
|
|
|
+Defold 支持物理关节. 一个关键基于某种限制连接两个物体. 支持的关节类型如下:
|
|
|
|
|
|
-* Fixed (physics.JOINT_TYPE_FIXED) - A rope joint that restricts the maximum distance between two points. In Box2D referred to as a Rope joint.
|
|
|
-* Hinge (physics.JOINT_TYPE_HINGE) - A hinge joint specifies an anchor point on two collision objects and moves them so that the two collision objects are always in the same place, and the relative rotation of the collision objects is not restricted. The hinge joint can enable a motor with a defined maximum engine torque and speed. In Box2D referred to as a Revolute joint.
|
|
|
-* Spring (physics.JOINT_TYPE_SPRING) - A spring joint keeps two collision objects at a constant distance from each other. The spring joint can be made soft like a spring with a frequency and damping ratio. In Box2D referred to as a Distance joint.
|
|
|
-* Slider (physics.JOINT_TYPE_SLIDER) - A slider joint allows for relative translation of two collision objects along a specified axis and prevents relative rotation. In Box2D referred to as a Prismatic joint.
|
|
|
+* Fixed (physics.JOINT_TYPE_FIXED) - 限制两物体最大距离的固定关节. 在 Box2D 被称为绳子关节.
|
|
|
+* Hinge (physics.JOINT_TYPE_HINGE) - 把两个物体通过一个锚点钉在一起的钉子关节. 两物体相对位置固定而相对旋转没有限制. 这种关节可以开启马达给一个最大扭力与速度. 在 Box2D 被称为旋转关节.
|
|
|
+* Spring (physics.JOINT_TYPE_SPRING) - 限制两个物体之间距离范围的弹簧关节. 弹簧关节通过设定其频率和阻尼比可以让物体像是被软弹簧连接. 在 Box2D 被称为距离关节.
|
|
|
+* Slider (physics.JOINT_TYPE_SLIDER) - 限制两物体只能在某个指定轴上相对移动而不允许相对转动的滑动关节. 在 Box2D 被称为活塞关节.
|
|
|
|
|
|
-### Creating joints
|
|
|
+### 建立关节
|
|
|
|
|
|
-Joints can currently only be created programmatically using [`physics.create_joint()`](/ref/physics/#physics.create_joint:joint_type-collisionobject_a-joint_id-position_a-collisionobject_b-position_b-[properties]):
|
|
|
-::: sidenote
|
|
|
-Editor support for creating joints is planned but no release date has been decided.
|
|
|
+目前只能使用 [`physics.create_joint()`](/ref/physics/#physics.create_joint:joint_type-collisionobject_a-joint_id-position_a-collisionobject_b-position_b-[properties]) 函数手动建立关节:
|
|
|
+
|
|
|
+::: 注意
|
|
|
+编辑器可是环境新建关节在支持计划中但发布时间未知.
|
|
|
:::
|
|
|
|
|
|
```lua
|
|
|
--- connect two collision objects with a fixed joint constraint (rope)
|
|
|
+-- 将两个碰撞物体用固定关节连接 (绳子)
|
|
|
physics.create_joint(physics.JOINT_TYPE_FIXED, "obj_a#collisionobject", "my_test_joint", vmath.vector3(10, 0, 0), "obj_b#collisionobject", vmath.vector3(0, 20, 0), { max_length = 20 })
|
|
|
```
|
|
|
|
|
|
-The above will create a fixed joint with id `my_test_joint` connected between the two collision object `obj_a#collisionobject` and `obj_b#collisionobject`. The joint is connected 10 pixels to the left of the center of collision object `obj_a#collisionobject` and 20 pixels above the center of collision object `obj_b#collisionobject`. The maximum length of the joint is 20 pixels.
|
|
|
+上述代码创建了一个固定关节, 其id为 `my_test_joint`, 连接了两个物体 `obj_a#collisionobject` 与 `obj_b#collisionobject`. 关节位于 `obj_a#collisionobject` 偏左10像素, `obj_b#collisionobject` 偏上20像素的位置上. 设定的最大距离是20像素.
|
|
|
|
|
|
-### Destroying joints
|
|
|
+### 删除关节
|
|
|
|
|
|
-A joint can be destroyed using [`physics.destroy_joint()`](/ref/physics/#physics.destroy_joint:collisionobject-joint_id):
|
|
|
+可以使用 [`physics.destroy_joint()`](/ref/physics/#physics.destroy_joint:collisionobject-joint_id) 函数删除关节:
|
|
|
|
|
|
```lua
|
|
|
--- destroy a joint previously connected to the first collision object
|
|
|
+-- 删除上面提到的第一个物体上的关节
|
|
|
physics.destroy_joint("obj_a#collisionobject", "my_test_joint")
|
|
|
```
|
|
|
|
|
|
-### Reading from and Updating joints
|
|
|
+### 关节属性及修改
|
|
|
|
|
|
-The properties of a joint can be read using [`physics.get_joint_properties()`](/ref/physics/#physics.get_joint_properties:collisionobject-joint_id) and set using [`physics.set_joint_properties()`](/ref/physics/#physics.set_joint_properties:collisionobject-joint_id-properties):
|
|
|
+可以使用 [`physics.get_joint_properties()`](/ref/physics/#physics.get_joint_properties:collisionobject-joint_id) 读取关节属性, 使用 [`physics.set_joint_properties()`](/ref/physics/#physics.set_joint_properties:collisionobject-joint_id-properties) 修改关节属性:
|
|
|
|
|
|
```lua
|
|
|
function update(self, dt)
|
|
|
if self.accelerating then
|
|
|
local hinge_props = physics.get_joint_properties("obj_a#collisionobject", "my_hinge")
|
|
|
- -- increase motor speed by 100 revolutions per second
|
|
|
+ -- 马达速度提升每秒100转
|
|
|
hinge_props.motor_speed = hinge_props.motor_speed + 100 * 2 * math.pi * dt
|
|
|
physics.set_joint_properties("obj_a#collisionobject", "my_hinge", hinge_props)
|
|
|
end
|
|
|
end
|
|
|
```
|
|
|
|
|
|
-### Get joint reaction force and torque
|
|
|
+### 关节反作用力和扭矩
|
|
|
|
|
|
-The reaction force and torque applied to a joint can be read using [`physics.get_joint_reaction_force()`](/ref/physics/#physics.get_joint_reaction_force:collisionobject-joint_id) and [`physics.get_joint_reaction_torque()`](/ref/physics/#physics.get_joint_reaction_torque:collisionobject-joint_id).
|
|
|
+可以使用 [`physics.get_joint_reaction_force()`](/ref/physics/#physics.get_joint_reaction_force:collisionobject-joint_id) 读取关节反作用力, 使用 [`physics.get_joint_reaction_torque()`](/ref/physics/#physics.get_joint_reaction_torque:collisionobject-joint_id) 读取关节扭力.
|
|
|
|
|
|
|
|
|
-## Caveats and common issues
|
|
|
+## 注意事项
|
|
|
|
|
|
-Collection proxies
|
|
|
-: Through collection proxies it is possible to load more than one top level collection, or *game world* into the engine. When doing so it is important to know that each top level collection is a separate physical world. Physics interactions (collisions, triggers, ray-casts) only happen between objects belonging to the same world. So even if the collision objects from two worlds visually sits right on top of each other, there cannot be any physics interaction between them.
|
|
|
+碰撞代理
|
|
|
+: 通过碰撞代理可以支持多个物理集合, 或称 *游戏世界*. 但是要记住每个集合都是一个单独的物理世界. 物理现象 (碰撞, 触发, 射线) 之发生在同一世界中. 两个不同集合的物体就算放到一块儿, 也不会发生物理碰撞.
|
|
|
|
|
|
-Collisions not detected
|
|
|
-: If you have problems with collisions not being handled or detected properly then make sure to read up on [physics debugging in the Debugging manual](/manuals/debugging/#debugging-problems-with-physics).
|
|
|
+碰撞漏检
|
|
|
+: 如果发现碰撞未检测或未处理请先阅读 [调试教程的物理调试部分](/manuals/debugging-game-logic/#物理引擎调试).
|