求生之路2关卡设计/导演查询机制

来自Valve Developer Community
跳转至: 导航搜索
English (en)Русский (ru)中文 (zh)
编辑

本简体中文页面由 Gloria 汉化。

logic_director_query 实体是L4D2新增的独有实体,当它被触发时,会返回一个指示A.I.导演当前有多“愤怒”的值。生还者表现得越好,导演就会越“生气”,游戏中感染者的生成也会越激进。

可以利用这一机制来让你的地图更动态化,根据玩家水平的不同做出响应。一个简单的例子是,在地图中分别创建几条长度/难度不同的路径,然后使用一个导演查询实体来控制某条路径的开闭。在对抗模式中,系统会在阵营互换时自动地重复第一局的选择,以保证游戏的公平性。

发起查询

我们来瞧瞧它是怎样的运作机制。

用于触发查询的固实体。

导演会持续地更新自身内部的状态,但出于地图编辑考虑,你必须通过某种触发器来显式地查询导演的状态。查询事件能反馈当前导演的愤怒值,让我们得以根据这个值设置不同的游戏逻辑。

在这个例子中,我们在生还者到达地图的特定点时发起一次查询。来,我们把一个触发器(trigger)固实体放在走廊中。关卡一开始就进行导演查询通常并没有什么卵用,因为此时生还者都是满血的,而导演的愤怒值通常也是最大的。但对于学习地图制作来说,这也足够了。

放置一个固体,选中它并在菜单栏中点击 Tools -> Tie to entity 转换为固实体。将实体类型更改为"trigger_once"并给它应用"tools/toolstrigger"纹理。

用于筛选触发器的可触发对象的过滤器。

我们当然希望这个触发器只对生还者做出反应,因此需要过滤它的输入。为了实现过滤,来放置一个"filter_activator_team"实体,命名为 "filter_survivor"。

选中触发器固实体,打开属性面板,将它的过滤器属性指定为"filter_survivor"。现在这个触发器就只能被生还者触发了,而感染者无法触发。

一个全新的 info_director_query 实体诞生了。

接下来,去走廊的另一头,找到通向安全屋的梯子。放置一个类型为"logic_director_query"的新实体,命名成"director_query_zombie"。

在属性面板中,将 Min Anger Range(最小愤怒值) 属性设置为 0,将 Max Anger Range(最大愤怒值) 属性设置为 9。导演自身真实的愤怒值在0~50之间,但我们将它分成10种情况。上述设置将会把导演查询的返回结果缩放到0~10之间。

愤怒值中的 Noise(噪声) 属性也是游戏体验重要的一环。一点点不确定性的加入能让玩家保持活跃。当然为了教学起见,我们先把 Noise 设置为"Pure"(无噪声)。它将关闭愤怒系统中内置的随机数。正常情况下不要这么做,因为这会消除流程中的惊喜元素,让游戏体验变得无趣,且可预测性太强。

发起一次查询。

现在选择地图开始位置的触发器固实体,添加一个"OnStartTouch"事件输出,输出到"director_query_zombie"实体的"HowAngry"事件上。

按下F9键运行地图。加载完成后,进入走廊以触发trigger固实体,同时马上打开控制台。导演查询会输出下面的内容:

TRUE Anger: 50.00  Processed Anger:  50  Out Anger:   9

可以看到查询被成功发出了。在地图制作过程中,可以将 sv_cheats 始终设置为 1,这能让你手动从控制台发起导演查询,我们这个例子中的命令是:

ent_fire director_query_zombie howangry

响应查询结果

下丧尸雨了。

既然我们已经可以从导演获取信息了,下面可以用来做一些事情,在地图中弄出一些变化。先生成一只感染者,但它的类型根据愤怒值不同而不同。

director_query 实体的正上方添加一个 commentary_zombie_spawner 实体。

属性中不同的条件分支(Case)

接下来,创建一个新的 logic_case 实体并命名为"zombie_case",为其中的每一种情况添加响应事件。我们的例子中,设置了10种不同情况下的响应。

条件分支输出

属性(Properties)选项卡设置完成后,打开输出(Outputs)选项卡,根据条件分支的不同把丧尸生成器设置成不同的类型。

现在,回到 logic_query_director 实体的 Outputs 选项卡,触发事件选择 OutAnger,目标实体选择"zombie_case",实体事件选择 InValue。这个输出会把 logic_query_director 查询转换后的愤怒值传递到 logic_case 实体上。logic_case 实体可以根据这个值做出相应的选择。

当条件分支与属性不匹配时,什么都不会发生。因此在我们的例子中,如果导演愤怒值在5以下,就不会触发事件。

而大于6时,logic_case实体会通知生成器强制刷出一只丧尸,至于是普通感染者,还是boomer、charger,甚至tank,都取决于愤怒值的大小。

其它用途

当你在制作地图时,最好仔细地优化地图逻辑,让每个与导演状态相关的事件都能让玩家感到有趣。如果你设置得太死了,玩家就能预测某个事件的发生,这就不好玩了。如果事件有一些随机性,其发生的概率与玩家的表现不完全成正比,这样玩家就不会被驱使着去完成你的要求。

那需要多大的随机性呢?这点视不同情况而定。对于不同的剧情,兴趣区的设置也是不同的,不是随随便便就能做好的。建议有计划的循环地观察玩家状态,调整地图行为,再次观察,再次调整……

下面是一个兴许对你的地图制作与调试有用的示例:

打开下面的文件:

sdk_content\mapsrc\Your_First_L4D_Level_Tutorial\tutorial07_complete.vmf
愤怒值调试器

图中是一个逻辑定时器(logic_timer),每隔固定时间触发一次 info_query。条件选择器(logic_case)计算愤怒值并启用对应笔刷的显示。这样就能将导演查询出的值就能以数字形式展现给玩家了。

当然,除了数字以外,你可以用它来做出更好玩的东西。人们通常会有“呈现出相关性的事物一定具有因果关系”的错觉,可以利用人们的这一心态来制造娱乐效果,或是拿来吓人。(甚至有可能实现盈利(profit)。)

下面是另一个值得学习的示例:

sdk_content/Deadline2/mapsrc/l4d_deadline01.vmf

死亡二号线示例的第一张地图使用了这一技术来实现路线选择,一条路短而直,另一条则较为曲折蜿蜒。还有一个放在生还者必经之路上的刷怪器,根据导演愤怒值的不同,会生成一只Boomer或是Witch,在这种狭窄的空间里,不论刷出哪个都够让玩家好受的了。



logic_director_query is a new L4D2-specific entity that, when triggered, returns a value that corresponds with how "angry" the A.I. Director is at that moment. The better survivors are doing, the angrier the Director will be, and the more aggressive the game will be in spawning infected.

You can take advantage of this to make your maps more dynamic and responsive to player skill level. A simple example would be to create multiple paths through an area of varying length/difficulty, then using a Director query to open and close the appropriate paths. In versus, the system will automatically repeat the decision when teams swap, thus providing for an even playing context.

Firing a query

Let's look at how this works.

A solid to trigger the query.

The Director is constantly updating its state internally, but for map-editing purposes, you must explicitly query it with some kind of trigger. The query gives us a snapshot of the Director's anger value and allows our game logic setup to respond accordingly.

For this example, let's fire off the query once the survivors reach a certain point in the map. Go ahead and place a trigger volume in the hallway. Querying the Director so close to the very beginning of a first map is not always useful, since survivors will be at full health and the Director will always be at its most angry. But for learning purposes, this will do.

Place a solid, then select it and choose Tools > Tie to entity from the menu bar. Change the entity class to "trigger_once" and assign it the material "tools/toolstrigger"

Filter what can activate the trigger.

We'll want this trigger to happen for survivors only, so we'll need to filter its output. To do so, let's place a new entity of class "filter_activator_team" and name it "filter_survivor".

Select the trigger volume and under properties, set its filter name to "filter_survivor" The trigger will now only be activated by survivors, and not by infected.
A new info_director_query is born.

Next, let's move down the other end of the hallway to the ladder leading up to the safe room. Place a new entity of class "logic_director_query". For a name, use "director_query_zombie".

Under Properties, set the Min. Anger Range to 0, and the Max Anger Range to 9. The Director itself keeps track of anger between 0 and 50, but for our purposes we will want to divide it into 10 cases. These settings remap the values that the Director query reports back to a scale between 0 and 10.

Noise in the anger value is a very important part of gameplay. A little bit of unpredictability is necessary to keep players on their toes. For tutorial purposes, let's set Noise to "Pure". This effectively turns off the built-in in randomness in the anger system. You typically will not want to do this, as it removes the element of procedural surprise, making gameplay boring and predictable.

Firing the query.

Go ahead and select the trigger volume at the start of the map and add an output "OnStartTouch" which will target "director_query_zombie" with an input of "HowAngry".

Hit F9 to run the map. Once it loads, step into the hallway to trigger the volume and then immediately bring up the console. The Director query will have spit out something like the following:

TRUE Anger: 50.00  Processed Anger:  50  Out Anger:   9

So your query is now firing for players. While working on your map, you will want to set sv_cheats to 1, thus allowing you to manually trigger the Director query from the console. For us that would be:

ent_fire director_query_zombie howangry

Reacting to the query

It's raining Zombies.

Now that we can have information about the Director, we need to do something with it, and that will typically be some kind of change in the world. Let's spawn an infected, but have the type vary depending on the anger.

Place a new entity of class commentary_zombie_spawner just above the director_query.
Case properties

Next, let's create a new logic_case entity named "zombie_case" and put in property values for each of the conditions we want to respond to. In this example, we've set it up to be able to respond to 10 different conditions.

Case outputs

Once the Properties are set up, we move on to the Outputs and signal the zombie spawner to do different things depending on the case.

Now, go back to your logic_query_director entity and go to Outputs there. Choose OutAnger as your output, "zombie_case" as your target, and InValue as your input. This will tell your logic_query_director to send the exact value of its remapped anger values to the logic_case. The logic_case will take this number and will correspond it to the cases you have set up.

If the case doesn't match the property, it won't do anything. So in this example, if the Director anger is 5 or below, it won't do anything.

Above 6, the case signals the spawner to force spawn a zombie, which will be either a common infected, a boomer, a charger, or a tank, depending on what the anger level was.

Other uses

When you're developing your maps, you'll want to carefully tune your map logic so that each Director-responsive scenario is FUN FOR PLAYERS. If your setup is too predictable, players will be able to anticipate it, and that's not fun. If it's so random that it's not clear that how well they are doing has some correlation with what happens, then they will not be motivated to do what you're asking them to do.

How much randomness should you use? It depends. The fun zone is different for each scenario, and achieving it seldom happens straight off. It is recommended that you plan for several iterations of observing players, tweaking the behavior, observing again.

Here's an example that you may find useful in developing and debugging your maps:

Open the file:

sdk_content\mapsrc\Your_First_L4D_Level_Tutorial\tutorial07_complete.vmf
Anger Debugging

Here we have a logic timer that has the info_query fire off a query at regular intervals. The logic_case evaluates the anger and enables the appropriate func_brush number. This gives a numerical readout of the anger value directly to players based on the Director query.

Of course, instead of numbers, you can do more subtle things. People often assume that correlation equals causality. You can use this to your advantage for entertainment and thrills. (And eventually perhaps even profit.)

Here's another example you should check out:

sdk_content/Deadline2/mapsrc/l4d_deadline01.vmf

The first map of Deadline2 example add-on campaign uses this to select alternate paths, one short and direct, one less direct and kinked. There is also a spawner that may place in the survivors path, depending on anger, a boomer or a witch, neither of which is good to have in a tight constrained space.