《城市天际线》MOD制作教程.docx

上传人:小飞机 文档编号:3064273 上传时间:2023-03-10 格式:DOCX 页数:13 大小:42.86KB
返回 下载 相关 举报
《城市天际线》MOD制作教程.docx_第1页
第1页 / 共13页
《城市天际线》MOD制作教程.docx_第2页
第2页 / 共13页
《城市天际线》MOD制作教程.docx_第3页
第3页 / 共13页
《城市天际线》MOD制作教程.docx_第4页
第4页 / 共13页
《城市天际线》MOD制作教程.docx_第5页
第5页 / 共13页
亲,该文档总共13页,到这儿已超出免费预览范围,如果喜欢就下载吧!
资源描述

《《城市天际线》MOD制作教程.docx》由会员分享,可在线阅读,更多相关《《城市天际线》MOD制作教程.docx(13页珍藏版)》请在三一办公上搜索。

1、城市天际线MOD制作教程6399游戏网 以下是小编为大家带来城市天际线MOD制作教程。 一、首先是天际线的基本概念体系,以及AI在其中所起的作用。 游戏里有很多的建筑物、人、车等事物。这些东西都有自己的属性,比如位置在哪?颜色?是生老病死,还是3级5级?移动速度?等等,描述的是物体的客观状态。还有一类,就是这些事物的行为方式: 例如小人是去买东西,还是去上班?出门是坐公交还是自己开车?公交车下一站往哪开?建筑物是升级还是废弃?这些基本都是由各个物件自己决定的,那么这个决策部分,就称之为AI,用面向对象来说,就是行为/方法 比如市民,市民是一个类,名字、男女、年龄、教育程度、健康状况、是否在开车

2、等等,是属性。但是市民有几十万,每一个市民都有自己不同的属性,有几十万的对象,在内存里都要占用相应的位置,但是他们的AI是一致的,AI只有一个。修改了这个AI,所有市民的行为方式都会相应变化。 然后是天际线中跟AI相关的有如下常见类名后缀: AI、Manager、Info AI毫无疑问就是AI类的了,CitizenAI就是市民AI Manager是所有相关对象引用的管理类,比如CitizenManager就是管理所有市民的管理器,无论是创建一个市民,还是查询所有生病的市民,都要通过这个管理器 Info是一类对象的“模板”。这里我用建筑物来解释。比如警察总局,就是一个BuildingInfo类的

3、对象。里面定义了这个物件的名称叫“警察总局”,所有警察总局的属性,比如造价、维护费用、占地大小等等,都是在这里的,警察总局的AI,也是在这里有一个引用。不管你在游戏中建几个“警察总局”,这个BuildingInfo对象都会只有一个,但是不同位置的警察总局,会有多个不同的Building对象(其实是6399游戏网 struct)来表达,比如具体的xz位置,或者你给他改名叫“天下第一警察总局”,那么名字也是存在这里的。 接着,是跟AI相关的横向概念。 天际线里AI总共分4类:建筑物、车辆(Vehicle)、市民(Citizen)、路网(Net)。 每类都会有一个上述英文名称的struct来表达数据

4、, 以及配套的前述3个类,和众多的相关衍生类。 当然这也只是一个最基本的分类,最深的继承关系可达7层,由于此图是在是太大,所以我在下图仅以市民AI举例说明: 在天际线中,CitizenAI其实应该翻译成是“生物AI”好点。它有2个子类:动物AI和人类AI。也就是说,你在游戏中看到的鸟啊,宠物狗啊什么的,其实都是算作是Citizen,都用Citizen这个struct来存储数据的,占用那104万上限。动物AI就不说了。人类AI中又分为服务人员AI、旅游者AI和居民AI。这里最多的就是居民了,104万的上限,我看有人达到了101万。 6399游戏网 那么,这所有的104万的Citizen,全部都是

5、由CitizenManager来管理的。CitizenManager中有创建市民的方法,销毁的方法,查询的方法等。当前市民数量、Citizen集合的引用等信息,都是这个类的变量,市民的总数上限啊、市民出行开车的概率啊、生孩子的概率啊、成为gay的概率啊等等常量,也都在这里。这个CitizenManager是单例的,你不能显式的去创建这个对象,调用单例的方法后面的代码里有。 另外还要提一句,市民上限是100万多点,但是不代表所有的市民都会被显卡“画出来”,只有被实例化的市民,才会交给frame,去具体的在界面上画出来。Instance的上限,我记得是65000+,所以大家不用担心人多了显卡“画”

6、不动 二、基本API解读 官方给出了一个基本的API文档。但是。真的是太基本了,基本什么也做不了。但是给的这些API又确实非常基础,无论你做什么MOD,这几个API还确实是很常用的。所以还是要大体上说一下的。 1、IUserMod 最简单,最常用的interface,没有之一。就是定义MOD的名称和描述。基本没其他作用。 代码: using ICities; namespace SuperBigTransport public class Mod : IUserMod public const int unit_number = 16; public string Name 6399游戏网 g

7、et return 超级客运+ unit_number * 5 + 人版 | SuperBigTransport + unit_number * 5; public string Description get return 公交车容量改为+ unit_number * 5 + ,火车改为 + unit_number * 5 * 8+ ,地铁改为 + unit_number * 5 * 6; 要注意的是namespace的定义。有些同学说我的mod怎么冲突了,其实就是这个namespace重名了。所以,不同的mod必须要起不同的namespace,即使类名不同也不行。所以推荐跟你的mod名称对

8、应。 其他应该很简单吧。我觉得好像没什么要解释的。unit_number这个问题我后面再说。 2、LoadingExtensionBase 6399游戏网 这个抽象类是在游戏存档加载时生效的。 4个方法,create、release是单例创建和销毁时触发的,这个貌似很少用 比较常用的是load和unload方法,就是存档加载和退出时的方法。 看代码: using System; using System.Collections.Generic; using ColossalFramework; using ICities; using UObject = UnityEngine.Object;

9、 namespace SuperBigTransport public class LoadingExtension : LoadingExtensionBase public override void OnLevelLoaded(LoadMode mode) /游戏加载开始。 ForEachPrefab(VehicleInfo i) =/在读取所有车辆信息时,对每一个车辆信息进行处理。主意这里不是每一辆车,是每一类车,注意是Info类 ReplaceVehicleAI ReplaceVehicleAI ); /游戏加载结束 6399游戏网 static void ReplaceVehicl

10、eAI where TOldAI : VehicleAI where TNewAI : VehicleAI, IAIReplacement, new var oldAI = i.gameObject.GetComponent; if (oldAI = null) return; i.gameObject.AddComponent;/必须先把新的AI注册进去,再取出来。好奇怪的写法,但是不这么写不行 var newAI = i.gameObject.GetComponent; newAI.CopyFrom(oldAI);/AI也有属性,如果要替换,必须把原有的属性也全部对拷,否则就会出现各种奇怪

11、的情况 i.m_vehicleAI = newAI; UObject.Destroy(oldAI); newAI.InitializeAI; static void ForEachPrefab(Actionf) where T : PrefabInfo for (var i = 0u; i 0) /判一下当前的容量数是多少 i+; cu = citizenManager.m_units.m_buffercu.m_nextUnit; if (i != Mod.unit_number) /如果不等于预期,就改 uint firstId; var random = new ColossalFrame

12、work.Math.Randomizer; citizenManager.CreateUnits(out firstId, ref random, 0, vehicleID, 0, 0, 0, Mod.unit_number * 5, 0);/citizenUnit既然是由CitizenManager来统一管理的,那么创建肯定也是由CitizenManager来统一做的。我们简单的在这里创建了一个符合我们预期长度的citizenUnit vehicleData.m_citizenUnits = firstId;/然后粗暴的直接替换 /citizenManager.ReleaseUnits(un

13、itId);/这里不能释放,释放了市民就找不到路了。释放了有什么效果请自行观察。 6399游戏网 return base.ArriveAtDestination(vehicleID, ref vehicleData); 好了,这里就是我们增容的核心代码了。那么现在有一个bug,就是公交会闪。在这里我表示我非常的冤枉,跟我真的没啥关系。我没动frame.我只是替换了个数组。 所以,这个替换是非常生硬的,直接的后果就是会导致存档发生变化。即使关闭了mod,也无法改变已经客观存在的链表结构。所以我说嘛。官方偷懒。不好好的调用那个容积属性进行判断。非要搞数组,还是链表结构的。真是无语。 然后,上面只是

14、公交车的,下面是地铁和客运火车的。我直接贴代码了,因为结构差不多,我就不解释了。有一个小bug,会导致一个不合理的现象,但是很隐蔽,不知道大家能发现么? using ColossalFramework; using System.Collections.Generic; namespace SuperBigTransport class BigPassengerTrainAI : PassengerTrainAI, IAIReplacement public void CopyFrom(PassengerTrainAI ai) m_passengerCapacity = Mod.unit_nu

15、mber * 5; m_ticketPrice = ai.m_ticketPrice; m_info = ai.m_info; 6399游戏网 m_arriveEffect = ai.m_arriveEffect; m_transportInfo = ai.m_transportInfo; CitizenManager citizenManager = Singleton.instance; public override bool ArriveAtDestination(ushort vehicleID, ref Vehicle vehicleData) var unitId = vehic

16、leData.m_citizenUnits; var cu = citizenManager.m_units.m_bufferunitId; int i = 1; while (cu.m_nextUnit 0) i+; cu = citizenManager.m_units.m_buffercu.m_nextUnit; uint firstId; int n; if (i Mod.unit_number) var random = new ColossalFramework.Math.Randomizer; if (vehicleData.m_transferType = 39)/metro

17、firstId = citizenManager.m_units.m_bufferunitId.m_nextUnit; citizenManager.ReleaseUnits(unitId); vehicleData.m_citizenUnits = firstId; n = (Mod.unit_number - 6) * 5 * 6 + 30; 6399游戏网 else firstId = citizenManager.m_units.m_bufferunitId.m_nextUnit; citizenManager.ReleaseUnits(unitId); vehicleData.m_c

18、itizenUnits = firstId; n = (Mod.unit_number - 6) * 5 * 8 + 30; citizenManager.CreateUnits(out firstId, ref random, 0, vehicleData.GetFirstVehicle(vehicleID), 0, 0, 0, n, 0); vehicleData.m_citizenUnits = firstId; return base.ArriveAtDestination(vehicleID, ref vehicleData); 四:其他要交代的 打印调试语句: DebugOutpu

19、tPanel.AddMessage(MessageType.Message,output something); 进入游戏后按F7,即可调出控制台 替换官方AI会导致跟其他mod冲突的概率大大加大,换句话说,如果其他mod也试图跟你替换同一个AI,那么一定最后只会有一个成功。所以,后来我基本不再写替换官方AI6399游戏网 的MOD了。做的那个出乎我自己意料的、大家很喜欢的、停车收费降居民需求的MOD,其实就是我替换自己建筑物的AI,从理论上讲,基本不会跟别人冲突掉。 另外,这个游戏是使用的UnityEngine引擎。其中大量的模拟了物理方面的规则。所以,在改代码的时候,时刻要牢记一定要符合物理规则。比如,把车辆速度调快,确实车速会增加的,但是,拐弯的时候也会翻车的,很真实,符合物理规则。

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 生活休闲 > 在线阅读


备案号:宁ICP备20000045号-2

经营许可证:宁B2-20210002

宁公网安备 64010402000987号