又想了想godot vs unity问题,godot的设计哲学更像是一个unity这种游戏引擎和flutter的缝合怪,与react能完全用函数式组件不同,flutter基本还是一个基于继承class(可以完全stateless、immutable)的声明式UI框架,你想要自定义一个组件,也是需要继承自一些框架给你的中间类来复用代码和实现虚函数,但和游戏不同的是写UI基本都是在写build(render)函数,靠这个拼布局,拼出来一个由各种组件构成的hierarchy。而游戏中hierarchy要么是静态创建出来的要么是指令式创建出来的。unity的GO+MB模式设想的理想代码架构模式,是GO内部或简单父子级关系靠GetComponent系函数,GO外部靠往字段里拖对象最后拿到的是MB实例,编辑器给你解决所有依赖注入,然后你写的MB是个胶水操作工操控其他各个控件和接受回调,这种思维是很直观的。可是进了godot,虽然拖对象还在,但很难生搬硬套这种思维,比如我写一个父级空Node充当GO,然后各种子级Node写互相调用是不太行得通的,因为godot里是没有GetComponent<Type>这种安全的按面向对象的类型获取兄弟节点的方式的,它GetNode那个泛型参数只是用来类型强转,想要这么干都得靠字符串进行名称查找遍地飞线,他推荐的跨node通信方式是signal(其实就是多播的event),要不然就都得经过父级Node来处理依赖注入,我认为这么干远不如prefab上一个待配置的字段/需求某接口来得痛快,很多时候我只是希望能有一个函数调用的手段/时机啊(我认为事件驱动的本质是轮询被包装为函数调用),这种需求根本用不着pubsub注册回调解耦,你外部靠字符串方式配置注入funcref之类告诉子节点调用什么,和我直接依赖一个接口对象有任何差别吗,甚至要回到用手动赋值依赖注入,这就更匪夷所思了(我要是知道两个对象彼此在哪(比如根本不是父子级关系),我还要你编辑器的序列化干什么?),我更痛恨eventbus.fire这种过时的模式。其实我觉得这何尝不是犯了flutter 老provider的错误,就是总觉得要局部性,要找到一个公共最小父级来处理子节点之间的问题,最后发现这么干一堆问题,riverpod直接改成了全局变量+顶层IOC容器的思路。
评论区
共 3 条评论热门最新