Making Modules/zh

From Procedural Objects
Jump to navigation Jump to search
    I18n.png  语言 En flag.jpg English Fr flag.png Français Es flag.png Español De flag.jpg Deutsch Nl flag.png Nederlands Ru flag.jpg Русский Ko flag.png 한국어 Zh flag.png 简体中文 Ja flag.png 日本語 Th flag.png ภาษาไทย
    Warning.png  警    告  AD 2023.02.13
此页面尚未与最新版本(1.7.8)同步。本模组已有新的变化并且此页面的一些信息可能已过时。

PO 对象可以附加 模块。Procedural Objects 允许创建 定制模块类型(custom module type)以扩展 PO 的功能。本文详述 Procedural Objects 提供的 API。默认您已了解 C#编程基础Cities: Skylines开发

定制PO模块类型(custom PO module type)由2个主要部分组成:

  • 1个 POModuleType 实例,规定“定制模块类型”的常规信息(名称,地图中的最大数量,等等)。
  • 1个继承于 POModule 的定制类,规定模块的行为。

源代码示例:

创建一个 POModuleType[edit | edit source]

一个“定制PO模块类型”的核心是一个标准的 Cities: Skylines 模组。确认在工程引用(project references)中添加 ProceduralObjects。使用 .NET 3.5 版本或能预防 Reflection 问题。

同样允许 OnSettingsUI(UIHelperBase helper) 被实现(implement)以作模块常规设置(下方未显示)。

下方示例定义了一个“鸟群模块(BirdFlocksModule)”类型。

using UnityEngine;
using ICities;
using ProceduralObjects;

namespace BirdFlocksPOModule
{
    public class BirdFlocksPOMod : LoadingExtensionBase, IUserMod
    {
        // 标准 C:S 模组设置
        public string Name { get { return "Bird Flocks Module"; } }
        public string Description { get { return "Bird flocks module for Procedural Objects"; } }

        private POModuleType moduleType;

        public override void OnCreated(ILoading loading)
        {
            base.OnCreated(loading);
            if (moduleType == null)
            {
                moduleType = new POModuleType()
                {
                    Name = Name,
                    Author = "Simon Royer",
                    help_URL = "http://wwww.mywebsite.com/birdflockshelp",    // 当“帮助”按钮被点击时打开的 URL(可选)
                    TypeID = "BirdFlocksModule",    // 这是类型的唯一标识符id。它应该在模块的工坊版本更新过程中始终保持不变
                    ModuleType = typeof(BirdFlocksModule),    // 定义作为模块的行为类的 POModule 类
                                                              // 显然您必须创建一个继承于 POModule 的 BirdFlocksModule 类(见下方)
                    maxModulesOnMap = 100,    // 设置为 0 表示无限制
                    keepOpenWhenLeaveObj = false    // 若您想在离开魔物编辑模式时让模块窗口保持开启则设置为“true”
                };
            }
            if (!ProceduralObjectsMod.ModuleTypes.Contains(moduleType))
                ProceduralObjectsMod.ModuleTypes.Add(moduleType);    // 添加 POModuleType 至 Procedural Objects 的支持类型列表
        }
        public override void OnReleased()
        {
            base.OnReleased();
            if (moduleType == null)
                return;
            if (ProceduralObjectsMod.ModuleTypes.Contains(moduleType))
                ProceduralObjectsMod.ModuleTypes.Remove(moduleType);
        }
    }
}

继承于 POModule 的定制类[edit | edit source]

模块类型的行为定义在继承于 POModule 类的定制类之内。

namespace BirdFlocksPOModule
{
    public class BirdFlocksModule : POModule
    {
        // POModule 可以含有定制变量和方法
        // ProceduralObjects 不使用 [Serializable]。执行 GetData() 和 LoadData() 以保存
        public List<BirdAgent> birds;
        public int BirdsCount;
        public Mesh birdMesh;
        public Material birdMaterial;
        private bool switchBackCalculation;
        private float cohesion = 5f, avoidance = 2f, alignment = 3f, speed = 2f, visionDist = 35f, reactivity = .7f;

        public override void OnModuleCreated(ProceduralObjectsLogic logic)
        {
            base.OnModuleCreated(logic);
            // 初始化自定义窗口大小。坐标任意
            window = new Rect(0, 0, 325, 175);
            // do stuff here...在这里做事...

            // 此方法不应该包含变量初始化(例如“cohesion = 5f”)
            // 因为此方法在加载存档后也会被调用,这样会破坏加载的数据
            // 应如上所示设置默认值
        }
        public override void UpdateModule(ProceduralObjectsLogic logic, bool simulationPaused, bool layerVisible)
        {
            // UpdateModule() 在 Update() 中运行(当模块是启用状态时)
            for (int i = 0; i < birds.Count; i++)
            {
                var bird = birds[i];
                bird.Render(birdMesh, birdMaterial);    // Render 调用必须位于 UpdateModule() 内
                if (!simulationPaused)
                    bird.CalculateMovement(birds, cohesion, avoidance, alignment, speed, visionDist, reactivity);
            }
        }
        public override void DrawCustomizationWindow(int id)
        {
            // base.DrawCustomizationWindow(id) 调用提供了基本窗口功能(关闭按钮,拖拽窗口……)
            base.DrawCustomizationWindow(id);
            GUI. ....    // 在此使用 UnityEngine.GUI 类绘制 UI  
                         // 扩展 UI 元素(分割线,等等)参见 ProceduralObjects.UI.GUIUtils 类
        }
        public override void GetData(Dictionary<string, string> data, bool forSaveGame)
        {
            // GetData() 调用于保存时。数据以如下方添加的 string 键/值对的形式保存。
            // 若您需要根据保存目的(为游戏存档还是导出魔物而保存模块)保存不同变量,读取 forSaveGame 变量以区分这些情况。
            data.Add("birdsCount", BirdsCount.ToString());
            data.Add("cohesion", cohesion.ToString());
            data.Add("avoidance", avoidance.ToString());
            data.Add("alignment", alignment.ToString());
            data.Add("speed", speed.ToString());
            data.Add("visionDist", visionDist.ToString());
            data.Add("reactivity", reactivity.ToString());
        }
        public override void LoadData(Dictionary<string, string> data, bool fromSaveGame)
        {
            // LoadData() 调用于加载时。数据以如下方读取的 string 键/值对的集合的形式加载。
            // 若您需要根据加载目的(从游戏存档还是导出魔物中加载模块)加载不同变量,读取 forSaveGame 变量以区分这些情况。
            // 本例仅使用 float 解析,但您可实现您自己的解析方法。
            // 始终使用如下方所示的 if 语句检查变量是否存在。
            // 作为提醒,变量的默认值必须在类的顶部而非 OnModuleCreated() 或任何方法中声明。
            if (data.ContainsKey("birdsCount"))
                BirdsCount = int.Parse(data["birdsCount"]);
            if (data.ContainsKey("cohesion"))
                cohesion = float.Parse(data["cohesion"]);
            if (data.ContainsKey("avoidance"))
                avoidance = float.Parse(data["avoidance"]);
            if (data.ContainsKey("alignment"))
                alignment = float.Parse(data["alignment"]);
            if (data.ContainsKey("speed"))
                speed = float.Parse(data["speed"]);
            if (data.ContainsKey("visionDist"))
                visionDist = float.Parse(data["visionDist"]);
            if (data.ContainsKey("reactivity"))
                reactivity = float.Parse(data["reactivity"]);
        }
    }
}

继承成员[edit | edit source]

POModule 继承类继承来自 POModule 的以下成员:

  • ProceduralObject parentObject : 模块所附加于的父对象(parent object)
  • bool enabled : 模块启用状态
  • bool showWindow : 模块自定义窗口状态
  • Rect window : 窗口矩形。如上所示在 OnModuleCreated() 内初始化
  • POModuleType ModuleType : 已在模组中创建的 ModuleType 实例(见上方)

可实现方法[edit | edit source]

POModule 类可以实现以下方法。并非全部需要实现,选择您需要的。

  • void OnModuleCreated(ProceduralObjectsLogic logic)
调用于游戏内模块创建时,无论是通过复制/粘贴、创建还是加载。此方法应考虑已启用域(enabled field),以备克隆模块之需。当加载存档而使用时,LoadData() 在 OnModuleCreated() 之前被调用。
  • void OnModuleRemoved(ProceduralObjectsLogic logic)
调用于父对象删除或模块移除时。
  • void OnModuleEnabled(ProceduralObjectsLogic logic)
调用于模块启用时。不会调用于 模块管理 中启用整个模块类型时。
  • void OnModuleDisabled(ProceduralObjectsLogic logic)
调用于模块禁用时。不会调用于 模块管理 中禁用整个模块类型时。
  • void OnModuleWindowOpen(ProceduralObjectsLogic logic)
调用于模块窗口打开时。
  • void OnModuleWindowClose(ProceduralObjectsLogic logic)
调用于模块窗口关闭时。
  • void OnParentPositionSet(ProceduralObjectsLogic logic, Vector3 oldPosition, Vector3 newPosition)
调用于父对象位置改变时。
  • void OnParentRotationSet(ProceduralObjectsLogic logic, Quaternion oldRotation, Quaternion newRotation)
调用于父对象方向改变时。
  • void OnApplyModelChange(Vertex[] vertices)
调用于应用父对象模型改变时。
  • void UpdateModule(ProceduralObjectsLogic logic, bool simulationPaused, bool layerVisible)
调用于 Update()(每帧)(仅在模块启用时)。此处为 Render 调用的位置。
  • void LoadData(Dictionary<string, string> data)
用提供的数据集(data set)初始化模块。此方法在 OnModuleCreated() 之前被调用。
  • void GetData(Dictionary<string, string> data)
当加载 LoadData() 时用 GetData() 内的 data.Add(string,string) 调用作为“键/值数据对”(Key/Value data pairs)。
  • void DrawCustomizationWindow(int id)
模块窗口绘制功能(使用 UnityEngine.GUI 方法)。使用 Rect window 域。如上示例所示在 OnModuleCreated() 内定义窗口大小。base.DrawCustomizationWindow(id) 调用提供了基本窗口功能(关闭按钮,拖拽窗口……)。
  • POModule Clone()
在克隆或复制/粘贴时使用。如果不实现此方法将使用 object.MemberwiseClone()。请提供实现,如果需要 深复制