Would you use this?

Miscellaneous Forums/General Discussion/Would you use this?

Okay, I'm asking this here as this forum undoubtedly gets viewed more, and also because it's not really a Blitzmax programming question (although it is Blitzmax related.)

I've mentioned it in a few other threads, but I'm coding a custom behavior system, and am really curious if others would be interested in using it once it's complete. If there is a lot of interest I will put even more effort into polishing it and optimizing it, whereas if there isn't all I need to do is get it to the point where it's working for my project :P.

Now, onto the purpose and design of the system. The system itself is a modular behavior system wherein a behavior is coded once, and then instances of that behavior are attached to BehaviorObjects. Generally, behaviors are coded as "finite state machines" that operate relatively autonomously on their owner, although they can be coded to do just about anything, really.

The real flexibility of the system is that behaviors can add or remove variables to itself or to it's owner, it can access any variable of it's owner (it doesn't even need to know it's name prior to runtime). The same is true for functions - functions can be added or swapped on the fly. Behaviors can also look for the existance of other behaviors owned by the same parent object, and modify their behavior based on the existance or lack of of one (or more) other behaviors. For instance, you could make a "drunken" behavior that modifies the strength and intelligence of it's parent object, and also checks to see if that parent object has a "chat" behavior, and if so it replaces the chat function with it's own version which modifies text and adds slurring to words and other little distortions to the speech. It could even be coded to check and see what race it's parent object is, and then provide different word slurring functions based on race (or gender, or whatever you want.)

Of course, some behaviors would be very game specific and may not be all that useful to others, but the real beauty of the system is that a lot of general purpose modules can be made and will truly be "plug'n'play." I've mentioned this in another thread, but one good example is a "Sin Modulation" behavior that takes some variables and modifies them according the a sin wave, whose parameters you can adjust either in code or during runtime. So this behavior can be attached to any BehaviorObject and modify any and/or all variables of that BehaviorObject. Also, each instance of the sin behavior would have it's own frequency and amplitude variables that could be adjusted.

As a trite example, you might attach the behavior to an enemy ship and have it linked to that ships X variable, so as it flys down the screen, it moves left to right in a sin pattern. You then create another instance of the sin behavior and attach it to the stars in the background, and have it modify their alpha value. So now the stars will fade in and out against the background. Now, you want to create another little effect and have a graphic on the HUD grow and shrink a bit over time, so you create another instance of the sin behavior, set it's frequency and amplitude values, and attach it to the X and Y scale of the HUD graphic, and now this graphic's size will fluctuate over time.

The key idea behind the behaviors is that they are highly interchangeable and are truly plug'n'play, where you could literally copy and paste someone elses code into your own game, and simply instantiating an instance of the behavior and attaching it to one of your behaviorObjects and it would work. At most, all you'd have to do is change the input variables fed to the behavior and the output variables that the behavior is modulating in some way. And, due to the system, these variables can be adjusted at runtime and can even be added at runtime.

So, that's the basic idea. Yes, the flexibility of the system (allowing dynamically typed variables to be created/added to objects, and allowing functions to be swapped, removed, or added during runtime) does have a small performance and memory hit, but it won't be enough to impact a casual game unless you had hundred and hundreds of behaviors attached to hundreds of onscreen BehaviorObjects.

Anyways, my kind of utopian ideal here is to get some interest in this and then have people openly sharing behaviors so that we can all benefit from each others work.

Oh, also, the BehaviorObject class that behaviors attached to are extremely flexible just as Behaviors themselves are. They've got a custom datastructure that allows you to add any variables/functions you want, either in code or during runtime. So, you could use a behaviorObject as is and easily make it into a "sprite object" or a "gui object" or whatever, OR, you could extend the BehaviorObject type and add your own code on top of it (although certain guidelines need to be followed if you want behaviors to be able to interact with your modified version of the class. Basically, you'd have to provide some functionality to the core BehaviorObject that allows it to get at the extended type information. This sounds complicated but it really isn't, and quite frankly, due to the flexibility of BehaviorObjects themselves, wouldn't be necessary often if at all under most circumstances.)

I would, only if I programmed BlitzMax, but I'm on Blitz3D. But this is something I have to put my head at eventually.

Yeah, unfortunately doing something like this in Blitz3D would be nearly impossible due to the need for OOP to make something like this work and have a basic API that is fairly transparent.

I think the problem I see, really, is that this does just sound like a glorified state machine. Put a map for variables in the mix and you basically have what you're saying, I think. It's fun to write them, and I'm sure it would save some time for people, but I think you might want to not play this up too much as the holy grail.

Well, I see what you are saying and in a way it is simply a state machine. I just thought that if it were fast, and the interface was clean and easy to use that it could gain some favor.

I don't think the system itself is a holy grail, by any means, although if it became popular enough that a lot of useful behaviors were made available to and by the community, I think it could sort of become one (for casual game development at least.)

The key ingredients to that recipe are of course well optimized code, a clean and sensible interface, and most importantly community involvement. Oh, and proper documentation, of course ^_^.

For what it's worth, the underlyine data structure is actually a custom hash table that is on par speed wise with Lua's tables. So, given that the behaviors themselves would be used in a similar manner to scripts, and given that it should run as fast or faster than lua (perhaps faster since there's no need for a virtual stack), I'm guessing it's performance should be good enough for most games.*

*Just an educated guess at this point of course. Within a week or less I should be able to benchmark the actual system.

Hash table is a small improvement, but for variables on a per-object basis I'm not sure how much of an improvement that is, unless you're allocating a table per object. If you are allocating one for every object, that's probably going to end up costing more than is preferable memory-wise (depending on the bucket size, mostly).

Yeah, it's one table for each instance of a behavior object or behavior. I realize this could be a bit much, but the bucket size is configurable and the table can grow dynamically if needed, so that should help allay the potential for huge memory consumption.

I'll have to experiment to see where the ideal default size is in terms of the performance/memory tradeoff.

Anyone else interested in possibly using this? I suppose it'll be much easier to generate interest once I've got a nice working example that shows how flexible/easy it is to use ;P.


Anyone else interested in possibly using this? I suppose it'll be much easier to generate interest once I've got a nice working example that shows how flexible/easy it is to use ;P



Thats usually the case! ;)

Dabz

This is a bit strange. I was testing the overhead of calling a function through a hash lookup and function pointer, versus calling an identical method.

I knew the hash lookup/function pointer would be slower, but I got some interesting results...

Well, when the function/method were empty functions, the function lookup/pointer method was 40-60 times slower over the course of 10 million function calls. (4475 vs 75 milliseconds were the averages for the 10 million calls.)

However, I then tested some more "complex" functions, the first just being a function that simply assigned Millisecs() to an integer. Well, with this more complex function, the function lookup method was only about 8 times slower over 10 million function calls.

Then I tested a slightly more intensive function, that assigned Sin(Millisecs()) to an integer, and in this case the function lookup method of calling the function (the method used by the behavior system) was only 3.75 times slower.

How can the overhead of simply calling the function change so much based on what's in the function? How can simply looking up an empty function be 80 times slower than calling an empty method, and yet once the function and method become slightly more complex that changes to a difference of only 3.75 times slower?

Granted, I"m not complaining because obviously I want the overhead of a function lookup to be as small as possible. I can't complain with a less than 4x difference in speed given the flexibility of this.


Hmm, new testing shows that when calling the function

testint:int
testint = Sin(Millisecs())
testint = Cos(Millisecs())
testint = Tan(Millisecs())

the results were

Calling through pointer, 10000000.000000000 times.
Milliseconds elapsed: 14023.000000000000

Calling through method, 10000000.000000000 times.
Milliseconds elapsed: 8935.0000000000000

which means that calling that function through a hash lookup and pointer was only 1.5 times slower. Hmm, that's quite impressive since calling an empty function yields a difference of 40-60 times slower.

Anyone have any idea why the overhead is changing so much?

That is an easy question to answer.

Look at it like this. To people, A and B, do something.

Person A takes 100 seconds to accomplish the first task and person B takes 1 second to accomplish the task.

Person B is 100 times faster. (100 vs. 1)

Now, we make them perform a second task. The second task takes them both 50 seconds.

They are equal.

Now we make them do both tasks.

Person a takes 150 seconds (100 + 50) and person B takes 51 seconds (1 + 50).

Now person B is only 3 times faster instead of 100 times faster.

That is what you have. Sure there is a huge difference in the overhead of the first task. But the minute you start adding more tasks that are equal, it soon begins to average out.

Oh, and if the system worked well and if you/the community made a lot of behaviors available, it would be great. I would use it.

I could imagine wanting to add a behavior and just needing to search for on or one similar instead of writing it myself. Or, better yet, browsing the available behaviors and finding ones that would be good in my program, that I would have never thought of.

Ah, I was thinking along that same line of logic TaskMaster but for some reason that solution was eluding me.

I'll blame it on the fact that I was still waking up. :P

The hardest part is not going to be coding the system but instead ironing out which "standards to enforce" and what not to enforce. Obviously, the more that is enforced the easier it will be to optimize code and make things more plug and play in general, but some flexibility will be sacrificed.

Maybe, when do you plan to release it or a demo or something?

Well, I don't want to give a time frame just yet as I need to iron out some design issues before proceeding. The basic framework is there already, I've got it to where you can attach a behavior to an object (or multiple objects) and it all works.

I've got to iron out what guidelines are needed to help make the behaviors "plug'n'play" while retaining as much freedom as possible, and this is what will take a while (along with writing proper documentation.) I'm hoping to have it ready within a month (and maybe some early testing in a week or less) but, no guarantees.

Well, this is still coming along quite nicely. I've spent some time optimizing the code and found that in a simple example where i'm just bouncing 1000 to 2000 sprites around on the screen, the behavior system is only twice as slow as coding it all by hand. And this example is sort of a 'worse case scenario' since the actual functions being called are simple and fast (pretty much only DrawImage), and so the behavior system's overhead is much more noticeable since almost no time is spent in the function calls themselves. Considering the behavior system is looking up all the variables used and functions called from a hashtable, whereas the handcoded version is simply accessing a field in the object, I must say I'm impressed that it's getting 30ms per frame whereas the handcoded version was getting 15. As the function calls become more complex and intensive, the gap should close even more as the overhead of the behavior system will be masked.

Also, I'm going to do some more optimization like writing a custom TList that requires no casting. Anything I can do to save a millisecond here or there.

I've still got to build a default timer behavior (basically just timing code existing ina behavior that can be swapped out if necessary - although it will feature things such as a global elapsed time, paused time variable, and a few other handy things), rewrite the error system a bit to make it even easier to track down stray variable calls or function calls to functions that don't exist, and a few other 'sub-systems'.

This is turning out to be more of a true framework than I originally imagined, but due to the nature of the flexibility of the design, anything can be changed quite simply. It's all modular.

Anyhow, I'll quit rambling about this since I don't really have anything that I can show as a true public demo yet (got to finish up the API first). Just thought I'd bump this for awareness.