キャラクターを移動させる

今回はアドオンでキャラクターを目的の座標まで移動させる方法をみていきたいと思います。

2020年12月のアンバスケード-エキスパートはクトゥルブ族です。
戦闘中に召喚されるお供の対処方法としてお供を"マラソン"する方法があります。
アンバスケードのフィールド内の"マラソン"を題材にしたいと思います。


余談になりますが、Mote-libsにはデフォルトで定義されているstate.Kitingというモードがあります。
Kitingというのは日本語のFF11用語(MMO用語?)でいう"マラソン(敵を引き連れてフィールドを周回する戦法)"を指す用語のようです。
sets.Kitingにはマラソン用の装備(移動速度UPなど)を定義すると良さそうです。
ffxiclopedia.fandom.com

話を戻して、アドオンでキャラクターを移動させる方法("マラソン"する方法)を考えてみます。
今回はキャラクターを移動させるにwindower.ffxi.run()を使用してみます。
windower.ffxi.run · Windower/Lua Wiki ·GitHub
WikiAPIの説明を見るとwindower.ffxi.run()は指定する引数で色々な動作ができるようです。

windower.ffxi.run() -- 現在向いている方向へ"歩く"
windower.ffxi.run(true) -- 現在向いている方向へ"走る"
windower.ffxi.run(false) -- 止まる

今回は方向を指定する方法として、 2つの値x(正の値が東), y(正の値が北)を与えて、自身を原点とするベクトルの向きに走る動作を使用しようと思います。

windower.ffxi.run(1, 0) -- 東へ走る
windower.ffxi.run(0, -1) -- 南へ走る
windower.ffxi.run(1, 1) -- 北東へ走る (x, yは正規化しなくても、自動で正規化されるようです)

windower.ffxi.run()を使って、アンバスケードのフィールド内を以下のように移動するスクリプトを作ってみます。

f:id:yyoshisaur:20201213234320p:plain
移動ルート
require('luau')

local allowable_dist = 0.5
local run_route = {
    {x=160, y=-135}, -- 1
    {x=185, y=-135}, -- 2
    {x=183, y=-160}, -- 3
    {x=180, y=-185}, -- 4
    {x=160, y=-183}, -- 5
    {x=135, y=-180}, -- 6
    {x=135, y=-160}, -- 7
}

local function move(target)
    while true do
        local me = windower.ffxi.get_mob_by_target("me")
        local d_x = math.sqrt(math.pow(target.x - me.x, 2))
        local d_y = math.sqrt(math.pow(target.y - me.y, 2))

        if d_x < allowable_dist and d_y < allowable_dist then
            -- 目標の座標に達すると移動を停止
            windower.ffxi.run(false)
            break
        end

         -- 移動を開始
        windower.ffxi.run(target.x-me.x, target.y-me.y)
        coroutine.sleep(0.1) -- 0.1秒待つ
        windower.ffxi.run(false) -- 移動を停止
    end
end

for _, pos in ipairs(run_route) do
    move(pos)
end

一定間隔で現在の座標を取得し、目的の座標に達したかを確認するようにします。
座標の更新タイミングや通信ラグ?の関係で目標とした座標ピッタリに停止することは難しいと思うので、ある程度の誤差を許容できるようにしています。
①から➆までの移動ができました。あとはこの動作を繰り返すと"マラソン"を実現することができると思います。
(敵の位置によって移動を待ったりする等、改善することはあると思います)

一例として繰り返しにはアドオンコマンドを使用してみます。
コマンドの引数を'run'として実行するとマラソンを開始するようにします。
'run'では一周分の動作を行い、動作終了後に再度'run'をwindower.send_commandで実行し、動作を繰り返すようにします。
(これでは無限に動作してしまうので、別途停止するコマンドもあったほうが良さそうです)

windower.register_event('addon command', function(...)
    local args = {...}
    if args[1] == 'run' then
        for _, pos in ipairs(run_route) do
            move(pos)
        end 
        windower.send_command(_addon.command..' run')
    end
end)