你们对力量一无所知
引言
回顾上文,我们谈完了World和Level级别的逻辑操纵控制,如同分离组合的AController一样,UE在World的层次上也采用了一个分离的AGameMode来抽离了游戏关卡逻辑,从而支持了逻辑的组合。本篇我们继续上升一个层次,考虑在World之上,游戏还需要哪些逻辑控制?
暂时不考虑别的功能系统(如社交系统,统计等各种),单从游戏性来讨论,现在闭上眼睛,想象我们已经藉着UE的伟力搭建了好了一个个LevelWorld,嗯,就像《西部世界》一样,场景已经搭建好了,世界规则故事也编写完善,现在需要干些什么?当然是开始派玩家进去玩啦!
大家都是老玩家了,想想我们之前玩的游戏类型:
- 玩家数目是单人还是多人
- 网络环境是只本地还是联网
- 窗口显示模式是单屏还是分屏
- 输入模式是共用设备还是分开控制(比如各有手柄)
- 也许还有别的不同
假如你是个开发游戏引擎的,会怎么支持这些不同的模式?以笔者见识过的大部分游戏引擎,解决这个问题的思路就是不解决,要嘛是限制功能,要嘛就是美名其曰让开发者自己灵活控制。不过想了一下,这也不能怪他们,毕竟很少有引擎能像UE这样历史悠久同时又能得到足够多的游戏磨练,才会有功夫在GamePlay框架上雕琢。大部分引擎还是更关注于实现各种绚丽的功能,至于怎么在上面开展游戏逻辑,那就是开发者自己的事了。一个引擎的功能是否强大,是基础比拼指标;而GamePlay框架作为最高层直面用户的对接接口,是一个引擎的脸面。所以有兴趣游戏引擎研究的朋友们,区分一个引擎是否“优秀”,第二个指标是看它是否设计了一个优雅的游戏逻辑编写框架,一般只有基础功能已经做得差不多了的引擎开发者才会有精力去开发GamePlay框架,游戏引擎不止渲染!
言归正传,按照软件工程的理念,没有什么问题是不能通过加一个间接层解决的,不行就加两层!所以既然我们在处理玩家模式的问题,理所当然的是加个间接层,将玩家这个概念抽象出来。
那么什么是玩家呢?狭义的讲,玩家就是真实的你,和你身旁的小伙伴。广义来说,按照图灵测试理论,如果你无法分辨另一方是AI还是人,那他其实就跟玩家毫无区别,所以并不妨碍我们将网络另一端的一条狗当作玩家。那么在游戏引擎看来,玩家就是输入的发起者。游戏说白了,也只是接受输入产生输出的一个程序。所以有多少输入,这些输入归多少组,就有多少个玩家。这里的输入不止包括本地键盘手柄等输入设备的按键,也包括网线里传过来的信号,是广义的该游戏能接受到的外界输入。注意输出并不是玩家的必要属性,一个玩家并不一定需要游戏的输出,想象你闭上眼睛玩马里奥或者有个网络连接不断发送来控制信号但是从来不接收反馈,虽然看起来意义不大,但也确实不能说这就不是游戏。
在UE的眼里,玩家也是如此广义的一个概念。本地的玩家是玩家,网络联机时虽然看不见对方,但是对方的网络连接也可以看作是个玩家。当然的,本地玩家和网络玩家毕竟还是差别很大,所以UE里也对二者进行了区分,才好更好的管理和应用到不同场景中去,比如网络玩家就跟本地设备的输入没多大关系了嘛。
UPlayer
让我们假装自己是UE,开始编写Player类吧。为了利用上UObject的那些现有特性,所以肯定是得从UObject继承了。那能否是AActor呢?Actor是必须在World中才能存在的,而Player却是比World更高一级的对象。玩游戏的过程中,LevelWorld在不停的切换,但是玩家的模式却是脱离不变的。另外,Player也不需要被摆放在Level中,也不需要各种Component组装,所以从AActor继承并不合适。那还是保持简单吧: