【发布时间】: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