Monday, July 15, 2013

Combining Multiple Behaviors

In last week's entry, I made a note at the end that there was a limitation in the way I had designed how Behaviors are attached to Entities--namely, that I was limited to one behavior per entity. This post is about how I solved the issue.

Technically, that's fine, since Behaviors are just references to code, and can be as complicated as I want them to be. But it doesn't necessarily yield good design with respect to reusable components. Let's take an example.

Let's say I have an entity with the lit torch graphic and I attach the ThrowableItem behavior to it:



And here's another entity with the PointLight behavior attached (the PointLight behavior attaches a child entity configured as a light source,  and has a few editable parameters such as size and color).



But what if I want to pick up the torch with the light on it? One solution would be to introduce an editor property to the ThrowableItem behavior, something like IsLightSource. Then, when the behavior is initialized, I could add a light entity as a child item. Unfortunately, that's a bad design.

Imagine I have another behavior called SpawnHeartWhenDestroyed which makes it so an entity drops a heart refill when its destroyed. Currently, when I throw an item and it hits the ground, it's destroyed. Would I really want to add a property to ThrowableItem, called SpawnsHeart that duplicated this behavior? What if I wanted a certain instance of an enemy to spawn a heart?

What's the point in having these nice componentized behaviors if I can't reuse them at will?

To solve this problem, I simple made it so an Entity can have multiple attached behaviors. Do you want your blob to also be a light source, spawn a heart when destroyed, and shake the screen every 6 seconds? No? Well, if you could if you wanted to. As a much more practical example, here's a torch that has both ThrowableItem and PointLight attached, which was the original inspiration for this architecture change. Check out the video!



Here is what the level editor looks like with this new feature. Launching the 'entity properties editor' of a single entity now shows a tabbed collection of behaviors--each with their own properties--instead of just one. Add and remove properties at will!

The entity properties editor--note the multiple behavior tabs


But remember, in the end, these behaviors are all acting on the same entity--that is, they could easily conflict if they both modify the same entity in incompatible ways. For example, you can't just make a Blob a ThrowableItem. You can try, but you're sure to get some weird behavior, since both of those things interact with the player in a mutually exclusive way. Is this a limitation of the engine? No, definitely not--the types of behaviors you'd expect from something that's both an enemy and throwable are just too complex to be automatically applied--it takes actual human programming to decide what it means to be an enemy and throwable. For example, does the enemy still damage the player when colliding with the player model? Does the graphic change? The engine can definitely allow you to define these things, but you'll have to do it explicitly in code.

As a bonus, here's a fun little video of a spotlight that follows the player around when he gets close.


Next up I'll be doing some things with music. Stay tuned and thanks for reading!

2 comments:

  1. Another nice post! Thanks for chronicling your progress in this blog.

    I take it from this post that you're working with an artist for your game's visual resources. How did you find them? Any advice on finding a good artist to work with?

    ReplyDelete
    Replies
    1. Yes, I'm working with an artist. His name is Dave and is the creator of the webcomic 'Dead Winter': http://deadwinter.cc/

      I found him through a gaming community (I play Team Fortress 2), so unfortunately I don't have any real advice. What are you working on?

      Delete