游戏开发中的物理之使用KinematicBody2D(02)

简介: 游戏开发中的物理之使用KinematicBody2D

运行此场景,您将看到它move_and_collide()按预期运行,沿速度矢量移动了身体。现在,让我们看看添加一些障碍时会发生什么。添加具有矩形碰撞形状的StaticBody2D。为了获得可见性,可以使用sprite,Polygon2D或从“调试”菜单中打开“可见碰撞形状”。


再次运行场景,然后尝试移入障碍物。您会看到KinematicBody2D 无法穿透障碍物。但是,尝试以一定角度移入障碍物,您会发现障碍物就像胶水一样-感觉身体被卡住了。


发生这种情况是因为没有碰撞响应。move_and_collide()发生碰撞时停止身体的运动。我们需要对碰撞产生的任何响应进行编码。


尝试将功能更改为move_and_slide(velocity)并再次运行。注意我们delta从速度计算中删除了。


move_and_slide()提供沿碰撞对象滑动主体的默认碰撞响应。这对于许多游戏类型都非常有用,并且可能只是获得所需行为的全部。


弹跳/反射


如果不想滑动碰撞响应怎么办?对于此示例(示例项目中的“ BounceandCollide.tscn”),我们有一个射击子弹的角色,我们希望这些子弹从墙上弹起。


本示例使用三个场景。主要场景包含播放器和墙壁。子弹头和墙是分开的场景,因此可以被实例化。


播放器由w和s键控制前进和后退。瞄准使用鼠标指针。这是Player的代码,使用move_and_slide():

using Godot;
using System;
public class KBExample : KinematicBody2D
{
    private PackedScene _bullet = (PackedScene)GD.Load("res://Bullet.tscn");
    public int Speed = 200;
    private Vector2 _velocity = new Vector2();
    public void GetInput()
    {
        // add these actions in Project Settings -> Input Map
        _velocity = new Vector2();
        if (Input.IsActionPressed("backward"))
        {
            _velocity = new Vector2(-Speed/3, 0).Rotated(Rotation);
        }
        if (Input.IsActionPressed("forward"))
        {
            _velocity = new Vector2(Speed, 0).Rotated(Rotation);
        }
        if (Input.IsActionPressed("mouse_click"))
        {
            Shoot();
        }
    }
    public void Shoot()
    {
        // "Muzzle" is a Position2D placed at the barrel of the gun
        var b = (Bullet)_bullet.Instance();
        b.Start(GetNode<Node2D>("Muzzle").GlobalPosition, Rotation);
        GetParent().AddChild(b);
    }
    public override void _PhysicsProcess(float delta)
    {
        GetInput();
        var dir = GetGlobalMousePosition() - GlobalPosition;
        // Don't move if too close to the mouse pointer
        if (dir.Length() > 5)
        {
            Rotation = dir.Angle();
            _velocity = MoveAndSlide(_velocity);
        }
    }
}


和子弹的代码:

using Godot;
using System;
public class Bullet : KinematicBody2D
{
    public int Speed = 750;
    private Vector2 _velocity = new Vector2();
    public void Start(Vector2 pos, float dir)
    {
        Rotation = dir;
        Position = pos;
        _velocity = new Vector2(speed, 0).Rotated(Rotation);
    }
    public override void _PhysicsProcess(float delta)
    {
        var collision = MoveAndCollide(_velocity * delta);
        if (collision != null)
        {
            _velocity = _velocity.Bounce(collision.Normal);
            if (collision.Collider.HasMethod("Hit"))
            {
                collision.Collider.Call("Hit");
            }
        }
    }
    public void OnVisibilityNotifier2DScreenExited()
    {
        QueueFree();
    }
}


该动作发生在中_physics_process()。使用后move_and_collide(),如果发生冲突,KinematicCollision2D则返回一个对象(否则返回Nil)。


如果有返回的碰撞,我们使用的normal来velocity通过Vector2.bounce()方法反映子弹的碰撞。


如果碰撞对象(collider)具有hit方法,我们也将其称为。在示例项目中,我们向“墙”添加了闪烁的色彩效果以演示这一点。

20201218155117707.gif



平台运动


让我们尝试一个更流行的示例:2D平台程序。move_and_slide() 是快速启动和运行功能字符控制器的理想选择。如果您已经下载了示例项目,则可以在“ Platformer.tscn”中找到它。


对于此示例,我们假设您有一个由StaticBody2D对象组成的关卡。它们可以是任何形状和大小。在示例项目中,我们使用 Polygon2D创建平台形状。


这是播放器主体的代码:

using Godot;
using System;
public class KBExample : KinematicBody2D
{
    [Export] public int RunSpeed = 100;
    [Export] public int JumpSpeed = -400;
    [Export] public int Gravity = 1200;
    Vector2 velocity = new Vector2();
    bool jumping = false;
    public void GetInput()
    {
        velocity.x = 0;
        bool right = Input.IsActionPressed("ui_right");
        bool left = Input.IsActionPressed("ui_left");
        bool jump = Input.IsActionPressed("ui_select");
        if (jump && IsOnFloor())
        {
            jumping = true;
            velocity.y = JumpSpeed;
        }
        if (right)
            velocity.x += RunSpeed;
        if (left)
            velocity.x -= RunSpeed;
    }
    public override void _PhysicsProcess(float delta)
    {
        GetInput();
        velocity.y += Gravity * delta;
        if (jumping && IsOnFloor())
            jumping = false;
        velocity = MoveAndSlide(velocity, new Vector2(0, -1));
    }
}

20201218155205460.gif

当使用时move_and_slide(),该函数返回一个向量,该向量表示发生滑动碰撞后剩余的运动。将该值重新设置为角色的值,velocity可以使我们平稳地上下倾斜。尝试删除并查看如果不这样做会发生什么。velocity =


另请注意,我们已将其添加为下限法线。该向量指向正上方。结果,如果角色与具有该法线的对象碰撞,则将其视为地板。Vector2(0, -1)


使用地面法线可以使用进行跳跃工作is_on_floor()。此功能仅会返回true一个后move_and_slide()碰撞,其中碰撞体的法线是在45度定地板载体。您可以通过设置来控制最大角度floor_max_angle。


例如,该角度还允许您使用来实现其他功能,例如墙跳 is_on_wall()。


目录
相关文章
5G 物理资源 |带你读《5G空口特性与关键技术》之八
基站信道带宽是指基站侧上下行所支持的单个 NR 射频载波。同一频段下,支持不同的 UE 信道带宽。在基站信道带宽范围内,UE 信道带宽可以灵活配置。UE 的 BWP 的信号等于或者小于 RF 载波的载波资源块数时,基站就能够在任何载波资源块上收发 UE 的 1 个或者多个 BWP 的信号。
5G 物理资源  |带你读《5G空口特性与关键技术》之八
|
7月前
|
芯片 数据格式 异构计算
LabVIEW开发虚拟与现实融合的数字电子技术渐进式实验系统
LabVIEW开发虚拟与现实融合的数字电子技术渐进式实验系统
51 1
|
7月前
|
Python
物理电学:原理、应用与编程实践
物理电学:原理、应用与编程实践
82 0
|
7月前
|
vr&ar Python
物理电学:基础概念与模拟实践
物理电学:基础概念与模拟实践
|
7月前
|
vr&ar Python
物理电学应用实践
物理电学应用实践
65 0
|
7月前
|
数据采集 算法 C++
物理电学的编程
物理电学的编程
57 1
|
7月前
|
Python
物理力学:基本概念、原理及计算机模拟实践
物理力学:基本概念、原理及计算机模拟实践
|
7月前
|
存储 人工智能 并行计算
计算机架构:漫游CPU的奥秘世界(二)
计算机架构:漫游CPU的奥秘世界
178 0
|
7月前
|
存储 人工智能 缓存
计算机架构:漫游CPU的奥秘世界(一)
计算机架构:漫游CPU的奥秘世界
183 0
|
7月前
|
C++ 开发者 Python
物理力学的编程
物理力学的编程
49 0