FMOD Studio User Manual 2.02

23. 脚本

FMOD Studio 的脚本功能可用于使用 JavaScript 控制 Studio 和编辑项目。命令可以输入到内置脚本界面,写入可以在 FMOD Studio 启动或运行时或通过 TCP/IP 连接加载的文件。

脚本可用于执行各种任务:

有关脚本 API 的更多信息,请参阅 脚本 API 参考

23.1 脚本文件

每次加载项目时都会自动评估脚本文件。FMOD Studio 从以下位置具有 .js 扩展名的任何文件中读取脚本:

在其中一个目录中添加或更改脚本后,可选择“脚本 > 重新加载”,使用新更新的脚本。

一些示例脚本包含在 FMOD Studio 中,可以在内置脚本目录中找到。

23.2 终端界面

Studio 还支持在 REPL 样式界面中评估脚本代码。这可用于从外部应用程序(例如关卡编辑器)远程控制 Studio。

与 Studio 的通信是通过端口 3663 上的 TCP/IP 连接完成的。传输到 Studio 的任何数据都将被解释为编码为 UTF-8 的 JavaScript。客户端接收到的任何数据都应解释为 UTF-8 字符串,表示已评估的代码。

此外,也可使用内置终端界面运行命令。可以通过在菜单栏中选择“窗口 > 控制台”或在 Windows 上使用快捷键组合 Control+0 或在 Mac 上使用 ⌘+0 来打开控制台窗口。这将打开控制台窗口,其中包含终端选项卡。可以直接在其中键入命令:

控制台

23.3 脚本示例

23.3.1 创建和删除事件

使用管理对象 API 以及 studio.project.create(entityName) 函数,可在项目中创建对象。例如,在项目的根文件夹中创建新事件:

    myEvent = studio.project.create("Event");
    myEvent.name = "My New Event";
    myEvent.folder = studio.project.workspace.masterEventFolder;

删除新创建的事件:

    myEvent.deleteObject();

23.3.2 检查工具版本

Studio 提供了 studio.version 脚本对象,可用于检查工具版本。在安装脚本功能之前要检查工具版本。例如:

    if(studio.version.productVersion == 1 && studio.version.majorVersion >= 7) {
        // 添加菜单栏项目
    }

23.3.3 修改全局上下文

当 Studio 在 Javascript 文件中加载脚本时,会在自己的范围内执行。这意味着,如果声明了一个叫做foo()的函数,仍然不能从 shell 界面直接调用foo()。要注册可以全局调用的函数,就必须把它们附加到全局上下文中。例如:

    var global = this;
    global.foo = function() { alert("Hello!"); }

23.3.4 定制菜单

    studio.menu.addMenuItem({
        name: "Greetings\\Say Hello",
        execute: function() { alert("Hello"); },
        keySequence: "Ctrl+H",
    });

    studio.menu.addMenuItem({
        name: "Greetings\\Say Bye",
        execute: function() { alert("Bye"); },
        isEnabled: false,
    });

    studio.menu.addMenuItem({ name: "Greetings\\----" }); // 使用所有的 “-”字符来创建一个分隔符

    studio.menu.addMenuItem({
        name: "Greetings\\Say Checked",
        execute: function() { alert("Checked toggled"); this.isChecked = !this.isChecked; },
        isChecked: true,
    });

    studio.menu.addMenuItem({
        name: "Greetings\\Advanced\\Say what's Selected",
        execute: function() { alert(studio.window.browserCurrent()); },
        isVisible: function() { return studio.window.browserCurrent(); }
    });

    studio.menu.addMenuItem({
        name: "Greetings\\Dynamic Submenu",
        subMenuItems: function() {
            var items = [];
            for(var i=0; i < 4; i++) {
                items.push({
                    name: "#" + i,
                    execute: function() { alert("Well hello there " + this.name); },
                });
            }
            return items;
        },
    });

23.3.5 自定义保存和构建菜单项

    studio.menu.addMenuItem({ name: "Save and Build", execute: function buildAndCopy() {
        studio.project.save();
        studio.project.build();
        alert("Save and Build complete!");
    }});

23.3.6 设置主音量

    var masterBus = studio.project.workspace.mixer.masterBus;
    masterBus.volume = -2;

23.3.7 选择事件并设置时间轴位置

    var eventId = "{aabe5118-c144-4dc3-839a-ff52a2b49162}";
    var timelinePos = 2.3;

    var event = studio.project.lookup(eventId);
    if(event) {
        studio.project.open(event);
        event.timeline.setCursorPosition(timelinePos);
        alert("Opened and scrubbed: " + event.name);
    }
    else {
        alert("Could not find event: " + eventId);
    }

23.3.8 为选定的事件添加新的组别轨道

    studio.menu.addMenuItem({ name: "Add Group Track",
        isEnabled: function() { var event = studio.window.browserCurrent(); return event && event.isOfExactType("Event"); },
        execute: function() {
            var trackName = studio.system.getText("Name of new group track:", "New Track");
            if(trackName) {
                var event = studio.window.browserCurrent();
                var track = studio.project.create("GroupTrack");
                track.mixerGroup.output = event.mixer.masterBus;
                track.mixerGroup.name = trackName;
                event.relationships.groupTracks.add(track);
            }
        },
    });

23.3.9 导入音频文件后进行分类

    function postAudioFileImported( audioFile ) {
        // 如果有“ABC”文件夹的话,请尽量将“abc_sound.wav”放入该文件夹。
        var fileName = audioFile.audioFilePath.split('/').pop();
        var prefix = fileName.substr(0, 3).toUpperCase();
        console.log(fileName + " has the prefix " + prefix);

        if(audioFile.container.id != studio.project.workspace.audioBinManager.masterAudioBinFolder.id) {
            console.log("The file isn't in the root folder -- user dragged to a specific folder so we can skip this.");
            return;
        }

        var items = studio.project.workspace.audioBinManager.masterAudioBinFolder.items;
        for(var i=0; i < items.length; i++) {
            if(items[i].isOfType("AudioBinFolder") && items[i].name === prefix) {
                audioFile.container = items[i];
                console.log("Moving" + fileName + " to " + items[i].name);
                return;
            } 
        }
    }
    studio.project.audioFileImported.connect(postAudioFileImported);