Godot 物理引擎 2D

collision object 碰撞物

area2d

area2d只提供检测,能够触发接触检测,区域进出检测,不可用于碰撞,可以想象成雷达。也可以检测区域是否重叠。区域也可以接收鼠标/触摸输入。

static body 2d

静态物,无法被移动,固定在场景中,可被碰撞。静态物体可以设置线性速度和线性角动量,用来影响碰撞的刚体。

rigid body 2d

刚体,最好不要直接移动物体,而是给物体施加力,否则会破坏其中的物理系统。当刚体不运动后,物体会保持静止,类似静态物一样,直到再次受力。

  • rigid:刚体模式,默认
  • static: 类似static body 2d 无法移动
  • charactor: 和rigid一样,只是无法旋转
  • kinematic:类似kinematic body 2d,只能通过代码来表现它的运动效果

kinematic body 2d

动态物体,不会被物理引擎约束,可以随意控制位置,能和刚体和静态物相互碰撞。
移动时不要使用move(),要使用move_and_collide()或者move_and_slide()方法。如果碰撞,则api会停止,碰撞触发后手动处理之后的事情。

碰撞形状

绝对不要对碰撞形状进行缩放

物理过程

在_process中刷新可能物理位置不稳定,使用_physics_process来处理

layer mask 层与遮罩

物体所在的层

遮罩

物体可以碰撞的层

可以在项目设置中对图层命名


2068504-224c4cd23fcbe55d.png

使用力,避免使用线性速度和角速度

extends RigidBody2D

var thrust = Vector2(0, 250)
var torque = 20000

func _integrate_forces(state):
    if Input.is_action_pressed("ui_up"):
        applied_force = thrust.rotated(rotation)
    else:
        applied_force = Vector2()
    var rotation_dir = 0
    if Input.is_action_pressed("ui_right"):
        rotation_dir += 1
    if Input.is_action_pressed("ui_left"):
        rotation_dir -= 1
    applied_torque = rotation_dir * torque

[!!!]当进入睡眠时,_integrate_forces()不再有效,你必须一直确保它与其他物体间有碰撞,或者关闭can_sleep

运动碰撞响应

move_and_collision

返回 空 或者 kinematic collision 2d对象,其中包含了碰撞信息

查找碰撞点

extends KinematicBody2D

var velocity = Vector2(250, 250)

func _physics_process(delta):
    var collision_info = move_and_collide(velocity * delta)
    if collision_info:
        var collision_point = collision_info.position

反弹效果:

extends KinematicBody2D

var velocity = Vector2(250, 250)

func _physics_process(delta):
    var collision_info = move_and_collide(velocity * delta)
    if collision_info:
        velocity = velocity.bounce(collision_info.normal)

move_and_slide

对move_and_collision的高级处理,直接进行滑动运动

move_and_slide包含了时间步长,所以向量不要乘delta

行走和跳跃

extends KinematicBody2D

var run_speed = 350
var jump_speed = -1000
var gravity = 2500

var velocity = Vector2()

func get_input():
    velocity.x = 0
    var right = Input.is_action_pressed('ui_right')
    var left = Input.is_action_pressed('ui_left')
    var jump = Input.is_action_just_pressed('ui_select')

    if is_on_floor() and jump:
        velocity.y = jump_speed
    if right:
        velocity.x += run_speed
    if left:
        velocity.x -= run_speed

func _physics_process(delta):
    velocity.y += gravity * delta
    get_input()
    velocity = move_and_slide(velocity, Vector2(0, -1))

move_and_collision 与 move_and_slide参数区别

move_and_collision参数需要乘delta

velocity.y += delta * GRAVITY
var motion = velocity * delta
move_and_collide(motion)

move_and_slide参数不需要乘delta

velocity.y += delta * GRAVITY
move_and_slide(velocity, Vector2(0, -1))

move_and_slide_with_snap 粘着
跳跃时会产生冲突,跳跃时可设置snap向量为0
用collision和slide来实现snap

# using move_and_collide
var collision = move_and_collide(velocity * delta)
if collision:
    velocity = velocity.slide(collision.normal)

# using move_and_slide
velocity = move_and_slide(velocity)

使用kinematic 和 rigid的controller区别

kinematic 不能被物理定律约束,比如主角落地后弹跳,摩擦系数等
rigid的controller 不能被有效的控制,有时候可能会因为物理约束导致不必要的结果

两种方案都需要在游戏中进行针对性的优化

射线 / 发射

获取physics 2d direct space state

要对物理空间执行查询,必须使用Physics2DDirectSpaceState

func _physics_process(delta):
    var space_rid = get_world_2d().space
    var space_state = Physics2DServer.space_get_direct_state(space_rid)

或者

func _physics_process(delta):
    var space_state = get_world_2d().direct_space_state

raycast查询

func _physics_process(delta):
    var space_state = get_world_2d().direct_space_state
    # use global coordinates, not local to node
    var result = space_state.intersect_ray(Vector2(0, 0), Vector2(50, 100))
    if result:
      print("Hit at point: ", result.position)

发生碰撞时, result 字典包含以下数据:

{
   position: Vector2 # point in world space for collision
   normal: Vector2 # normal in world space for collision
   collider: Object # Object collided or null (if unassociated)
   collider_id: ObjectID # Object it collided against
   rid: RID # RID it collided against
   shape: int # shape index of collider
   metadata: Variant() # metadata of collider
}

碰撞异常

排除掉对自身的检测

extends KinematicBody2D

func _physics_process(delta):
    var space_state = get_world_2d().direct_space_state
    var result = space_state.intersect_ray(global_position, enemy_position, [self])

碰撞遮罩

对大型系统来讲,使用碰撞遮罩更好

extends KinematicBody2D

func _physics_process(delta):
    var space_state = get_world().direct_space_state
    var result = space_state.intersect_ray(global_position, enemy_position,
                            [self], collision_mask)

摄像机投射射线

const ray_length = 1000

func _input(event):
    if event is InputEventMouseButton and event.pressed and event.button_index == 1:
          var camera = $Camera
          var from = camera.project_ray_origin(event.position)
          var to = from + camera.project_ray_normal(event.position) * ray_length
2068504-a7e3309885ca1ff3.png

请记住,在 _input() 期间,空间可能被锁定,所以实际上这个查询应该在 _physics_process() 中运行。

软体只有3d下有,2d下官方没有

猜你喜欢

转载自blog.csdn.net/weixin_33795806/article/details/90923508