当前位置: 首页 > 知识库问答 >
问题:

持续瞄准马尔默的目标

欧浩淼
2023-03-14

Malmo是微软针对Minecraft的人工智能框架,由游戏本身的一个模块和一个用于发送输入和接收世界数据的多平台框架组成。

Minecraft的瞄准是圆柱形的。它存储在偏航(左和右)和俯仰(上和下)中,而不是完全旋转的四元数。偏航从最左侧的-180度变为最右侧的180度。音高从-90直接指向上(天顶)到90直接指向下(最低点)。在我的代码中,我将它们存储为矢量2(重新创建,使其工作方式与XNA非常相似),这样X代表偏航,Y代表俯仰。

我在创建一个连续瞄准目标算法时遇到了困难,这样人工智能就能够将相机对准给定的目标偏航和俯仰。因为这样做的唯一方法是通过连续瞄准(设置偏航和俯仰速度,而不是值),同时仍然允许连续移动,所以我需要重复增加朝向目标方向的偏航和俯仰。

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

从理论上看,这似乎会使相机的目标直接指向目标方向(不包括偏航环绕)。然而,客户机的音高通常会直接超过目标方向,尽管更新方法发送了一个音高命令,指示方向相反。这意味着音高不知何故会在天顶和最低点“卡住”,但会自行修复,并在几秒钟后“掉头”并在相反的极点卡住。每次转弯前被卡住的时间似乎都呈指数增长(或者可能是二次增长)。

以下是我的aim更新方法的源代码:

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次)。

上一次我运行人工智能(它被困在最低点)时,我的目标调试数据如下所示:

// 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个答案

赫连俊悟
2023-03-14

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

>

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

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

    我假设重复使用velocity是因为你简化了代码以便如此使用而造成的打字错误?否则,这肯定可以解释这种行为。

    你的缩放代码很有趣——你有什么理由需要保持横摆速度与增量速度的比率相同吗?i、 你真的需要数学吗。Max(Math.Abs(deltaAim.X),Math。Abs(deltaAim.Y))term?这两个动作(偏航和俯仰)是完全独立的,因此没有理由依赖于它们进行缩放,除非它以某种我没有发现的聪明方式提高性能。

    您可能需要考虑振动/阻尼。想象你的偏航是正确的(deltaYaw==0)。缩放意味着俯仰增量速度始终处于最大值(1或-1,取决于方向)。换句话说,即使三角螺距仅为0.0001,您仍将以最大速度进行调整,并将显著超调。(显然,使用AIM_CLOSE_足够的将有助于实现这一点,但我认为仍然有可能出现振荡——特别是如果你有一个高turnspeedgs设置,请参阅http://microsoft.github.io/malmo/0.17.0/Schemas/MissionHandlers.html#element_ContinuousMovementCommands)

    例如,我们可以看看cart_测试。py样本-https://github.com/Microsoft/malmo/blob/master/Malmo/samples/Python_examples/cart_test.py

    这是相关的代码片段。yaw_to_mob是目标偏航,偏航是玩家当前的偏航。

    # 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相同的位置),并将turnspeedgs增加两到三倍。Minecraft会在渲染滴答时间(而不是世界滴答时间)更新俯仰/偏航,因此渲染速度较慢会产生更大的振荡问题。

  • 裴星洲
    2023-03-14

    据我所知,数学是优雅的,并得到验证。如果俯仰速度在最低点为负,并且没有向下移动,对我来说,这看起来像是gent.send指挥部没有做好它的工作。

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

     类似资料:
    • 我正在libGDX中制作一个游戏,我在设置Bullet类时遇到了麻烦。我无法让射弹去鼠标位置。 我试图用Math.atan()来找到我需要射击的角度,但是我不能让它工作。现在我只是用距离来寻找x轴和y轴上的速度。

    • 我想让我的用户能够订阅特定的事件(频道),以限制他们收到的推送通知。 例 当事件发生在第8组时。 如何向订阅组8的所有用户发送推送通知?-在我上面的例子中,通知应该发送到user1和user2,而不是3。

    • 1. 马尔科夫链概述 马尔科夫链定义本身比较简单,它假设某一时刻状态转移的概率只依赖于它的前一个状态。举个形象的比喻,假如每天的天气是一个状态的话,那个今天是不是晴天只依赖于昨天的天气,而和前天的天气没有任何关系。当然这么说可能有些武断,但是这样做可以大大简化模型的复杂度,因此马尔科夫链在很多时间序列模型中得到广泛的应用,比如循环神经网络RNN,隐式马尔科夫模型HMM等,当然MCMC也需要它。 如

    • 它们还提供了一个警告:如果您能够持续部署到测试系统,有时也会使用术语“持续部署”。 这一切让我很困惑。任何更详细的解释(或附带一个例子)都是赞赏的!

    • 我对推送通知和FCM(Firebase云消息传递)非常陌生。 我有一个应用程序,用户可以登录,我想发送推通知给这个特定的用户。用户可以同时登录多个设备,因此必须向所有这些设备发送通知。 我知道如何向特定设备发送通知,因为我已经按照官方留档的教程进行了操作,并且我有一个用户注册的服务器。 所以我想保存令牌()发送到我的服务器,然后向保存在此用户下的所有令牌发送推送通知。 但有两个问题: 如果用户注销

    • 问题内容: 我正在使用JAXB marshaller创建和格式化我的.xml文件。除了一个地方,它运作良好。缩进缺少两个地方: .xml文件的其余部分看起来不错。我正在使用这种方法来美化整个代码: 不幸的是,它不适用于这两个元素。有任何想法吗? 问题答案: 可以通过将javax Transformer应用于输出来解决此烦人的问题。