持续瞄准马尔默的目标

时间:2016-07-16 04:00:04

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

Malmo是微软的Minecraft AI框架,包括游戏本身的mod,以及用于发送输入和接收有关世界数据的多平台框架。

Minecraft的瞄准是圆柱形的。它存储在偏航(左和右)和俯仰(上下)中,而不是全开旋转四元数。偏航从最左边的-180度开始,到最右边的180度。俯仰从-90指向直接向上(天顶)到90直接向下(最低点)。在我的代码中,我将它们存储为Vector2(重新设置为与XNA类似),使得X代表Yaw,Y代表Pitch。

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

我是通过将目标方向存储在可空属性中来实现的。如果属性为null,则表示不更改目标。否则,每次调用更新方法时,减去存储值(目标瞄准)和当前瞄准(通过参数提供)之间的距离。然后它缩放差异,使得偏航或俯仰为1(最大速度),而另一个正确地按比例分配。这个比例Vector2速度被分成偏航和俯仰,然后通过turnpitch命令发送给客户端。一旦在目标方向的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,并且由于某些原因没有得到纠正。我在做数学吗?

2 个答案:

答案 0 :(得分:2)

从我所能看到的一切,数学都是优雅的并且结束了。如果在最低点的俯仰速度为负并且它没有向下移动,对我来说,它看起来像 Agent.sendCommand 没有正常工作。

设置速度时,它是否保持在您设置的速度,直到另一个设置为止?或者速度是否相互增加?如果音高超出范围会发生什么?

答案 1 :(得分:1)

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

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

    Agent.sendCommand("turn " + velocity);
    Agent.sendCommand("pitch " + velocity);
    
  2. 我认为重复使用velocity是在简化SO使用代码时所做的拼写错误?否则这肯定会解释这种行为。

    1. 您的缩放代码很有趣 - 您是否有任何理由需要保持偏航速度与delta速度的比率相同?你真的需要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

      < / LI>

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

      这是相关的代码段。 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在渲染刻度时更新俯仰/偏航,而不是世界刻度时间,因此较慢的渲染速度将产生更大的振荡问题。