这篇文章转自http://va.lent.in/should-you-use-playmaker-in-production/

此文作者大概深受其苦,吐槽了playmaker的多个蛋疼的地方,这其实说明了两个问题,一个是作者能力有限,对工具的应用和理解不到位。另一个是警示,不要完全依赖其他工具,拿来要会改会用。

So, should you use Playmaker in production? Short answer is:

Long answer follows.

Playmaker

Playmaker is a visual scripting tool for Unity. It has been a top-selling asset in the Asset Store for a couple of years.

Learning environment

I get invited to host Unity workshops from time to time. One of these workshops consisted of 6 lessons and the audience didn't know anything about programming. That's where I finally decided to try to build an entire game using Playmaker.

The game was really small with Unity physics doing most of the work, but anyway many small scripts to handle interactivity were needed. And here Playmaker worked really great.

The concept of states and actions appears to be very intuitive, so even people with near to no programming experience could "script" simple interactions very fast.

So, for teaching Unity I will definitely use Playmaker again.

State machines

Well, I'm a huge fan of state machines. I usually structure my code so I know exactly in which states all the modules of my application are. And every action is controlled from top to bottom in a hierarchy of simple state machines. This apporach keeps the code very simple and easy to follow and debug.

It seemed that Playmaker being a visual state machine framework would fit fine in my pipeline. But, oh God, how I was wrong.

Code, OOP and software architecture

If you are an experienced software engineer you know how important it is to structure your code right.

We all remember those days spent trying to debug a spaghetti mess of interlinked code promising to God to never be so lazy again if he helps us find why this monstrosity doesn't work.

Sooner or later you inevitably come to a set of good practices of software architecture and code structuring. If you do everything right and use a good IDE like Visual Studio which allows you to easily browse code and jump to lines where a function is defined or called, it's really easy to follow what's going on in your code and usually is not hard to figure out why something is not working.

The critical features here are:

  • Ability to see where methods are called from,
  • Transparent control hierarchy (i.e. a chain of command with no global events or variables),
  • Right encapsulation with no external state exposed.

Playmaker violates all these statemens and adds even more ugly stuff.

Playmaker in production

Now I'm going to list all the problems I found in Playmaker I could remember while working on a real project. In no particular order.

If you know a good workaround for any of these problems feel free to post them in comments at the end of the article.

1. Playmaker breaks encapsulation

If you don't want to shoot yourself in a foot you absolutely shouldn't expose object's internal state to the world.

Well, Playmaker does just that. It completely breaks encapsulation.

Most likely you would have a script on the same object with Playmaker FSM which exposes API to control the object. This script does some work and makes the FSM to change state. It's a normal behavior but here you have state moved outside of the object, visible to everyone, state which can be modified by anything any time.

Even if you are an experieced developer and you understand possible consequences of this decision, believe me, you WILL be tempted to do the wrong thing and modify this state bypassing proper API calls. Young programmers will do this immediately if you give them any chance at all.

2. Playmaker makes it impossible to see control flow

Any action in any state can call any method or change a local or global variable. There's no way to find out what changes what except going through every state and every action by hand.

There's no Find Usages or Go to Definition like in any good IDE, if someone decides to bypass the API (and they will) you will have a very hard time trying to find out what really is happening there.

3. Playmaker is incompatible with git

Seriously, we had so much pain in the ass because of how Playmaker saves its graphs into Unity scene. It seems that it does this the most unmergeable way possible. And you don't even know that something was damaged during a merge right away. Beleive me or not it was happening a lot even if someone just moved some states around to make them look better...

4. Playmaker makes scripts more complicated

Playmaker was created to make coding simpler, right? Not really.

Playmaker makes small "code" simpler to write but large complicated code becomes a complete mess.

This is actually a problem of all visual languages. Believe me, I worked a lot with visual scripting environments.

In a visual language you connect nodes which do simple tasks, like adding two numbers or calling a method. And there's a threshold where you have to delete all your "visual" code and reimplement this logic as anode or an action in Playmaker terminology. Because visual "code" becomes too complicated very quickly.

Sooner or later you'll end up with this.

Which is MUCH harder to follow than code.

Of course, you can develop common practices to try to fix this mess. Like, having one action with major logic per state or design your action in some modular fashion. But you can't get rid of this problem completely especially when you have a set of actions which you probably can combine into a Frankenstein's monster to do what you want. Because the cost of making a new action (multiplied by laziness) is higher.

4.1 Passing data

Unlike dataflow visual languages where you pass modified data around, to pass something from one action to another you have to use variables. Which is (a) another huge layer of complexity and (b) makes one more huge hole in encapsulation.

So, instead of doing action2(action1("hi")); in code you have to (a) add one or more variables, (b) add variable support to both actions, (c)configure to use same variables on both instances of these actions.Which is adding a lot of unnecessary complexity.

4.2 Events on state change

It's surprising, but there's no way for a script to be notified when a FSM changes state. If you want to sync a FSM's state with something else you will have to put a special action in every state yourself. Which makes states even bigger.

5. Playmaker uses global variables and events

You probably know or at least heard that global variables and global events are evil. Usually it's wrong to say that something is 100% bad or 100% good because world is not black and white. There are ways to use global variables/singletons and global events/messages without driving yourself crazy.

But how global events and global variables are implemented in Playmaker is the same as giving you a loaded machine gun and aiming it to your foot.

Anything can dispatch an event or change a global variable, and any other object can react to this. And due to (2) you have no way of debugging this.

And because Playmaker encourages you to use global events and global variables, even if you are aware of the consequences, sooner or later you will start using them. And you'll regret about this decision at the end...

6. Playmaker makes state machines excessively complicated

This one might be my personal choice, but anyway these are my personal thoughts so I ought to list it too.

There are several ways to implement a state machine. Different implementations might be called a Mealy machine, or a Moore machine, or another way to combine current state and current input into action.

The thing is that Playmaker forces you to have all the logic in states.So, to execute something you have to change state. This gets even more complicated considering the execute in every frame flag which many actions have. Because in current system it's either a transition from a state to itself (while during this transition not all the actions get executed) or a piece of logic which executes without a transition. Both of these options break the execution model Playmaker offers.

What's more, if you want to add a constant logic for an event which behaves the same in most of the states you will have to add this logic to all states in Playmaker.

I think you can use several FSMs to deal with this problem but having several FSMs just adds even more complexity.

Another model (which I use in my code) would be to use states as filters what to do with incoming events. In this case you need much less states and all your event handlers will look like this:

private void EventHandler() {
switch (currentState) {
case State.One:
// ignore
break;
case State.Two:
doSomeStuff();
break;
case State.Three:
doOtherStuff();
break;
}
}

I don't have to change states when I want to execute some logic in response to an event. Also, I'm absolutely sure that this event will have no effect if current state is State.One.

Of course, you can have some logic executed right when state changes. Anyway, this abstraction of state machines allows to have less states and is easy to read in code.

Good stuff

But there are some good points. When I was trying to list good sides of Playmaker I came up only with two:

  1. Visual representation of states and transitions,
  2. Usually it's easy to see what is being done in a state.

I am an experienced software engineer and I can keep in mind most of the nested graphs of state machines in my app. But it's always better to have a visual representation.

One of my less experienced colleague told me that he really liked working with Playmaker, because he was able to see actual state graphs.

Of course, guess who was in charge of fixing all the mess Playmaker introduced with these shiny graphs... But he has a point. Visualizing control flow and state graphs does help.

As for individual states, if you structure and name all the actions rightit's really easier to read what's going on in the state comparing to reading a bunch of unrelated methods in source code. But as I noticed this type of "coding" actively uses another part of your brain and keeps wasting brain power on how "code" looks instead of focusing on how it works.

Not that it's a completely bad thing but it easily drives you from what you need to do into some sort of "playing with fonts" procrastination.

Conclusion

First of all, I will never use Playmaker in my app again.

Second, there might be a better paradigm and a better way to use a visual state machine in Unity. The one which doesn't have all the flaws Playmaker has.

This is just another field for me to explore.

转一篇关于Unity的PlayMaker的更多相关文章

  1. 【浅墨Unity3D Shader编程】之二 雪山飞狐篇:Unity的基本Shader框架写法&颜色、光照与材质

    本系列文章由@浅墨_毛星云 出品,转载请注明出处. 文章链接:http://blog.csdn.net/poem_qianmo/article/details/40955607 作者:毛星云(浅墨)  ...

  2. 【Unity3D技术文档翻译】第1.9篇 使用 Unity AssetBundle Browser tool (AssetBundle系列完结)

    上一章:[Unity3D技术文档翻译]第1.8篇 AssetBundles 问题及解决方法 本章原文所在章节:[Unity Manual]→[Working in Unity]→[Advanced D ...

  3. Playmaker Input篇教程之Playmaker购买下载和导入

    Playmaker Input篇教程之Playmaker购买下载和导入 Playmaker Input篇认识Playmaker Playmaker是Unity的插件,其标志如图1-1所示.开发者使用它 ...

  4. 用好lua+unity,让性能飞起来——luajit集成篇/平台相关篇

    luajit集成篇 大家都知道luajit比原生lua快,快在jit这三个字上. 但实际情况是,luajit的行为十分复杂.尤其jit并不是一个简单的把代码翻译成机器码的机制,背后有很多会影响性能的因 ...

  5. Unity性能优化(4)-官方教程Optimizing graphics rendering in Unity games翻译

    本文是Unity官方教程,性能优化系列的第四篇<Optimizing graphics rendering in Unity games>的翻译. 相关文章: Unity性能优化(1)-官 ...

  6. Unity性能优化(2)-官方教程Diagnosing performance problems using the Profiler window翻译

    本文是Unity官方教程,性能优化系列的第二篇<Diagnosing performance problems using the Profiler window>的简单翻译. 相关文章: ...

  7. unity之初识shader

    自己做个总结先.当然文中很多内容都是从各位大神的文档当中看的.我只是站在巨人的肩膀上.       首先什么是shader?其实就是一个在显示屏当中的显示程序,俗称着色器.它可以定义物体在硬件显示屏当 ...

  8. 对想进入Unity开发新人的一些建议

    提前声明:本文只是写给那些非职业游戏开发人士,只面向那些在校本科生,或已就业但无unity背景的同学们,当然是面对程序员方向的.本人刚工作也没多久,资历尚浅,之前在网上有一位同学让我谈谈一些想法,所以 ...

  9. Unity协程(Coroutine)原理深入剖析

    Unity协程(Coroutine)原理深入剖析 By D.S.Qiu 尊重他人的劳动,支持原创,转载请注明出处:http.dsqiu.iteye.com 其实协程并没有那么复杂,网上很多地方都说是多 ...

随机推荐

  1. Oracle not in子连接查询不到值的问题(not in 不能查询null数据)

    前几天在项目中,做数据导入时,发现not in和in 查出来的条数不互补.ATABLE2明明中有些记录在ATABLE3中不存在,但是not in时查不出记录. CREATE TABLE ATABLE2 ...

  2. MemSQL分布式架构介绍(一)

    最近在了解MemSQL架构,看了些官方文档,在这里做个记录,原文在这里:http://docs.memsql.com/latest/concepts/distributed_architecture/ ...

  3. linux 进程管理相关内容

    简介 当我们运行程序时,Linux会为程序创建一个特殊的环境,该环境包含程序运行需要的所有资源,以保证程序能够独立运行,不受其他程序的干扰.这个特殊的环境就称为进程. 每个 Linux 命令都与系统中 ...

  4. hadoop2.6---windows下开发环境搭建

    一.准备插件 1.自己编译 1.1 安装Ant 官网下载Ant,apache-ant-1.9.6-bin.zip 配置环境变量,新建ANT_HOME,值是E:\apache-ant-1.9.6:PAT ...

  5. Ubuntu14.02.2下安装JDK并配置Jetty服务器

    首先第一步先取得JDK的安装文件,由于我的系统是64位的,所以安装包是jdk-7u80-linux-x64.gz 上传到unbuntu服务器下 执行tar -xvf jdk-7u80-linux-x6 ...

  6. 理解 OpenStack Swift (2):架构、原理及功能 [Architecture, Implementation and Features]

    本系列文章着重学习和研究OpenStack Swift,包括环境搭建.原理.架构.监控和性能等. (1)OpenStack + 三节点Swift 集群+ HAProxy + UCARP 安装和配置 ( ...

  7. 02 Hibernate错题分析

    解析:使用final修饰的成员变量是常量 解析:不存在StateMoreSession的对象 解析:一个PreparedStatement 可以执行多次executQuery方法 解析:A   使用H ...

  8. AC日记——过滤多余的空格 1.7 23

    23:过滤多余的空格 总时间限制:  1000ms 内存限制:   65536kB 描述 一个句子中也许有多个连续空格,过滤掉多余的空格,只留下一个空格. 输入 一行,一个字符串(长度不超过200), ...

  9. 炮(棋盘DP)

    一直以为自己写的就是状态压缩,结果写完才知道是个棋盘dp 首先看一下题目 嗯,象棋 ,还是只有炮的象棋 对于方案数有几种,我第一个考虑是dfs,但是超时稳稳的,所以果断放弃 然后记得以前有过和这个题差 ...

  10. Nginx/Apache服务连接数梳理

    统计连接数,使用netstat命令或ss命令都可以1)统计连接数(80端口)[root@wang ~]# netstat -nat|grep -i "80"|wc -l872 或者 ...