【问题标题】:Continuous aim to target in Malmo持续瞄准马尔默
【发布时间】:2016-07-16 04:00:04
【问题描述】:

Malmo 是 Microsoft 的 Minecraft 人工智能框架,由游戏本身的 mod 和用于发送输入和接收世界数据的多平台框架组成。

Minecraft 的瞄准是圆柱形的。它存储在偏航(左右)和俯仰(上下)而不是完全旋转的四元数中。偏航从最左边的 -180 度转到最右边的 180 度。音高从 -90 直接向上(天顶)到 90 直接向下(最低点)。在我的代码中,我将它们存储为 Vector2(重新创建以像 XNA 一样工作),这样 X 代表 Yaw,Y 代表 Pitch。

我无法创建连续瞄准目标算法,以便 AI 能够将其相机瞄准给定的目标偏航和俯仰角。因为在仍然允许连续移动的同时这样做的唯一方法是通过连续瞄准(设置偏航和俯仰速度,而不是值),我需要朝着目标方向反复增加偏航和俯仰。

我通过将目标方向存储在一个可为空的属性中来做到这一点。如果该属性为空,则表示不改变目标。否则,每次调用更新方法时,减去存储值(目标目标)和当前目标(通过参数提供)之间的距离。然后它会缩放差异,使偏航或俯仰为 1(最大速度),而另一个则为此正确成比例。这个成比例的Vector2 速度被分成它的偏航和俯仰,然后通过turn 和pitch 命令发送给客户端。一旦在目标方向的 10 度范围内,目标将设置为空。

在纸面上,这似乎会使相机的目标直接朝向目标方向(不包括偏航环绕)。然而,尽管更新方法发送了一个pitch 命令说要走相反的方向,但客户端的音调通常直接越过目标方向。这意味着球场会以某种方式“卡”在天顶和最低点,但会自行固定并“转身”,并在几秒钟后卡在对面的极点。在转身之前花费的时间似乎每次都呈指数(或二次)增加。

这是我的目标更新方法的源代码:

public void UpdateAim(Observations obs)
{
    // AimTarget is a Vector2? property
    if (AimTarget == null || obs == null)
    {
        return;
    }

    if (AimTarget.Value.Distance(obs.Aim) < AIM_CLOSE_ENOUGH) // < 10
    {
        Logger.LogInfo("Reached {0}", AimTarget.Value);
        Look(Vector2.Zero);
        AimTarget = null;
        return;
    }

    double deltaYaw = AimTarget.Value.X - obs.Aim.X;
    double deltaPitch = AimTarget.Value.Y - obs.Aim.Y;

    // These two are stored as private Vector2 fields
    deltaAim = new Vector2(deltaYaw, deltaPitch);
    scaledAim = deltaAim / Math.Max(Math.Abs(deltaAim.X), Math.Abs(deltaAim.Y));

    Look(scaledAim); // sets continuous aim velocity
}

还有Look(Vector2)的(简化)源代码:

public void Look(Vector2 direction)
{
    // Agent is an AgentHost property
    Agent.sendCommand("turn " + velocity);
    Agent.sendCommand("pitch " + velocity);
}

UpdateAim() 在主游戏循环期间每秒被调用 20 次(尽管我尝试过高达每秒 50 次和低至 5 次)。

在我最后一次运行 AI 时(卡在最低点),我的瞄准调试数据如下所示:

// Format: (yaw, pitch)
Target Aim: (134.75, 27.90)
Actual In-Game Aim: (-6.50, 90.00) // Lines up with MC's debug screen
Delta Aim :  (145.17, -62.10) // Total degrees needed to go in yaw and pitch
Scaled Aim Velocity: (1.00, -0.43)

缩放后的瞄准速度是提供给Look() 的。正如你所看到的,俯仰速度是负的,因为它应该是负的,但实际游戏中的目标仍然是 90 并且由于某种原因没有得到纠正。我算对了吗?

【问题讨论】:

    标签: c# camera artificial-intelligence minecraft-forge malmo


    【解决方案1】:

    从我所看到的一切来看,数学是优雅的并且检查出来的。如果俯仰速度在最低点处为负并且没有向下移动,那么在我看来,Agent.sendCommand 没有正常工作。

    在设置速度时,是否会保持您设置的速度,直到设置另一个速度?还是速度会相互叠加?如果球场出界会怎样?

    【讨论】:

    • 我已经使用从控制台获取命令的 AI 对此进行了测试,当我运行 pitch -1 后跟 pitch 1(以及它们之间的各种值)时,响应是即时的。也许它有积压。我不完全确定,因为在循环运行之间以 500 毫秒的延迟对其进行测试会导致严重的不准确和过度校正,这几乎无法与这个问题区分开来。
    【解决方案2】:

    您可能在很久以前就设法解决了这个问题,但以防万一,这里有一些想法:

    1. 在您的 Look() 方法中,您有以下内容:

      Agent.sendCommand("turn " + velocity);
      Agent.sendCommand("pitch " + velocity);
      

    我认为重复使用 velocity 是您简化 SO 使用代码时的拼写错误?否则这肯定会解释这种行为。

    1. 您的缩放代码很有趣 - 是否有任何理由需要保持偏航速度与增量速度的比率相同?即你真的需要Math.Max(Math.Abs(deltaAim.X), Math.Abs(deltaAim.Y))这个词吗?这两个运动(偏航和俯仰)是完全独立的,因此没有理由独立地缩放它们,除非它以我没有发现的某种巧妙方式提高性能。

    2. 您可能需要考虑振荡/阻尼。想象一下你的偏航是正确的 (deltaYaw == 0)。您的缩放意味着您的俯仰增量速度将始终处于最大值(1 或 -1 取决于方向)。换句话说,即使增量螺距只有 0.0001,您仍然会以最大速度进行调整,并且会显着超调。 (显然AIM_CLOSE_ENOUGH 的使用会对此有所帮助,但我认为它仍然可能出现振荡 - 特别是如果您设置了较高的turnSpeedDegs - 请参阅http://microsoft.github.io/malmo/0.17.0/Schemas/MissionHandlers.html#element_ContinuousMovementCommands)

    有关此类工作的示例,请查看 cart_test.py 示例 - https://github.com/Microsoft/malmo/blob/master/Malmo/samples/Python_examples/cart_test.py

    这里是相关代码sn-p。 yaw_to_mob 是目标偏航角,yaw 是玩家当前的偏航角。

    # Find shortest angular distance between the two yaws, preserving sign:
    deltaYaw = yaw_to_mob - yaw
    while deltaYaw < -180:
        deltaYaw += 360;
    while deltaYaw > 180:
        deltaYaw -= 360;
    deltaYaw /= 180.0;
    # And turn:
    agent_host.sendCommand("turn " + str(deltaYaw))
    

    如果您想查看实际的振荡问题,顺便说一下,请查看 MazeRunner.py 示例(与 cart_test.py 相同的位置)并将turnSpeedDegs 增加两到三倍。 Minecraft 在渲染时间而不是世界时间更新俯仰/偏航,因此较慢的渲染速度会产生更大的振荡问题。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-04-20
      • 2011-07-21
      • 1970-01-01
      • 1970-01-01
      • 2010-11-12
      • 2018-04-01
      • 2011-07-26
      • 1970-01-01
      相关资源
      最近更新 更多